1 /* 2 * Unit test suite for AVI Functions 3 * 4 * Copyright 2008 Detlef Riekenberg 5 * 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. 10 * 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. 15 * 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 19 * 20 */ 21 22 #define COBJMACROS 23 #define CONST_VTABLE 24 25 #include "wine/test.h" 26 #include "initguid.h" 27 #include "wingdi.h" 28 #include "vfw.h" 29 30 /* ########################### */ 31 32 DEFINE_AVIGUID(CLSID_WAVFile, 0x00020003, 0, 0); 33 static const CHAR winetest0[] = "winetest0"; 34 static const CHAR winetest1[] = "winetest1"; 35 static const CHAR testfilename[] = "wine_avifil32_test.avi"; 36 37 /* ########################### */ 38 39 static const DWORD deffh[] = /* file_header */ 40 { 41 FOURCC_RIFF, 0x34c6 /* length */, formtypeAVI, 42 FOURCC_LIST, 0x1ac /* length */, 43 listtypeAVIHEADER, ckidAVIMAINHDR, sizeof(MainAVIHeader), 44 }; 45 46 static const MainAVIHeader defmah = 47 { 48 0x00008256, /* dwMicroSecPerFrame */ 49 0x000080e8, /* dwMaxBytesPerSec */ 50 0x00000000, /* dwPaddingGranularity */ 51 0x00000910, /* dwFlags */ 52 1, /* dwTotalFrames */ 53 0, /* dwInitialFrames */ 54 2, /* dwStreams */ 55 0x00100000, /* dwSuggestedBufferSize*/ 56 8, /* dwWidth */ 57 6, /* dwHeight */ 58 { 0, 0, 0, 0 } /* dwReserved[4] */ 59 }; 60 61 static const AVIStreamHeader defash0 = 62 { 63 streamtypeVIDEO, /* fccType */ 64 0x30323449, /* fccHandler */ 65 0x00000000, /* dwFlags */ 66 0, /* wPriority */ 67 0, /* wLanguage */ 68 0, /* dwInitialFrames */ 69 0x000003e9, /* dwScale */ 70 0x00007530, /* dwRate */ 71 0, /* dwStart */ 72 1, /* dwLength */ 73 0x00100000, /* dwSuggestedBufferSize*/ 74 0xffffffff, /* dwQuality */ 75 0, /* dwSampleSize */ 76 { 0, 0, 0, 0 } /* short left right top bottom */ 77 }; 78 79 static const AVIStreamHeader defash1 = 80 { 81 /* AVIStreamHeader */ 82 streamtypeAUDIO, /* fccType */ 83 1, /* fccHandler */ 84 0, /* dwFlags */ 85 0, /* wPriority */ 86 0, /* wLanguage */ 87 0, /* dwInitialFrames */ 88 1, /* dwScale */ 89 0x00002b11, /* dwRate */ 90 0, /* dwStart */ 91 0x00000665, /* dwLength */ 92 0x00003000, /* dwSuggestedBufferSize*/ 93 0xffffffff, /* dwQuality */ 94 2, /* dwSampleSize */ 95 { 0, 0, 0, 0 } /* short left right top bottom */ 96 }; 97 98 static const PCMWAVEFORMAT defpcmwf = 99 { 100 { 101 1, /* wFormatTag */ 102 2, /* nChannels */ 103 11025, /* nSamplesPerSec */ 104 22050, /* nAvgBytesPerSec */ 105 2, /* nBlockAlign */ 106 }, 107 8, /* wBitsPerSample */ 108 }; 109 110 typedef struct common_avi_headers { 111 DWORD fh[sizeof(deffh)]; 112 MainAVIHeader mah; 113 AVIStreamHeader ash0; 114 AVIStreamHeader ash1; 115 PCMWAVEFORMAT pcmwf; 116 } COMMON_AVI_HEADERS; 117 118 /* Extra data needed to get the VFW API to load the file */ 119 /* DWORD deffh */ 120 /* MainAVIHeader mah */ 121 static const DWORD streamlist[] = 122 { 123 FOURCC_LIST, 0xd4 /* length */, 124 listtypeSTREAMHEADER, ckidSTREAMHEADER, 0x38 /* length */, 125 }; 126 /* AVIStreamHeader ash0 */ 127 static const DWORD videostreamformat[] = 128 { 129 ckidSTREAMFORMAT, 0x28 /* length */, 130 0x00000028, 0x00000008, 0x00000006, 0x00180001, 131 0x30323449, 0x00000090, 0x00000000, 0x00000000, 132 0x00000000, 0x00000000, 133 }; 134 static const DWORD padding1[] = 135 { 136 ckidAVIPADDING, 0xc /* length */, 137 0x00000004, 0x00000000, 0x63643030 138 }; 139 static const DWORD videopropheader[] = 140 { 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 */, 149 }; 150 /* AVIStreamHeader ash1 */ 151 static const DWORD audiostreamformat_pre[] = 152 { 153 ckidSTREAMFORMAT, sizeof(PCMWAVEFORMAT) /* length */, 154 }; 155 /* PCMWAVEFORMAT pcmwf */ 156 static DWORD data[] = 157 { 158 ckidAVIPADDING, 0xc /* length */, 159 0x00000004, 0x00000000, 0x62773130, 160 ckidAVIPADDING, 0xc /* length */, 161 0x6c6d646f, 0x686c6d64, 0x000000f8, 162 FOURCC_LIST, 0x18 /* length */, 163 0x4f464e49, 164 0x54465349, 0xc /* length */, 165 0x6676614c, 0x332e3235, 0x00302e37, 166 ckidAVIPADDING, 0x4 /* length */, 167 0, 168 FOURCC_LIST, 0xd1b /* length */, listtypeAVIMOVIE, 169 0, 0 170 }; 171 172 /* ########################### */ 173 174 static void test_AVISaveOptions(void) 175 { 176 AVICOMPRESSOPTIONS options[2]; 177 LPAVICOMPRESSOPTIONS poptions[2]; 178 PAVISTREAM streams[2] = {NULL, NULL}; 179 HRESULT hres; 180 DWORD res; 181 LONG lres; 182 183 poptions[0] = &options[0]; 184 poptions[1] = &options[1]; 185 ZeroMemory(options, sizeof(options)); 186 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]); 190 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]); 194 195 SetLastError(0xdeadbeef); 196 hres = EditStreamSetNameA(streams[0], winetest0); 197 ok(hres == AVIERR_OK, "0: got 0x%x (expected AVIERR_OK)\n", hres); 198 199 SetLastError(0xdeadbeef); 200 hres = EditStreamSetNameA(streams[1], winetest1); 201 ok(hres == AVIERR_OK, "1: got 0x%x (expected AVIERR_OK)\n", hres); 202 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()); 208 } 209 210 SetLastError(0xdeadbeef); 211 lres = AVISaveOptionsFree(2, poptions); 212 ok(lres == AVIERR_OK, "got 0x%x with 0x%x/%u\n", lres, GetLastError(), GetLastError()); 213 214 SetLastError(0xdeadbeef); 215 res = AVIStreamRelease(streams[0]); 216 ok(res == 0, "0: got refcount %u (expected 0)\n", res); 217 218 SetLastError(0xdeadbeef); 219 res = AVIStreamRelease(streams[1]); 220 ok(res == 0, "1: got refcount %u (expected 0)\n", res); 221 222 } 223 224 /* ########################### */ 225 226 static void test_EditStreamSetInfo(void) 227 { 228 PAVISTREAM stream = NULL; 229 HRESULT hres; 230 AVISTREAMINFOA info, info2; 231 232 hres = CreateEditableStream(&stream, NULL); 233 ok(hres == AVIERR_OK, "got 0x%08X, expected AVIERR_OK\n", hres); 234 235 /* Size parameter is somehow checked (notice the crash with size=-1 below) */ 236 hres = EditStreamSetInfoA(stream, NULL, 0); 237 ok( hres == AVIERR_BADSIZE, "got 0x%08X, expected AVIERR_BADSIZE\n", hres); 238 239 hres = EditStreamSetInfoA(stream, NULL, sizeof(AVISTREAMINFOA)-1 ); 240 ok( hres == AVIERR_BADSIZE, "got 0x%08X, expected AVIERR_BADSIZE\n", hres); 241 242 if(0) 243 { 244 /* Crashing - first parameter not checked */ 245 EditStreamSetInfoA(NULL, &info, sizeof(info) ); 246 247 /* Crashing - second parameter not checked */ 248 EditStreamSetInfoA(stream, NULL, sizeof(AVISTREAMINFOA) ); 249 250 EditStreamSetInfoA(stream, NULL, -1); 251 } 252 253 hres = AVIStreamInfoA(stream, &info, sizeof(info) ); 254 ok( hres == 0, "got 0x%08X, expected 0\n", hres); 255 256 /* Does the function check what's it's updating ? */ 257 258 #define IS_INFO_UPDATED(m) do { \ 259 hres = EditStreamSetInfoA(stream, &info, sizeof(info) ); \ 260 ok( hres == 0, "got 0x%08X, expected 0\n", hres); \ 261 hres = AVIStreamInfoA(stream, &info2, sizeof(info2) ); \ 262 ok( hres == 0, "got 0x%08X, expected 0\n", hres); \ 263 ok( info2.m == info.m, "EditStreamSetInfo did not update "#m" parameter\n" ); \ 264 } while(0) 265 266 info.dwStart++; 267 IS_INFO_UPDATED(dwStart); 268 info.dwStart = 0; 269 IS_INFO_UPDATED(dwStart); 270 271 info.wPriority++; 272 IS_INFO_UPDATED(wPriority); 273 info.wPriority = 0; 274 IS_INFO_UPDATED(wPriority); 275 276 info.wLanguage++; 277 IS_INFO_UPDATED(wLanguage); 278 info.wLanguage = 0; 279 IS_INFO_UPDATED(wLanguage); 280 281 info.dwScale++; 282 IS_INFO_UPDATED(dwScale); 283 info.dwScale = 0; 284 IS_INFO_UPDATED(dwScale); 285 286 info.dwRate++; 287 IS_INFO_UPDATED(dwRate); 288 info.dwRate = 0; 289 IS_INFO_UPDATED(dwRate); 290 291 info.dwQuality++; 292 IS_INFO_UPDATED(dwQuality); 293 info.dwQuality = 0; 294 IS_INFO_UPDATED(dwQuality); 295 info.dwQuality = -2; 296 IS_INFO_UPDATED(dwQuality); 297 info.dwQuality = ICQUALITY_HIGH+1; 298 IS_INFO_UPDATED(dwQuality); 299 300 info.rcFrame.left = 0; 301 IS_INFO_UPDATED(rcFrame.left); 302 info.rcFrame.top = 0; 303 IS_INFO_UPDATED(rcFrame.top); 304 info.rcFrame.right = 0; 305 IS_INFO_UPDATED(rcFrame.right); 306 info.rcFrame.bottom = 0; 307 IS_INFO_UPDATED(rcFrame.bottom); 308 309 info.rcFrame.left = -1; 310 IS_INFO_UPDATED(rcFrame.left); 311 info.rcFrame.top = -1; 312 IS_INFO_UPDATED(rcFrame.top); 313 info.rcFrame.right = -1; 314 IS_INFO_UPDATED(rcFrame.right); 315 info.rcFrame.bottom = -1; 316 IS_INFO_UPDATED(rcFrame.bottom); 317 AVIStreamRelease(stream); 318 #undef IS_INFO_UPDATED 319 } 320 321 322 static void init_test_struct(COMMON_AVI_HEADERS *cah) 323 { 324 memcpy(cah->fh, deffh, sizeof(deffh)); 325 cah->mah = defmah; 326 cah->ash0 = defash0; 327 cah->ash1 = defash1; 328 cah->pcmwf = defpcmwf; 329 } 330 331 static void create_avi_file(const COMMON_AVI_HEADERS *cah, char *filename) 332 { 333 HANDLE hFile; 334 DWORD written; 335 336 hFile = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 337 338 ok(hFile != INVALID_HANDLE_VALUE, "Couldn't create file\n"); 339 340 WriteFile(hFile, &cah->fh, sizeof(deffh), &written, NULL); 341 WriteFile(hFile, &cah->mah, sizeof(MainAVIHeader), &written, NULL); 342 WriteFile(hFile, streamlist, sizeof(streamlist), &written, NULL); 343 WriteFile(hFile, &cah->ash0, 0x38, &written, NULL); 344 WriteFile(hFile, videostreamformat, sizeof(videostreamformat), &written, NULL); 345 WriteFile(hFile, padding1, sizeof(padding1), &written, NULL); 346 WriteFile(hFile, videopropheader, sizeof(videopropheader), &written, NULL); 347 WriteFile(hFile, &cah->ash1, 0x38, &written, NULL); 348 WriteFile(hFile, audiostreamformat_pre, sizeof(audiostreamformat_pre), &written, NULL); 349 WriteFile(hFile, &cah->pcmwf, sizeof(PCMWAVEFORMAT), &written, NULL); 350 WriteFile(hFile, data, sizeof(data), &written, NULL); 351 352 CloseHandle(hFile); 353 } 354 355 static void test_default_data(void) 356 { 357 COMMON_AVI_HEADERS cah; 358 char filename[MAX_PATH]; 359 PAVIFILE pFile; 360 int res; 361 LONG lSize; 362 PAVISTREAM pStream0; 363 PAVISTREAM pStream1; 364 AVISTREAMINFOA asi0, asi1; 365 WAVEFORMATEX wfx; 366 367 GetTempPathA(MAX_PATH, filename); 368 strcpy(filename+strlen(filename), testfilename); 369 370 init_test_struct(&cah); 371 create_avi_file(&cah, filename); 372 373 res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L); 374 ok(res == 0, "Unable to open file: error=%u\n", res); 375 376 pStream0 = (void *)0xdeadbeef; 377 res = AVIFileGetStream(pFile, &pStream0, ~0U, 0); 378 ok(res == AVIERR_NODATA, "expected AVIERR_NODATA, got %u\n", res); 379 ok(pStream0 == NULL, "AVIFileGetStream should set stream to NULL\n"); 380 381 res = AVIFileGetStream(pFile, &pStream0, 0, 0); 382 ok(res == 0, "Unable to open video stream: error=%u\n", res); 383 384 res = AVIFileGetStream(pFile, &pStream1, 0, 1); 385 ok(res == 0, "Unable to open audio stream: error=%u\n", res); 386 387 res = AVIStreamInfoA(pStream0, &asi0, sizeof(asi0)); 388 ok(res == 0, "Unable to read stream info: error=%u\n", res); 389 390 res = AVIStreamInfoA(pStream1, &asi1, sizeof(asi1)); 391 ok(res == 0, "Unable to read stream info: error=%u\n", res); 392 393 res = AVIStreamReadFormat(pStream0, AVIStreamStart(pStream1), NULL, &lSize); 394 ok(res == 0, "Unable to read format size: error=%u\n", res); 395 396 res = AVIStreamReadFormat(pStream1, AVIStreamStart(pStream1), &wfx, &lSize); 397 ok(res == 0, "Unable to read format: error=%u\n", res); 398 399 ok(asi0.fccType == streamtypeVIDEO, "got 0x%x (expected streamtypeVIDEO)\n", asi0.fccType); 400 ok(asi0.fccHandler == 0x30323449, "got 0x%x (expected 0x30323449)\n", asi0.fccHandler); 401 ok(asi0.dwFlags == 0, "got %u (expected 0)\n", asi0.dwFlags); 402 ok(asi0.wPriority == 0, "got %u (expected 0)\n", asi0.wPriority); 403 ok(asi0.wLanguage == 0, "got %u (expected 0)\n", asi0.wLanguage); 404 ok(asi0.dwScale == 1001, "got %u (expected 1001)\n", asi0.dwScale); 405 ok(asi0.dwRate == 30000, "got %u (expected 30000)\n", asi0.dwRate); 406 ok(asi0.dwStart == 0, "got %u (expected 0)\n", asi0.dwStart); 407 ok(asi0.dwLength == 1, "got %u (expected 1)\n", asi0.dwLength); 408 ok(asi0.dwInitialFrames == 0, "got %u (expected 0)\n", asi0.dwInitialFrames); 409 ok(asi0.dwSuggestedBufferSize == 0, "got %u (expected 0)\n", asi0.dwSuggestedBufferSize); 410 ok(asi0.dwQuality == 0xffffffff, "got 0x%x (expected 0xffffffff)\n", asi0.dwQuality); 411 ok(asi0.dwSampleSize == 0, "got %u (expected 0)\n", asi0.dwSampleSize); 412 ok(asi0.rcFrame.left == 0, "got %u (expected 0)\n", asi0.rcFrame.left); 413 ok(asi0.rcFrame.top == 0, "got %u (expected 0)\n", asi0.rcFrame.top); 414 ok(asi0.rcFrame.right == 8, "got %u (expected 8)\n", asi0.rcFrame.right); /* these are based on the values in the mah and not */ 415 ok(asi0.rcFrame.bottom == 6, "got %u (expected 6)\n", asi0.rcFrame.bottom);/* on the ones in the ash which are 0 here */ 416 ok(asi0.dwEditCount == 0, "got %u (expected 0)\n", asi0.dwEditCount); 417 ok(asi0.dwFormatChangeCount == 0, "got %u (expected 0)\n", asi0.dwFormatChangeCount); 418 419 ok(asi1.fccType == streamtypeAUDIO, "got 0x%x (expected streamtypeVIDEO)\n", asi1.fccType); 420 ok(asi1.fccHandler == 0x1, "got 0x%x (expected 0x1)\n", asi1.fccHandler); 421 ok(asi1.dwFlags == 0, "got %u (expected 0)\n", asi1.dwFlags); 422 ok(asi1.wPriority == 0, "got %u (expected 0)\n", asi1.wPriority); 423 ok(asi1.wLanguage == 0, "got %u (expected 0)\n", asi1.wLanguage); 424 ok(asi1.dwScale == 1, "got %u (expected 1)\n", asi1.dwScale); 425 ok(asi1.dwRate == 11025, "got %u (expected 11025)\n", asi1.dwRate); 426 ok(asi1.dwStart == 0, "got %u (expected 0)\n", asi1.dwStart); 427 ok(asi1.dwLength == 1637, "got %u (expected 1637)\n", asi1.dwLength); 428 ok(asi1.dwInitialFrames == 0, "got %u (expected 0)\n", asi1.dwInitialFrames); 429 ok(asi1.dwSuggestedBufferSize == 0, "got %u (expected 0)\n", asi1.dwSuggestedBufferSize); 430 ok(asi1.dwQuality == 0xffffffff, "got 0x%x (expected 0xffffffff)\n", asi1.dwQuality); 431 ok(asi1.dwSampleSize == 2, "got %u (expected 2)\n", asi1.dwSampleSize); 432 ok(asi1.rcFrame.left == 0, "got %u (expected 0)\n", asi1.rcFrame.left); 433 ok(asi1.rcFrame.top == 0, "got %u (expected 0)\n", asi1.rcFrame.top); 434 ok(asi1.rcFrame.right == 0, "got %u (expected 0)\n", asi1.rcFrame.right); 435 ok(asi1.rcFrame.bottom == 0, "got %u (expected 0)\n", asi1.rcFrame.bottom); 436 ok(asi1.dwEditCount == 0, "got %u (expected 0)\n", asi1.dwEditCount); 437 ok(asi1.dwFormatChangeCount == 0, "got %u (expected 0)\n", asi1.dwFormatChangeCount); 438 439 ok(wfx.wFormatTag == 1, "got %u (expected 1)\n",wfx.wFormatTag); 440 ok(wfx.nChannels == 2, "got %u (expected 2)\n",wfx.nChannels); 441 ok(wfx.wFormatTag == 1, "got %u (expected 1)\n",wfx.wFormatTag); 442 ok(wfx.nSamplesPerSec == 11025, "got %u (expected 11025)\n",wfx.nSamplesPerSec); 443 ok(wfx.nAvgBytesPerSec == 22050, "got %u (expected 22050)\n",wfx.nAvgBytesPerSec); 444 ok(wfx.nBlockAlign == 2, "got %u (expected 2)\n",wfx.nBlockAlign); 445 446 AVIStreamRelease(pStream0); 447 AVIStreamRelease(pStream1); 448 AVIFileRelease(pFile); 449 ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename); 450 } 451 452 static void test_amh_corruption(void) 453 { 454 COMMON_AVI_HEADERS cah; 455 char filename[MAX_PATH]; 456 PAVIFILE pFile; 457 int res; 458 459 GetTempPathA(MAX_PATH, filename); 460 strcpy(filename+strlen(filename), testfilename); 461 462 /* Make sure only AVI files with the proper headers will be loaded */ 463 init_test_struct(&cah); 464 cah.fh[3] = mmioFOURCC('A', 'V', 'i', ' '); 465 466 create_avi_file(&cah, filename); 467 res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L); 468 ok(res != 0, "Able to open file: error=%u\n", res); 469 470 ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename); 471 } 472 473 static void test_ash1_corruption(void) 474 { 475 COMMON_AVI_HEADERS cah; 476 char filename[MAX_PATH]; 477 PAVIFILE pFile; 478 int res; 479 PAVISTREAM pStream1; 480 AVISTREAMINFOA asi1; 481 482 GetTempPathA(MAX_PATH, filename); 483 strcpy(filename+strlen(filename), testfilename); 484 485 /* Corrupt the sample size in the audio stream header */ 486 init_test_struct(&cah); 487 cah.ash1.dwSampleSize = 0xdeadbeef; 488 489 create_avi_file(&cah, filename); 490 491 res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L); 492 ok(res == 0, "Unable to open file: error=%u\n", res); 493 494 res = AVIFileGetStream(pFile, &pStream1, 0, 1); 495 ok(res == 0, "Unable to open audio stream: error=%u\n", res); 496 497 res = AVIStreamInfoA(pStream1, &asi1, sizeof(asi1)); 498 ok(res == 0, "Unable to read stream info: error=%u\n", res); 499 500 /* The result will still be 2, because the value is dynamically replaced with the nBlockAlign 501 value from the stream format header. The next test will prove this */ 502 ok(asi1.dwSampleSize == 2, "got %u (expected 2)\n", asi1.dwSampleSize); 503 504 AVIStreamRelease(pStream1); 505 AVIFileRelease(pFile); 506 ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename); 507 } 508 509 static void test_ash1_corruption2(void) 510 { 511 COMMON_AVI_HEADERS cah; 512 char filename[MAX_PATH]; 513 PAVIFILE pFile; 514 int res; 515 PAVISTREAM pStream1; 516 AVISTREAMINFOA asi1; 517 518 GetTempPathA(MAX_PATH, filename); 519 strcpy(filename+strlen(filename), testfilename); 520 521 /* Corrupt the block alignment in the audio format header */ 522 init_test_struct(&cah); 523 cah.pcmwf.wf.nBlockAlign = 0xdead; 524 525 create_avi_file(&cah, filename); 526 527 res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L); 528 ok(res == 0, "Unable to open file: error=%u\n", res); 529 530 res = AVIFileGetStream(pFile, &pStream1, 0, 1); 531 ok(res == 0, "Unable to open audio stream: error=%u\n", res); 532 533 ok(AVIStreamInfoA(pStream1, &asi1, sizeof(asi1)) == 0, "Unable to read stream info\n"); 534 535 /* The result will also be the corrupt value, as explained above. */ 536 ok(asi1.dwSampleSize == 0xdead, "got 0x%x (expected 0xdead)\n", asi1.dwSampleSize); 537 538 AVIStreamRelease(pStream1); 539 AVIFileRelease(pFile); 540 ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename); 541 } 542 543 /* Outer IUnknown for COM aggregation tests */ 544 struct unk_impl { 545 IUnknown IUnknown_iface; 546 LONG ref; 547 IUnknown *inner_unk; 548 }; 549 550 static inline struct unk_impl *impl_from_IUnknown(IUnknown *iface) 551 { 552 return CONTAINING_RECORD(iface, struct unk_impl, IUnknown_iface); 553 } 554 555 static HRESULT WINAPI unk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 556 { 557 struct unk_impl *This = impl_from_IUnknown(iface); 558 LONG ref = This->ref; 559 HRESULT hr; 560 561 if (IsEqualGUID(riid, &IID_IUnknown)) 562 { 563 *ppv = iface; 564 IUnknown_AddRef(iface); 565 return S_OK; 566 } 567 568 hr = IUnknown_QueryInterface(This->inner_unk, riid, ppv); 569 if (hr == S_OK) 570 { 571 trace("Working around COM aggregation ref counting bug\n"); 572 ok(ref == This->ref, "Outer ref count expected %d got %d\n", ref, This->ref); 573 IUnknown_AddRef((IUnknown*)*ppv); 574 ref = IUnknown_Release(This->inner_unk); 575 ok(ref == 1, "Inner ref count expected 1 got %d\n", ref); 576 } 577 578 return hr; 579 } 580 581 static ULONG WINAPI unk_AddRef(IUnknown *iface) 582 { 583 struct unk_impl *This = impl_from_IUnknown(iface); 584 585 return InterlockedIncrement(&This->ref); 586 } 587 588 static ULONG WINAPI unk_Release(IUnknown *iface) 589 { 590 struct unk_impl *This = impl_from_IUnknown(iface); 591 592 return InterlockedDecrement(&This->ref); 593 } 594 595 static const IUnknownVtbl unk_vtbl = 596 { 597 unk_QueryInterface, 598 unk_AddRef, 599 unk_Release 600 }; 601 602 static void test_COM(void) 603 { 604 struct unk_impl unk_obj = {{&unk_vtbl}, 19, NULL}; 605 IAVIFile *avif = NULL; 606 IPersistFile *pf; 607 IUnknown *unk; 608 LONG refcount; 609 HRESULT hr; 610 611 /* COM aggregation */ 612 hr = CoCreateInstance(&CLSID_AVIFile, &unk_obj.IUnknown_iface, CLSCTX_INPROC_SERVER, 613 &IID_IUnknown, (void**)&unk_obj.inner_unk); 614 ok(hr == S_OK, "COM aggregation failed: %08x, expected S_OK\n", hr); 615 hr = IUnknown_QueryInterface(&unk_obj.IUnknown_iface, &IID_IAVIFile, (void**)&avif); 616 ok(hr == S_OK, "QueryInterface for IID_IAVIFile failed: %08x\n", hr); 617 refcount = IAVIFile_AddRef(avif); 618 ok(refcount == unk_obj.ref, "AVIFile just pretends to support COM aggregation\n"); 619 refcount = IAVIFile_Release(avif); 620 ok(refcount == unk_obj.ref, "AVIFile just pretends to support COM aggregation\n"); 621 hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf); 622 ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08x\n", hr); 623 refcount = IPersistFile_Release(pf); 624 ok(refcount == unk_obj.ref, "AVIFile just pretends to support COM aggregation\n"); 625 refcount = IAVIFile_Release(avif); 626 ok(refcount == 19, "Outer ref count should be back at 19 but is %d\n", refcount); 627 refcount = IUnknown_Release(unk_obj.inner_unk); 628 ok(refcount == 0, "Inner ref count should be 0 but is %u\n", refcount); 629 630 /* Invalid RIID */ 631 hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIStream, 632 (void**)&avif); 633 ok(hr == E_NOINTERFACE, "AVIFile create failed: %08x, expected E_NOINTERFACE\n", hr); 634 635 /* Same refcount */ 636 hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIFile, (void**)&avif); 637 ok(hr == S_OK, "AVIFile create failed: %08x, expected S_OK\n", hr); 638 refcount = IAVIFile_AddRef(avif); 639 ok(refcount == 2, "refcount == %u, expected 2\n", refcount); 640 hr = IAVIFile_QueryInterface(avif, &IID_IUnknown, (void**)&unk); 641 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr); 642 refcount = IUnknown_AddRef(unk); 643 ok(refcount == 4, "refcount == %u, expected 4\n", refcount); 644 hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf); 645 ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08x\n", hr); 646 refcount = IPersistFile_AddRef(pf); 647 ok(refcount == 6, "refcount == %u, expected 6\n", refcount); 648 649 while (IAVIFile_Release(avif)); 650 } 651 652 static void test_COM_wavfile(void) 653 { 654 struct unk_impl unk_obj = {{&unk_vtbl}, 19, NULL}; 655 IAVIFile *avif = NULL; 656 IPersistFile *pf; 657 IAVIStream *avis; 658 IUnknown *unk; 659 ULONG refcount; 660 HRESULT hr; 661 662 /* COM aggregation */ 663 hr = CoCreateInstance(&CLSID_WAVFile, &unk_obj.IUnknown_iface, CLSCTX_INPROC_SERVER, 664 &IID_IUnknown, (void**)&unk_obj.inner_unk); 665 ok(hr == S_OK, "COM aggregation failed: %08x, expected S_OK\n", hr); 666 hr = IUnknown_QueryInterface(&unk_obj.IUnknown_iface, &IID_IAVIFile, (void**)&avif); 667 ok(hr == S_OK, "QueryInterface for IID_IAVIFile failed: %08x\n", hr); 668 refcount = IAVIFile_AddRef(avif); 669 ok(refcount == unk_obj.ref, "WAVFile just pretends to support COM aggregation\n"); 670 refcount = IAVIFile_Release(avif); 671 ok(refcount == unk_obj.ref, "WAVFile just pretends to support COM aggregation\n"); 672 hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf); 673 ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08x\n", hr); 674 refcount = IPersistFile_Release(pf); 675 ok(refcount == unk_obj.ref, "WAVFile just pretends to support COM aggregation\n"); 676 refcount = IAVIFile_Release(avif); 677 ok(refcount == 19, "Outer ref count should be back at 19 but is %d\n", refcount); 678 refcount = IUnknown_Release(unk_obj.inner_unk); 679 ok(refcount == 0, "Inner ref count should be 0 but is %u\n", refcount); 680 681 /* Invalid RIID */ 682 hr = CoCreateInstance(&CLSID_WAVFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIStreaming, 683 (void**)&avif); 684 ok(hr == E_NOINTERFACE, "WAVFile create failed: %08x, expected E_NOINTERFACE\n", hr); 685 686 /* Same refcount for all WAVFile interfaces */ 687 hr = CoCreateInstance(&CLSID_WAVFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIFile, (void**)&avif); 688 ok(hr == S_OK, "WAVFile create failed: %08x, expected S_OK\n", hr); 689 refcount = IAVIFile_AddRef(avif); 690 ok(refcount == 2, "refcount == %u, expected 2\n", refcount); 691 692 hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf); 693 ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08x\n", hr); 694 refcount = IPersistFile_AddRef(pf); 695 ok(refcount == 4, "refcount == %u, expected 4\n", refcount); 696 refcount = IPersistFile_Release(pf); 697 698 hr = IAVIFile_QueryInterface(avif, &IID_IAVIStream, (void**)&avis); 699 ok(hr == S_OK, "QueryInterface for IID_IAVIStream failed: %08x\n", hr); 700 refcount = IAVIStream_AddRef(avis); 701 ok(refcount == 5, "refcount == %u, expected 5\n", refcount); 702 refcount = IAVIStream_Release(avis); 703 704 hr = IAVIFile_QueryInterface(avif, &IID_IUnknown, (void**)&unk); 705 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr); 706 refcount = IUnknown_AddRef(unk); 707 ok(refcount == 6, "refcount == %u, expected 6\n", refcount); 708 refcount = IUnknown_Release(unk); 709 710 while (IAVIFile_Release(avif)); 711 } 712 713 static void test_COM_editstream(void) 714 { 715 IAVIEditStream *edit; 716 IAVIStream *stream; 717 IUnknown *unk; 718 ULONG refcount; 719 HRESULT hr; 720 721 /* Same refcount for all AVIEditStream interfaces */ 722 hr = CreateEditableStream(&stream, NULL); 723 ok(hr == S_OK, "AVIEditStream create failed: %08x, expected S_OK\n", hr); 724 refcount = IAVIStream_AddRef(stream); 725 ok(refcount == 2, "refcount == %u, expected 2\n", refcount); 726 727 hr = IAVIStream_QueryInterface(stream, &IID_IAVIEditStream, (void**)&edit); 728 ok(hr == S_OK, "QueryInterface for IID_IAVIEditStream failed: %08x\n", hr); 729 refcount = IAVIEditStream_AddRef(edit); 730 ok(refcount == 4, "refcount == %u, expected 4\n", refcount); 731 refcount = IAVIEditStream_Release(edit); 732 733 hr = IAVIEditStream_QueryInterface(edit, &IID_IUnknown, (void**)&unk); 734 ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr); 735 refcount = IUnknown_AddRef(unk); 736 ok(refcount == 5, "refcount == %u, expected 5\n", refcount); 737 IUnknown_Release(unk); 738 739 while (IAVIEditStream_Release(edit)); 740 } 741 742 START_TEST(api) 743 { 744 745 AVIFileInit(); 746 test_EditStreamSetInfo(); 747 test_AVISaveOptions(); 748 test_default_data(); 749 test_amh_corruption(); 750 test_ash1_corruption(); 751 test_ash1_corruption2(); 752 test_COM(); 753 test_COM_wavfile(); 754 test_COM_editstream(); 755 AVIFileExit(); 756 757 } 758