Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44490 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=23175 Signed-off-by: Zebediah Figura z.figura12@gmail.com --- v2: fix test failures on w7u
dlls/msvfw32/msvideo_main.c | 136 ++++++++++++++++-------- dlls/msvfw32/tests/msvfw.c | 248 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 341 insertions(+), 43 deletions(-)
diff --git a/dlls/msvfw32/msvideo_main.c b/dlls/msvfw32/msvideo_main.c index 5dc99a4..e3bedd9 100644 --- a/dlls/msvfw32/msvideo_main.c +++ b/dlls/msvfw32/msvideo_main.c @@ -223,6 +223,15 @@ static int compare_fourcc(DWORD fcc1, DWORD fcc2) return strncasecmp(fcc_str1, fcc_str2, 4); }
+static DWORD get_size_image(LONG width, LONG height, WORD depth) +{ + DWORD ret = width * depth; + ret = (ret + 7) / 8; /* divide by byte size, rounding up */ + ret = (ret + 3) & ~3; /* align to 4 bytes */ + ret *= abs(height); + return ret; +} + typedef BOOL (*enum_handler_t)(const char *name, const char *driver, unsigned int index, void *param);
static BOOL enum_drivers(DWORD fccType, enum_handler_t handler, void* param) @@ -715,57 +724,98 @@ HIC VFWAPI ICLocate(DWORD fccType, DWORD fccHandler, LPBITMAPINFOHEADER lpbiIn, /*********************************************************************** * ICGetDisplayFormat [MSVFW32.@] */ -HIC VFWAPI ICGetDisplayFormat( - HIC hic,LPBITMAPINFOHEADER lpbiIn,LPBITMAPINFOHEADER lpbiOut, - INT depth,INT dx,INT dy) +HIC VFWAPI ICGetDisplayFormat(HIC hic, BITMAPINFOHEADER *in, BITMAPINFOHEADER *out, + int depth, int width, int height) { - HIC tmphic = hic; + HIC tmphic = hic;
- TRACE("(%p,%p,%p,%d,%d,%d)!\n",hic,lpbiIn,lpbiOut,depth,dx,dy); + TRACE("(%p, %p, %p, %d, %d, %d)\n", hic, in, out, depth, width, height);
- if (!tmphic) { - tmphic=ICLocate(ICTYPE_VIDEO,0,lpbiIn,NULL,ICMODE_DECOMPRESS); - if (!tmphic) - return tmphic; - } - if ((dy == lpbiIn->biHeight) && (dx == lpbiIn->biWidth)) - dy = dx = 0; /* no resize needed */ + if (!tmphic) + { + tmphic = ICLocate(ICTYPE_VIDEO, 0, in, NULL, ICMODE_DECOMPRESS); + if (!tmphic) + return NULL; + }
- /* Can we decompress it ? */ - if (ICDecompressQuery(tmphic,lpbiIn,NULL) != 0) - goto errout; /* no, sorry */ + if (ICDecompressQuery(tmphic, in, NULL)) + goto err;
- ICSendMessage(tmphic, ICM_DECOMPRESS_GET_FORMAT, (DWORD_PTR)lpbiIn, (DWORD_PTR)lpbiOut); + if (width <= 0 || height <= 0) + { + width = in->biWidth; + height = in->biHeight; + }
- if (lpbiOut->biCompression != 0) { - FIXME("Ooch, how come decompressor outputs compressed data (%d)??\n", - lpbiOut->biCompression); - } - if (lpbiOut->biSize < sizeof(*lpbiOut)) { - FIXME("Ooch, size of output BIH is too small (%d)\n", - lpbiOut->biSize); - lpbiOut->biSize = sizeof(*lpbiOut); - } - if (!depth) { - HDC hdc; + if (!depth) + depth = 32;
- hdc = GetDC(0); - depth = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES); - ReleaseDC(0,hdc); - if (depth==15) depth = 16; - if (depth<8) depth = 8; - } - if (lpbiIn->biBitCount == 8) - depth = 8; + *out = *in; + out->biSize = sizeof(*out); + out->biWidth = width; + out->biHeight = height; + out->biCompression = BI_RGB; + out->biSizeImage = get_size_image(width, height, depth);
- TRACE("=> %p\n", tmphic); - return tmphic; -errout: - if (hic!=tmphic) - ICClose(tmphic); + /* first try the given depth */ + out->biBitCount = depth; + out->biSizeImage = get_size_image(width, height, out->biBitCount); + if (!ICDecompressQuery(tmphic, in, out)) + { + if (depth == 8) + ICDecompressGetPalette(tmphic, in, out); + return tmphic; + }
- TRACE("=> 0\n"); - return 0; + /* then try 16, both with BI_RGB and BI_BITFIELDS */ + if (depth <= 16) + { + out->biBitCount = 16; + out->biSizeImage = get_size_image(width, height, out->biBitCount); + if (!ICDecompressQuery(tmphic, in, out)) + return tmphic; + + out->biCompression = BI_BITFIELDS; + if (!ICDecompressQuery(tmphic, in, out)) + return tmphic; + out->biCompression = BI_RGB; + } + + /* then try 24 */ + if (depth <= 24) + { + out->biBitCount = 24; + out->biSizeImage = get_size_image(width, height, out->biBitCount); + if (!ICDecompressQuery(tmphic, in, out)) + return tmphic; + } + + /* then try 32 */ + if (depth <= 32) + { + out->biBitCount = 32; + out->biSizeImage = get_size_image(width, height, out->biBitCount); + if (!ICDecompressQuery(tmphic, in, out)) + return tmphic; + } + + /* as a last resort, try 32 bpp with the original width and height */ + out->biWidth = in->biWidth; + out->biHeight = in->biHeight; + out->biBitCount = 32; + out->biSizeImage = get_size_image(out->biWidth, out->biHeight, out->biBitCount); + if (!ICDecompressQuery(tmphic, in, out)) + return tmphic; + + /* finally, ask the compressor for its default output format */ + if (!ICSendMessage(tmphic, ICM_DECOMPRESS_GET_FORMAT, (DWORD_PTR)in, (DWORD_PTR)out)) + return tmphic; + +err: + if (hic != tmphic) + ICClose(tmphic); + + return NULL; }
/*********************************************************************** @@ -1358,7 +1408,7 @@ HANDLE VFWAPI ICImageDecompress(
biSizeImage = lpbiOut->bmiHeader.biSizeImage; if ( biSizeImage == 0 ) - biSizeImage = ((((lpbiOut->bmiHeader.biWidth * lpbiOut->bmiHeader.biBitCount + 7) >> 3) + 3) & (~3)) * abs(lpbiOut->bmiHeader.biHeight); + biSizeImage = get_size_image(lpbiOut->bmiHeader.biWidth, lpbiOut->bmiHeader.biHeight, lpbiOut->bmiHeader.biBitCount);
TRACE( "call ICDecompressBegin\n" );
diff --git a/dlls/msvfw32/tests/msvfw.c b/dlls/msvfw32/tests/msvfw.c index beeca9f..406a35b 100644 --- a/dlls/msvfw32/tests/msvfw.c +++ b/dlls/msvfw32/tests/msvfw.c @@ -316,10 +316,258 @@ static void test_ICInfo(void) ok(info.fccHandler == mmioFOURCC('f','a','k','e'), "got 0x%08x\n", info.fccHandler); }
+static int get_display_format_test; + +static DWORD get_size_image(LONG width, LONG height, WORD depth) +{ + DWORD ret = width * depth; + ret = (ret + 7) / 8; /* divide by byte size, rounding up */ + ret = (ret + 3) & ~3; /* align to 4 bytes */ + ret *= abs(height); + return ret; +} + +static const RGBQUAD color_yellow = {0x00, 0xff, 0xff, 0x00}; + +static BITMAPINFOHEADER gdf_in, *gdf_out; + +LRESULT CALLBACK gdf_driver_proc(DWORD_PTR id, HDRVR driver, UINT msg, + LPARAM lparam1, LPARAM lparam2) +{ + LRESULT ret = 0; + + if (winetest_debug > 1) + trace("(%#lx, %p, %#x, %#lx, %#lx)\n", id, driver, msg, lparam1, lparam2); + + switch(msg) + { + case DRV_LOAD: + case DRV_OPEN: + case DRV_CLOSE: + case DRV_FREE: + return 1; + case ICM_DECOMPRESS_QUERY: + { + BITMAPINFOHEADER *out = (BITMAPINFOHEADER *)lparam2; + DWORD expected_size; + + ok(lparam1 == (LPARAM)&gdf_in, "got input %#lx\n", lparam1); + + if (!out) + return ICERR_OK; + + ok(out == gdf_out, "got output %p\n", out); + + ok(out->biSize == sizeof(*out), "got size %d\n", out->biSize); + expected_size = get_size_image(out->biWidth, out->biHeight, out->biBitCount); + ok(out->biSizeImage == expected_size, "expected image size %d, got %d\n", + expected_size, out->biSizeImage); + + ok(out->biPlanes == 0xcccc, "got planes %d\n", out->biPlanes); + ok(out->biXPelsPerMeter == 0xcccccccc && out->biYPelsPerMeter == 0xcccccccc, + "got resolution %dx%d\n", out->biXPelsPerMeter, out->biYPelsPerMeter); + ok(out->biClrUsed == 0xcccccccc, "got biClrUsed %u\n", out->biClrUsed); + ok(out->biClrImportant == 0xcccccccc, "got biClrImportant %u\n", out->biClrImportant); + + switch (get_display_format_test) + { + case 0: + return ICERR_OK; + case 1: + if (out->biWidth == 30 && out->biHeight == 40 && out->biCompression == BI_RGB && out->biBitCount == 16) + return ICERR_OK; + break; + case 2: + if (out->biWidth == 30 && out->biHeight == 40 && out->biCompression == BI_BITFIELDS && out->biBitCount == 16) + return ICERR_OK; + break; + case 3: + if (out->biWidth == 30 && out->biHeight == 40 && out->biCompression == BI_RGB && out->biBitCount == 24) + return ICERR_OK; + break; + case 4: + if (out->biWidth == 30 && out->biHeight == 40 && out->biCompression == BI_RGB && out->biBitCount == 32) + return ICERR_OK; + break; + case 5: + if (out->biWidth == 10 && out->biHeight == 20 && out->biCompression == BI_RGB && out->biBitCount == 32) + return ICERR_OK; + break; + case 6: + break; + } + + return ICERR_BADFORMAT; + } + case ICM_DECOMPRESS_GET_FORMAT: + { + BITMAPINFOHEADER *out = (BITMAPINFOHEADER *)lparam2; + + ok(lparam1 == (LPARAM)&gdf_in, "got input %#lx\n", lparam1); + if (out) + { + ok(out == gdf_out, "got output %p\n", out); + + memset(out, 0x55, sizeof(*out)); + out->biWidth = 50; + out->biHeight = 60; + out->biBitCount = 0xdead; + out->biCompression = 0xbeef; + out->biSizeImage = 0; + + return ICERR_OK; + } + } + case ICM_DECOMPRESS_GET_PALETTE: + { + BITMAPINFO *out = (BITMAPINFO *)lparam2; + + ok(lparam1 == (LPARAM)&gdf_in, "got input %#lx\n", lparam1); + if (out) + { + ok(out == (BITMAPINFO *)gdf_out, "got output %p\n", out); + + out->bmiHeader.biClrUsed = 1; + out->bmiColors[0] = color_yellow; + + return 0xdeadbeef; + } + } + } + + return ret; +} + +static void check_bitmap_header_(int line, BITMAPINFOHEADER *header, LONG width, LONG height, WORD depth, DWORD compression) +{ + ok_(__FILE__, line)(header->biWidth == width, "expected %d, got %d\n", width, header->biWidth); + ok_(__FILE__, line)(header->biHeight == height, "expected %d, got %d\n", height, header->biHeight); + ok_(__FILE__, line)(header->biBitCount == depth, "expected %d, got %d\n", depth, header->biBitCount); + ok_(__FILE__, line)(header->biCompression == compression, "expected %#x, got %#x\n", compression, header->biCompression); +} +#define check_bitmap_header(a,b,c,d,e) check_bitmap_header_(__LINE__,a,b,c,d,e) + +static void test_ICGetDisplayFormat(void) +{ + static const DWORD testcc = mmioFOURCC('t','e','s','t'); + char outbuf[FIELD_OFFSET(BITMAPINFO, bmiColors[256])]; + BITMAPINFO *out_bmi; + LRESULT lres; + BOOL ret; + HIC hic; + + memset(&gdf_in, 0xcc, sizeof(gdf_in)); + gdf_in.biSize = sizeof(gdf_in); + gdf_in.biWidth = 10; + gdf_in.biHeight = 20; + gdf_in.biBitCount = 1; + gdf_in.biCompression = testcc; + + ret = ICInstall(ICTYPE_VIDEO, testcc, (LPARAM)gdf_driver_proc, NULL, ICINSTALL_FUNCTION); + ok(ret, "ICInstall failed\n"); + + hic = ICOpen(ICTYPE_VIDEO, testcc, ICMODE_DECOMPRESS); + ok(ret, "ICOpen failed\n"); + + memset(outbuf, 0, sizeof(outbuf)); + gdf_out = (BITMAPINFOHEADER *)outbuf; + + /* ICGetDisplayFormat tries several default formats; make sure those work */ + get_display_format_test = 0; + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 30, 40, 1, BI_RGB); + + get_display_format_test = 1; + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 30, 40, 16, BI_RGB); + + get_display_format_test = 2; + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 30, 40, 16, BI_BITFIELDS); + + get_display_format_test = 3; + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 30, 40, 24, BI_RGB); + + get_display_format_test = 4; + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 30, 40, 32, BI_RGB); + + get_display_format_test = 5; + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 10, 20, 32, BI_RGB); + + /* if every default format is rejected, the output of + * ICM_DECOMPRESS_GET_FORMAT is returned */ + get_display_format_test = 6; + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 50, 60, 0xdead, 0xbeef); + + /* given bpp is treated as a lower bound */ + get_display_format_test = 1; + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 24, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 50, 60, 0xdead, 0xbeef); + + get_display_format_test = 3; + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 24, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 30, 40, 24, BI_RGB); + + get_display_format_test = 0; + + /* width or height <= 0 causes the input width and height to be supplied */ + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 0, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 10, 20, 1, BI_RGB); + + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, 0); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 10, 20, 1, BI_RGB); + + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, -10, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 10, 20, 1, BI_RGB); + + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 1, 30, -10); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 10, 20, 1, BI_RGB); + + /* zero bpp causes 32 bpp to be supplied */ + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 0, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + ok(gdf_out->biBitCount == 32 || gdf_out->biBitCount == 24, + "got %d\n", gdf_out->biBitCount); + ok(gdf_out->biCompression == BI_RGB, "got %#x\n", gdf_out->biCompression); + + /* specifying 8 bpp yields a request for palette colours */ + hic = ICGetDisplayFormat(hic, &gdf_in, gdf_out, 8, 30, 40); + ok(hic != NULL, "ICGetDisplayFormat failed\n"); + check_bitmap_header(gdf_out, 30, 40, 8, BI_RGB); + ok(gdf_out->biClrUsed == 1, "got biClrUsed %u\n", gdf_out->biClrUsed); + out_bmi = (BITMAPINFO *)gdf_out; + ok(!memcmp(&out_bmi->bmiColors[0], &color_yellow, sizeof(color_yellow)), + "got wrong colour\n"); + + lres = ICClose(hic); + ok(lres == ICERR_OK, "got %ld\n", lres); + + ret = ICRemove(ICTYPE_VIDEO, testcc, 0); + ok(ret, "ICRemove failed\n"); +} + START_TEST(msvfw) { test_OpenCase(); test_Locate(); test_ICSeqCompress(); test_ICInfo(); + test_ICGetDisplayFormat(); }