According to the tests in 23b72ad, when we are reading a compressed stream, the type returned by `stream_props_GetMediaType()` should reflect compressed format even if we finnally output uncomressed data. For example, if we use wmvcore reader to read a WMV3 stream and output RGB24, the format information returned by `stream_props_GetMediaType()` should be WMV3, not RGB24.
This patch set is marked as draft now, because PATCH 2 and PATCH 3 is affected by 3e8936a2 in MR !2258. So I'll submit a newer version of this after !2258 get merged.
-- v2: winegstreamer: Use codec format in stream_props_GetMediaType. winegstreamer: Implement amt_from_wg_format_video_wmv. winegstreamer: Implement wg_format_from_caps_video_wmv. winegstreamer: Implement wg_parser_stream_get_codec_format.
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/main.c | 13 +++++++++++ dlls/winegstreamer/unixlib.h | 7 ++++++ dlls/winegstreamer/wg_parser.c | 37 +++++++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 5b4c01a3cd0..8627c1f0d97 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -82,6 +82,7 @@ uint32_t wg_parser_get_stream_count(struct wg_parser *parser); struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index);
void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format); +void wg_parser_stream_get_codec_format(struct wg_parser_stream *stream, struct wg_format *format); void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format); void wg_parser_stream_disable(struct wg_parser_stream *stream);
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 1afa51ac0aa..ba8b01497a3 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -185,6 +185,19 @@ void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, stru WINE_UNIX_CALL(unix_wg_parser_stream_get_preferred_format, ¶ms); }
+void wg_parser_stream_get_codec_format(struct wg_parser_stream *stream, struct wg_format *format) +{ + struct wg_parser_stream_get_codec_format_params params = + { + .stream = stream, + .format = format, + }; + + TRACE("stream %p, format %p.\n", stream, format); + + WINE_UNIX_CALL(unix_wg_parser_stream_get_codec_format, ¶ms); +} + void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) { struct wg_parser_stream_enable_params params = diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 19629d12fd0..42ce5ca598b 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -230,6 +230,12 @@ struct wg_parser_stream_get_preferred_format_params struct wg_format *format; };
+struct wg_parser_stream_get_codec_format_params +{ + struct wg_parser_stream *stream; + struct wg_format *format; +}; + struct wg_parser_stream_enable_params { struct wg_parser_stream *stream; @@ -338,6 +344,7 @@ enum unix_funcs unix_wg_parser_get_stream,
unix_wg_parser_stream_get_preferred_format, + unix_wg_parser_stream_get_codec_format, unix_wg_parser_stream_enable, unix_wg_parser_stream_disable,
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c index 5bb824f4399..d2cd18eeaee 100644 --- a/dlls/winegstreamer/wg_parser.c +++ b/dlls/winegstreamer/wg_parser.c @@ -96,6 +96,9 @@ struct wg_parser bool unlimited_buffering;
gchar *sink_caps; + + GstCaps *video_codec_sink_caps; + GstCaps *audio_codec_sink_caps; };
struct wg_parser_stream @@ -106,7 +109,7 @@ struct wg_parser_stream GstPad *their_src, *post_sink, *post_src, *my_sink; GstElement *flip; GstSegment segment; - struct wg_format preferred_format, current_format; + struct wg_format preferred_format, current_format, codec_format;
pthread_cond_t event_cond, event_empty_cond; GstBuffer *buffer; @@ -208,6 +211,14 @@ static NTSTATUS wg_parser_stream_get_preferred_format(void *args) return S_OK; }
+static NTSTATUS wg_parser_stream_get_codec_format(void *args) +{ + struct wg_parser_stream_get_codec_format_params *params = args; + + *params->format = params->stream->codec_format; + return S_OK; +} + static NTSTATUS wg_parser_stream_enable(void *args) { const struct wg_parser_stream_enable_params *params = args; @@ -499,6 +510,14 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, if (!parser->sink_caps && strstr(klass, GST_ELEMENT_FACTORY_KLASS_DEMUXER)) parser->sink_caps = g_strdup(gst_structure_get_name(gst_caps_get_structure(caps, 0)));
+ if (strstr(klass, GST_ELEMENT_FACTORY_KLASS_DECODER) || strstr(klass, GST_ELEMENT_FACTORY_KLASS_ENCODER)) + { + if (!parser->video_codec_sink_caps && strstr(klass, GST_ELEMENT_FACTORY_KLASS_MEDIA_VIDEO)) + parser->video_codec_sink_caps = gst_caps_ref(caps); + else if (!parser->audio_codec_sink_caps && strstr(klass, GST_ELEMENT_FACTORY_KLASS_MEDIA_AUDIO)) + parser->audio_codec_sink_caps = gst_caps_ref(caps); + } + return GST_AUTOPLUG_SELECT_TRY; }
@@ -783,6 +802,7 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser) stream->parser = parser; stream->number = parser->stream_count; stream->current_format.major_type = WG_MAJOR_TYPE_UNKNOWN; + stream->codec_format.major_type = WG_MAJOR_TYPE_UNKNOWN; pthread_cond_init(&stream->event_cond, NULL); pthread_cond_init(&stream->event_empty_cond, NULL);
@@ -884,6 +904,8 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); stream->post_src = gst_element_get_static_pad(vconv2, "src"); stream->flip = flip; + if (parser->video_codec_sink_caps) + wg_format_from_caps(&stream->codec_format, parser->video_codec_sink_caps); } else if (!strcmp(name, "audio/x-raw")) { @@ -901,6 +923,8 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user)
stream->post_sink = gst_element_get_static_pad(convert, "sink"); stream->post_src = gst_element_get_static_pad(convert, "src"); + if (parser->audio_codec_sink_caps) + wg_format_from_caps(&stream->codec_format, parser->audio_codec_sink_caps); }
if (stream->post_sink) @@ -1516,6 +1540,11 @@ out: g_free(parser->sink_caps); parser->sink_caps = NULL;
+ gst_caps_unref(parser->video_codec_sink_caps); + gst_caps_unref(parser->audio_codec_sink_caps); + parser->video_codec_sink_caps = NULL; + parser->audio_codec_sink_caps = NULL; + pthread_mutex_lock(&parser->mutex); parser->sink_connected = false; pthread_mutex_unlock(&parser->mutex); @@ -1562,6 +1591,11 @@ static NTSTATUS wg_parser_disconnect(void *args) g_free(parser->sink_caps); parser->sink_caps = NULL;
+ gst_caps_unref(parser->video_codec_sink_caps); + gst_caps_unref(parser->audio_codec_sink_caps); + parser->video_codec_sink_caps = NULL; + parser->audio_codec_sink_caps = NULL; + return S_OK; }
@@ -1797,6 +1831,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = X(wg_parser_get_stream),
X(wg_parser_stream_get_preferred_format), + X(wg_parser_stream_get_codec_format), X(wg_parser_stream_enable), X(wg_parser_stream_disable),
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/wg_format.c | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+)
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c index 63f1e3931b5..f9abe02a3b5 100644 --- a/dlls/winegstreamer/wg_format.c +++ b/dlls/winegstreamer/wg_format.c @@ -232,6 +232,40 @@ static void wg_format_from_caps_video_cinepak(struct wg_format *format, const Gs format->u.video_cinepak.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); + gint width, height, fps_n, fps_d, version; + + 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_int(structure, "wmvversion", &version)) + { + GST_WARNING("Missing "wmvversion" 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_WMV; + format->u.video_wmv.width = width; + format->u.video_wmv.height = height; + format->u.video_wmv.version = version; + format->u.video_wmv.fps_n = fps_n; + format->u.video_wmv.fps_d = fps_d; +} + void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) { const GstStructure *structure = gst_caps_get_structure(caps, 0); @@ -261,6 +295,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-wmv")) + { + wg_format_from_caps_video_wmv(format, caps); + } else { gchar *str = gst_caps_to_string(caps);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/quartz_parser.c | 52 +++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-)
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index c12e9ee3397..ffe4ecdc00a 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -538,6 +538,54 @@ static bool amt_from_wg_format_video_cinepak(AM_MEDIA_TYPE *mt, const struct wg_
return true; } +static bool amt_from_wg_format_video_wmv(AM_MEDIA_TYPE *mt, const struct wg_format *format) +{ + VIDEOINFO *video_format; + uint32_t frame_time; + const GUID *subtype; + + if (!(video_format = CoTaskMemAlloc(sizeof(*video_format)))) + return false; + + switch (format->u.video_wmv.version) + { + case 1: + subtype = &MEDIASUBTYPE_WMV1; + break; + case 2: + subtype = &MEDIASUBTYPE_WMV2; + break; + case 3: + subtype = &MEDIASUBTYPE_WMV3; + break; + default: + WARN("Invalid wmvversion %u.\n", format->u.video_wmv.version); + return false; + } + + mt->majortype = MEDIATYPE_Video; + mt->subtype = *subtype; + mt->bFixedSizeSamples = FALSE; + mt->bTemporalCompression = TRUE; + mt->lSampleSize = 0; + mt->formattype = FORMAT_VideoInfo; + mt->cbFormat = sizeof(VIDEOINFOHEADER); + mt->pbFormat = (BYTE *)video_format; + + memset(video_format, 0, sizeof(*video_format)); + SetRect(&video_format->rcSource, 0, 0, format->u.video_wmv.width, format->u.video_wmv.height); + video_format->rcTarget = video_format->rcSource; + if ((frame_time = MulDiv(10000000, format->u.video_wmv.fps_d, format->u.video_wmv.fps_n)) != -1) + video_format->AvgTimePerFrame = frame_time; + video_format->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + video_format->bmiHeader.biWidth = format->u.video_wmv.width; + video_format->bmiHeader.biHeight = format->u.video_wmv.height; + video_format->bmiHeader.biPlanes = 1; + video_format->bmiHeader.biBitCount = 24; + video_format->bmiHeader.biCompression = mt->subtype.Data1; + + return true; +}
bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool wm) { @@ -548,7 +596,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_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 */ @@ -566,6 +613,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_WMV: + return amt_from_wg_format_video_wmv(mt, format); }
assert(0);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/winegstreamer/wm_reader.c | 10 +++++++++- dlls/wmvcore/tests/wmvcore.c | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 736dbba452c..64bd4ce800b 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -544,12 +544,20 @@ static HRESULT WINAPI stream_props_GetType(IWMMediaProps *iface, GUID *major_typ static HRESULT WINAPI stream_props_GetMediaType(IWMMediaProps *iface, WM_MEDIA_TYPE *mt, DWORD *size) { struct stream_config *config = impl_from_IWMMediaProps(iface); + const struct wg_format *format; + struct wg_format codec_format; const DWORD req_size = *size; AM_MEDIA_TYPE stream_mt;
TRACE("iface %p, mt %p, size %p.\n", iface, mt, size);
- if (!amt_from_wg_format(&stream_mt, &config->stream->format, true)) + wg_parser_stream_get_codec_format(config->stream->wg_stream, &codec_format); + if (codec_format.major_type != WG_MAJOR_TYPE_UNKNOWN) + format = &codec_format; + else + format = &config->stream->format; + + if (!amt_from_wg_format(&stream_mt, format, true)) return E_OUTOFMEMORY;
*size = sizeof(stream_mt) + stream_mt.cbFormat; diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index f07abb8d4bb..0cd37990b49 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -1549,7 +1549,7 @@ static void test_sync_reader_types(void) if (IsEqualGUID(&majortype, &MEDIATYPE_Audio)) test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx, TRUE); else - test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo, TRUE); + test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo, FALSE);
ref = IWMStreamConfig_Release(config); ok(!ref, "Got outstanding refcount %ld.\n", ref); @@ -3429,7 +3429,7 @@ static void test_async_reader_types(void) if (IsEqualGUID(&majortype, &MEDIATYPE_Audio)) test_stream_media_props(config, &MEDIATYPE_Audio, &MEDIASUBTYPE_MSAUDIO1, &FORMAT_WaveFormatEx, TRUE); else - test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo, TRUE); + test_stream_media_props(config, &MEDIATYPE_Video, &MEDIASUBTYPE_WMV1, &FORMAT_VideoInfo, FALSE);
ref = IWMStreamConfig_Release(config); ok(!ref, "Got outstanding refcount %ld.\n", ref);