[PATCH v4 1/5] winegstreamer: Insert videoconvert into decoded-video streams.

Derek Lesho dlesho at codeweavers.com
Tue Oct 13 09:52:52 CDT 2020


Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
---
v4: Address nits.
---
 dlls/winegstreamer/media_source.c | 125 ++++++++++++++++++++++++++----
 1 file changed, 111 insertions(+), 14 deletions(-)

diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index 5f3c43a0204..3371585328d 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -384,6 +384,43 @@ static const IMFMediaStreamVtbl media_stream_vtbl =
     media_stream_RequestSample
 };
 
+/* Setup a chain of elements which should hopefully allow transformations to any IMFMediaType
+   the user throws at us through gstreamer's caps negotiation. */
+static HRESULT media_stream_connect_to_sink(struct media_stream *stream)
+{
+    GstCaps *source_caps = gst_pad_get_current_caps(stream->their_src);
+    const gchar *stream_type;
+
+    if (!source_caps)
+        return E_FAIL;
+
+    stream_type = gst_structure_get_name(gst_caps_get_structure(source_caps, 0));
+    gst_caps_unref(source_caps);
+
+    if (!strcmp(stream_type, "video/x-raw"))
+    {
+        GstElement *videoconvert = gst_element_factory_make("videoconvert", NULL);
+
+        gst_bin_add(GST_BIN(stream->parent_source->container), videoconvert);
+
+        stream->my_sink = gst_element_get_static_pad(videoconvert, "sink");
+
+        if (!gst_element_link(videoconvert, stream->appsink))
+            return E_FAIL;
+
+        gst_element_sync_state_with_parent(videoconvert);
+    }
+    else
+    {
+        stream->my_sink = gst_element_get_static_pad(stream->appsink, "sink");
+    }
+
+    if (gst_pad_link(stream->their_src, stream->my_sink) != GST_PAD_LINK_OK)
+        return E_FAIL;
+
+    return S_OK;
+}
+
 static HRESULT new_media_stream(struct media_source *source, GstPad *pad, DWORD stream_id, struct media_stream **out_stream)
 {
     struct media_stream *object = heap_alloc_zero(sizeof(*object));
@@ -414,8 +451,8 @@ static HRESULT new_media_stream(struct media_source *source, GstPad *pad, DWORD
     g_object_set(object->appsink, "sync", FALSE, NULL);
     g_object_set(object->appsink, "max-buffers", 5, NULL);
 
-    object->my_sink = gst_element_get_static_pad(object->appsink, "sink");
-    gst_pad_link(object->their_src, object->my_sink);
+    if (FAILED(hr = media_stream_connect_to_sink(object)))
+        goto fail;
 
     gst_element_sync_state_with_parent(object->appsink);
 
@@ -435,28 +472,88 @@ static HRESULT media_stream_init_desc(struct media_stream *stream)
 {
     GstCaps *current_caps = gst_pad_get_current_caps(stream->their_src);
     IMFMediaTypeHandler *type_handler;
+    IMFMediaType **stream_types = NULL;
     IMFMediaType *stream_type = NULL;
+    DWORD type_count = 0;
+    const gchar *major_type;
+    unsigned int i;
     HRESULT hr;
 
-    stream_type = mf_media_type_from_caps(current_caps);
-    gst_caps_unref(current_caps);
-    if (!stream_type)
-        return E_FAIL;
+    major_type = gst_structure_get_name(gst_caps_get_structure(current_caps, 0));
+
+    if (!strcmp(major_type, "video/x-raw"))
+    {
+        /* These are the most common native output types of decoders:
+            https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */
+        static const GUID *const video_types[] =
+        {
+            &MFVideoFormat_NV12,
+            &MFVideoFormat_YV12,
+            &MFVideoFormat_YUY2,
+            &MFVideoFormat_IYUV,
+            &MFVideoFormat_I420,
+        };
 
-    hr = MFCreateStreamDescriptor(stream->stream_id, 1, &stream_type, &stream->descriptor);
+        IMFMediaType *base_type = mf_media_type_from_caps(current_caps);
+        GUID base_subtype;
 
-    IMFMediaType_Release(stream_type);
+        IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype);
 
-    if (FAILED(hr))
-        return hr;
+        stream_types = heap_alloc( sizeof(IMFMediaType *) * ARRAY_SIZE(video_types) + 1);
 
-    if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
-        return hr;
+        stream_types[0] = base_type;
+        type_count = 1;
 
-    hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_type);
+        for (i = 0; i < ARRAY_SIZE(video_types); i++)
+        {
+            IMFMediaType *new_type;
 
-    IMFMediaTypeHandler_Release(type_handler);
+            if (IsEqualGUID(&base_subtype, video_types[i]))
+                continue;
 
+            if (FAILED(hr = MFCreateMediaType(&new_type)))
+                goto done;
+            stream_types[type_count++] = new_type;
+
+            if (FAILED(hr = IMFMediaType_CopyAllItems(base_type, (IMFAttributes *) new_type)))
+                goto done;
+            if (FAILED(hr = IMFMediaType_SetGUID(new_type, &MF_MT_SUBTYPE, video_types[i])))
+                goto done;
+        }
+    }
+    else
+    {
+        stream_type = mf_media_type_from_caps(current_caps);
+        if (stream_type)
+        {
+            stream_types = &stream_type;
+            type_count = 1;
+        }
+    }
+
+    if (!type_count)
+    {
+        ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
+        return E_FAIL;
+    }
+
+    if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, type_count, stream_types, &stream->descriptor)))
+        goto done;
+
+    if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
+        goto done;
+
+    if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0])))
+        goto done;
+
+done:
+    gst_caps_unref(current_caps);
+    if (type_handler)
+        IMFMediaTypeHandler_Release(type_handler);
+    for (i = 0; i < type_count; i++)
+        IMFMediaType_Release(stream_types[i]);
+    if (stream_types != &stream_type)
+        heap_free(stream_types);
     return hr;
 }
 
-- 
2.28.0




More information about the wine-devel mailing list