| /* |
| * Unit test suite for AVI Functions |
| * |
| * Copyright 2008 Detlef Riekenberg |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| * |
| */ |
| |
| #define COBJMACROS |
| #define CONST_VTABLE |
| |
| #include "wine/test.h" |
| #include "initguid.h" |
| #include "wingdi.h" |
| #include "vfw.h" |
| |
| /* ########################### */ |
| |
| DEFINE_AVIGUID(CLSID_WAVFile, 0x00020003, 0, 0); |
| static const CHAR winetest0[] = "winetest0"; |
| static const CHAR winetest1[] = "winetest1"; |
| static const CHAR testfilename[] = "wine_avifil32_test.avi"; |
| |
| /* ########################### */ |
| |
| static const DWORD deffh[] = /* file_header */ |
| { |
| FOURCC_RIFF, 0x34c6 /* length */, formtypeAVI, |
| FOURCC_LIST, 0x1ac /* length */, |
| listtypeAVIHEADER, ckidAVIMAINHDR, sizeof(MainAVIHeader), |
| }; |
| |
| static const MainAVIHeader defmah = |
| { |
| 0x00008256, /* dwMicroSecPerFrame */ |
| 0x000080e8, /* dwMaxBytesPerSec */ |
| 0x00000000, /* dwPaddingGranularity */ |
| 0x00000910, /* dwFlags */ |
| 1, /* dwTotalFrames */ |
| 0, /* dwInitialFrames */ |
| 2, /* dwStreams */ |
| 0x00100000, /* dwSuggestedBufferSize*/ |
| 8, /* dwWidth */ |
| 6, /* dwHeight */ |
| { 0, 0, 0, 0 } /* dwReserved[4] */ |
| }; |
| |
| static const AVIStreamHeader defash0 = |
| { |
| streamtypeVIDEO, /* fccType */ |
| 0x30323449, /* fccHandler */ |
| 0x00000000, /* dwFlags */ |
| 0, /* wPriority */ |
| 0, /* wLanguage */ |
| 0, /* dwInitialFrames */ |
| 0x000003e9, /* dwScale */ |
| 0x00007530, /* dwRate */ |
| 0, /* dwStart */ |
| 1, /* dwLength */ |
| 0x00100000, /* dwSuggestedBufferSize*/ |
| 0xffffffff, /* dwQuality */ |
| 0, /* dwSampleSize */ |
| { 0, 0, 0, 0 } /* short left right top bottom */ |
| }; |
| |
| static const AVIStreamHeader defash1 = |
| { |
| /* AVIStreamHeader */ |
| streamtypeAUDIO, /* fccType */ |
| 1, /* fccHandler */ |
| 0, /* dwFlags */ |
| 0, /* wPriority */ |
| 0, /* wLanguage */ |
| 0, /* dwInitialFrames */ |
| 1, /* dwScale */ |
| 0x00002b11, /* dwRate */ |
| 0, /* dwStart */ |
| 0x00000665, /* dwLength */ |
| 0x00003000, /* dwSuggestedBufferSize*/ |
| 0xffffffff, /* dwQuality */ |
| 2, /* dwSampleSize */ |
| { 0, 0, 0, 0 } /* short left right top bottom */ |
| }; |
| |
| static const PCMWAVEFORMAT defpcmwf = |
| { |
| { |
| 1, /* wFormatTag */ |
| 2, /* nChannels */ |
| 11025, /* nSamplesPerSec */ |
| 22050, /* nAvgBytesPerSec */ |
| 2, /* nBlockAlign */ |
| }, |
| 8, /* wBitsPerSample */ |
| }; |
| |
| typedef struct common_avi_headers { |
| DWORD fh[sizeof(deffh)]; |
| MainAVIHeader mah; |
| AVIStreamHeader ash0; |
| AVIStreamHeader ash1; |
| PCMWAVEFORMAT pcmwf; |
| } COMMON_AVI_HEADERS; |
| |
| /* Extra data needed to get the VFW API to load the file */ |
| /* DWORD deffh */ |
| /* MainAVIHeader mah */ |
| static const DWORD streamlist[] = |
| { |
| FOURCC_LIST, 0xd4 /* length */, |
| listtypeSTREAMHEADER, ckidSTREAMHEADER, 0x38 /* length */, |
| }; |
| /* AVIStreamHeader ash0 */ |
| static const DWORD videostreamformat[] = |
| { |
| ckidSTREAMFORMAT, 0x28 /* length */, |
| 0x00000028, 0x00000008, 0x00000006, 0x00180001, |
| 0x30323449, 0x00000090, 0x00000000, 0x00000000, |
| 0x00000000, 0x00000000, |
| }; |
| static const DWORD padding1[] = |
| { |
| ckidAVIPADDING, 0xc /* length */, |
| 0x00000004, 0x00000000, 0x63643030 |
| }; |
| static const DWORD videopropheader[] = |
| { |
| 0x70727076, 0x44 /* length */, |
| 0x00000000, 0x00000000, |
| 0x0000001e, 0x00000008, 0x00000006, 0x00100009, |
| 0x00000008, 0x00000006, 0x00000001, 0x00000006, |
| 0x00000008, 0x00000006, 0x00000008, 0x00000000, |
| 0x00000000, 0x00000000, 0x00000000, |
| FOURCC_LIST, 0x70 /* length */, |
| listtypeSTREAMHEADER, ckidSTREAMHEADER, 0x38 /* length */, |
| }; |
| /* AVIStreamHeader ash1 */ |
| static const DWORD audiostreamformat_pre[] = |
| { |
| ckidSTREAMFORMAT, sizeof(PCMWAVEFORMAT) /* length */, |
| }; |
| /* PCMWAVEFORMAT pcmwf */ |
| static DWORD data[] = |
| { |
| ckidAVIPADDING, 0xc /* length */, |
| 0x00000004, 0x00000000, 0x62773130, |
| ckidAVIPADDING, 0xc /* length */, |
| 0x6c6d646f, 0x686c6d64, 0x000000f8, |
| FOURCC_LIST, 0x18 /* length */, |
| 0x4f464e49, |
| 0x54465349, 0xc /* length */, |
| 0x6676614c, 0x332e3235, 0x00302e37, |
| ckidAVIPADDING, 0x4 /* length */, |
| 0, |
| FOURCC_LIST, 0xd1b /* length */, listtypeAVIMOVIE, |
| 0, 0 |
| }; |
| |
| /* ########################### */ |
| |
| static void test_AVISaveOptions(void) |
| { |
| AVICOMPRESSOPTIONS options[2]; |
| LPAVICOMPRESSOPTIONS poptions[2]; |
| PAVISTREAM streams[2] = {NULL, NULL}; |
| HRESULT hres; |
| DWORD res; |
| LONG lres; |
| |
| poptions[0] = &options[0]; |
| poptions[1] = &options[1]; |
| ZeroMemory(options, sizeof(options)); |
| |
| SetLastError(0xdeadbeef); |
| hres = CreateEditableStream(&streams[0], NULL); |
| ok(hres == AVIERR_OK, "0: got 0x%x and %p (expected AVIERR_OK)\n", hres, streams[0]); |
| |
| SetLastError(0xdeadbeef); |
| hres = CreateEditableStream(&streams[1], NULL); |
| ok(hres == AVIERR_OK, "1: got 0x%x and %p (expected AVIERR_OK)\n", hres, streams[1]); |
| |
| SetLastError(0xdeadbeef); |
| hres = EditStreamSetNameA(streams[0], winetest0); |
| ok(hres == AVIERR_OK, "0: got 0x%x (expected AVIERR_OK)\n", hres); |
| |
| SetLastError(0xdeadbeef); |
| hres = EditStreamSetNameA(streams[1], winetest1); |
| ok(hres == AVIERR_OK, "1: got 0x%x (expected AVIERR_OK)\n", hres); |
| |
| if (winetest_interactive) { |
| SetLastError(0xdeadbeef); |
| res = AVISaveOptions(0, ICMF_CHOOSE_DATARATE |ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_ALLCOMPRESSORS, |
| 2, streams, poptions); |
| trace("got %u with 0x%x/%u\n", res, GetLastError(), GetLastError()); |
| } |
| |
| SetLastError(0xdeadbeef); |
| lres = AVISaveOptionsFree(2, poptions); |
| ok(lres == AVIERR_OK, "got 0x%x with 0x%x/%u\n", lres, GetLastError(), GetLastError()); |
| |
| SetLastError(0xdeadbeef); |
| res = AVIStreamRelease(streams[0]); |
| ok(res == 0, "0: got refcount %u (expected 0)\n", res); |
| |
| SetLastError(0xdeadbeef); |
| res = AVIStreamRelease(streams[1]); |
| ok(res == 0, "1: got refcount %u (expected 0)\n", res); |
| |
| } |
| |
| /* ########################### */ |
| |
| static void test_EditStreamSetInfo(void) |
| { |
| PAVISTREAM stream = NULL; |
| HRESULT hres; |
| AVISTREAMINFOA info, info2; |
| |
| hres = CreateEditableStream(&stream, NULL); |
| ok(hres == AVIERR_OK, "got 0x%08X, expected AVIERR_OK\n", hres); |
| |
| /* Size parameter is somehow checked (notice the crash with size=-1 below) */ |
| hres = EditStreamSetInfoA(stream, NULL, 0); |
| ok( hres == AVIERR_BADSIZE, "got 0x%08X, expected AVIERR_BADSIZE\n", hres); |
| |
| hres = EditStreamSetInfoA(stream, NULL, sizeof(AVISTREAMINFOA)-1 ); |
| ok( hres == AVIERR_BADSIZE, "got 0x%08X, expected AVIERR_BADSIZE\n", hres); |
| |
| if(0) |
| { |
| /* Crashing - first parameter not checked */ |
| EditStreamSetInfoA(NULL, &info, sizeof(info) ); |
| |
| /* Crashing - second parameter not checked */ |
| EditStreamSetInfoA(stream, NULL, sizeof(AVISTREAMINFOA) ); |
| |
| EditStreamSetInfoA(stream, NULL, -1); |
| } |
| |
| hres = AVIStreamInfoA(stream, &info, sizeof(info) ); |
| ok( hres == 0, "got 0x%08X, expected 0\n", hres); |
| |
| /* Does the function check what's it's updating ? */ |
| |
| #define IS_INFO_UPDATED(m) do { \ |
| hres = EditStreamSetInfoA(stream, &info, sizeof(info) ); \ |
| ok( hres == 0, "got 0x%08X, expected 0\n", hres); \ |
| hres = AVIStreamInfoA(stream, &info2, sizeof(info2) ); \ |
| ok( hres == 0, "got 0x%08X, expected 0\n", hres); \ |
| ok( info2.m == info.m, "EditStreamSetInfo did not update "#m" parameter\n" ); \ |
| } while(0) |
| |
| info.dwStart++; |
| IS_INFO_UPDATED(dwStart); |
| info.dwStart = 0; |
| IS_INFO_UPDATED(dwStart); |
| |
| info.wPriority++; |
| IS_INFO_UPDATED(wPriority); |
| info.wPriority = 0; |
| IS_INFO_UPDATED(wPriority); |
| |
| info.wLanguage++; |
| IS_INFO_UPDATED(wLanguage); |
| info.wLanguage = 0; |
| IS_INFO_UPDATED(wLanguage); |
| |
| info.dwScale++; |
| IS_INFO_UPDATED(dwScale); |
| info.dwScale = 0; |
| IS_INFO_UPDATED(dwScale); |
| |
| info.dwRate++; |
| IS_INFO_UPDATED(dwRate); |
| info.dwRate = 0; |
| IS_INFO_UPDATED(dwRate); |
| |
| info.dwQuality++; |
| IS_INFO_UPDATED(dwQuality); |
| info.dwQuality = 0; |
| IS_INFO_UPDATED(dwQuality); |
| info.dwQuality = -2; |
| IS_INFO_UPDATED(dwQuality); |
| info.dwQuality = ICQUALITY_HIGH+1; |
| IS_INFO_UPDATED(dwQuality); |
| |
| info.rcFrame.left = 0; |
| IS_INFO_UPDATED(rcFrame.left); |
| info.rcFrame.top = 0; |
| IS_INFO_UPDATED(rcFrame.top); |
| info.rcFrame.right = 0; |
| IS_INFO_UPDATED(rcFrame.right); |
| info.rcFrame.bottom = 0; |
| IS_INFO_UPDATED(rcFrame.bottom); |
| |
| info.rcFrame.left = -1; |
| IS_INFO_UPDATED(rcFrame.left); |
| info.rcFrame.top = -1; |
| IS_INFO_UPDATED(rcFrame.top); |
| info.rcFrame.right = -1; |
| IS_INFO_UPDATED(rcFrame.right); |
| info.rcFrame.bottom = -1; |
| IS_INFO_UPDATED(rcFrame.bottom); |
| AVIStreamRelease(stream); |
| #undef IS_INFO_UPDATED |
| } |
| |
| |
| static void init_test_struct(COMMON_AVI_HEADERS *cah) |
| { |
| memcpy(cah->fh, deffh, sizeof(deffh)); |
| cah->mah = defmah; |
| cah->ash0 = defash0; |
| cah->ash1 = defash1; |
| cah->pcmwf = defpcmwf; |
| } |
| |
| static void create_avi_file(const COMMON_AVI_HEADERS *cah, char *filename) |
| { |
| HANDLE hFile; |
| DWORD written; |
| |
| hFile = CreateFileA(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
| |
| ok(hFile != INVALID_HANDLE_VALUE, "Couldn't create file\n"); |
| |
| WriteFile(hFile, &cah->fh, sizeof(deffh), &written, NULL); |
| WriteFile(hFile, &cah->mah, sizeof(MainAVIHeader), &written, NULL); |
| WriteFile(hFile, streamlist, sizeof(streamlist), &written, NULL); |
| WriteFile(hFile, &cah->ash0, 0x38, &written, NULL); |
| WriteFile(hFile, videostreamformat, sizeof(videostreamformat), &written, NULL); |
| WriteFile(hFile, padding1, sizeof(padding1), &written, NULL); |
| WriteFile(hFile, videopropheader, sizeof(videopropheader), &written, NULL); |
| WriteFile(hFile, &cah->ash1, 0x38, &written, NULL); |
| WriteFile(hFile, audiostreamformat_pre, sizeof(audiostreamformat_pre), &written, NULL); |
| WriteFile(hFile, &cah->pcmwf, sizeof(PCMWAVEFORMAT), &written, NULL); |
| WriteFile(hFile, data, sizeof(data), &written, NULL); |
| |
| CloseHandle(hFile); |
| } |
| |
| static void test_default_data(void) |
| { |
| COMMON_AVI_HEADERS cah; |
| char filename[MAX_PATH]; |
| PAVIFILE pFile; |
| int res; |
| LONG lSize; |
| PAVISTREAM pStream0; |
| PAVISTREAM pStream1; |
| AVISTREAMINFOA asi0, asi1; |
| WAVEFORMATEX wfx; |
| |
| GetTempPathA(MAX_PATH, filename); |
| strcpy(filename+strlen(filename), testfilename); |
| |
| init_test_struct(&cah); |
| create_avi_file(&cah, filename); |
| |
| res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L); |
| ok(res == 0, "Unable to open file: error=%u\n", res); |
| |
| pStream0 = (void *)0xdeadbeef; |
| res = AVIFileGetStream(pFile, &pStream0, ~0U, 0); |
| ok(res == AVIERR_NODATA, "expected AVIERR_NODATA, got %u\n", res); |
| ok(pStream0 == NULL, "AVIFileGetStream should set stream to NULL\n"); |
| |
| res = AVIFileGetStream(pFile, &pStream0, 0, 0); |
| ok(res == 0, "Unable to open video stream: error=%u\n", res); |
| |
| res = AVIFileGetStream(pFile, &pStream1, 0, 1); |
| ok(res == 0, "Unable to open audio stream: error=%u\n", res); |
| |
| res = AVIStreamInfoA(pStream0, &asi0, sizeof(asi0)); |
| ok(res == 0, "Unable to read stream info: error=%u\n", res); |
| |
| res = AVIStreamInfoA(pStream1, &asi1, sizeof(asi1)); |
| ok(res == 0, "Unable to read stream info: error=%u\n", res); |
| |
| res = AVIStreamReadFormat(pStream0, AVIStreamStart(pStream1), NULL, &lSize); |
| ok(res == 0, "Unable to read format size: error=%u\n", res); |
| |
| res = AVIStreamReadFormat(pStream1, AVIStreamStart(pStream1), &wfx, &lSize); |
| ok(res == 0, "Unable to read format: error=%u\n", res); |
| |
| ok(asi0.fccType == streamtypeVIDEO, "got 0x%x (expected streamtypeVIDEO)\n", asi0.fccType); |
| ok(asi0.fccHandler == 0x30323449, "got 0x%x (expected 0x30323449)\n", asi0.fccHandler); |
| ok(asi0.dwFlags == 0, "got %u (expected 0)\n", asi0.dwFlags); |
| ok(asi0.wPriority == 0, "got %u (expected 0)\n", asi0.wPriority); |
| ok(asi0.wLanguage == 0, "got %u (expected 0)\n", asi0.wLanguage); |
| ok(asi0.dwScale == 1001, "got %u (expected 1001)\n", asi0.dwScale); |
| ok(asi0.dwRate == 30000, "got %u (expected 30000)\n", asi0.dwRate); |
| ok(asi0.dwStart == 0, "got %u (expected 0)\n", asi0.dwStart); |
| ok(asi0.dwLength == 1, "got %u (expected 1)\n", asi0.dwLength); |
| ok(asi0.dwInitialFrames == 0, "got %u (expected 0)\n", asi0.dwInitialFrames); |
| ok(asi0.dwSuggestedBufferSize == 0, "got %u (expected 0)\n", asi0.dwSuggestedBufferSize); |
| ok(asi0.dwQuality == 0xffffffff, "got 0x%x (expected 0xffffffff)\n", asi0.dwQuality); |
| ok(asi0.dwSampleSize == 0, "got %u (expected 0)\n", asi0.dwSampleSize); |
| ok(asi0.rcFrame.left == 0, "got %u (expected 0)\n", asi0.rcFrame.left); |
| ok(asi0.rcFrame.top == 0, "got %u (expected 0)\n", asi0.rcFrame.top); |
| ok(asi0.rcFrame.right == 8, "got %u (expected 8)\n", asi0.rcFrame.right); /* these are based on the values in the mah and not */ |
| ok(asi0.rcFrame.bottom == 6, "got %u (expected 6)\n", asi0.rcFrame.bottom);/* on the ones in the ash which are 0 here */ |
| ok(asi0.dwEditCount == 0, "got %u (expected 0)\n", asi0.dwEditCount); |
| ok(asi0.dwFormatChangeCount == 0, "got %u (expected 0)\n", asi0.dwFormatChangeCount); |
| |
| ok(asi1.fccType == streamtypeAUDIO, "got 0x%x (expected streamtypeVIDEO)\n", asi1.fccType); |
| ok(asi1.fccHandler == 0x1, "got 0x%x (expected 0x1)\n", asi1.fccHandler); |
| ok(asi1.dwFlags == 0, "got %u (expected 0)\n", asi1.dwFlags); |
| ok(asi1.wPriority == 0, "got %u (expected 0)\n", asi1.wPriority); |
| ok(asi1.wLanguage == 0, "got %u (expected 0)\n", asi1.wLanguage); |
| ok(asi1.dwScale == 1, "got %u (expected 1)\n", asi1.dwScale); |
| ok(asi1.dwRate == 11025, "got %u (expected 11025)\n", asi1.dwRate); |
| ok(asi1.dwStart == 0, "got %u (expected 0)\n", asi1.dwStart); |
| ok(asi1.dwLength == 1637, "got %u (expected 1637)\n", asi1.dwLength); |
| ok(asi1.dwInitialFrames == 0, "got %u (expected 0)\n", asi1.dwInitialFrames); |
| ok(asi1.dwSuggestedBufferSize == 0, "got %u (expected 0)\n", asi1.dwSuggestedBufferSize); |
| ok(asi1.dwQuality == 0xffffffff, "got 0x%x (expected 0xffffffff)\n", asi1.dwQuality); |
| ok(asi1.dwSampleSize == 2, "got %u (expected 2)\n", asi1.dwSampleSize); |
| ok(asi1.rcFrame.left == 0, "got %u (expected 0)\n", asi1.rcFrame.left); |
| ok(asi1.rcFrame.top == 0, "got %u (expected 0)\n", asi1.rcFrame.top); |
| ok(asi1.rcFrame.right == 0, "got %u (expected 0)\n", asi1.rcFrame.right); |
| ok(asi1.rcFrame.bottom == 0, "got %u (expected 0)\n", asi1.rcFrame.bottom); |
| ok(asi1.dwEditCount == 0, "got %u (expected 0)\n", asi1.dwEditCount); |
| ok(asi1.dwFormatChangeCount == 0, "got %u (expected 0)\n", asi1.dwFormatChangeCount); |
| |
| ok(wfx.wFormatTag == 1, "got %u (expected 1)\n",wfx.wFormatTag); |
| ok(wfx.nChannels == 2, "got %u (expected 2)\n",wfx.nChannels); |
| ok(wfx.wFormatTag == 1, "got %u (expected 1)\n",wfx.wFormatTag); |
| ok(wfx.nSamplesPerSec == 11025, "got %u (expected 11025)\n",wfx.nSamplesPerSec); |
| ok(wfx.nAvgBytesPerSec == 22050, "got %u (expected 22050)\n",wfx.nAvgBytesPerSec); |
| ok(wfx.nBlockAlign == 2, "got %u (expected 2)\n",wfx.nBlockAlign); |
| |
| AVIStreamRelease(pStream0); |
| AVIStreamRelease(pStream1); |
| AVIFileRelease(pFile); |
| ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename); |
| } |
| |
| static void test_amh_corruption(void) |
| { |
| COMMON_AVI_HEADERS cah; |
| char filename[MAX_PATH]; |
| PAVIFILE pFile; |
| int res; |
| |
| GetTempPathA(MAX_PATH, filename); |
| strcpy(filename+strlen(filename), testfilename); |
| |
| /* Make sure only AVI files with the proper headers will be loaded */ |
| init_test_struct(&cah); |
| cah.fh[3] = mmioFOURCC('A', 'V', 'i', ' '); |
| |
| create_avi_file(&cah, filename); |
| res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L); |
| ok(res != 0, "Able to open file: error=%u\n", res); |
| |
| ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename); |
| } |
| |
| static void test_ash1_corruption(void) |
| { |
| COMMON_AVI_HEADERS cah; |
| char filename[MAX_PATH]; |
| PAVIFILE pFile; |
| int res; |
| PAVISTREAM pStream1; |
| AVISTREAMINFOA asi1; |
| |
| GetTempPathA(MAX_PATH, filename); |
| strcpy(filename+strlen(filename), testfilename); |
| |
| /* Corrupt the sample size in the audio stream header */ |
| init_test_struct(&cah); |
| cah.ash1.dwSampleSize = 0xdeadbeef; |
| |
| create_avi_file(&cah, filename); |
| |
| res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L); |
| ok(res == 0, "Unable to open file: error=%u\n", res); |
| |
| res = AVIFileGetStream(pFile, &pStream1, 0, 1); |
| ok(res == 0, "Unable to open audio stream: error=%u\n", res); |
| |
| res = AVIStreamInfoA(pStream1, &asi1, sizeof(asi1)); |
| ok(res == 0, "Unable to read stream info: error=%u\n", res); |
| |
| /* The result will still be 2, because the value is dynamically replaced with the nBlockAlign |
| value from the stream format header. The next test will prove this */ |
| ok(asi1.dwSampleSize == 2, "got %u (expected 2)\n", asi1.dwSampleSize); |
| |
| AVIStreamRelease(pStream1); |
| AVIFileRelease(pFile); |
| ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename); |
| } |
| |
| static void test_ash1_corruption2(void) |
| { |
| COMMON_AVI_HEADERS cah; |
| char filename[MAX_PATH]; |
| PAVIFILE pFile; |
| int res; |
| PAVISTREAM pStream1; |
| AVISTREAMINFOA asi1; |
| |
| GetTempPathA(MAX_PATH, filename); |
| strcpy(filename+strlen(filename), testfilename); |
| |
| /* Corrupt the block alignment in the audio format header */ |
| init_test_struct(&cah); |
| cah.pcmwf.wf.nBlockAlign = 0xdead; |
| |
| create_avi_file(&cah, filename); |
| |
| res = AVIFileOpenA(&pFile, filename, OF_SHARE_DENY_WRITE, 0L); |
| ok(res == 0, "Unable to open file: error=%u\n", res); |
| |
| res = AVIFileGetStream(pFile, &pStream1, 0, 1); |
| ok(res == 0, "Unable to open audio stream: error=%u\n", res); |
| |
| ok(AVIStreamInfoA(pStream1, &asi1, sizeof(asi1)) == 0, "Unable to read stream info\n"); |
| |
| /* The result will also be the corrupt value, as explained above. */ |
| ok(asi1.dwSampleSize == 0xdead, "got 0x%x (expected 0xdead)\n", asi1.dwSampleSize); |
| |
| AVIStreamRelease(pStream1); |
| AVIFileRelease(pFile); |
| ok(DeleteFileA(filename) !=0, "Deleting file %s failed\n", filename); |
| } |
| |
| /* Outer IUnknown for COM aggregation tests */ |
| struct unk_impl { |
| IUnknown IUnknown_iface; |
| LONG ref; |
| IUnknown *inner_unk; |
| }; |
| |
| static inline struct unk_impl *impl_from_IUnknown(IUnknown *iface) |
| { |
| return CONTAINING_RECORD(iface, struct unk_impl, IUnknown_iface); |
| } |
| |
| static HRESULT WINAPI unk_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) |
| { |
| struct unk_impl *This = impl_from_IUnknown(iface); |
| LONG ref = This->ref; |
| HRESULT hr; |
| |
| if (IsEqualGUID(riid, &IID_IUnknown)) |
| { |
| *ppv = iface; |
| IUnknown_AddRef(iface); |
| return S_OK; |
| } |
| |
| hr = IUnknown_QueryInterface(This->inner_unk, riid, ppv); |
| if (hr == S_OK) |
| { |
| trace("Working around COM aggregation ref counting bug\n"); |
| ok(ref == This->ref, "Outer ref count expected %d got %d\n", ref, This->ref); |
| IUnknown_AddRef((IUnknown*)*ppv); |
| ref = IUnknown_Release(This->inner_unk); |
| ok(ref == 1, "Inner ref count expected 1 got %d\n", ref); |
| } |
| |
| return hr; |
| } |
| |
| static ULONG WINAPI unk_AddRef(IUnknown *iface) |
| { |
| struct unk_impl *This = impl_from_IUnknown(iface); |
| |
| return InterlockedIncrement(&This->ref); |
| } |
| |
| static ULONG WINAPI unk_Release(IUnknown *iface) |
| { |
| struct unk_impl *This = impl_from_IUnknown(iface); |
| |
| return InterlockedDecrement(&This->ref); |
| } |
| |
| static const IUnknownVtbl unk_vtbl = |
| { |
| unk_QueryInterface, |
| unk_AddRef, |
| unk_Release |
| }; |
| |
| static void test_COM(void) |
| { |
| struct unk_impl unk_obj = {{&unk_vtbl}, 19, NULL}; |
| IAVIFile *avif = NULL; |
| IPersistFile *pf; |
| IUnknown *unk; |
| LONG refcount; |
| HRESULT hr; |
| |
| /* COM aggregation */ |
| hr = CoCreateInstance(&CLSID_AVIFile, &unk_obj.IUnknown_iface, CLSCTX_INPROC_SERVER, |
| &IID_IUnknown, (void**)&unk_obj.inner_unk); |
| ok(hr == S_OK, "COM aggregation failed: %08x, expected S_OK\n", hr); |
| hr = IUnknown_QueryInterface(&unk_obj.IUnknown_iface, &IID_IAVIFile, (void**)&avif); |
| ok(hr == S_OK, "QueryInterface for IID_IAVIFile failed: %08x\n", hr); |
| refcount = IAVIFile_AddRef(avif); |
| ok(refcount == unk_obj.ref, "AVIFile just pretends to support COM aggregation\n"); |
| refcount = IAVIFile_Release(avif); |
| ok(refcount == unk_obj.ref, "AVIFile just pretends to support COM aggregation\n"); |
| hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf); |
| ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08x\n", hr); |
| refcount = IPersistFile_Release(pf); |
| ok(refcount == unk_obj.ref, "AVIFile just pretends to support COM aggregation\n"); |
| refcount = IAVIFile_Release(avif); |
| ok(refcount == 19, "Outer ref count should be back at 19 but is %d\n", refcount); |
| refcount = IUnknown_Release(unk_obj.inner_unk); |
| ok(refcount == 0, "Inner ref count should be 0 but is %u\n", refcount); |
| |
| /* Invalid RIID */ |
| hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIStream, |
| (void**)&avif); |
| ok(hr == E_NOINTERFACE, "AVIFile create failed: %08x, expected E_NOINTERFACE\n", hr); |
| |
| /* Same refcount */ |
| hr = CoCreateInstance(&CLSID_AVIFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIFile, (void**)&avif); |
| ok(hr == S_OK, "AVIFile create failed: %08x, expected S_OK\n", hr); |
| refcount = IAVIFile_AddRef(avif); |
| ok(refcount == 2, "refcount == %u, expected 2\n", refcount); |
| hr = IAVIFile_QueryInterface(avif, &IID_IUnknown, (void**)&unk); |
| ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr); |
| refcount = IUnknown_AddRef(unk); |
| ok(refcount == 4, "refcount == %u, expected 4\n", refcount); |
| hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf); |
| ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08x\n", hr); |
| refcount = IPersistFile_AddRef(pf); |
| ok(refcount == 6, "refcount == %u, expected 6\n", refcount); |
| |
| while (IAVIFile_Release(avif)); |
| } |
| |
| static void test_COM_wavfile(void) |
| { |
| struct unk_impl unk_obj = {{&unk_vtbl}, 19, NULL}; |
| IAVIFile *avif = NULL; |
| IPersistFile *pf; |
| IAVIStream *avis; |
| IUnknown *unk; |
| ULONG refcount; |
| HRESULT hr; |
| |
| /* COM aggregation */ |
| hr = CoCreateInstance(&CLSID_WAVFile, &unk_obj.IUnknown_iface, CLSCTX_INPROC_SERVER, |
| &IID_IUnknown, (void**)&unk_obj.inner_unk); |
| ok(hr == S_OK, "COM aggregation failed: %08x, expected S_OK\n", hr); |
| hr = IUnknown_QueryInterface(&unk_obj.IUnknown_iface, &IID_IAVIFile, (void**)&avif); |
| ok(hr == S_OK, "QueryInterface for IID_IAVIFile failed: %08x\n", hr); |
| refcount = IAVIFile_AddRef(avif); |
| ok(refcount == unk_obj.ref, "WAVFile just pretends to support COM aggregation\n"); |
| refcount = IAVIFile_Release(avif); |
| ok(refcount == unk_obj.ref, "WAVFile just pretends to support COM aggregation\n"); |
| hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf); |
| ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08x\n", hr); |
| refcount = IPersistFile_Release(pf); |
| ok(refcount == unk_obj.ref, "WAVFile just pretends to support COM aggregation\n"); |
| refcount = IAVIFile_Release(avif); |
| ok(refcount == 19, "Outer ref count should be back at 19 but is %d\n", refcount); |
| refcount = IUnknown_Release(unk_obj.inner_unk); |
| ok(refcount == 0, "Inner ref count should be 0 but is %u\n", refcount); |
| |
| /* Invalid RIID */ |
| hr = CoCreateInstance(&CLSID_WAVFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIStreaming, |
| (void**)&avif); |
| ok(hr == E_NOINTERFACE, "WAVFile create failed: %08x, expected E_NOINTERFACE\n", hr); |
| |
| /* Same refcount for all WAVFile interfaces */ |
| hr = CoCreateInstance(&CLSID_WAVFile, NULL, CLSCTX_INPROC_SERVER, &IID_IAVIFile, (void**)&avif); |
| ok(hr == S_OK, "WAVFile create failed: %08x, expected S_OK\n", hr); |
| refcount = IAVIFile_AddRef(avif); |
| ok(refcount == 2, "refcount == %u, expected 2\n", refcount); |
| |
| hr = IAVIFile_QueryInterface(avif, &IID_IPersistFile, (void**)&pf); |
| ok(hr == S_OK, "QueryInterface for IID_IPersistFile failed: %08x\n", hr); |
| refcount = IPersistFile_AddRef(pf); |
| ok(refcount == 4, "refcount == %u, expected 4\n", refcount); |
| refcount = IPersistFile_Release(pf); |
| |
| hr = IAVIFile_QueryInterface(avif, &IID_IAVIStream, (void**)&avis); |
| ok(hr == S_OK, "QueryInterface for IID_IAVIStream failed: %08x\n", hr); |
| refcount = IAVIStream_AddRef(avis); |
| ok(refcount == 5, "refcount == %u, expected 5\n", refcount); |
| refcount = IAVIStream_Release(avis); |
| |
| hr = IAVIFile_QueryInterface(avif, &IID_IUnknown, (void**)&unk); |
| ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr); |
| refcount = IUnknown_AddRef(unk); |
| ok(refcount == 6, "refcount == %u, expected 6\n", refcount); |
| refcount = IUnknown_Release(unk); |
| |
| while (IAVIFile_Release(avif)); |
| } |
| |
| static void test_COM_editstream(void) |
| { |
| IAVIEditStream *edit; |
| IAVIStream *stream; |
| IUnknown *unk; |
| ULONG refcount; |
| HRESULT hr; |
| |
| /* Same refcount for all AVIEditStream interfaces */ |
| hr = CreateEditableStream(&stream, NULL); |
| ok(hr == S_OK, "AVIEditStream create failed: %08x, expected S_OK\n", hr); |
| refcount = IAVIStream_AddRef(stream); |
| ok(refcount == 2, "refcount == %u, expected 2\n", refcount); |
| |
| hr = IAVIStream_QueryInterface(stream, &IID_IAVIEditStream, (void**)&edit); |
| ok(hr == S_OK, "QueryInterface for IID_IAVIEditStream failed: %08x\n", hr); |
| refcount = IAVIEditStream_AddRef(edit); |
| ok(refcount == 4, "refcount == %u, expected 4\n", refcount); |
| refcount = IAVIEditStream_Release(edit); |
| |
| hr = IAVIEditStream_QueryInterface(edit, &IID_IUnknown, (void**)&unk); |
| ok(hr == S_OK, "QueryInterface for IID_IUnknown failed: %08x\n", hr); |
| refcount = IUnknown_AddRef(unk); |
| ok(refcount == 5, "refcount == %u, expected 5\n", refcount); |
| IUnknown_Release(unk); |
| |
| while (IAVIEditStream_Release(edit)); |
| } |
| |
| START_TEST(api) |
| { |
| |
| AVIFileInit(); |
| test_EditStreamSetInfo(); |
| test_AVISaveOptions(); |
| test_default_data(); |
| test_amh_corruption(); |
| test_ash1_corruption(); |
| test_ash1_corruption2(); |
| test_COM(); |
| test_COM_wavfile(); |
| test_COM_editstream(); |
| AVIFileExit(); |
| |
| } |