[PATCH v2 06/18] winegstreamer: Implement IMFMediaStream::GetStreamDescriptor.

Derek Lesho dlesho at codeweavers.com
Wed Apr 1 17:05:27 CDT 2020


Signed-off-by: Derek Lesho <dlesho at codeweavers.com>
---
 dlls/winegstreamer/gst_private.h  |   4 +
 dlls/winegstreamer/media_source.c |  54 ++++++++-
 dlls/winegstreamer/mfplat.c       | 186 ++++++++++++++++++++++++++++++
 3 files changed, 243 insertions(+), 1 deletion(-)

diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 71ca429088..780cf1b02f 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -36,6 +36,7 @@
 #include "winuser.h"
 #include "dshow.h"
 #include "strmif.h"
+#include "mfobjects.h"
 #include "wine/heap.h"
 #include "wine/strmbase.h"
 
@@ -54,6 +55,9 @@ void start_dispatch_thread(void) DECLSPEC_HIDDEN;
 
 extern HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
 
+GstCaps *make_mf_compatible_caps(GstCaps *caps);
+IMFMediaType *mf_media_type_from_caps(GstCaps *caps);
+
 enum source_type
 {
     SOURCE_TYPE_MPEG_4,
diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c
index ae9880847c..080d2c43ca 100644
--- a/dlls/winegstreamer/media_source.c
+++ b/dlls/winegstreamer/media_source.c
@@ -207,7 +207,10 @@ static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IM
     if (This->state == STREAM_SHUTDOWN)
         return MF_E_SHUTDOWN;
 
-    return E_NOTIMPL;
+    IMFStreamDescriptor_AddRef(This->descriptor);
+    *descriptor = This->descriptor;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
@@ -269,6 +272,9 @@ static void media_stream_teardown(struct media_stream *This)
 static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad, DWORD stream_id, struct media_stream **out_stream)
 {
     HRESULT hr;
+    GstCaps *caps = NULL, *compatible_caps = NULL;
+    IMFMediaType *media_type;
+    IMFMediaTypeHandler *type_handler;
     struct media_stream *This = heap_alloc_zero(sizeof(*This));
 
     TRACE("(%p %p)->(%p)\n", source, pad, out_stream);
@@ -297,6 +303,44 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
     g_object_set(This->appsink, "sync", FALSE, NULL);
     g_signal_connect(This->appsink, "new-sample", G_CALLBACK(stream_new_sample_wrapper), This);
 
+    if (FAILED(hr = MFCreateMediaType(&media_type)))
+    {
+        goto fail;
+    }
+
+    caps = gst_pad_query_caps(pad, NULL);
+
+    if (!(caps))
+    {
+        goto fail;
+    }
+
+    compatible_caps = make_mf_compatible_caps(caps);
+    media_type = mf_media_type_from_caps(compatible_caps);
+
+    if (!media_type)
+        goto fail;
+
+    MFCreateStreamDescriptor(stream_id, 1, &media_type, &This->descriptor);
+
+    IMFStreamDescriptor_GetMediaTypeHandler(This->descriptor, &type_handler);
+    IMFMediaTypeHandler_SetCurrentMediaType(type_handler, media_type);
+    IMFMediaTypeHandler_Release(type_handler);
+    IMFMediaType_Release(media_type);
+    media_type = NULL;
+
+    if (TRACE_ON(mfplat))
+    {
+        gchar *caps_str = gst_caps_to_string(caps), *compatible_caps_str = gst_caps_to_string(compatible_caps);
+        TRACE("caps %s compatible caps %s\n", debugstr_a(caps_str), debugstr_a(compatible_caps_str));
+        g_free(caps_str);
+        g_free(compatible_caps_str);
+    }
+    gst_caps_unref(caps);
+    caps = NULL;
+    gst_caps_unref(compatible_caps);
+    compatible_caps = NULL;
+
     This->their_src = pad;
     This->my_sink = gst_element_get_static_pad(This->appsink, "sink");
     gst_pad_set_element_private(pad, This);
@@ -316,6 +360,14 @@ static HRESULT media_stream_constructor(struct media_source *source, GstPad *pad
     fail:
     WARN("Failed to construct media stream, hr %#x.\n", hr);
 
+    /* Destroy temporary objects */
+    if (caps)
+        gst_caps_unref(caps);
+    if (compatible_caps)
+        gst_caps_unref(compatible_caps);
+    if (media_type)
+        IMFMediaType_Release(media_type);
+
     media_stream_teardown(This);
     heap_free(This);
     return hr;
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 16e55247de..09266ffab4 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -16,6 +16,11 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "config.h"
+#include <gst/gst.h>
+
+#include "gst_private.h"
+
 #include <stdarg.h>
 
 #include "gst_private.h"
@@ -442,3 +447,184 @@ HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj)
 
     return CLASS_E_CLASSNOTAVAILABLE;
 }
+
+const static struct
+{
+    const GUID *subtype;
+    GstVideoFormat format;
+}
+uncompressed_formats[] =
+{
+    {&MFVideoFormat_ARGB32,  GST_VIDEO_FORMAT_BGRA},
+    {&MFVideoFormat_RGB32,   GST_VIDEO_FORMAT_BGRx},
+    {&MFVideoFormat_RGB24,   GST_VIDEO_FORMAT_BGR},
+    {&MFVideoFormat_RGB565,  GST_VIDEO_FORMAT_BGR16},
+    {&MFVideoFormat_RGB555,  GST_VIDEO_FORMAT_BGR15},
+};
+
+/* caps will be modified to represent the exact type needed for the format */
+static IMFMediaType* transform_to_media_type(GstCaps *caps)
+{
+    IMFMediaType *media_type;
+    GstStructure *info;
+    const char *mime_type;
+
+    if (TRACE_ON(mfplat))
+    {
+        gchar *human_readable = gst_caps_to_string(caps);
+        TRACE("caps = %s\n", debugstr_a(human_readable));
+        g_free(human_readable);
+    }
+
+    if (FAILED(MFCreateMediaType(&media_type)))
+    {
+        return NULL;
+    }
+
+    info = gst_caps_get_structure(caps, 0);
+    mime_type = gst_structure_get_name(info);
+
+    if (!(strncmp(mime_type, "video", 5)))
+    {
+        GstVideoInfo video_info;
+
+        if (!(gst_video_info_from_caps(&video_info, caps)))
+        {
+            return NULL;
+        }
+
+        IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video);
+
+        IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, ((UINT64)video_info.width << 32) | video_info.height);
+
+        IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, ((UINT64)video_info.fps_n << 32) | video_info.fps_d);
+
+        if (!(strcmp(mime_type, "video/x-raw")))
+        {
+            GUID fourcc_subtype = MFVideoFormat_Base;
+            unsigned int i;
+
+            IMFMediaType_SetUINT32(media_type, &MF_MT_COMPRESSED, FALSE);
+
+            /* First try FOURCC */
+            if ((fourcc_subtype.Data1 = gst_video_format_to_fourcc(video_info.finfo->format)))
+            {
+                IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &fourcc_subtype);
+            }
+            else
+            {
+                for (i = 0; i < ARRAY_SIZE(uncompressed_formats); i++)
+                {
+                    if (uncompressed_formats[i].format == video_info.finfo->format)
+                    {
+                        IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, uncompressed_formats[i].subtype);
+                        break;
+                    }
+                }
+                if (i == ARRAY_SIZE(uncompressed_formats))
+                    FIXME("Unrecognized format.\n");
+            }
+        }
+        else
+            FIXME("Unrecognized video format %s\n", mime_type);
+    }
+    else if (!(strncmp(mime_type, "audio", 5)))
+    {
+        IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio);
+
+        if (!(strcmp(mime_type, "audio/x-raw")))
+        {
+            const char *format;
+            if ((format = gst_structure_get_string(info, "format")))
+            {
+                char type;
+                unsigned int bits_per_sample;
+                char endian[2];
+                char new_format[6];
+                if ((strlen(format) > 5) || (sscanf(format, "%c%u%2c", &type, &bits_per_sample, endian) < 2))
+                {
+                    FIXME("Unhandled audio format %s\n", format);
+                    IMFMediaType_Release(media_type);
+                    return NULL;
+                }
+
+                if (type == 'F')
+                {
+                    IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_Float);
+                }
+                else if (type == 'U' || type == 'S')
+                {
+                    IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, &MFAudioFormat_PCM);
+                    if (bits_per_sample == 8)
+                        type = 'U';
+                    else
+                        type = 'S';
+                }
+                else
+                {
+                    FIXME("Unrecognized audio format: %s\n", format);
+                    IMFMediaType_Release(media_type);
+                    return NULL;
+                }
+
+                IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, bits_per_sample);
+
+                if (endian[0] == 'B')
+                    endian[0] = 'L';
+
+                sprintf(new_format, "%c%u%.2s", type, bits_per_sample, bits_per_sample > 8 ? endian : 0);
+                gst_caps_set_simple(caps, "format", G_TYPE_STRING, new_format, NULL);
+            }
+            else
+            {
+                ERR("Failed to get audio format\n");
+            }
+        }
+        else
+            FIXME("Unrecognized audio format %s\n", mime_type);
+    }
+    else
+    {
+        IMFMediaType_Release(media_type);
+        return NULL;
+    }
+
+    return media_type;
+}
+
+/* returns NULL if doesn't match exactly */
+IMFMediaType *mf_media_type_from_caps(GstCaps *caps)
+{
+    GstCaps *writeable_caps;
+    IMFMediaType *ret;
+
+    writeable_caps = gst_caps_copy(caps);
+    ret = transform_to_media_type(writeable_caps);
+
+    if (!(gst_caps_is_equal(caps, writeable_caps)))
+    {
+        IMFMediaType_Release(ret);
+        ret = NULL;
+    }
+    gst_caps_unref(writeable_caps);
+    return ret;
+}
+
+GstCaps *make_mf_compatible_caps(GstCaps *caps)
+{
+    GstCaps *ret;
+    IMFMediaType *media_type;
+
+    ret = gst_caps_copy(caps);
+
+    if ((media_type = transform_to_media_type(ret)))
+        IMFMediaType_Release(media_type);
+
+    if (!media_type)
+    {
+        gst_caps_unref(ret);
+        return NULL;
+    }
+
+    return ret;
+}
\ No newline at end of file
-- 
2.26.0




More information about the wine-devel mailing list