[PATCH v2 0/5] MR10467: iyuv/tests: Add stub DLL and tests.
This MR adds a stub for the `iyuv_32.dll` and tests its functionality. -- v2: iyuv_32/tests: Add a compression test. iyuv_32/tests: Add a decompression test. iyuv_32/tests: Test which formats are supported. iyuv_32/tests: Add test stub. iyuv_32: Add stub dll. https://gitlab.winehq.org/wine/wine/-/merge_requests/10467
From: Brendan McGrath <bmcgrath@codeweavers.com> --- configure.ac | 1 + dlls/iyuv_32/Makefile.in | 6 ++ dlls/iyuv_32/iyuv.c | 184 ++++++++++++++++++++++++++++++++++++ dlls/iyuv_32/iyuv_32.rc | 29 ++++++ dlls/iyuv_32/iyuv_32.spec | 1 + dlls/iyuv_32/iyuv_private.h | 34 +++++++ loader/wine.inf.in | 2 + 7 files changed, 257 insertions(+) create mode 100644 dlls/iyuv_32/Makefile.in create mode 100644 dlls/iyuv_32/iyuv.c create mode 100644 dlls/iyuv_32/iyuv_32.rc create mode 100644 dlls/iyuv_32/iyuv_32.spec create mode 100644 dlls/iyuv_32/iyuv_private.h diff --git a/configure.ac b/configure.ac index 9a437851996..953edcce7b9 100644 --- a/configure.ac +++ b/configure.ac @@ -2880,6 +2880,7 @@ WINE_CONFIG_MAKEFILE(dlls/irprops.cpl) WINE_CONFIG_MAKEFILE(dlls/itircl) WINE_CONFIG_MAKEFILE(dlls/itss) WINE_CONFIG_MAKEFILE(dlls/itss/tests) +WINE_CONFIG_MAKEFILE(dlls/iyuv_32) WINE_CONFIG_MAKEFILE(dlls/joy.cpl) WINE_CONFIG_MAKEFILE(dlls/jscript) WINE_CONFIG_MAKEFILE(dlls/jscript/tests) diff --git a/dlls/iyuv_32/Makefile.in b/dlls/iyuv_32/Makefile.in new file mode 100644 index 00000000000..c386ec9b924 --- /dev/null +++ b/dlls/iyuv_32/Makefile.in @@ -0,0 +1,6 @@ +MODULE = iyuv_32.dll +IMPORTS = user32 mfplat ole32 + +SOURCES = \ + iyuv.c \ + iyuv_32.rc diff --git a/dlls/iyuv_32/iyuv.c b/dlls/iyuv_32/iyuv.c new file mode 100644 index 00000000000..d1ebd4d383a --- /dev/null +++ b/dlls/iyuv_32/iyuv.c @@ -0,0 +1,184 @@ +/* + * iyuv Video "Decoder" + * Copyright 2026 Brendan McGrath for CodeWeavers + * + * 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 + * + */ + +#include <stdarg.h> +#include <stdlib.h> +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "vfw.h" +#include "initguid.h" +#include "wmcodecdsp.h" +#include "iyuv_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(iyuv_32); + +static HINSTANCE IYUV_32_hModule; + +static LRESULT IYUV_Open( const ICINFO *icinfo ) +{ + FIXME("DRV_OPEN %p\n", icinfo); + + return 0; +} + +static LRESULT IYUV_DecompressQuery( const BITMAPINFOHEADER *in, const BITMAPINFOHEADER *out ) +{ + FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + + return ICERR_UNSUPPORTED; +} + +static LRESULT IYUV_DecompressGetFormat( BITMAPINFOHEADER *in, BITMAPINFOHEADER *out ) +{ + FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + + return ICERR_UNSUPPORTED; +} + +static LRESULT IYUV_DecompressBegin( IMFTransform *transform, const BITMAPINFOHEADER *in, const BITMAPINFOHEADER *out ) +{ + FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", transform, in, out); + + return ICERR_UNSUPPORTED; +} + +static LRESULT IYUV_Decompress( IMFTransform *transform, const ICDECOMPRESS *params ) +{ + FIXME("ICM_DECOMPRESS %p %p\n", transform, params); + + return ICERR_UNSUPPORTED; +} + +static LRESULT IYUV_GetInfo( ICINFO *icinfo, DWORD dwSize ) +{ + FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); + + return ICERR_UNSUPPORTED; +} + +/*********************************************************************** + * DriverProc (IYUV_32.@) + */ +LRESULT WINAPI IYUV_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, + LPARAM lParam1, LPARAM lParam2 ) +{ + IMFTransform *transform = (IMFTransform *) dwDriverId; + LRESULT r = ICERR_UNSUPPORTED; + + TRACE("%Id %p %04x %08Ix %08Ix\n", dwDriverId, hdrvr, msg, lParam1, lParam2); + + switch( msg ) + { + case DRV_LOAD: + TRACE("DRV_LOAD\n"); + r = TRUE; + break; + + case DRV_OPEN: + r = IYUV_Open((ICINFO *)lParam2); + break; + + case DRV_CLOSE: + TRACE("DRV_CLOSE\n"); + if ( transform ) + IMFTransform_Release( transform ); + r = TRUE; + break; + + case DRV_ENABLE: + case DRV_DISABLE: + case DRV_FREE: + break; + + case ICM_GETINFO: + r = IYUV_GetInfo( (ICINFO *) lParam1, (DWORD) lParam2 ); + break; + + case ICM_DECOMPRESS_QUERY: + r = IYUV_DecompressQuery( (BITMAPINFOHEADER *)lParam1, (BITMAPINFOHEADER *)lParam2 ); + break; + + case ICM_DECOMPRESS_GET_FORMAT: + r = IYUV_DecompressGetFormat( (BITMAPINFOHEADER*) lParam1, (BITMAPINFOHEADER*) lParam2 ); + break; + + case ICM_DECOMPRESS_GET_PALETTE: + FIXME("ICM_DECOMPRESS_GET_PALETTE\n"); + break; + + case ICM_DECOMPRESS: + r = IYUV_Decompress( transform, (ICDECOMPRESS *)lParam1 ); + break; + + case ICM_DECOMPRESS_BEGIN: + r = IYUV_DecompressBegin( transform, (BITMAPINFOHEADER *)lParam1, (BITMAPINFOHEADER *)lParam2 ); + break; + + case ICM_DECOMPRESS_END: + r = ICERR_OK; + break; + + case ICM_DECOMPRESSEX_QUERY: + case ICM_DECOMPRESSEX_BEGIN: + case ICM_DECOMPRESSEX: + case ICM_DECOMPRESSEX_END: + /* unsupported */ + break; + + case ICM_COMPRESS_QUERY: + r = ICERR_BADFORMAT; + /* fall through */ + case ICM_COMPRESS_GET_FORMAT: + case ICM_COMPRESS_END: + case ICM_COMPRESS: + FIXME("compression not implemented\n"); + break; + + case ICM_CONFIGURE: + break; + + default: + FIXME("Unknown message: %04x %Id %Id\n", msg, lParam1, lParam2); + } + + return r; +} + +/*********************************************************************** + * DllMain + */ +BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) +{ + TRACE("(%p,%lu,%p)\n", hModule, dwReason, lpReserved); + + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + IYUV_32_hModule = hModule; + break; + } + return TRUE; +} diff --git a/dlls/iyuv_32/iyuv_32.rc b/dlls/iyuv_32/iyuv_32.rc new file mode 100644 index 00000000000..a9705a2bd76 --- /dev/null +++ b/dlls/iyuv_32/iyuv_32.rc @@ -0,0 +1,29 @@ +/* + * Copyright 2026 Brendan McGrath for CodeWeavers + * + * 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 + */ + +#include "iyuv_private.h" + +#pragma makedep po + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE +{ + IDS_NAME "IYUV codec" + IDS_DESCRIPTION "IYUV codec" +} diff --git a/dlls/iyuv_32/iyuv_32.spec b/dlls/iyuv_32/iyuv_32.spec new file mode 100644 index 00000000000..a0c64b96696 --- /dev/null +++ b/dlls/iyuv_32/iyuv_32.spec @@ -0,0 +1 @@ +@ stdcall -private DriverProc(long long long long long) IYUV_DriverProc diff --git a/dlls/iyuv_32/iyuv_private.h b/dlls/iyuv_32/iyuv_private.h new file mode 100644 index 00000000000..00b5a577c9f --- /dev/null +++ b/dlls/iyuv_32/iyuv_private.h @@ -0,0 +1,34 @@ +/* + * Copyright 2026 Brendan McGrath for CodeWeavers + * + * 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 + */ + +#ifndef __IYUV_PRIVATE_H +#define __IYUV_PRIVATE_H + +#include "windef.h" + +#define COBJMACROS +#include "mfapi.h" +#include "mferror.h" +#include "mfobjects.h" +#include "mfidl.h" +#include "mftransform.h" + +#define IDS_NAME 100 +#define IDS_DESCRIPTION 101 + +#endif /* __IYUV_PRIVATE_H */ diff --git a/loader/wine.inf.in b/loader/wine.inf.in index 8c58fb781e4..fc3f085e68b 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -887,6 +887,8 @@ system.ini, drivers32,,"vidc.mrle=msrle32.dll" system.ini, drivers32,,"vidc.msvc=msvidc32.dll" system.ini, drivers32,,"vidc.cvid=iccvid.dll" system.ini, drivers32,,"vidc.IV50=ir50_32.dll" +system.ini, drivers32,,"vidc.i420=iyuv_32.dll" +system.ini, drivers32,,"vidc.iyuv=iyuv_32.dll" system.ini, drivers32,,"; vidc.IV31=ir32_32.dll" system.ini, drivers32,,"; vidc.IV32=ir32_32.dll" -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10467
From: Brendan McGrath <bmcgrath@codeweavers.com> --- configure.ac | 1 + dlls/iyuv_32/tests/Makefile.in | 6 ++++ dlls/iyuv_32/tests/i420frame.bmp | Bin 0 -> 50742 bytes dlls/iyuv_32/tests/iyuv_32.c | 45 +++++++++++++++++++++++++ dlls/iyuv_32/tests/resource.rc | 30 +++++++++++++++++ dlls/iyuv_32/tests/rgb24frame_flip.bmp | Bin 0 -> 27702 bytes 6 files changed, 82 insertions(+) create mode 100644 dlls/iyuv_32/tests/Makefile.in create mode 100755 dlls/iyuv_32/tests/i420frame.bmp create mode 100644 dlls/iyuv_32/tests/iyuv_32.c create mode 100644 dlls/iyuv_32/tests/resource.rc create mode 100644 dlls/iyuv_32/tests/rgb24frame_flip.bmp diff --git a/configure.ac b/configure.ac index 953edcce7b9..bc898b9bbb5 100644 --- a/configure.ac +++ b/configure.ac @@ -2881,6 +2881,7 @@ WINE_CONFIG_MAKEFILE(dlls/itircl) WINE_CONFIG_MAKEFILE(dlls/itss) WINE_CONFIG_MAKEFILE(dlls/itss/tests) WINE_CONFIG_MAKEFILE(dlls/iyuv_32) +WINE_CONFIG_MAKEFILE(dlls/iyuv_32/tests) WINE_CONFIG_MAKEFILE(dlls/joy.cpl) WINE_CONFIG_MAKEFILE(dlls/jscript) WINE_CONFIG_MAKEFILE(dlls/jscript/tests) diff --git a/dlls/iyuv_32/tests/Makefile.in b/dlls/iyuv_32/tests/Makefile.in new file mode 100644 index 00000000000..7d47050a25b --- /dev/null +++ b/dlls/iyuv_32/tests/Makefile.in @@ -0,0 +1,6 @@ +TESTDLL = iyuv_32.dll +IMPORTS = msvfw32 + +SOURCES = \ + iyuv_32.c \ + resource.rc diff --git a/dlls/iyuv_32/tests/i420frame.bmp b/dlls/iyuv_32/tests/i420frame.bmp new file mode 100755 index 0000000000000000000000000000000000000000..acebee03e4d77aa6f5720df1c0b0bc04940c67fe GIT binary patch literal 50742 zcmZ?rHJiWy24)Nl3>pj!3<(Sj3=97M|If&v02XI}%0oC1^54II|3~p?7>uTY(KIlc z21e7sXc`zz1EXnRG!2ZVfzdQDng&MGz-Ss6O#`E8VECp1hQELRkK)lV7)=ACX<#%B zjHZFnG%%V5M$^D(8W>FjqiJ9?4UDFN(KIlc21e7s@J$2%|1<m_#iL;`ng&MGz-Ss6 zO#`E8U^ESkrh(BkFq#HN)4*sN7)=ACX<#%BjHZF%n+6#EGW;LKqhT<b21e7sXc`zz z1EXnRG!2ZVfzdQDng&MGz-Ss6O#`E8U^ESkrh(y`2L3So`#*|D!(cQGjHZFnG%%V5 zM$^D(8W>FjqiJ9?4UDFN(KIlc21e7sXc`zz1H(5BFfjc2KZ-}gU^ESkrh(BkFq#HN z)4*sN7)=ACX<#%BjHZFnG%%V5M$^D(8W>Fj!#555XJGh0ibum>G!2ZVfzdQDng&MG zz-Ss6O#`E8U^ESkrh(BkFq#HN)4*sN7)=AiHw`c_F#I3IqhT<b21e7sXc`zz1EXnR zG!2ZVfzdQDng&MGz-Ss6O#`E8U^ESkrh(y`240VX(GVC7fzc2cpb)q?3PwX<Gz3ON zV1Pnk)hHMZfzc2c4S@j)feE8vGz3ONU^D~<C<L-b!DtAKhQMeD3{VIJj)Kt;7!85Z z5E!5k&>RJ$Aut*OqaiRrAs{dcMnhmU1V%$(fI^^Q6yObk0g9F(W9_n0fHwrpMgiUs zI5`UNhCtLPz#9S|MgiUsz+1VEN{)sAfe@H93h;)&kZGt5kVBP60p1X}Hwy5E!23~v RHw5xV0p1WGP`!<KX#n}>2Mz!L literal 0 HcmV?d00001 diff --git a/dlls/iyuv_32/tests/iyuv_32.c b/dlls/iyuv_32/tests/iyuv_32.c new file mode 100644 index 00000000000..01b67cc110f --- /dev/null +++ b/dlls/iyuv_32/tests/iyuv_32.c @@ -0,0 +1,45 @@ +/* + * Copyright 2026 Brendan McGrath for CodeWeavers + * + * 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 + */ + +#include <windef.h> +#include <wingdi.h> +#include <vfw.h> +#include "wine/test.h" + +#define FOURCC_I420 mmioFOURCC('I','4','2','0') + +START_TEST(iyuv_32) +{ + BITMAPINFOHEADER in = + { + .biSize = sizeof(BITMAPINFOHEADER), + .biCompression = FOURCC_I420, + .biPlanes = 1, + .biWidth = 96, + .biHeight = 96, + .biSizeImage = 96 * 96 * 3 / 2, + }; + HIC hic; + + hic = ICLocate(ICTYPE_VIDEO, FOURCC_I420, &in, NULL, ICMODE_DECOMPRESS); + todo_wine + ok(!!hic, "Failed to locate iyuv codec\n"); + if (!hic) + return; + ICClose(hic); +} diff --git a/dlls/iyuv_32/tests/resource.rc b/dlls/iyuv_32/tests/resource.rc new file mode 100644 index 00000000000..d963e812105 --- /dev/null +++ b/dlls/iyuv_32/tests/resource.rc @@ -0,0 +1,30 @@ +/* + * Copyright 2026 Brendan McGrath for CodeWeavers + * + * 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 + */ + +#include "windef.h" + +/* Generated with: */ +/* ffmpeg -f lavfi -i pal100bars=size=96x96 \ + * -vf transpose -pix_fmt bgr24 -frames:v 1 \ + * rgb24frame_flip.bmp */ +/* @makedep: rgb24frame_flip.bmp */ +rgb24frame_flip.bmp RCDATA rgb24frame_flip.bmp + +/* Generated by running the compression test on Windows */ +/* @makedep: i420frame.bmp */ +i420frame.bmp RCDATA i420frame.bmp diff --git a/dlls/iyuv_32/tests/rgb24frame_flip.bmp b/dlls/iyuv_32/tests/rgb24frame_flip.bmp new file mode 100644 index 0000000000000000000000000000000000000000..7795fcf3989b8bf6594935c15eedf22829f14229 GIT binary patch literal 27702 zcmZ?rHOpZD12YB&1`P%Vh6E^PWRL)hGeG4boKbQ#1V%$(Gz3ONU^E0qLtr!nMnhmU z1V%$(Gz3ONfSw`nkAYznjfTKz2#kinXb6mkz-S1JhQMeDjE2By2#kinXb8|D1Q;0p zj-t^J7!85Z5Eu=C(GVC7fzc2c4S~@R7!85Z5Eu;sI)uPqhJT}IGz3ONU^E0qLtr!n zMnhmU1V%$(Gz3ONU^E0qLx2t;FuMA1Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3ONU^E0q zLx4UZ@c%!<C>jlc(GVC7fzc2c4S~@R7!85Z5Eu=C(GVC7fzc44LkKYZ{X2?ALtr!n zMnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1n3X~|3|@S2#kinXb6mkz-S1JhQMeDjE2By Q2#kinXb6mk09`@=09!zwZ~y=R literal 0 HcmV?d00001 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10467
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/iyuv_32/tests/iyuv_32.c | 137 +++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/dlls/iyuv_32/tests/iyuv_32.c b/dlls/iyuv_32/tests/iyuv_32.c index 01b67cc110f..ee7b9de689e 100644 --- a/dlls/iyuv_32/tests/iyuv_32.c +++ b/dlls/iyuv_32/tests/iyuv_32.c @@ -22,9 +22,138 @@ #include "wine/test.h" #define FOURCC_I420 mmioFOURCC('I','4','2','0') +#define FOURCC_IYUV mmioFOURCC('I','Y','U','V') + +static void test_formats(DWORD handler) +{ + BITMAPINFOHEADER in = {.biSize = sizeof(BITMAPINFOHEADER)}; + BITMAPINFOHEADER out = {.biSize = sizeof(BITMAPINFOHEADER)}; + ICINFO info; + LRESULT lr; + DWORD res; + HIC hic; + + in.biCompression = handler; + + hic = ICLocate(ICTYPE_VIDEO, handler, &in, NULL, ICMODE_DECOMPRESS); + ok(!hic, "Should fail to open codec without width and/or height.\n"); + + in.biWidth = 320; + in.biHeight = 240; + + hic = ICLocate(ICTYPE_VIDEO, handler, &in, NULL, ICMODE_DECOMPRESS); + ok(!!hic, "Failed to open codec.\n"); + + lr = ICGetInfo(hic, &info, sizeof(info)); + ok(lr == sizeof(info), "Got %Id.\n", lr); + ok(info.dwSize == sizeof(info), "Got size %lu.\n", info.dwSize); + ok(info.fccType == ICTYPE_VIDEO, "Got type %#lx.\n", info.fccType); + ok(info.fccHandler == FOURCC_IYUV, "Got handler %#lx.\n", info.fccHandler); + ok(info.dwFlags == 0, "Got flags %#lx.\n", info.dwFlags); + ok(info.dwVersion == 0, "Got version %#lx.\n", info.dwVersion); + ok(info.dwVersionICM == ICVERSION, "Got ICM version %#lx.\n", info.dwVersionICM); + + res = ICDecompressQuery(hic, &in, NULL); + ok(res == ICERR_OK, "Got %ld.\n", res); + + res = ICDecompressGetFormat(hic, &in, NULL); + ok(res == sizeof(BITMAPINFOHEADER), "Got %ld.\n", res); + + res = ICDecompressGetFormat(hic, &in, &out); + ok(res == ICERR_OK, "Got %ld.\n", res); + ok(out.biSize == sizeof(BITMAPINFOHEADER), "Got size %lu.\n", out.biSize); + ok(out.biWidth == 320, "Got width %ld.\n", out.biWidth); + ok(out.biHeight == 240, "Got height %ld.\n", out.biHeight); + ok(out.biPlanes == 1, "Got %u planes.\n", out.biPlanes); + ok(out.biBitCount == 24, "Got depth %u.\n", out.biBitCount); + ok(out.biCompression == BI_RGB, "Got compression %#lx.\n", out.biCompression); + ok(out.biSizeImage == 320 * 240 * 3, "Got image size %lu.\n", out.biSizeImage); + ok(!out.biXPelsPerMeter, "Got horizontal resolution %ld.\n", out.biXPelsPerMeter); + ok(!out.biYPelsPerMeter, "Got vertical resolution %ld.\n", out.biYPelsPerMeter); + ok(!out.biClrUsed, "Got %lu used colours.\n", out.biClrUsed); + ok(!out.biClrImportant, "Got %lu important colours.\n", out.biClrImportant); + + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_OK, "Got %ld.\n", res); + + out.biHeight = -240; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + + out.biHeight = -480; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + + out.biHeight = 480; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + + out.biWidth = 640; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + + out.biWidth = 160; + out.biHeight = 120; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + + out.biWidth = 320; + out.biHeight = 240; + out.biBitCount = 8; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_OK, "Got %ld.\n", res); + out.biBitCount = 16; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_OK, "Got %ld.\n", res); + out.biBitCount = 32; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + + out.biBitCount = 16; + out.biCompression = BI_BITFIELDS; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + + out.biCompression = mmioFOURCC('C','L','J','R'); + out.biBitCount = 8; + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + + out.biBitCount = 16; + out.biCompression = mmioFOURCC('U','Y','V','Y'); + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + out.biCompression = mmioFOURCC('Y','U','Y','2'); + res = ICDecompressQuery(hic, &in, &out); + ok(res == ICERR_BADFORMAT, "Got %ld.\n", res); + + res = ICDecompressEnd(hic); + ok(res == ICERR_OK, "Got %ld.\n", res); + + out.biCompression = BI_RGB; + out.biBitCount = 24; + res = ICDecompressBegin(hic, &in, &out); + todo_wine + ok(res == ICERR_OK, "Got %ld.\n", res); + + res = ICDecompressEnd(hic); + ok(res == ICERR_OK, "Got %ld.\n", res); + + lr = ICDecompressExQuery(hic, 0, &in, NULL, 0, 0, 320, 240, NULL, NULL, 0, 0, 0, 0); + ok(lr == ICERR_UNSUPPORTED, "Got %Id.\n", lr); + + lr = ICDecompressExBegin(hic, 0, &in, NULL, 0, 0, 320, 240, &out, NULL, 20, 20, 320, 240); + ok(lr == ICERR_UNSUPPORTED, "Got %Id.\n", lr); + lr = ICDecompressExEnd(hic); + ok(lr == ICERR_UNSUPPORTED, "Got %Id.\n", lr); + + res = ICClose(hic); + ok(res == ICERR_OK, "Got %ld.\n", res); +} START_TEST(iyuv_32) { + static const DWORD handler[] = { FOURCC_IYUV, FOURCC_I420 }; BITMAPINFOHEADER in = { .biSize = sizeof(BITMAPINFOHEADER), @@ -35,6 +164,7 @@ START_TEST(iyuv_32) .biSizeImage = 96 * 96 * 3 / 2, }; HIC hic; + int i; hic = ICLocate(ICTYPE_VIDEO, FOURCC_I420, &in, NULL, ICMODE_DECOMPRESS); todo_wine @@ -42,4 +172,11 @@ START_TEST(iyuv_32) if (!hic) return; ICClose(hic); + + for (i = 0; i < ARRAY_SIZE(handler); i++) + { + winetest_push_context("handler %.4s", (char*)&handler[i]); + test_formats(handler[i]); + winetest_pop_context(); + } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10467
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/iyuv_32/tests/iyuv_32.c | 132 +++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/dlls/iyuv_32/tests/iyuv_32.c b/dlls/iyuv_32/tests/iyuv_32.c index ee7b9de689e..efe4158566c 100644 --- a/dlls/iyuv_32/tests/iyuv_32.c +++ b/dlls/iyuv_32/tests/iyuv_32.c @@ -24,6 +24,65 @@ #define FOURCC_I420 mmioFOURCC('I','4','2','0') #define FOURCC_IYUV mmioFOURCC('I','Y','U','V') +#pragma pack(push,2) +struct bmp_header +{ + char magic[2]; + DWORD length; + DWORD reserved; + DWORD offset; +}; +#pragma pack(pop) + + +static void write_bitmap_to_file(const BITMAPINFOHEADER *bitmap_header, const BYTE *data, HANDLE output) +{ + struct bmp_header header = + { + .magic = "BM", + .length = sizeof(header) + sizeof(*bitmap_header) + bitmap_header->biSizeImage, + .offset = sizeof(header) + sizeof(*bitmap_header), + }; + DWORD written; + BOOL ret; + + ret = WriteFile(output, &header, sizeof(header), &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == sizeof(header), "written %lu bytes\n", written); + ret = WriteFile(output, bitmap_header, sizeof(*bitmap_header), &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == sizeof(*bitmap_header), "written %lu bytes\n", written); + ret = WriteFile(output, data, bitmap_header->biSizeImage, &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == bitmap_header->biSizeImage, "written %lu bytes\n", written); +} + +static HANDLE open_temp_file(const WCHAR *output_filename) +{ + WCHAR path[MAX_PATH]; + HANDLE output; + + GetTempPathW(ARRAY_SIZE(path), path); + lstrcatW(path, output_filename); + + output = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(output != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu\n", GetLastError()); + + trace("created %s\n", debugstr_w(path)); + + return output; +} + +static void write_bitmap(const BITMAPINFOHEADER *bitmap_header, const BYTE *data, const WCHAR *output_filename) +{ + HANDLE output; + + output = open_temp_file(output_filename); + write_bitmap_to_file(bitmap_header, data, output); + + CloseHandle(output); +} + static void test_formats(DWORD handler) { BITMAPINFOHEADER in = {.biSize = sizeof(BITMAPINFOHEADER)}; @@ -151,6 +210,78 @@ static void test_formats(DWORD handler) ok(res == ICERR_OK, "Got %ld.\n", res); } +static void test_decompress(DWORD handler) +{ + static const DWORD width = 96, height = 96; + + const struct bmp_header *expect_rgb_header; + const BYTE *expect_rgb_data; + BYTE rgb_data[96 * 96 * 3]; + DWORD res, diff; + BYTE *i420_data; + HRSRC resource; + HIC hic; + + BITMAPINFOHEADER i420_info = + { + .biSize = sizeof(i420_info), + .biWidth = width, + .biHeight = height, + .biPlanes = 1, + .biBitCount = 12, + .biCompression = handler, + }; + + BITMAPINFOHEADER rgb_info = + { + .biSize = sizeof(rgb_info), + .biWidth = width, + .biHeight = height, + .biPlanes = 1, + .biBitCount = 24, + .biCompression = BI_RGB, + .biSizeImage = sizeof(rgb_data), + }; + + resource = FindResourceW(NULL, L"i420frame.bmp", (const WCHAR *)RT_RCDATA); + i420_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + i420_data += *(DWORD*)(i420_data+2); + i420_info.biSizeImage = SizeofResource(GetModuleHandleW(NULL), resource); + + hic = ICOpen(ICTYPE_VIDEO, handler, ICMODE_DECOMPRESS); + ok(!!hic, "Failed to open codec.\n"); + + res = ICDecompressBegin(hic, &i420_info, &rgb_info); + todo_wine + ok(res == ICERR_OK, "Got %ld.\n", res); + + if (res != ICERR_OK) + goto skip_decompression_tests; + + res = ICDecompress(hic, 0, &i420_info, i420_data, &rgb_info, rgb_data); + todo_wine + ok(res == ICERR_OK, "Got %ld.\n", res); + res = ICDecompressEnd(hic); + ok(res == ICERR_OK, "Got %ld.\n", res); + + write_bitmap(&rgb_info, rgb_data, L"rgb24frame_flip.bmp"); + + resource = FindResourceW(NULL, L"rgb24frame_flip.bmp", (const WCHAR *)RT_RCDATA); + expect_rgb_header = ((const struct bmp_header *)LockResource(LoadResource(GetModuleHandleW(NULL), resource))); + expect_rgb_data = (const BYTE*)((uintptr_t)expect_rgb_header + expect_rgb_header->offset); + + diff = 0; + for (unsigned int i = 0; i < rgb_info.biSizeImage; ++i) + diff += abs((int)rgb_data[i] - (int)expect_rgb_data[i]); + diff = diff * 100 / 256 / rgb_info.biSizeImage; + todo_wine + ok(diff == 0, "Got %lu%% difference.\n", diff); + +skip_decompression_tests: + res = ICClose(hic); + ok(res == ICERR_OK, "Got %ld.\n", res); +} + START_TEST(iyuv_32) { static const DWORD handler[] = { FOURCC_IYUV, FOURCC_I420 }; @@ -177,6 +308,7 @@ START_TEST(iyuv_32) { winetest_push_context("handler %.4s", (char*)&handler[i]); test_formats(handler[i]); + test_decompress(handler[i]); winetest_pop_context(); } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10467
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/iyuv_32/tests/iyuv_32.c | 157 +++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/dlls/iyuv_32/tests/iyuv_32.c b/dlls/iyuv_32/tests/iyuv_32.c index efe4158566c..00cd93d10cd 100644 --- a/dlls/iyuv_32/tests/iyuv_32.c +++ b/dlls/iyuv_32/tests/iyuv_32.c @@ -34,6 +34,7 @@ struct bmp_header }; #pragma pack(pop) +typedef UINT32 (*yuv_to_bgr32_converter)(WORD x, WORD y, WORD stride, WORD height, const BYTE *data); static void write_bitmap_to_file(const BITMAPINFOHEADER *bitmap_header, const BYTE *data, HANDLE output) { @@ -83,6 +84,80 @@ static void write_bitmap(const BITMAPINFOHEADER *bitmap_header, const BYTE *data CloseHandle(output); } +static void convert_yuv_and_write_bitmap(const BITMAPINFOHEADER *bitmap_header, const BYTE *data, yuv_to_bgr32_converter convert, const WCHAR *output_filename) +{ + BITMAPINFOHEADER bgr32_header; + UINT32 *bgr32_ptr; + BYTE *bgr32_data; + HANDLE output; + DWORD written; + WORD x, y; + BOOL ret; + + bgr32_header = *bitmap_header; + bgr32_header.biBitCount = 32; + bgr32_header.biCompression = BI_RGB; + bgr32_header.biSizeImage = bgr32_header.biWidth * bgr32_header.biHeight * bgr32_header.biBitCount / 8; + bgr32_header.biHeight = -bitmap_header->biHeight; + bgr32_data = malloc(bgr32_header.biSizeImage); + + output = open_temp_file(output_filename); + bgr32_ptr = (UINT32*)bgr32_data; + for (y = 0; y < bitmap_header->biWidth; y++) + for (x = 0; x < bitmap_header->biHeight; x++) + *bgr32_ptr++ = convert(x, y, bitmap_header->biWidth, bitmap_header->biHeight, data); + + write_bitmap_to_file(&bgr32_header, (BYTE*)bgr32_data, output); + ret = WriteFile(output, data, bitmap_header->biSizeImage, &written, NULL); + ok(ret, "WriteFile failed, error %lu\n", GetLastError()); + ok(written == bitmap_header->biSizeImage, "written %lu bytes\n", written); + + free(bgr32_data); + CloseHandle(output); +} + +#define CLAMP(x) ((x) > 255 ? 255 : (x) < 0 ? 0 : (x)) + +static UINT32 convert_yuv_to_bgr32(INT y, INT u, INT v) +{ + const INT y_offset = 16; + const INT uv_offset = 128; + const INT adj = 1024; + const INT c1 = 1.164 * adj + .5; + const INT c2 = 1.596 * adj + .5; + const INT c3 = 0.391 * adj + .5; + const INT c4 = 0.813 * adj + .5; + const INT c5 = 2.018 * adj + .5; + + INT r, g, b; + + y -= y_offset; + u -= uv_offset; + v -= uv_offset; + + r = CLAMP((c1 * y + c2 * v) / adj); + g = CLAMP((c1 * y - c4 * v - c3 * u) / adj); + b = CLAMP((c1 * y + c5 * u) / adj); + + return 0xff000000 | r << 16 | g << 8 | b; +} + +static UINT32 convert_i420_to_bgr32(WORD x, WORD y, WORD stride, WORD height, const BYTE *data) +{ + WORD uv_offset, u_offset, v_offset; + BYTE yuv_y, yuv_u, yuv_v; + + u_offset = height * stride; + v_offset = u_offset * 5 / 4; + uv_offset = (y / 2) * stride / 2 + x / 2; + + yuv_y = data[y * stride + x]; + yuv_u = data[u_offset + uv_offset]; + yuv_v = data[v_offset + uv_offset]; + + return convert_yuv_to_bgr32(yuv_y, yuv_u, yuv_v); +} + static void test_formats(DWORD handler) { BITMAPINFOHEADER in = {.biSize = sizeof(BITMAPINFOHEADER)}; @@ -282,6 +357,87 @@ skip_decompression_tests: ok(res == ICERR_OK, "Got %ld.\n", res); } +static void test_compress(DWORD handler) +{ + const struct bmp_header *expect_i420_header; + const struct bmp_header *rgb_header; + const BITMAPINFOHEADER *rgb_info; + BYTE i420_data[96 * 96 * 3 / 2]; + const BYTE *expect_i420_data; + BITMAPINFOHEADER i420_info; + DWORD res, flags, diff; + const BYTE *rgb_data; + HRSRC resource; + HIC hic; + + hic = ICOpen(ICTYPE_VIDEO, handler, ICMODE_COMPRESS); + ok(!!hic, "Failed to open codec.\n"); + + resource = FindResourceW(NULL, L"rgb24frame_flip.bmp", (const WCHAR *)RT_RCDATA); + rgb_header = ((const struct bmp_header *)LockResource(LoadResource(GetModuleHandleW(NULL), resource))); + rgb_info = (const BITMAPINFOHEADER *)(rgb_header+1); + rgb_data = (const BYTE *)(rgb_info+1); + + res = ICCompressQuery(hic, rgb_info, NULL); + todo_wine + ok(res == ICERR_OK, "Got %ld.\n", res); + + if (res != ICERR_OK) + goto skip_compression_tests; + + res = ICCompressGetSize(hic, rgb_info, NULL); + ok(res == rgb_info->biWidth * rgb_info->biHeight * 3, "Got %ld.\n", res); + + res = ICCompressGetFormatSize(hic, rgb_info); + ok(res == sizeof(BITMAPINFOHEADER), "Got %ld.\n", res); + + memset(&i420_info, 0xcc, sizeof(i420_info)); + res = ICCompressGetFormat(hic, rgb_info, &i420_info); + ok(res == ICERR_OK, "Got %ld.\n", res); + ok(i420_info.biSize == sizeof(BITMAPINFOHEADER), "Got size %lu.\n", i420_info.biSize); + ok(i420_info.biWidth == 96, "Got width %ld.\n", i420_info.biWidth); + ok(i420_info.biHeight == 96, "Got height %ld.\n", i420_info.biHeight); + ok(i420_info.biPlanes == 1, "Got %u planes.\n", i420_info.biPlanes); + ok(i420_info.biBitCount == 24, "Got depth %u.\n", i420_info.biBitCount); + ok(i420_info.biCompression == FOURCC_IYUV, + "Got compression %#lx.\n", i420_info.biCompression); + ok(i420_info.biSizeImage == rgb_info->biWidth * rgb_info->biHeight * 3, "Got image size %lu.\n", i420_info.biSizeImage); + ok(!i420_info.biXPelsPerMeter, "Got horizontal resolution %ld.\n", i420_info.biXPelsPerMeter); + ok(!i420_info.biYPelsPerMeter, "Got vertical resolution %ld.\n", i420_info.biYPelsPerMeter); + ok(!i420_info.biClrUsed, "Got %lu used colours.\n", i420_info.biClrUsed); + ok(!i420_info.biClrImportant, "Got %lu important colours.\n", i420_info.biClrImportant); + + res = ICCompressQuery(hic, rgb_info, &i420_info); + ok(res == ICERR_OK, "Got %ld.\n", res); + + res = ICCompressBegin(hic, rgb_info, &i420_info); + ok(res == ICERR_OK, "Got %ld.\n", res); + memset(i420_data, 0xcd, sizeof(i420_data)); + res = ICCompress(hic, ICCOMPRESS_KEYFRAME, &i420_info, i420_data, + (BITMAPINFOHEADER *)rgb_info, (void *)rgb_data, NULL, &flags, 1, 0, 0, NULL, NULL); + ok(res == ICERR_OK, "Got %ld.\n", res); + ok(flags == AVIIF_KEYFRAME, "got flags %#lx\n", flags); + ok(i420_info.biSizeImage == sizeof(i420_data), "Got size %ld.\n", i420_info.biSizeImage); + res = ICCompressEnd(hic); + ok(res == ICERR_OK, "Got %ld.\n", res); + + convert_yuv_and_write_bitmap(&i420_info, i420_data, convert_i420_to_bgr32, L"i420frame.bmp"); + + resource = FindResourceW(NULL, L"i420frame.bmp", (const WCHAR *)RT_RCDATA); + expect_i420_header = ((const struct bmp_header *)LockResource(LoadResource(GetModuleHandleW(NULL), resource))); + expect_i420_data = (const BYTE*)((uintptr_t)expect_i420_header + expect_i420_header->length); + + diff = 0; + for (unsigned int i = 0; i < i420_info.biSizeImage; ++i) + diff += abs((int)i420_data[i] - (int)expect_i420_data[i]); + diff = diff * 100 / 256 / i420_info.biSizeImage; + ok(diff == 0, "Got %lu%% difference.\n", diff); + +skip_compression_tests: + res = ICClose(hic); + ok(res == ICERR_OK, "Got %ld.\n", res); +} + START_TEST(iyuv_32) { static const DWORD handler[] = { FOURCC_IYUV, FOURCC_I420 }; @@ -309,6 +465,7 @@ START_TEST(iyuv_32) winetest_push_context("handler %.4s", (char*)&handler[i]); test_formats(handler[i]); test_decompress(handler[i]); + test_compress(handler[i]); winetest_pop_context(); } } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10467
On Fri Mar 27 07:10:12 2026 +0000, Zhiyi Zhang wrote:
Right, you don't need to add configure. Thanks again. I've made that change.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10467#note_133978
v2: - Remove generated files - Remove `winegstreamer` and `mfuuid` from `Makefile.in` (they were not needed) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10467#note_133979
Rémi Bernon (@rbernon) commented about dlls/iyuv_32/iyuv.c:
+ + return ICERR_UNSUPPORTED; +} + +static LRESULT IYUV_GetInfo( ICINFO *icinfo, DWORD dwSize ) +{ + FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); + + return ICERR_UNSUPPORTED; +} + +/*********************************************************************** + * DriverProc (IYUV_32.@) + */ +LRESULT WINAPI IYUV_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, + LPARAM lParam1, LPARAM lParam2 ) We shouldn't use Hungarian notation for new code. Also lets start with a consistent code style across the file, there are various spacing differences.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10467#note_133987
Rémi Bernon (@rbernon) commented about dlls/iyuv_32/tests/resource.rc:
+ * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "windef.h" + +/* Generated with: */ +/* ffmpeg -f lavfi -i pal100bars=size=96x96 \ + * -vf transpose -pix_fmt bgr24 -frames:v 1 \ + * rgb24frame_flip.bmp */ +/* @makedep: rgb24frame_flip.bmp */ +rgb24frame_flip.bmp RCDATA rgb24frame_flip.bmp + +/* Generated by running the compression test on Windows */ +/* @makedep: i420frame.bmp */ +i420frame.bmp RCDATA i420frame.bmp These are unused at this point.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10467#note_133988
On Fri Mar 27 08:59:32 2026 +0000, Rémi Bernon wrote:
We shouldn't use Hungarian notation for new code. Also lets start with a consistent code style across the file, there are various spacing differences. OK, I'll fix that. Are you aware if there is a formatting tool folks are using?
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10467#note_134138
On Fri Mar 27 21:14:57 2026 +0000, Brendan McGrath wrote:
OK, I'll fix that. Are you aware if there is a formatting tool folks are using? I don't think many Wine developers use formatting tools. I use clang-format from time to time, it can be configured to match more or less the styles we use, although sometimes also trips on some cases so it needs to be watched over. Most annoying part is probably the configuration management, as we have different styles in different modules, I have some local patches to store the configs in a separate folder as well as a couple of extra tweaks. It also only handles spacing and indentation and doesn't handle the casing style.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10467#note_134162
participants (3)
-
Brendan McGrath -
Brendan McGrath (@redmcg) -
Rémi Bernon (@rbernon)