Hi Dmitry,
Thanks a lot for your feedback! I should've solved most issues you pointed me at. I have attached a new version of the patch.
Dmitry Timoshkov wrote:
Indentation of above structure and all others below this one look strange. 4 spaces would be quite enough.
This was supposed to represent the RIFF tree with the headers being tested taken out. The bottom part of the data is just needed to allow both Windows' VFW and Wine's VFW to load the file.
Roderick also just found the indentation strange, so I got rid of it now.
Do you really need all that separate structures? Wouldn't it be simpler to have a single buffer like in dlls/winmm/tests/mmio.c?
The reasons I chose to separate the structures: To be able to separate the headers out that I specifically want to test. I added an actual test to this version which shows how I imagine it to be used. The values can be easily 'corrupted' now using the structures as defined by the actual VFW headers. To keep some structure. I only took a proper look at the audio stream, but if someone has more knowledge on the video stream, they may now just take the videopropheader array, move it up in the source, structure it properly and write tests against it.
With the attached patch, all tests pass on MS Windows XP.
Regards, Julius
From 50ecf7728c68b60ebcff0c5e46e8332d124f1266 Mon Sep 17 00:00:00 2001
From: Julius Schwartzenberg julius.schwartzenberg@gmail.com Date: Fri, 25 Dec 2009 20:29:43 +0100 Subject: initial version of avifile testing framework plus the first simple tests
--- dlls/avifil32/tests/api.c | 320 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 320 insertions(+), 0 deletions(-)
diff --git a/dlls/avifil32/tests/api.c b/dlls/avifil32/tests/api.c index 55b194f..cfef4dc 100644 --- a/dlls/avifil32/tests/api.c +++ b/dlls/avifil32/tests/api.c @@ -35,6 +35,138 @@ static const CHAR winetest1[] = "winetest1";
/* ########################### */
+typedef struct common_avi_headers { + MainAVIHeader mah; + AVIStreamHeader ash0; + AVIStreamHeader ash1; + PCMWAVEFORMAT pcmwf; +} COMMON_AVI_HEADERS; + +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 */ +}; + +/* Extra data needed to get the VFW API to load the file */ +static DWORD file_header[] = +{ + FOURCC_RIFF, 0x34c6 /* length */, formtypeAVI, + FOURCC_LIST, 0x1ac /* length */, + listtypeAVIHEADER, ckidAVIMAINHDR, sizeof(MainAVIHeader), +}; +/* MainAVIHeader mah */ +static DWORD streamlist[] = +{ + FOURCC_LIST, 0xd4 /* length */, + listtypeSTREAMHEADER, ckidSTREAMHEADER, 0x38 /* length */, +}; +/* AVIStreamHeader ash0 */ +static DWORD videostreamformat[] = +{ + ckidSTREAMFORMAT, 0x28 /* length */, + 0x00000028, 0x00000008, 0x00000006, 0x00180001, + 0x30323449, 0x00000090, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, +}; +static DWORD padding1[] = +{ + ckidAVIPADDING, 0xc /* length */, + 0x00000004, 0x00000000, 0x63643030 +}; +static 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 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]; @@ -87,11 +219,199 @@ static void test_AVISaveOptions(void)
/* ########################### */
+static void init_test_struct(COMMON_AVI_HEADERS *cah) +{ + memcpy(&cah->mah, &defmah, sizeof(defmah)); + memcpy(&cah->ash0, &defash0, sizeof(defash0)); + memcpy(&cah->ash1, &defash1, sizeof(defash1)); + memcpy(&cah->pcmwf, &defpcmwf, sizeof(defpcmwf)); +} + +static void create_avi_file(const COMMON_AVI_HEADERS *cah) +{ + HANDLE hFile; + DWORD written; + + hFile = CreateFile("small.avi", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + ok(hFile != INVALID_HANDLE_VALUE, "Couldn't create file\n"); + + WriteFile(hFile, file_header, sizeof(file_header), &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; + PAVIFILE pFile; + int res; + LONG lSize; + PAVISTREAM pStream0; + PAVISTREAM pStream1; + AVISTREAMINFO asi0; + AVISTREAMINFO asi1; + WAVEFORMATEX wfx; + + init_test_struct(&cah); + create_avi_file(&cah); + + res = AVIFileOpen(&pFile, "small.avi", OF_SHARE_DENY_WRITE, 0L); + ok(res == 0, "Unable to open file: error=%u\n", res); + + 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 = AVIStreamInfo(pStream0, &asi0, sizeof(AVISTREAMINFO)); + ok(res == 0, "Unable to read stream info: error=%u\n", res); + + res = AVIStreamInfo(pStream1, &asi1, sizeof(AVISTREAMINFO)); + 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(DeleteFile("small.avi") !=0, "Deleting file small.avi failed"); +} + +static void test_ash1_corruption(void) { + COMMON_AVI_HEADERS cah; + PAVIFILE pFile; + int res; + PAVISTREAM pStream1; + AVISTREAMINFO asi1; + + init_test_struct(&cah); + + /* Corrupt the sample size in the audio stream header */ + cah.ash1.dwSampleSize = 0xdeadbeef; + + create_avi_file(&cah); + + res = AVIFileOpen(&pFile, "small.avi", 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 = AVIStreamInfo(pStream1, &asi1, sizeof(AVISTREAMINFO)); + 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(DeleteFile("small.avi") !=0, "Deleting file small.avi failed"); +} + +static void test_ash1_corruption2(void) { + COMMON_AVI_HEADERS cah; + PAVIFILE pFile; + int res; + PAVISTREAM pStream1; + AVISTREAMINFO asi1; + + init_test_struct(&cah); + + /* Corrupt the block alignment in the audio format header */ + cah.pcmwf.wf.nBlockAlign = 0xdead; + + create_avi_file(&cah); + + res = AVIFileOpen(&pFile, "small.avi", 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(AVIStreamInfo(pStream1, &asi1, sizeof(AVISTREAMINFO)) == 0, "Unable to read stream info\n"); + + /* The result will also be the corrupt value, as explained above. */ + ok(asi1.dwSampleSize == 0xdead, "got %u (expected 0xdead)\n", asi1.dwSampleSize); + + AVIStreamRelease(pStream1); + AVIFileRelease(pFile); + ok(DeleteFile("small.avi") !=0, "Deleting file small.avi failed"); +} + +/* ########################### */ + START_TEST(api) {
AVIFileInit(); test_AVISaveOptions(); + test_default_data(); + test_ash1_corruption(); + test_ash1_corruption2(); AVIFileExit();
}