2 * Unit test suite for AVI Functions
4 * Copyright 2008 Detlef Riekenberg
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wine/test.h"
31 /* ########################### */
33 static const CHAR winetest0[] = "winetest0";
34 static const CHAR winetest1[] = "winetest1";
35 static const CHAR testfilename[] = "wine_avifil32_test.avi";
37 /* ########################### */
39 static const DWORD deffh[] = /* file_header */
41 FOURCC_RIFF, 0x34c6 /* length */, formtypeAVI,
42 FOURCC_LIST, 0x1ac /* length */,
43 listtypeAVIHEADER, ckidAVIMAINHDR, sizeof(MainAVIHeader),
46 static const MainAVIHeader defmah =
48 0x00008256, /* dwMicroSecPerFrame */
49 0x000080e8, /* dwMaxBytesPerSec */
50 0x00000000, /* dwPaddingGranularity */
51 0x00000910, /* dwFlags */
52 1, /* dwTotalFrames */
53 0, /* dwInitialFrames */
55 0x00100000, /* dwSuggestedBufferSize*/
58 { 0, 0, 0, 0 } /* dwReserved[4] */
61 static const AVIStreamHeader defash0 =
63 streamtypeVIDEO, /* fccType */
64 0x30323449, /* fccHandler */
65 0x00000000, /* dwFlags */
68 0, /* dwInitialFrames */
69 0x000003e9, /* dwScale */
70 0x00007530, /* dwRate */
73 0x00100000, /* dwSuggestedBufferSize*/
74 0xffffffff, /* dwQuality */
76 { 0, 0, 0, 0 } /* short left right top bottom */
79 static const AVIStreamHeader defash1 =
82 streamtypeAUDIO, /* fccType */
87 0, /* dwInitialFrames */
89 0x00002b11, /* dwRate */
91 0x00000665, /* dwLength */
92 0x00003000, /* dwSuggestedBufferSize*/
93 0xffffffff, /* dwQuality */
95 { 0, 0, 0, 0 } /* short left right top bottom */
98 static const PCMWAVEFORMAT defpcmwf =
103 11025, /* nSamplesPerSec */
104 22050, /* nAvgBytesPerSec */
107 8, /* wBitsPerSample */
110 typedef struct common_avi_headers {
111 DWORD fh[sizeof(deffh)];
113 AVIStreamHeader ash0;
114 AVIStreamHeader ash1;
116 } COMMON_AVI_HEADERS;
118 /* Extra data needed to get the VFW API to load the file */
120 /* MainAVIHeader mah */
121 static const DWORD streamlist[] =
123 FOURCC_LIST, 0xd4 /* length */,
124 listtypeSTREAMHEADER, ckidSTREAMHEADER, 0x38 /* length */,
126 /* AVIStreamHeader ash0 */
127 static const DWORD videostreamformat[] =
129 ckidSTREAMFORMAT, 0x28 /* length */,
130 0x00000028, 0x00000008, 0x00000006, 0x00180001,
131 0x30323449, 0x00000090, 0x00000000, 0x00000000,
132 0x00000000, 0x00000000,
134 static const DWORD padding1[] =
136 ckidAVIPADDING, 0xc /* length */,
137 0x00000004, 0x00000000, 0x63643030
139 static const DWORD videopropheader[] =
141 0x70727076, 0x44 /* length */,
142 0x00000000, 0x00000000,
143 0x0000001e, 0x00000008, 0x00000006, 0x00100009,
144 0x00000008, 0x00000006, 0x00000001, 0x00000006,
145 0x00000008, 0x00000006, 0x00000008, 0x00000000,
146 0x00000000, 0x00000000, 0x00000000,
147 FOURCC_LIST, 0x70 /* length */,
148 listtypeSTREAMHEADER, ckidSTREAMHEADER, 0x38 /* length */,
150 /* AVIStreamHeader ash1 */
151 static const DWORD audiostreamformat_pre[] =
153 ckidSTREAMFORMAT, sizeof(PCMWAVEFORMAT) /* length */,
155 /* PCMWAVEFORMAT pcmwf */
156 static DWORD data[] =
158 ckidAVIPADDING, 0xc /* length */,
159 0x00000004, 0x00000000, 0x62773130,
160 ckidAVIPADDING, 0xc /* length */,
161 0x6c6d646f, 0x686c6d64, 0x000000f8,
162 FOURCC_LIST, 0x18 /* length */,
164 0x54465349, 0xc /* length */,
165 0x6676614c, 0x332e3235, 0x00302e37,
166 ckidAVIPADDING, 0x4 /* length */,
168 FOURCC_LIST, 0xd1b /* length */, listtypeAVIMOVIE,
172 /* ########################### */
174 static void test_AVISaveOptions(void)
176 AVICOMPRESSOPTIONS options[2];
177 LPAVICOMPRESSOPTIONS poptions[2];
178 PAVISTREAM streams[2] = {NULL, NULL};
183 poptions[0] = &options[0];
184 poptions[1] = &options[1];
185 ZeroMemory(options, sizeof(options));
187 SetLastError(0xdeadbeef);
188 hres = CreateEditableStream(&streams[0], NULL);
189 ok(hres == AVIERR_OK, "0: got 0x%x and %p (expected AVIERR_OK)\n", hres, streams[0]);
191 SetLastError(0xdeadbeef);
192 hres = CreateEditableStream(&streams[1], NULL);
193 ok(hres == AVIERR_OK, "1: got 0x%x and %p (expected AVIERR_OK)\n", hres, streams[1]);
195 SetLastError(0xdeadbeef);
196 hres = EditStreamSetNameA(streams[0], winetest0);
197 ok(hres == AVIERR_OK, "0: got 0x%x (expected AVIERR_OK)\n", hres);
199 SetLastError(0xdeadbeef);
200 hres = EditStreamSetNameA(streams[1], winetest1);
201 ok(hres == AVIERR_OK, "1: got 0x%x (expected AVIERR_OK)\n", hres);
203 if (winetest_interactive) {
204 SetLastError(0xdeadbeef);
205 res = AVISaveOptions(0, ICMF_CHOOSE_DATARATE |ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_ALLCOMPRESSORS,
206 2, streams, poptions);
207 trace("got %u with 0x%x/%u\n", res, GetLastError(), GetLastError());
210 SetLastError(0xdeadbeef);
211 lres = AVISaveOptionsFree(2, poptions);
212 ok(lres == AVIERR_OK, "got 0x%x with 0x%x/%u\n", lres, GetLastError(), GetLastError());
214 SetLastError(0xdeadbeef);
215 res = AVIStreamRelease(streams[0]);
216 ok(res == 0, "0: got refcount %u (expected 0)\n", res);
218 SetLastError(0xdeadbeef);
219 res = AVIStreamRelease(streams[1]);
220 ok(res == 0, "1: got refcount %u (expected 0)\n", res);
224 /* ########################### */
226 static void test_EditStreamSetInfo(void)
228 PAVISTREAM stream = NULL;
230 AVISTREAMINFO info, info2;
232 hres = CreateEditableStream(&stream, NULL);
233 ok(hres == AVIERR_OK, "got 0x%08X, expected AVIERR_OK\n", hres);
236 if(0) /* Crashing - first parameter not checked */
237 hres = EditStreamSetInfo(NULL, &info, sizeof(AVISTREAMINFO) );
239 /* Size parameter is somehow checked (notice the crash with size=-1 below) */
240 hres = EditStreamSetInfo(stream, NULL, 0);
241 ok( hres == AVIERR_BADSIZE, "got 0x%08X, expected AVIERR_BADSIZE\n", hres);
243 hres = EditStreamSetInfo(stream, NULL, sizeof(AVISTREAMINFO)-1 );
244 ok( hres == AVIERR_BADSIZE, "got 0x%08X, expected AVIERR_BADSIZE\n", hres);
247 { /* Crashing - second parameter not checked */
248 hres = EditStreamSetInfo(stream, NULL, sizeof(AVISTREAMINFO) );
250 hres = EditStreamSetInfo(stream, NULL, -1);
251 ok( hres == AVIERR_BADSIZE, "got 0x%08X, expected AVIERR_BADSIZE\n", hres);
254 hres = AVIStreamInfo(stream, &info, sizeof(AVISTREAMINFO) );
255 ok( hres == 0, "got 0x%08X, expected 0\n", hres);
257 /* Does the function check what's it's updating ? */
259 #define IS_INFO_UPDATED(m) do { \
260 hres = EditStreamSetInfo(stream, &info, sizeof(AVISTREAMINFO) ); \
261 ok( hres == 0, "got 0x%08X, expected 0\n", hres); \
262 hres = AVIStreamInfo(stream, &info2, sizeof(AVISTREAMINFO) ); \
263 ok( hres == 0, "got 0x%08X, expected 0\n", hres); \
264 ok( info2.m == info.m, "EditStreamSetInfo did not update "#m" parameter\n" ); \
268 IS_INFO_UPDATED(dwStart);
270 IS_INFO_UPDATED(dwStart);
273 IS_INFO_UPDATED(wPriority);
275 IS_INFO_UPDATED(wPriority);
278 IS_INFO_UPDATED(wLanguage);
280 IS_INFO_UPDATED(wLanguage);
283 IS_INFO_UPDATED(dwScale);
285 IS_INFO_UPDATED(dwScale);
288 IS_INFO_UPDATED(dwRate);
290 IS_INFO_UPDATED(dwRate);
293 IS_INFO_UPDATED(dwQuality);
295 IS_INFO_UPDATED(dwQuality);
297 IS_INFO_UPDATED(dwQuality);
298 info.dwQuality = ICQUALITY_HIGH+1;
299 IS_INFO_UPDATED(dwQuality);
301 info.rcFrame.left = 0;
302 IS_INFO_UPDATED(rcFrame.left);
303 info.rcFrame.top = 0;
304 IS_INFO_UPDATED(rcFrame.top);
305 info.rcFrame.right = 0;
306 IS_INFO_UPDATED(rcFrame.right);
307 info.rcFrame.bottom = 0;
308 IS_INFO_UPDATED(rcFrame.bottom);
310 info.rcFrame.left = -1;
311 IS_INFO_UPDATED(rcFrame.left);
312 info.rcFrame.top = -1;
313 IS_INFO_UPDATED(rcFrame.top);
314 info.rcFrame.right = -1;
315 IS_INFO_UPDATED(rcFrame.right);
316 info.rcFrame.bottom = -1;
317 IS_INFO_UPDATED(rcFrame.bottom);
318 AVIStreamRelease(stream);
319 #undef IS_INFO_UPDATED
323 static void init_test_struct(COMMON_AVI_HEADERS *cah)
325 memcpy(cah->fh, deffh, sizeof(deffh));
329 cah->pcmwf = defpcmwf;
332 static void create_avi_file(const COMMON_AVI_HEADERS *cah, char *filename)
337 hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
339 ok(hFile != INVALID_HANDLE_VALUE, "Couldn't create file\n");
341 WriteFile(hFile, &cah->fh, sizeof(deffh), &written, NULL);
342 WriteFile(hFile, &cah->mah, sizeof(MainAVIHeader), &written, NULL);
343 WriteFile(hFile, streamlist, sizeof(streamlist), &written, NULL);
344 WriteFile(hFile, &cah->ash0, 0x38, &written, NULL);
345 WriteFile(hFile, videostreamformat, sizeof(videostreamformat), &written, NULL);
346 WriteFile(hFile, padding1, sizeof(padding1), &written, NULL);
347 WriteFile(hFile, videopropheader, sizeof(videopropheader), &written, NULL);
348 WriteFile(hFile, &cah->ash1, 0x38, &written, NULL);
349 WriteFile(hFile, audiostreamformat_pre, sizeof(audiostreamformat_pre), &written, NULL);
350 WriteFile(hFile, &cah->pcmwf, sizeof(PCMWAVEFORMAT), &written, NULL);
351 WriteFile(hFile, data, sizeof(data), &written, NULL);
356 static void test_default_data(void)
358 COMMON_AVI_HEADERS cah;
359 char filename[MAX_PATH];
369 GetTempPath(MAX_PATH, filename);
370 strcpy(filename+strlen(filename), testfilename);
372 init_test_struct(&cah);
373 create_avi_file(&cah, filename);
375 res = AVIFileOpen(&pFile, filename, OF_SHARE_DENY_WRITE, 0L);
376 ok(res != AVIERR_BADFORMAT, "Unable to open file: error1=%u\n", AVIERR_BADFORMAT);
377 ok(res != AVIERR_MEMORY, "Unable to open file: error2=%u\n", AVIERR_MEMORY);
378 ok(res != AVIERR_FILEREAD, "Unable to open file: error3=%u\n", AVIERR_FILEREAD);
379 ok(res != AVIERR_FILEOPEN, "Unable to open file: error4=%u\n", AVIERR_FILEOPEN);
380 ok(res != REGDB_E_CLASSNOTREG, "Unable to open file: error5=%u\n", REGDB_E_CLASSNOTREG);
381 ok(res == 0, "Unable to open file: error=%u\n", res);
383 res = AVIFileGetStream(pFile, &pStream0, 0, 0);
384 ok(res == 0, "Unable to open video stream: error=%u\n", res);
386 res = AVIFileGetStream(pFile, &pStream1, 0, 1);
387 ok(res == 0, "Unable to open audio stream: error=%u\n", res);
389 res = AVIStreamInfo(pStream0, &asi0, sizeof(AVISTREAMINFO));
390 ok(res == 0, "Unable to read stream info: error=%u\n", res);
392 res = AVIStreamInfo(pStream1, &asi1, sizeof(AVISTREAMINFO));
393 ok(res == 0, "Unable to read stream info: error=%u\n", res);
395 res = AVIStreamReadFormat(pStream0, AVIStreamStart(pStream1), NULL, &lSize);
396 ok(res == 0, "Unable to read format size: error=%u\n", res);
398 res = AVIStreamReadFormat(pStream1, AVIStreamStart(pStream1), &wfx, &lSize);
399 ok(res == 0, "Unable to read format: error=%u\n", res);
401 ok(asi0.fccType == streamtypeVIDEO, "got 0x%x (expected streamtypeVIDEO)\n", asi0.fccType);
402 ok(asi0.fccHandler == 0x30323449, "got 0x%x (expected 0x30323449)\n", asi0.fccHandler);
403 ok(asi0.dwFlags == 0, "got %u (expected 0)\n", asi0.dwFlags);
404 ok(asi0.wPriority == 0, "got %u (expected 0)\n", asi0.wPriority);
405 ok(asi0.wLanguage == 0, "got %u (expected 0)\n", asi0.wLanguage);
406 ok(asi0.dwScale == 1001, "got %u (expected 1001)\n", asi0.dwScale);
407 ok(asi0.dwRate == 30000, "got %u (expected 30000)\n", asi0.dwRate);
408 ok(asi0.dwStart == 0, "got %u (expected 0)\n", asi0.dwStart);
409 ok(asi0.dwLength == 1, "got %u (expected 1)\n", asi0.dwLength);
410 ok(asi0.dwInitialFrames == 0, "got %u (expected 0)\n", asi0.dwInitialFrames);
411 ok(asi0.dwSuggestedBufferSize == 0, "got %u (expected 0)\n", asi0.dwSuggestedBufferSize);
412 ok(asi0.dwQuality == 0xffffffff, "got 0x%x (expected 0xffffffff)\n", asi0.dwQuality);
413 ok(asi0.dwSampleSize == 0, "got %u (expected 0)\n", asi0.dwSampleSize);
414 ok(asi0.rcFrame.left == 0, "got %u (expected 0)\n", asi0.rcFrame.left);
415 ok(asi0.rcFrame.top == 0, "got %u (expected 0)\n", asi0.rcFrame.top);
416 ok(asi0.rcFrame.right == 8, "got %u (expected 8)\n", asi0.rcFrame.right); /* these are based on the values in the mah and not */
417 ok(asi0.rcFrame.bottom == 6, "got %u (expected 6)\n", asi0.rcFrame.bottom);/* on the ones in the ash which are 0 here */
418 ok(asi0.dwEditCount == 0, "got %u (expected 0)\n", asi0.dwEditCount);
419 ok(asi0.dwFormatChangeCount == 0, "got %u (expected 0)\n", asi0.dwFormatChangeCount);
421 ok(asi1.fccType == streamtypeAUDIO, "got 0x%x (expected streamtypeVIDEO)\n", asi1.fccType);
422 ok(asi1.fccHandler == 0x1, "got 0x%x (expected 0x1)\n", asi1.fccHandler);
423 ok(asi1.dwFlags == 0, "got %u (expected 0)\n", asi1.dwFlags);
424 ok(asi1.wPriority == 0, "got %u (expected 0)\n", asi1.wPriority);
425 ok(asi1.wLanguage == 0, "got %u (expected 0)\n", asi1.wLanguage);
426 ok(asi1.dwScale == 1, "got %u (expected 1)\n", asi1.dwScale);
427 ok(asi1.dwRate == 11025, "got %u (expected 11025)\n", asi1.dwRate);
428 ok(asi1.dwStart == 0, "got %u (expected 0)\n", asi1.dwStart);
429 ok(asi1.dwLength == 1637, "got %u (expected 1637)\n", asi1.dwLength);
430 ok(asi1.dwInitialFrames == 0, "got %u (expected 0)\n", asi1.dwInitialFrames);
431 ok(asi1.dwSuggestedBufferSize == 0, "got %u (expected 0)\n", asi1.dwSuggestedBufferSize);
432 ok(asi1.dwQuality == 0xffffffff, "got 0x%x (expected 0xffffffff)\n", asi1.dwQuality);
433 ok(asi1.dwSampleSize == 2, "got %u (expected 2)\n", asi1.dwSampleSize);
434 ok(asi1.rcFrame.left == 0, "got %u (expected 0)\n", asi1.rcFrame.left);
435 ok(asi1.rcFrame.top == 0, "got %u (expected 0)\n", asi1.rcFrame.top);
436 ok(asi1.rcFrame.right == 0, "got %u (expected 0)\n", asi1.rcFrame.right);
437 ok(asi1.rcFrame.bottom == 0, "got %u (expected 0)\n", asi1.rcFrame.bottom);
438 ok(asi1.dwEditCount == 0, "got %u (expected 0)\n", asi1.dwEditCount);
439 ok(asi1.dwFormatChangeCount == 0, "got %u (expected 0)\n", asi1.dwFormatChangeCount);
441 ok(wfx.wFormatTag == 1, "got %u (expected 1)\n",wfx.wFormatTag);
442 ok(wfx.nChannels == 2, "got %u (expected 2)\n",wfx.nChannels);
443 ok(wfx.wFormatTag == 1, "got %u (expected 1)\n",wfx.wFormatTag);
444 ok(wfx.nSamplesPerSec == 11025, "got %u (expected 11025)\n",wfx.nSamplesPerSec);
445 ok(wfx.nAvgBytesPerSec == 22050, "got %u (expected 22050)\n",wfx.nAvgBytesPerSec);
446 ok(wfx.nBlockAlign == 2, "got %u (expected 2)\n",wfx.nBlockAlign);
448 AVIStreamRelease(pStream0);
449 AVIStreamRelease(pStream1);
450 AVIFileRelease(pFile);
451 ok(DeleteFile(filename) !=0, "Deleting file %s failed\n", filename);
454 static void test_amh_corruption(void)
456 COMMON_AVI_HEADERS cah;
457 char filename[MAX_PATH];
461 GetTempPath(MAX_PATH, filename);
462 strcpy(filename+strlen(filename), testfilename);
464 /* Make sure only AVI files with the proper headers will be loaded */
465 init_test_struct(&cah);
466 cah.fh[3] = mmioFOURCC('A', 'V', 'i', ' ');
468 create_avi_file(&cah, filename);
469 res = AVIFileOpen(&pFile, filename, OF_SHARE_DENY_WRITE, 0L);
470 ok(res != 0, "Able to open file: error=%u\n", res);
472 ok(DeleteFile(filename) !=0, "Deleting file %s failed\n", filename);
475 static void test_ash1_corruption(void)
477 COMMON_AVI_HEADERS cah;
478 char filename[MAX_PATH];
484 GetTempPath(MAX_PATH, filename);
485 strcpy(filename+strlen(filename), testfilename);
487 /* Corrupt the sample size in the audio stream header */
488 init_test_struct(&cah);
489 cah.ash1.dwSampleSize = 0xdeadbeef;
491 create_avi_file(&cah, filename);
493 res = AVIFileOpen(&pFile, filename, OF_SHARE_DENY_WRITE, 0L);
494 ok(res == 0, "Unable to open file: error=%u\n", res);
496 res = AVIFileGetStream(pFile, &pStream1, 0, 1);
497 ok(res == 0, "Unable to open audio stream: error=%u\n", res);
499 res = AVIStreamInfo(pStream1, &asi1, sizeof(AVISTREAMINFO));
500 ok(res == 0, "Unable to read stream info: error=%u\n", res);
502 /* The result will still be 2, because the value is dynamically replaced with the nBlockAlign
503 value from the stream format header. The next test will prove this */
504 ok(asi1.dwSampleSize == 2, "got %u (expected 2)\n", asi1.dwSampleSize);
506 AVIStreamRelease(pStream1);
507 AVIFileRelease(pFile);
508 ok(DeleteFile(filename) !=0, "Deleting file %s failed\n", filename);
511 static void test_ash1_corruption2(void)
513 COMMON_AVI_HEADERS cah;
514 char filename[MAX_PATH];
520 GetTempPath(MAX_PATH, filename);
521 strcpy(filename+strlen(filename), testfilename);
523 /* Corrupt the block alignment in the audio format header */
524 init_test_struct(&cah);
525 cah.pcmwf.wf.nBlockAlign = 0xdead;
527 create_avi_file(&cah, filename);
529 res = AVIFileOpen(&pFile, filename, OF_SHARE_DENY_WRITE, 0L);
530 ok(res == 0, "Unable to open file: error=%u\n", res);
532 res = AVIFileGetStream(pFile, &pStream1, 0, 1);
533 ok(res == 0, "Unable to open audio stream: error=%u\n", res);
535 ok(AVIStreamInfo(pStream1, &asi1, sizeof(AVISTREAMINFO)) == 0, "Unable to read stream info\n");
537 /* The result will also be the corrupt value, as explained above. */
538 ok(asi1.dwSampleSize == 0xdead, "got 0x%x (expected 0xdead)\n", asi1.dwSampleSize);
540 AVIStreamRelease(pStream1);
541 AVIFileRelease(pFile);
542 ok(DeleteFile(filename) !=0, "Deleting file %s failed\n", filename);
545 /* ########################### */
551 test_EditStreamSetInfo();
552 test_AVISaveOptions();
554 test_amh_corruption();
555 test_ash1_corruption();
556 test_ash1_corruption2();