Adds an indeo5 video decoder for winmm. This is used by games such as Richman 4 and Zwei: The Arges Adventure.
From: Shaun Ren sren@codeweavers.com
--- configure | 2 + configure.ac | 1 + dlls/ir50_32/Makefile.in | 7 ++ dlls/ir50_32/ir50.c | 181 ++++++++++++++++++++++++++++++++++++ dlls/ir50_32/ir50_32.rc | 29 ++++++ dlls/ir50_32/ir50_32.spec | 1 + dlls/ir50_32/ir50_private.h | 34 +++++++ 7 files changed, 255 insertions(+) create mode 100644 dlls/ir50_32/Makefile.in create mode 100644 dlls/ir50_32/ir50.c create mode 100644 dlls/ir50_32/ir50_32.rc create mode 100644 dlls/ir50_32/ir50_32.spec create mode 100644 dlls/ir50_32/ir50_private.h
diff --git a/configure b/configure index c1c6c4cf93b..9b50e2a7f20 100755 --- a/configure +++ b/configure @@ -1162,6 +1162,7 @@ enable_inkobj enable_inseng enable_iphlpapi enable_iprop +enable_ir50_32 enable_irprops_cpl enable_itircl enable_itss @@ -21281,6 +21282,7 @@ wine_fn_config_makefile dlls/inseng enable_inseng wine_fn_config_makefile dlls/iphlpapi enable_iphlpapi wine_fn_config_makefile dlls/iphlpapi/tests enable_tests wine_fn_config_makefile dlls/iprop enable_iprop +wine_fn_config_makefile dlls/ir50_32 enable_ir50_32 wine_fn_config_makefile dlls/irprops.cpl enable_irprops_cpl wine_fn_config_makefile dlls/itircl enable_itircl wine_fn_config_makefile dlls/itss enable_itss diff --git a/configure.ac b/configure.ac index 9ff7c5e8914..2b0e0eaccff 100644 --- a/configure.ac +++ b/configure.ac @@ -2653,6 +2653,7 @@ WINE_CONFIG_MAKEFILE(dlls/inseng) WINE_CONFIG_MAKEFILE(dlls/iphlpapi) WINE_CONFIG_MAKEFILE(dlls/iphlpapi/tests) WINE_CONFIG_MAKEFILE(dlls/iprop) +WINE_CONFIG_MAKEFILE(dlls/ir50_32) WINE_CONFIG_MAKEFILE(dlls/irprops.cpl) WINE_CONFIG_MAKEFILE(dlls/itircl) WINE_CONFIG_MAKEFILE(dlls/itss) diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in new file mode 100644 index 00000000000..7bac0ccc9ca --- /dev/null +++ b/dlls/ir50_32/Makefile.in @@ -0,0 +1,7 @@ +MODULE = ir50_32.dll +IMPORTS = user32 + +C_SRCS = \ + ir50.c + +RC_SRCS = ir50_32.rc diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c new file mode 100644 index 00000000000..6cabc141878 --- /dev/null +++ b/dlls/ir50_32/ir50.c @@ -0,0 +1,181 @@ +/* + * Intel Indeo 5 Video Decoder + * Copyright 2023 Shaun Ren 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 "ir50_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ir50_32); + +static HINSTANCE IR50_32_hModule; + + +static LRESULT +IV50_Open( const ICINFO *icinfo ) +{ + FIXME("DRV_OPEN %p\n", icinfo); + return 0; +} + +static LRESULT +IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT +IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size ) +{ + FIXME("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) +{ + FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); + return ICERR_UNSUPPORTED; +} + +/*********************************************************************** + * DriverProc (IR50_32.@) + */ +LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, + LPARAM lParam1, LPARAM lParam2 ) +{ + IMFTransform *decoder = (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 = 1; + break; + + case DRV_OPEN: + r = IV50_Open((ICINFO *)lParam2); + break; + + case DRV_CLOSE: + TRACE("DRV_CLOSE\n"); + if ( decoder ) + IMFTransform_Release( decoder ); + r = 1; + break; + + case DRV_ENABLE: + case DRV_DISABLE: + case DRV_FREE: + break; + + case ICM_GETINFO: + r = IV50_GetInfo( (ICINFO *) lParam1, (DWORD) lParam2 ); + break; + + case ICM_DECOMPRESS_QUERY: + r = IV50_DecompressQuery( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_GET_FORMAT: + r = IV50_DecompressGetFormat( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_GET_PALETTE: + FIXME("ICM_DECOMPRESS_GET_PALETTE\n"); + break; + + case ICM_DECOMPRESS: + r = IV50_Decompress( decoder, (ICDECOMPRESS *) lParam1, (DWORD) lParam2 ); + break; + + case ICM_DECOMPRESS_BEGIN: + r = IV50_DecompressBegin( decoder, (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_END: + r = ICERR_UNSUPPORTED; + break; + + case ICM_DECOMPRESSEX_QUERY: + FIXME("ICM_DECOMPRESSEX_QUERY\n"); + break; + + case ICM_DECOMPRESSEX: + FIXME("ICM_DECOMPRESSEX\n"); + 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); + IR50_32_hModule = hModule; + break; + } + return TRUE; +} diff --git a/dlls/ir50_32/ir50_32.rc b/dlls/ir50_32/ir50_32.rc new file mode 100644 index 00000000000..fd98f76fbf6 --- /dev/null +++ b/dlls/ir50_32/ir50_32.rc @@ -0,0 +1,29 @@ +/* + * Copyright 2023 Shaun Ren 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 "ir50_private.h" + +#pragma makedep po + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE +{ + IDS_NAME "Indeo5" + IDS_DESCRIPTION "Indeo Video Interactive version 5 video codec" +} diff --git a/dlls/ir50_32/ir50_32.spec b/dlls/ir50_32/ir50_32.spec new file mode 100644 index 00000000000..e5c54ef9c56 --- /dev/null +++ b/dlls/ir50_32/ir50_32.spec @@ -0,0 +1 @@ +@ stdcall -private DriverProc(long long long long long) IV50_DriverProc diff --git a/dlls/ir50_32/ir50_private.h b/dlls/ir50_32/ir50_private.h new file mode 100644 index 00000000000..c022a8196d2 --- /dev/null +++ b/dlls/ir50_32/ir50_private.h @@ -0,0 +1,34 @@ +/* + * Copyright 2023 Shaun Ren 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 __IR50_PRIVATE_H +#define __IR50_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 /* __IR50_PRIVATE_H */
From: Shaun Ren sren@codeweavers.com
--- dlls/ir50_32/ir50.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 6cabc141878..a55268fba96 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -70,8 +70,23 @@ static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD
static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) { - FIXME("ICM_GETINFO %p %lu\n", icinfo, dwSize); - return ICERR_UNSUPPORTED; + TRACE("ICM_GETINFO %p %lu\n", icinfo, dwSize); + + if ( !icinfo ) return sizeof(ICINFO); + if ( dwSize < sizeof(ICINFO) ) return 0; + + icinfo->dwSize = sizeof(ICINFO); + icinfo->fccType = ICTYPE_VIDEO; + icinfo->fccHandler = IV50_MAGIC; + icinfo->dwFlags = 0; + icinfo->dwVersion = ICVERSION; + icinfo->dwVersionICM = ICVERSION; + + LoadStringW( IR50_32_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName) ); + LoadStringW( IR50_32_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(icinfo->szDescription) ); + /* msvfw32 will fill icinfo->szDriver for us */ + + return sizeof(ICINFO); }
/***********************************************************************
From: Shaun Ren sren@codeweavers.com
--- dlls/ir50_32/ir50.c | 47 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-)
diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index a55268fba96..53f44e787d7 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -45,8 +45,51 @@ IV50_Open( const ICINFO *icinfo ) static LRESULT IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); - return ICERR_UNSUPPORTED; + TRACE("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + + TRACE("in->planes = %d\n", in->bmiHeader.biPlanes); + TRACE("in->bpp = %d\n", in->bmiHeader.biBitCount); + TRACE("in->height = %ld\n", in->bmiHeader.biHeight); + TRACE("in->width = %ld\n", in->bmiHeader.biWidth); + TRACE("in->compr = %#lx\n", in->bmiHeader.biCompression); + + if ( in->bmiHeader.biCompression != IV50_MAGIC ) + { + TRACE("can't do %#lx compression\n", in->bmiHeader.biCompression); + return ICERR_BADFORMAT; + } + + /* output must be same dimensions as input */ + if ( out ) + { + TRACE("out->planes = %d\n", out->bmiHeader.biPlanes); + TRACE("out->bpp = %d\n", out->bmiHeader.biBitCount); + TRACE("out->height = %ld\n", out->bmiHeader.biHeight); + TRACE("out->width = %ld\n", out->bmiHeader.biWidth); + TRACE("out->compr = %#lx\n", out->bmiHeader.biCompression); + + if ( out->bmiHeader.biCompression != BI_RGB ) + { + TRACE("incompatible compression requested\n"); + return ICERR_BADFORMAT; + } + + if ( out->bmiHeader.biBitCount != 32 && out->bmiHeader.biBitCount != 16 ) + { + TRACE("incompatible depth requested\n"); + return ICERR_BADFORMAT; + } + + if ( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes || + in->bmiHeader.biHeight != abs(out->bmiHeader.biHeight) || + in->bmiHeader.biWidth != out->bmiHeader.biWidth ) + { + TRACE("incompatible output dimensions requested\n"); + return ICERR_BADFORMAT; + } + } + + return ICERR_OK; }
static LRESULT
From: Shaun Ren sren@codeweavers.com
--- dlls/ir50_32/ir50.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 53f44e787d7..847378a8965 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -95,8 +95,28 @@ IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) static LRESULT IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); - return ICERR_UNSUPPORTED; + DWORD size; + + TRACE("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + + if ( !in ) + return ICERR_BADPARAM; + + if ( in->bmiHeader.biCompression != IV50_MAGIC ) + return ICERR_BADFORMAT; + + size = in->bmiHeader.biSize; + if ( out ) + { + memcpy( out, in, size ); + out->bmiHeader.biHeight = abs(in->bmiHeader.biHeight); + out->bmiHeader.biCompression = BI_RGB; + out->bmiHeader.biBitCount = 32; + out->bmiHeader.biSizeImage = out->bmiHeader.biWidth * out->bmiHeader.biHeight * 4; + return ICERR_OK; + } + + return size; }
static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out )
From: Shaun Ren sren@codeweavers.com
--- dlls/winegstreamer/mfplat.c | 31 ++++++++++++++++++++++++++++++ dlls/winegstreamer/quartz_parser.c | 2 ++ dlls/winegstreamer/unixlib.h | 7 +++++++ dlls/winegstreamer/wg_format.c | 22 +++++++++++++++++++++ dlls/winegstreamer/wg_transform.c | 2 ++ dlls/winegstreamer/wm_reader.c | 4 ++++ 6 files changed, 68 insertions(+)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c index a09c67b4f11..1f9fd0642b8 100644 --- a/dlls/winegstreamer/mfplat.c +++ b/dlls/winegstreamer/mfplat.c @@ -38,6 +38,7 @@ DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0 DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70); DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC,WAVE_FORMAT_RAW_AAC1); DEFINE_MEDIATYPE_GUID(MFVideoFormat_VC1S,MAKEFOURCC('V','C','1','S')); +DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50,MAKEFOURCC('I','V','5','0'));
struct class_factory { @@ -555,6 +556,7 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: @@ -804,6 +806,33 @@ static void mf_media_type_to_wg_format_video_h264(IMFMediaType *type, struct wg_ format->u.video_h264.level = level; }
+static void mf_media_type_to_wg_format_video_indeo(IMFMediaType *type, uint32_t version, struct wg_format *format) +{ + UINT64 frame_rate, frame_size; + + memset(format, 0, sizeof(*format)); + format->major_type = WG_MAJOR_TYPE_VIDEO_INDEO; + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + format->u.video_indeo.width = frame_size >> 32; + format->u.video_indeo.height = (UINT32)frame_size; + } + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) + { + format->u.video_indeo.fps_n = frame_rate >> 32; + format->u.video_indeo.fps_d = (UINT32)frame_rate; + } + else + { + format->u.video_indeo.fps_n = 1; + format->u.video_indeo.fps_d = 1; + } + + format->u.video_indeo.version = version; +} + void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) { GUID major_type, subtype; @@ -837,6 +866,8 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) { if (IsEqualGUID(&subtype, &MFVideoFormat_H264)) mf_media_type_to_wg_format_video_h264(type, format); + else if (IsEqualGUID(&subtype, &MFVideoFormat_IV50)) + mf_media_type_to_wg_format_video_indeo(type, 5, format); else mf_media_type_to_wg_format_video(type, &subtype, format); } diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 5561b106327..c12e9ee3397 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -377,6 +377,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); return 0;
@@ -548,6 +549,7 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 5424633003e..17517d6e8d6 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -43,6 +43,7 @@ struct wg_format WG_MAJOR_TYPE_VIDEO_CINEPAK, WG_MAJOR_TYPE_VIDEO_H264, WG_MAJOR_TYPE_VIDEO_WMV, + WG_MAJOR_TYPE_VIDEO_INDEO, } major_type;
union @@ -133,6 +134,12 @@ struct wg_format uint32_t fps_n, fps_d; uint32_t version; } video_wmv; + struct + { + int32_t width, height; + uint32_t fps_n, fps_d; + uint32_t version; + } video_indeo; } u; };
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index a7876977d6c..63f1e3931b5 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -573,6 +573,25 @@ static GstCaps *wg_format_to_caps_video_wmv(const struct wg_format *format) return caps; }
+static GstCaps *wg_format_to_caps_video_indeo(const struct wg_format *format) +{ + GstCaps *caps; + + if (!(caps = gst_caps_new_empty_simple("video/x-indeo"))) + return NULL; + + if (format->u.video_indeo.width) + gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video_indeo.width, NULL); + if (format->u.video_indeo.height) + gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video_indeo.height, NULL); + if (format->u.video_indeo.fps_d || format->u.video_indeo.fps_n) + gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video_indeo.fps_n, format->u.video_indeo.fps_d, NULL); + if (format->u.video_indeo.version) + gst_caps_set_simple(caps, "indeoversion", G_TYPE_INT, format->u.video_indeo.version, NULL); + + return caps; +} + GstCaps *wg_format_to_caps(const struct wg_format *format) { switch (format->major_type) @@ -595,6 +614,8 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) return wg_format_to_caps_video_h264(format); case WG_MAJOR_TYPE_VIDEO_WMV: return wg_format_to_caps_video_wmv(format); + case WG_MAJOR_TYPE_VIDEO_INDEO: + return wg_format_to_caps_video_indeo(format); } assert(0); return NULL; @@ -612,6 +633,7 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: GST_FIXME("Format %u not implemented!", a->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 302a64eb57b..7a3e2a69ce4 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -427,6 +427,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_CINEPAK: + case WG_MAJOR_TYPE_VIDEO_INDEO: if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps)) || !transform_append_element(transform, element, &first, &last)) { @@ -482,6 +483,7 @@ NTSTATUS wg_transform_create(void *args) case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_UNKNOWN: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: GST_FIXME("Format %u not implemented!", output_format.major_type); goto out; } diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 18b0e8a90bc..6a0068ced3c 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1579,6 +1579,8 @@ static const char *get_major_type_string(enum wg_major_type type) return "h264"; case WG_MAJOR_TYPE_VIDEO_WMV: return "wmv"; + case WG_MAJOR_TYPE_VIDEO_INDEO: + return "indeo"; case WG_MAJOR_TYPE_UNKNOWN: return "unknown"; } @@ -1933,6 +1935,7 @@ static HRESULT WINAPI reader_GetOutputFormat(IWMSyncReader2 *iface, case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format.major_type); break; case WG_MAJOR_TYPE_UNKNOWN: @@ -1974,6 +1977,7 @@ static HRESULT WINAPI reader_GetOutputFormatCount(IWMSyncReader2 *iface, DWORD o case WG_MAJOR_TYPE_VIDEO_CINEPAK: case WG_MAJOR_TYPE_VIDEO_H264: case WG_MAJOR_TYPE_VIDEO_WMV: + case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format.major_type); /* fallthrough */ case WG_MAJOR_TYPE_AUDIO:
From: Shaun Ren sren@codeweavers.com
--- dlls/winegstreamer/Makefile.in | 1 + dlls/winegstreamer/video_decoder.c | 229 ++++++++++++++++++++++++++ dlls/winegstreamer/winegstreamer.spec | 1 + 3 files changed, 231 insertions(+) create mode 100644 dlls/winegstreamer/video_decoder.c
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in index 064a8b68343..82b1c148d6b 100644 --- a/dlls/winegstreamer/Makefile.in +++ b/dlls/winegstreamer/Makefile.in @@ -16,6 +16,7 @@ C_SRCS = \ quartz_parser.c \ quartz_transform.c \ resampler.c \ + video_decoder.c \ video_processor.c \ wg_allocator.c \ wg_format.c \ diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c new file mode 100644 index 00000000000..5706bd13325 --- /dev/null +++ b/dlls/winegstreamer/video_decoder.c @@ -0,0 +1,229 @@ +/* Generic Video Decoder Transform + * + * Copyright 2022 Rémi Bernon for CodeWeavers + * Copyright 2023 Shaun Ren 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 "gst_private.h" + +#include "mfapi.h" +#include "mferror.h" +#include "mfobjects.h" +#include "mftransform.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) +{ + FIXME("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + return E_NOTIMPL; +} + +static ULONG WINAPI transform_AddRef(IMFTransform *iface) +{ + FIXME("iface %p.\n", iface); + return E_NOTIMPL; +} + +static ULONG WINAPI transform_Release(IMFTransform *iface) +{ + FIXME("iface %p.\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, + DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) +{ + FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", + iface, input_minimum, input_maximum, output_minimum, output_maximum); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) +{ + TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, + DWORD output_size, DWORD *outputs) +{ + FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, + input_size, inputs, output_size, outputs); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) +{ + FIXME("iface %p, id %#lx, info %p.\n", iface, id, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) +{ + FIXME("iface %p, attributes %p semi-stub!\n", iface, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p.\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes) +{ + FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id) +{ + FIXME("iface %p, id %#lx.\n", iface, id); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) +{ + FIXME("iface %p, streams %lu, ids %p.\n", iface, streams, ids); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, + IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, + DWORD index, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) +{ + FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) +{ + FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) +{ + FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags) +{ + FIXME("iface %p, flags %p stub!\n", iface, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) +{ + TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) +{ + FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) +{ + FIXME("iface %p, message %#x, param %Ix stub!\n", iface, message, param); + return S_OK; +} + +static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) +{ + FIXME("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, + MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) +{ + FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + return E_NOTIMPL; +} + +static const IMFTransformVtbl transform_vtbl = +{ + transform_QueryInterface, + transform_AddRef, + transform_Release, + transform_GetStreamLimits, + transform_GetStreamCount, + transform_GetStreamIDs, + transform_GetInputStreamInfo, + transform_GetOutputStreamInfo, + transform_GetAttributes, + transform_GetInputStreamAttributes, + transform_GetOutputStreamAttributes, + transform_DeleteInputStream, + transform_AddInputStreams, + transform_GetInputAvailableType, + transform_GetOutputAvailableType, + transform_SetInputType, + transform_SetOutputType, + transform_GetInputCurrentType, + transform_GetOutputCurrentType, + transform_GetInputStatus, + transform_GetOutputStatus, + transform_SetOutputBounds, + transform_ProcessEvent, + transform_ProcessMessage, + transform_ProcessInput, + transform_ProcessOutput, +}; + +HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) +{ + FIXME("out %p.\n", out); + return E_NOTIMPL; +} diff --git a/dlls/winegstreamer/winegstreamer.spec b/dlls/winegstreamer/winegstreamer.spec index 9804e324044..095f75a0865 100644 --- a/dlls/winegstreamer/winegstreamer.spec +++ b/dlls/winegstreamer/winegstreamer.spec @@ -3,3 +3,4 @@ @ stdcall -private DllRegisterServer() @ stdcall -private DllUnregisterServer() @ stdcall winegstreamer_create_wm_sync_reader(ptr ptr) +@ stdcall winegstreamer_create_video_decoder(ptr)
From: Shaun Ren sren@codeweavers.com
--- dlls/winegstreamer/video_decoder.c | 425 +++++++++++++++++++++++++++-- 1 file changed, 400 insertions(+), 25 deletions(-)
diff --git a/dlls/winegstreamer/video_decoder.c b/dlls/winegstreamer/video_decoder.c index 5706bd13325..90f0b43adc9 100644 --- a/dlls/winegstreamer/video_decoder.c +++ b/dlls/winegstreamer/video_decoder.c @@ -29,43 +29,190 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0')); + +static const GUID *const input_types[] = +{ + &MFVideoFormat_H264, + &MFVideoFormat_IV50, +}; +static const GUID *const output_types[] = +{ + &MFVideoFormat_YV12, + &MFVideoFormat_YUY2, + &MFVideoFormat_NV11, + &MFVideoFormat_NV12, + &MFVideoFormat_RGB32, + &MFVideoFormat_RGB24, + &MFVideoFormat_RGB565, + &MFVideoFormat_RGB555, + &MFVideoFormat_RGB8, +}; + +struct video_decoder +{ + IMFTransform IMFTransform_iface; + LONG refcount; + + IMFMediaType *input_type; + IMFMediaType *output_type; + + struct wg_format wg_format; + struct wg_transform *wg_transform; + struct wg_sample_queue *wg_sample_queue; +}; + +static struct video_decoder *impl_from_IMFTransform(IMFTransform *iface) +{ + return CONTAINING_RECORD(iface, struct video_decoder, IMFTransform_iface); +} + +static HRESULT try_create_wg_transform(struct video_decoder *decoder) +{ + struct wg_format input_format; + struct wg_format output_format; + + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + decoder->wg_transform = NULL; + + mf_media_type_to_wg_format(decoder->input_type, &input_format); + if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + mf_media_type_to_wg_format(decoder->output_type, &output_format); + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) + return MF_E_INVALIDMEDIATYPE; + + /* Don't force any specific size, the video stream already has the metadata for it + * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later. + */ + output_format.u.video.width = 0; + output_format.u.video.height = 0; + output_format.u.video.fps_d = 0; + output_format.u.video.fps_n = 0; + + if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) + { + ERR("Failed to create transform with input major_type %u.\n", input_format.major_type); + return E_FAIL; + } + + return S_OK; +} + +static HRESULT fill_output_media_type(struct video_decoder *decoder, IMFMediaType *media_type) +{ + struct wg_format *wg_format = &decoder->wg_format; + UINT32 value, width, height; + UINT64 ratio; + GUID subtype; + HRESULT hr; + + if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &ratio))) + { + ratio = (UINT64)wg_format->u.video.width << 32 | wg_format->u.video.height; + if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ratio))) + return hr; + } + width = ratio >> 32; + height = ratio; + + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL))) + { + ratio = (UINT64)wg_format->u.video.fps_n << 32 | wg_format->u.video.fps_d; + if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ratio))) + return hr; + } + + if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) + { + if (FAILED(hr = MFCalculateImageSize(&subtype, width, height, &value))) + return hr; + if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value))) + return hr; + } + + return S_OK; +} + static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out) { - FIXME("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || + IsEqualGUID(iid, &IID_IMFTransform)) + *out = &decoder->IMFTransform_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; }
static ULONG WINAPI transform_AddRef(IMFTransform *iface) { - FIXME("iface %p.\n", iface); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedIncrement(&decoder->refcount); + + TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); + + return refcount; }
static ULONG WINAPI transform_Release(IMFTransform *iface) { - FIXME("iface %p.\n", iface); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + ULONG refcount = InterlockedDecrement(&decoder->refcount); + + TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); + + if (!refcount) + { + if (decoder->wg_transform) + wg_transform_destroy(decoder->wg_transform); + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + + wg_sample_queue_destroy(decoder->wg_sample_queue); + free(decoder); + } + + return refcount; }
static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) { - FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", + TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum); - return E_NOTIMPL; + *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; + return S_OK; }
static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) { TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs); - return E_NOTIMPL; + *inputs = *outputs = 1; + return S_OK; }
static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, DWORD output_size, DWORD *outputs) { - FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, - input_size, inputs, output_size, outputs); + TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface, + input_size, inputs, output_size, outputs); return E_NOTIMPL; }
@@ -114,27 +261,175 @@ static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD strea static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); - return E_NOTIMPL; + IMFMediaType *media_type; + const GUID *subtype; + HRESULT hr; + + TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + + *type = NULL; + + if (index >= ARRAY_SIZE(input_types)) + return MF_E_NO_MORE_TYPES; + subtype = input_types[index]; + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + + if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) && + SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype))) + IMFMediaType_AddRef((*type = media_type)); + + IMFMediaType_Release(media_type); + return hr; }
static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, IMFMediaType **type) { - FIXME("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + IMFMediaType *media_type; + const GUID *output_type; + HRESULT hr; + + TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); + + if (!decoder->input_type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *type = NULL; + + if (index >= ARRAY_SIZE(output_types)) + return MF_E_NO_MORE_TYPES; + output_type = output_types[index]; + + if (FAILED(hr = MFCreateMediaType(&media_type))) + return hr; + + if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) + goto done; + if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) + goto done; + + hr = fill_output_media_type(decoder, media_type); + +done: + if (SUCCEEDED(hr)) + IMFMediaType_AddRef((*type = media_type)); + + IMFMediaType_Release(media_type); + return hr; }
static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + GUID major, subtype; + UINT64 frame_size; + HRESULT hr; + ULONG i; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || + FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + return E_INVALIDARG; + + if (!IsEqualGUID(&major, &MFMediaType_Video)) + return MF_E_INVALIDMEDIATYPE; + + for (i = 0; i < ARRAY_SIZE(input_types); ++i) + if (IsEqualGUID(&subtype, input_types[i])) + break; + if (i == ARRAY_SIZE(input_types)) + return MF_E_INVALIDMEDIATYPE; + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + + if (decoder->output_type) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + + if (decoder->input_type) + IMFMediaType_Release(decoder->input_type); + IMFMediaType_AddRef((decoder->input_type = type)); + + if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) + { + decoder->wg_format.u.video.width = frame_size >> 32; + decoder->wg_format.u.video.height = (UINT32)frame_size; + } + + return S_OK; }
static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) { - FIXME("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + GUID major, subtype; + UINT64 frame_size; + HRESULT hr; + ULONG i; + + TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); + + if (!decoder->input_type) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || + FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (!IsEqualGUID(&major, &MFMediaType_Video)) + return MF_E_INVALIDMEDIATYPE; + + for (i = 0; i < ARRAY_SIZE(output_types); ++i) + if (IsEqualGUID(&subtype, output_types[i])) + break; + if (i == ARRAY_SIZE(output_types)) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(hr = IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)) + || (frame_size >> 32) != decoder->wg_format.u.video.width + || (UINT32)frame_size != decoder->wg_format.u.video.height) + return MF_E_INVALIDMEDIATYPE; + if (flags & MFT_SET_TYPE_TEST_ONLY) + return S_OK; + + if (decoder->output_type) + IMFMediaType_Release(decoder->output_type); + IMFMediaType_AddRef((decoder->output_type = type)); + + if (decoder->wg_transform) + { + struct wg_format output_format; + mf_media_type_to_wg_format(decoder->output_type, &output_format); + + /* Don't force any specific size, the video stream already has the metadata for it + * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later. + */ + output_format.u.video.width = 0; + output_format.u.video.height = 0; + output_format.u.video.fps_d = 0; + output_format.u.video.fps_n = 0; + + if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN + || !wg_transform_set_output_format(decoder->wg_transform, &output_format)) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + return MF_E_INVALIDMEDIATYPE; + } + } + else if (FAILED(hr = try_create_wg_transform(decoder))) + { + IMFMediaType_Release(decoder->output_type); + decoder->output_type = NULL; + } + + return hr; }
static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) @@ -181,15 +476,71 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_
static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) { - FIXME("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + HRESULT hr; + + TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + hr = wg_transform_push_mf(decoder->wg_transform, sample, decoder->wg_sample_queue); + + return hr; }
static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) { - FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); - return E_NOTIMPL; + struct video_decoder *decoder = impl_from_IMFTransform(iface); + struct wg_format wg_format; + UINT32 sample_size; + UINT64 frame_rate; + GUID subtype; + HRESULT hr; + + TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); + + if (count != 1) + return E_INVALIDARG; + + if (!decoder->wg_transform) + return MF_E_TRANSFORM_TYPE_NOT_SET; + + *status = samples->dwStatus = 0; + if (!samples->pSample) + return E_INVALIDARG; + + if (FAILED(hr = IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, + decoder->wg_format.u.video.height, &sample_size))) + return hr; + + if (SUCCEEDED(hr = wg_transform_read_mf(decoder->wg_transform, samples->pSample, + sample_size, &wg_format, &samples->dwStatus))) + wg_sample_queue_flush(decoder->wg_sample_queue, false); + + if (hr == MF_E_TRANSFORM_STREAM_CHANGE) + { + decoder->wg_format = wg_format; + + if (FAILED(hr = MFCalculateImageSize(&subtype, decoder->wg_format.u.video.width, + decoder->wg_format.u.video.height, &sample_size))) + return hr; + + /* keep the frame rate that was requested, GStreamer doesn't provide any */ + if (SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &frame_rate))) + { + decoder->wg_format.u.video.fps_n = frame_rate >> 32; + decoder->wg_format.u.video.fps_d = (UINT32)frame_rate; + } + + samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; + } + + return hr; }
static const IMFTransformVtbl transform_vtbl = @@ -224,6 +575,30 @@ static const IMFTransformVtbl transform_vtbl =
HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) { - FIXME("out %p.\n", out); - return E_NOTIMPL; + struct video_decoder *decoder; + HRESULT hr; + + TRACE("out %p.\n", out); + + if (!(decoder = calloc(1, sizeof(*decoder)))) + return E_OUTOFMEMORY; + + decoder->IMFTransform_iface.lpVtbl = &transform_vtbl; + decoder->refcount = 1; + decoder->wg_format.u.video.format = WG_VIDEO_FORMAT_UNKNOWN; + decoder->wg_format.u.video.width = 1920; + decoder->wg_format.u.video.height = 1080; + decoder->wg_format.u.video.fps_n = 30000; + decoder->wg_format.u.video.fps_d = 1001; + + if (FAILED(hr = wg_sample_queue_create(&decoder->wg_sample_queue))) + goto failed; + + *out = &decoder->IMFTransform_iface; + TRACE("created decoder %p.\n", *out); + return S_OK; + +failed: + free(decoder); + return hr; }
From: Shaun Ren sren@codeweavers.com
--- dlls/ir50_32/Makefile.in | 3 +- dlls/ir50_32/ir50.c | 172 ++++++++++++++++++++++++++++++++++-- dlls/ir50_32/ir50_private.h | 2 + 3 files changed, 170 insertions(+), 7 deletions(-)
diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in index 7bac0ccc9ca..2db9c8076c9 100644 --- a/dlls/ir50_32/Makefile.in +++ b/dlls/ir50_32/Makefile.in @@ -1,5 +1,6 @@ MODULE = ir50_32.dll -IMPORTS = user32 +IMPORTS = user32 mfplat mfuuid +DELAYIMPORTS = winegstreamer
C_SRCS = \ ir50.c diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 847378a8965..170cfe870ea 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -30,16 +30,36 @@
#include "wine/debug.h"
+DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0')); + WINE_DEFAULT_DEBUG_CHANNEL(ir50_32);
static HINSTANCE IR50_32_hModule;
+#define IV50_MAGIC mmioFOURCC('I','V','5','0') +#define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) + + +static inline UINT64 +make_uint64( UINT32 high, UINT32 low ) +{ + return ((UINT64)high << 32) | low; +}
static LRESULT IV50_Open( const ICINFO *icinfo ) { - FIXME("DRV_OPEN %p\n", icinfo); - return 0; + IMFTransform *decoder = NULL; + + TRACE("DRV_OPEN %p\n", icinfo); + + if ( icinfo && compare_fourcc( icinfo->fccType, ICTYPE_VIDEO ) ) + return 0; + + if ( FAILED(winegstreamer_create_video_decoder( &decoder )) ) + return 0; + + return (LRESULT)decoder; }
static LRESULT @@ -121,14 +141,154 @@ IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out )
static LRESULT IV50_DecompressBegin( IMFTransform *decoder, LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); - return ICERR_UNSUPPORTED; + IMFMediaType *input_type, *output_type; + const GUID *output_subtype; + LRESULT r = ICERR_INTERNAL; + + TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", decoder, in, out); + + if ( !decoder ) + return ICERR_BADPARAM; + + TRACE("out->planes = %d\n", out->bmiHeader.biPlanes); + TRACE("out->bpp = %d\n", out->bmiHeader.biBitCount); + TRACE("out->height = %ld\n", out->bmiHeader.biHeight); + TRACE("out->width = %ld\n", out->bmiHeader.biWidth); + TRACE("out->compr = %#lx\n", out->bmiHeader.biCompression); + + if ( out->bmiHeader.biBitCount == 32 ) + output_subtype = &MFVideoFormat_RGB32; + else if ( out->bmiHeader.biBitCount == 16 ) + output_subtype = &MFVideoFormat_RGB555; + else + return ICERR_BADFORMAT; + + if ( FAILED(MFCreateMediaType( &input_type )) ) + return ICERR_INTERNAL; + + if ( FAILED(MFCreateMediaType( &output_type )) ) + { + IMFMediaType_Release( input_type ); + return ICERR_INTERNAL; + } + + if ( FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) || + FAILED(IMFMediaType_SetGUID( input_type, &MF_MT_SUBTYPE, &MFVideoFormat_IV50 )) ) + goto done; + if ( FAILED(IMFMediaType_SetUINT64( + input_type, &MF_MT_FRAME_SIZE, + make_uint64( in->bmiHeader.biWidth, in->bmiHeader.biHeight ) )) ) + goto done; + + if ( FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) || + FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_SUBTYPE, output_subtype )) ) + goto done; + if ( FAILED(IMFMediaType_SetUINT64( + output_type, &MF_MT_FRAME_SIZE, + make_uint64( out->bmiHeader.biWidth, abs(out->bmiHeader.biHeight) ) )) ) + goto done; + + if ( FAILED(IMFTransform_SetInputType( decoder, 0, input_type, 0 )) || + FAILED(IMFTransform_SetOutputType( decoder, 0, output_type, 0 )) ) + goto done; + + IMFTransform_ProcessMessage( decoder, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0 ); + + r = ICERR_OK; + +done: + IMFMediaType_Release( input_type ); + IMFMediaType_Release( output_type ); + return r; }
static LRESULT IV50_Decompress( IMFTransform *decoder, ICDECOMPRESS *icd, DWORD size ) { - FIXME("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); - return ICERR_UNSUPPORTED; + IMFSample *in_sample = NULL, *out_sample = NULL; + IMFMediaBuffer *in_buf = NULL, *out_buf = NULL; + MFT_OUTPUT_DATA_BUFFER mft_buf; + DWORD mft_status; + BYTE *data; + HRESULT hr; + LRESULT r = ICERR_INTERNAL; + + TRACE("ICM_DECOMPRESS %p %p %lu\n", decoder, icd, size); + + if ( FAILED(MFCreateSample( &in_sample )) ) + return ICERR_INTERNAL; + + if ( FAILED(MFCreateMemoryBuffer( icd->lpbiInput->biSizeImage, &in_buf )) ) + goto done; + + if ( FAILED(IMFSample_AddBuffer( in_sample, in_buf )) ) + goto done; + + if ( FAILED(MFCreateSample( &out_sample )) ) + goto done; + + if ( FAILED(MFCreateMemoryBuffer( icd->lpbiOutput->biSizeImage, &out_buf )) ) + goto done; + + if ( FAILED(IMFSample_AddBuffer( out_sample, out_buf )) ) + goto done; + + if ( FAILED(IMFMediaBuffer_Lock( in_buf, &data, NULL, NULL ))) + goto done; + + memcpy( data, icd->lpInput, icd->lpbiInput->biSizeImage ); + + if ( FAILED(IMFMediaBuffer_Unlock( in_buf )) ) + goto done; + + if ( FAILED(IMFMediaBuffer_SetCurrentLength( in_buf, icd->lpbiInput->biSizeImage )) ) + goto done; + + if ( FAILED(IMFTransform_ProcessInput( decoder, 0, in_sample, 0 )) ) + goto done; + + memset( &mft_buf, 0, sizeof(mft_buf) ); + mft_buf.pSample = out_sample; + + hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); + if ( SUCCEEDED(hr) && (mft_status & MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE) ) + hr = IMFTransform_ProcessOutput( decoder, 0, 1, &mft_buf, &mft_status ); + + if ( SUCCEEDED(hr) ) + { + LONG width = icd->lpbiOutput->biWidth * (icd->lpbiOutput->biBitCount / 8); + LONG height = abs( icd->lpbiOutput->biHeight ); + LONG data_stride = (width + 3) & ~3; + LONG out_stride = icd->lpbiOutput->biHeight >= 0 ? -data_stride : data_stride; + BYTE *output_start = (BYTE *)icd->lpOutput; + + if (out_stride < 0) + output_start += (height - 1) * abs(out_stride); + + if ( FAILED(IMFMediaBuffer_Lock( out_buf, &data, NULL, NULL ))) + goto done; + + MFCopyImage( output_start, out_stride, data, data_stride, width, height ); + + IMFMediaBuffer_Unlock( out_buf ); + r = ICERR_OK; + } + else if ( hr == MF_E_TRANSFORM_NEED_MORE_INPUT ) + { + TRACE("no output received.\n"); + r = ICERR_OK; + } + +done: + if ( in_buf ) + IMFMediaBuffer_Release( in_buf ); + if ( in_sample ) + IMFSample_Release( in_sample ); + if ( out_buf ) + IMFMediaBuffer_Release( out_buf ); + if ( out_sample ) + IMFSample_Release( out_sample ); + + return r; }
static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) diff --git a/dlls/ir50_32/ir50_private.h b/dlls/ir50_32/ir50_private.h index c022a8196d2..c0b96bc17e4 100644 --- a/dlls/ir50_32/ir50_private.h +++ b/dlls/ir50_32/ir50_private.h @@ -31,4 +31,6 @@ #define IDS_NAME 100 #define IDS_DESCRIPTION 101
+HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out); + #endif /* __IR50_PRIVATE_H */
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=129037
Your paranoid android.
=== debian11 (build log) ===
/home/winetest/tools/testbot/var/wine-win32/include/mfobjects.h:2135: undefined reference to `MFVideoFormat_IV50' collect2: error: ld returned 1 exit status Task: The win32 Wine build failed
=== debian11b (build log) ===
/usr/bin/x86_64-w64-mingw32-ld: dlls/ir50_32/x86_64-windows/ir50.o:ir50.c:(.rdata$.refptr.MFVideoFormat_IV50[.refptr.MFVideoFormat_IV50]+0x0): undefined reference to `MFVideoFormat_IV50' collect2: error: ld returned 1 exit status Task: The wow64 Wine build failed
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/video_decoder.c:
- transform_SetOutputType,
- transform_GetInputCurrentType,
- transform_GetOutputCurrentType,
- transform_GetInputStatus,
- transform_GetOutputStatus,
- transform_SetOutputBounds,
- transform_ProcessEvent,
- transform_ProcessMessage,
- transform_ProcessInput,
- transform_ProcessOutput,
+};
+HRESULT WINAPI winegstreamer_create_video_decoder(IMFTransform **out) +{
- FIXME("out %p.\n", out);
- return E_NOTIMPL;
You should at least allocate the object, set the vtable and implement refcounting, otherwise all the stub methods are dead code.
Rémi Bernon (@rbernon) commented about configure:
enable_inseng enable_iphlpapi enable_iprop +enable_ir50_32
You don't *need* (as in unnecessary) to commit the `configure` changes, only `configure.ac`. It will be generated by Alexandre to make sure it's all generated with the same autotools version before merging.
Rémi Bernon (@rbernon) commented about dlls/ir50_32/ir50.c:
- switch( msg )
- {
- case DRV_LOAD:
TRACE("DRV_LOAD\n");
r = 1;
break;
- case DRV_OPEN:
r = IV50_Open((ICINFO *)lParam2);
break;
- case DRV_CLOSE:
TRACE("DRV_CLOSE\n");
if ( decoder )
IMFTransform_Release( decoder );
Maybe this should be moved to the commit where you implement `DRV_OPEN`?
Rémi Bernon (@rbernon) commented about dlls/ir50_32/ir50.c:
make_uint64( in->bmiHeader.biWidth, in->bmiHeader.biHeight ) )) )
goto done;
- if ( FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video )) ||
FAILED(IMFMediaType_SetGUID( output_type, &MF_MT_SUBTYPE, output_subtype )) )
goto done;
- if ( FAILED(IMFMediaType_SetUINT64(
output_type, &MF_MT_FRAME_SIZE,
make_uint64( out->bmiHeader.biWidth, abs(out->bmiHeader.biHeight) ) )) )
goto done;
- if ( FAILED(IMFTransform_SetInputType( decoder, 0, input_type, 0 )) ||
FAILED(IMFTransform_SetOutputType( decoder, 0, output_type, 0 )) )
goto done;
- IMFTransform_ProcessMessage( decoder, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0 );
I don't think you need this.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/video_decoder.c:
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+DEFINE_MEDIATYPE_GUID(MFVideoFormat_IV50, MAKEFOURCC('I','V','5','0'));
+static const GUID *const input_types[] = +{
- &MFVideoFormat_H264,
Probably H264 shouldn't be included here for now.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/video_decoder.c:
- mf_media_type_to_wg_format(decoder->input_type, &input_format);
- if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
return MF_E_INVALIDMEDIATYPE;
- mf_media_type_to_wg_format(decoder->output_type, &output_format);
- if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
return MF_E_INVALIDMEDIATYPE;
- /* Don't force any specific size, the video stream already has the metadata for it
* and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
*/
- output_format.u.video.width = 0;
- output_format.u.video.height = 0;
- output_format.u.video.fps_d = 0;
- output_format.u.video.fps_n = 0;
Isn't that only true for H264? I think you can skip the format change support entirely for this simpler decoder.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/video_decoder.c:
IMFMediaType_Release(decoder->input_type);
if (decoder->output_type)
IMFMediaType_Release(decoder->output_type);
wg_sample_queue_destroy(decoder->wg_sample_queue);
free(decoder);
- }
- return refcount;
}
static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum) {
- FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
- TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
I think you should keep all the methods you're not using in the client as stubs for now. So these and the media type enumeration methods. It'll avoid dead code, make the changes smaller, and easier to get reviewed and merged.
Rémi Bernon (@rbernon) commented about dlls/winegstreamer/video_decoder.c:
- return E_NOTIMPL;
- struct video_decoder *decoder;
- HRESULT hr;
- TRACE("out %p.\n", out);
- if (!(decoder = calloc(1, sizeof(*decoder))))
return E_OUTOFMEMORY;
- decoder->IMFTransform_iface.lpVtbl = &transform_vtbl;
- decoder->refcount = 1;
- decoder->wg_format.u.video.format = WG_VIDEO_FORMAT_UNKNOWN;
- decoder->wg_format.u.video.width = 1920;
- decoder->wg_format.u.video.height = 1080;
- decoder->wg_format.u.video.fps_n = 30000;
- decoder->wg_format.u.video.fps_d = 1001;
The `wg_format` member is only useful for format change support for the H264 decoder. I think you don't need that here for IR50 so you can probably drop it.
It looks okay overall, with a few nitpicks above, then I think you could split the MR in half to make it easier to review and to keep changes a bit more targeted.
I think a first MR should include changes up to 9966e0bea0e317862fbfa3e9b9c5dc1b8479371f, plus a change implementing the video decoder stub and using it, at the same time, for the client Open / Close.
Then, in a second MR you would implement the format support and decompression methods, ideally ICM_DECOMPRESS_BEGIN and ICM_DECOMPRESS in separate changes.
On Thu Feb 2 09:30:42 2023 +0000, Rémi Bernon wrote:
Isn't that only true for H264? I think you can skip the format change support entirely for this simpler decoder.
This is also true for IV50 (that the stream has metadata for frame size), but maybe it is not necessary here.
This merge request was closed by Shaun Ren.
See !2102 for the first part of the split MRs.