-- v2: winegstreamer: Support the Indeo 5.0 format in DirectShow.
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/winegstreamer/quartz_parser.c | 78 +++++++++++++++++++++++++++++- dlls/winegstreamer/wg_format.c | 50 ++++++++++++++++++- 2 files changed, 125 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 67aaaa3e134..abfe4763697 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -37,6 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz);
static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; +static const GUID MEDIASUBTYPE_IV50 = {mmioFOURCC('I','V','5','0'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_VC1S = {mmioFOURCC('V','C','1','S'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_MP3 = {WAVE_FORMAT_MPEGLAYER3, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}}; static const GUID MEDIASUBTYPE_WMV_Unknown = {0x7ce12ca9, 0xbfbf, 0x43d9, {0x9d, 0x00, 0x82, 0xb8, 0xed, 0x54, 0x31, 0x6b}}; @@ -397,6 +398,10 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) /* Both ffmpeg's encoder and a Cinepak file seen in the wild report * 24 bpp. ffmpeg sets biSizeImage as below; others may be smaller, * but as long as every sample fits into our allocator, we're fine. */ + case WG_MAJOR_TYPE_VIDEO_INDEO: + /* Similar situation, though we don't even have ffmpeg to comapre. + * Files from Close Combat 3 report 24 bpp, but a smaller + * biSizeImage. */ return format->u.video.width * format->u.video.height * 3;
case WG_MAJOR_TYPE_VIDEO_MPEG1: @@ -461,7 +466,6 @@ unsigned int wg_format_get_max_size(const struct wg_format *format)
case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_VIDEO_H264: - case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); return 0;
@@ -558,7 +562,10 @@ static bool amt_from_wg_format_video(AM_MEDIA_TYPE *mt, const struct wg_format * uint32_t frame_time;
if (format->u.video.format == WG_VIDEO_FORMAT_UNKNOWN) + { + WARN("Unknown video format.\n"); return false; + }
if (!(video_format = CoTaskMemAlloc(sizeof(*video_format)))) return false; @@ -634,6 +641,43 @@ static bool amt_from_wg_format_video_cinepak(AM_MEDIA_TYPE *mt, const struct wg_ return true; }
+static bool amt_from_wg_format_video_indeo(AM_MEDIA_TYPE *mt, const struct wg_format *format) +{ + VIDEOINFOHEADER *video_format; + uint32_t frame_time; + + if (!(video_format = CoTaskMemAlloc(sizeof(*video_format)))) + return false; + + mt->majortype = MEDIATYPE_Video; + if (format->u.video.version == 5) + { + mt->subtype = MEDIASUBTYPE_IV50; + } + else + { + FIXME("Unhandled version %u.\n", format->u.video.version); + return false; + } + mt->lSampleSize = 1; + mt->formattype = FORMAT_VideoInfo; + mt->cbFormat = sizeof(*video_format); + mt->pbFormat = (BYTE *)video_format; + + memset(video_format, 0, sizeof(*video_format)); + if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1) + video_format->AvgTimePerFrame = frame_time; + video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + video_format->bmiHeader.biWidth = format->u.video.width; + video_format->bmiHeader.biHeight = format->u.video.height; + video_format->bmiHeader.biPlanes = 1; + video_format->bmiHeader.biBitCount = 24; + video_format->bmiHeader.biCompression = mt->subtype.Data1; + video_format->bmiHeader.biSizeImage = wg_format_get_max_size(format); + + return true; +} + static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm) { VIDEOINFOHEADER *video_format; @@ -732,7 +776,6 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool { case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_VIDEO_H264: - case WG_MAJOR_TYPE_VIDEO_INDEO: FIXME("Format %u not implemented!\n", format->major_type); /* fallthrough */ case WG_MAJOR_TYPE_UNKNOWN: @@ -753,6 +796,9 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool case WG_MAJOR_TYPE_VIDEO_CINEPAK: return amt_from_wg_format_video_cinepak(mt, format);
+ case WG_MAJOR_TYPE_VIDEO_INDEO: + return amt_from_wg_format_video_indeo(mt, format); + case WG_MAJOR_TYPE_VIDEO_WMV: return amt_from_wg_format_video_wmv(mt, format, wm);
@@ -1008,6 +1054,32 @@ static bool amt_to_wg_format_video_cinepak(const AM_MEDIA_TYPE *mt, struct wg_fo return true; }
+static bool amt_to_wg_format_video_indeo(const AM_MEDIA_TYPE *mt, struct wg_format *format) +{ + const VIDEOINFOHEADER *video_format = (const VIDEOINFOHEADER *)mt->pbFormat; + + if (!IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo)) + { + FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype)); + return false; + } + if (mt->cbFormat < sizeof(VIDEOINFOHEADER) || !mt->pbFormat) + { + ERR("Unexpected format size %lu.\n", mt->cbFormat); + return false; + } + + format->major_type = WG_MAJOR_TYPE_VIDEO_CINEPAK; + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_IV50)) + format->u.video.version = 5; + format->u.video.width = video_format->bmiHeader.biWidth; + format->u.video.height = video_format->bmiHeader.biHeight; + format->u.video.fps_n = 10000000; + format->u.video.fps_d = video_format->AvgTimePerFrame; + + return true; +} + static bool amt_to_wg_format_video_wmv(const AM_MEDIA_TYPE *mt, struct wg_format *format) { const VIDEOINFOHEADER *video_format = (const VIDEOINFOHEADER *)mt->pbFormat; @@ -1084,6 +1156,8 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) { if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_CVID)) return amt_to_wg_format_video_cinepak(mt, format); + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_IV50)) + return amt_to_wg_format_video_indeo(mt, format); if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV1) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMV2) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WMVA) diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 027184e0846..9916a5a9961 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -358,6 +358,45 @@ static void wg_format_from_caps_video_cinepak(struct wg_format *format, const Gs format->u.video.fps_d = fps_d; }
+static void wg_format_from_caps_video_indeo(struct wg_format *format, const GstCaps *caps) +{ + const GstStructure *structure = gst_caps_get_structure(caps, 0); + gint version, width, height, fps_n, fps_d; + + if (!gst_structure_get_int(structure, "indeoversion", &version)) + { + GST_WARNING("Missing "indeoversion" value."); + return; + } + if (version != 5) + { + GST_FIXME("Unknown version %d.", version); + return; + } + if (!gst_structure_get_int(structure, "width", &width)) + { + GST_WARNING("Missing "width" value."); + return; + } + if (!gst_structure_get_int(structure, "height", &height)) + { + GST_WARNING("Missing "height" value."); + return; + } + if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) + { + fps_n = 0; + fps_d = 1; + } + + format->major_type = WG_MAJOR_TYPE_VIDEO_INDEO; + format->u.video.version = version; + format->u.video.width = width; + format->u.video.height = height; + format->u.video.fps_n = fps_n; + format->u.video.fps_d = fps_d; +} + static void wg_format_from_caps_video_wmv(struct wg_format *format, const GstCaps *caps) { const GstStructure *structure = gst_caps_get_structure(caps, 0); @@ -613,6 +652,10 @@ void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) { wg_format_from_caps_video_cinepak(format, caps); } + else if (!strcmp(name, "video/x-indeo")) + { + wg_format_from_caps_video_indeo(format, caps); + } else if (!strcmp(name, "video/x-wmv")) { wg_format_from_caps_video_wmv(format, caps); @@ -1094,7 +1137,6 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) case WG_MAJOR_TYPE_AUDIO_MPEG4: case WG_MAJOR_TYPE_AUDIO_WMA: case WG_MAJOR_TYPE_VIDEO_H264: - case WG_MAJOR_TYPE_VIDEO_INDEO: case WG_MAJOR_TYPE_VIDEO_MPEG1: GST_FIXME("Format %u not implemented!", a->major_type); /* fallthrough */ @@ -1118,6 +1160,12 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) return a->u.video.width == b->u.video.width && a->u.video.height == b->u.video.height;
+ case WG_MAJOR_TYPE_VIDEO_INDEO: + /* Do not compare FPS. */ + return a->u.video.version == b->u.video.version + && a->u.video.width == b->u.video.width + && a->u.video.height == b->u.video.height; + case WG_MAJOR_TYPE_VIDEO_WMV: /* Do not compare FPS. */ return a->u.video.format == b->u.video.format
On Thu Jun 19 23:49:15 2025 +0000, Elizabeth Figura wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/8381/diffs?diff_id=187205&start_sha=ff80221dc470ba2911ec646795581151b01d0ab9#27c6ed14a736425bf4c58d79fa5f03ebca5fb623_368_368)
Thanks.
On Thu Jun 19 23:49:15 2025 +0000, Elizabeth Figura wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/8381/diffs?diff_id=187205&start_sha=ff80221dc470ba2911ec646795581151b01d0ab9#27c6ed14a736425bf4c58d79fa5f03ebca5fb623_373_373)
Thanks.
On Thu Jun 19 23:10:05 2025 +0000, Alfred Agrell wrote:
Looks a little odd how this one doesn't have an else clause with a fixme... but this entire function is only reached for IV50, so your choice.
Yes, else would be odd since it's clearly unreachable. There are other Indeo versions but they're not handled yet.
I don't really mind but why is this needed? IIUC Indeo codec is only available on Windows through the ir50_32 library, which we have now. Shouldn't DirectShow be able to use it?
This isn't adding a decoder. In fact the VFW wrapper is the only (or at least preferred) way to decode iv50 on Windows.
This patch adds format translation to and from AM_MEDIA_TYPE. In practice what this achieves is allowing the AVI splitter to correctly output the type.
Oh I see, thanks.