[PATCH v3 3/5] winegstreamer: Try creating a wg_transform in the H264 decoder.

Rémi Bernon rbernon at codeweavers.com
Mon Mar 21 15:11:02 CDT 2022


Adding H264 format support in wg_format.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/winegstreamer/h264_decoder.c  | 35 ++++++++++++++-
 dlls/winegstreamer/mfplat.c        | 47 +++++++++++++++++---
 dlls/winegstreamer/quartz_parser.c | 11 ++---
 dlls/winegstreamer/unixlib.h       |  8 ++++
 dlls/winegstreamer/wg_format.c     | 69 ++++++++++++++++++++++++++++--
 dlls/winegstreamer/wg_transform.c  |  4 ++
 dlls/winegstreamer/wm_reader.c     |  8 +++-
 7 files changed, 165 insertions(+), 17 deletions(-)

diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c
index 36ca33ceca3..4edd4cdf39c 100644
--- a/dlls/winegstreamer/h264_decoder.c
+++ b/dlls/winegstreamer/h264_decoder.c
@@ -48,6 +48,8 @@ struct h264_decoder
     LONG refcount;
     IMFMediaType *input_type;
     IMFMediaType *output_type;
+
+    struct wg_transform *wg_transform;
 };
 
 static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
@@ -55,6 +57,29 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface)
     return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface);
 }
 
+static HRESULT try_create_wg_transform(struct h264_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;
+
+    if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format)))
+        return E_FAIL;
+
+    return S_OK;
+}
+
 static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type)
 {
     UINT32 value, width, height;
@@ -183,6 +208,8 @@ static ULONG WINAPI transform_Release(IMFTransform *iface)
 
     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)
@@ -416,7 +443,13 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF
         IMFMediaType_Release(decoder->output_type);
     IMFMediaType_AddRef((decoder->output_type = type));
 
-    return S_OK;
+    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)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index ed460144e8b..97e27bb7301 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -659,11 +659,11 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format)
 {
     switch (format->major_type)
     {
-        case WG_MAJOR_TYPE_UNKNOWN:
-            return NULL;
-
+        case WG_MAJOR_TYPE_H264:
         case WG_MAJOR_TYPE_WMA:
-            FIXME("WMA format not implemented!\n");
+            FIXME("Format %u not implemented!\n", format->major_type);
+            /* fallthrough */
+        case WG_MAJOR_TYPE_UNKNOWN:
             return NULL;
 
         case WG_MAJOR_TYPE_AUDIO:
@@ -822,6 +822,38 @@ static void mf_media_type_to_wg_format_wma(IMFMediaType *type, const GUID *subty
     memcpy(format->u.wma.codec_data, codec_data, codec_data_len);
 }
 
+static void mf_media_type_to_wg_format_h264(IMFMediaType *type, struct wg_format *format)
+{
+    UINT64 frame_rate, frame_size;
+    UINT32 profile, level;
+
+    memset(format, 0, sizeof(*format));
+    format->major_type = WG_MAJOR_TYPE_H264;
+
+    if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size)))
+    {
+        format->u.h264.width = frame_size >> 32;
+        format->u.h264.height = (UINT32)frame_size;
+    }
+
+    if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate)
+    {
+        format->u.h264.fps_n = frame_rate >> 32;
+        format->u.h264.fps_d = (UINT32)frame_rate;
+    }
+    else
+    {
+        format->u.h264.fps_n = 1;
+        format->u.h264.fps_d = 1;
+    }
+
+    if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile)))
+        format->u.h264.profile = profile;
+
+    if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level)))
+        format->u.h264.level = level;
+}
+
 void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format)
 {
     GUID major_type, subtype;
@@ -850,7 +882,12 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format)
             mf_media_type_to_wg_format_audio(type, &subtype, format);
     }
     else if (IsEqualGUID(&major_type, &MFMediaType_Video))
-        mf_media_type_to_wg_format_video(type, &subtype, format);
+    {
+        if (IsEqualGUID(&subtype, &MFVideoFormat_H264))
+            mf_media_type_to_wg_format_h264(type, format);
+        else
+            mf_media_type_to_wg_format_video(type, &subtype, format);
+    }
     else
         FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type));
 }
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c
index d369d4c7f20..bb7a71283c3 100644
--- a/dlls/winegstreamer/quartz_parser.c
+++ b/dlls/winegstreamer/quartz_parser.c
@@ -328,8 +328,9 @@ unsigned int wg_format_get_max_size(const struct wg_format *format)
             break;
         }
 
+        case WG_MAJOR_TYPE_H264:
         case WG_MAJOR_TYPE_WMA:
-            FIXME("WMA format not implemented!\n");
+            FIXME("Format %u not implemented!\n", format->major_type);
             return 0;
 
         case WG_MAJOR_TYPE_UNKNOWN:
@@ -423,11 +424,11 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool
 
     switch (format->major_type)
     {
-    case WG_MAJOR_TYPE_UNKNOWN:
-        return false;
-
+    case WG_MAJOR_TYPE_H264:
     case WG_MAJOR_TYPE_WMA:
-        FIXME("WMA format not implemented!\n");
+        FIXME("Format %u not implemented!\n", format->major_type);
+        /* fallthrough */
+    case WG_MAJOR_TYPE_UNKNOWN:
         return false;
 
     case WG_MAJOR_TYPE_AUDIO:
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h
index e1c0ec3f3b7..f4e2ea4966b 100644
--- a/dlls/winegstreamer/unixlib.h
+++ b/dlls/winegstreamer/unixlib.h
@@ -38,6 +38,7 @@ struct wg_format
         WG_MAJOR_TYPE_VIDEO,
         WG_MAJOR_TYPE_AUDIO,
         WG_MAJOR_TYPE_WMA,
+        WG_MAJOR_TYPE_H264,
     } major_type;
 
     union
@@ -100,6 +101,13 @@ struct wg_format
             uint32_t codec_data_len;
             unsigned char codec_data[64];
         } wma;
+        struct
+        {
+            int32_t width, height;
+            uint32_t fps_n, fps_d;
+            uint32_t profile;
+            uint32_t level;
+        } h264;
     } u;
 };
 
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c
index fc50fad6d12..b4455a6e6d0 100644
--- a/dlls/winegstreamer/wg_format.c
+++ b/dlls/winegstreamer/wg_format.c
@@ -35,6 +35,7 @@
 #include <gst/audio/audio.h>
 
 #include "winternl.h"
+#include "codecapi.h"
 #include "dshow.h"
 
 #include "unix_private.h"
@@ -431,6 +432,64 @@ static GstCaps *wg_format_to_caps_wma(const struct wg_format *format)
     return caps;
 }
 
+static GstCaps *wg_format_to_caps_h264(const struct wg_format *format)
+{
+    const char *profile, *level;
+    GstCaps *caps;
+
+    caps = gst_caps_new_empty_simple("video/x-h264");
+    gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL);
+    gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL);
+
+    if (format->u.h264.width)
+        gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.h264.width, NULL);
+    if (format->u.h264.height)
+        gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.h264.height, NULL);
+    if (format->u.h264.fps_n || format->u.h264.fps_d)
+        gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.h264.fps_n, format->u.h264.fps_d, NULL);
+
+    switch (format->u.h264.profile)
+    {
+        case eAVEncH264VProfile_Main: profile = "main"; break;
+        case eAVEncH264VProfile_High: profile = "high"; break;
+        case eAVEncH264VProfile_444:  profile = "high-4:4:4"; break;
+        default:
+            GST_FIXME("H264 profile attribute %u not implemented.", format->u.h264.profile);
+            profile = NULL;
+            break;
+    }
+    if (profile)
+        gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL);
+
+    switch (format->u.h264.level)
+    {
+        case eAVEncH264VLevel1:   level = "1";   break;
+        case eAVEncH264VLevel1_1: level = "1.1"; break;
+        case eAVEncH264VLevel1_2: level = "1.2"; break;
+        case eAVEncH264VLevel1_3: level = "1.3"; break;
+        case eAVEncH264VLevel2:   level = "2";   break;
+        case eAVEncH264VLevel2_1: level = "2.1"; break;
+        case eAVEncH264VLevel2_2: level = "2.2"; break;
+        case eAVEncH264VLevel3:   level = "3";   break;
+        case eAVEncH264VLevel3_1: level = "3.1"; break;
+        case eAVEncH264VLevel3_2: level = "3.2"; break;
+        case eAVEncH264VLevel4:   level = "4";   break;
+        case eAVEncH264VLevel4_1: level = "4.1"; break;
+        case eAVEncH264VLevel4_2: level = "4.2"; break;
+        case eAVEncH264VLevel5:   level = "5";   break;
+        case eAVEncH264VLevel5_1: level = "5.1"; break;
+        case eAVEncH264VLevel5_2: level = "5.2"; break;
+        default:
+            GST_FIXME("H264 level attribute %u not implemented.", format->u.h264.level);
+            level = NULL;
+            break;
+    }
+    if (level)
+        gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL);
+
+    return caps;
+}
+
 GstCaps *wg_format_to_caps(const struct wg_format *format)
 {
     switch (format->major_type)
@@ -439,6 +498,8 @@ GstCaps *wg_format_to_caps(const struct wg_format *format)
             return NULL;
         case WG_MAJOR_TYPE_WMA:
             return wg_format_to_caps_wma(format);
+        case WG_MAJOR_TYPE_H264:
+            return wg_format_to_caps_h264(format);
         case WG_MAJOR_TYPE_AUDIO:
             return wg_format_to_caps_audio(format);
         case WG_MAJOR_TYPE_VIDEO:
@@ -455,11 +516,11 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b)
 
     switch (a->major_type)
     {
-        case WG_MAJOR_TYPE_UNKNOWN:
-            return false;
-
         case WG_MAJOR_TYPE_WMA:
-            GST_FIXME("WMA format not implemented!\n");
+        case WG_MAJOR_TYPE_H264:
+            GST_FIXME("Format %u not implemented!", a->major_type);
+            /* fallthrough */
+        case WG_MAJOR_TYPE_UNKNOWN:
             return false;
 
         case WG_MAJOR_TYPE_AUDIO:
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c
index 6e272634653..0c43a9a0c5a 100644
--- a/dlls/winegstreamer/wg_transform.c
+++ b/dlls/winegstreamer/wg_transform.c
@@ -211,6 +211,7 @@ NTSTATUS wg_transform_create(void *args)
 
     switch (input_format.major_type)
     {
+        case WG_MAJOR_TYPE_H264:
         case WG_MAJOR_TYPE_WMA:
             if (!(element = transform_find_element(GST_ELEMENT_FACTORY_TYPE_DECODER, src_caps, raw_caps))
                     || !transform_append_element(transform, element, &first, &last))
@@ -251,6 +252,9 @@ NTSTATUS wg_transform_create(void *args)
             break;
 
         case WG_MAJOR_TYPE_VIDEO:
+            break;
+
+        case WG_MAJOR_TYPE_H264:
         case WG_MAJOR_TYPE_WMA:
         case WG_MAJOR_TYPE_UNKNOWN:
             GST_FIXME("Format %u not implemented!", output_format.major_type);
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c
index c911cb59d1f..57ba8633a84 100644
--- a/dlls/winegstreamer/wm_reader.c
+++ b/dlls/winegstreamer/wm_reader.c
@@ -1687,7 +1687,8 @@ HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output
             break;
 
         case WG_MAJOR_TYPE_WMA:
-            FIXME("WMA format not implemented!\n");
+        case WG_MAJOR_TYPE_H264:
+            FIXME("Format %u not implemented!\n", format.major_type);
             /* fallthrough */
         case WG_MAJOR_TYPE_AUDIO:
         case WG_MAJOR_TYPE_UNKNOWN:
@@ -1736,7 +1737,8 @@ HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output,
             break;
 
         case WG_MAJOR_TYPE_WMA:
-            FIXME("WMA format not implemented!\n");
+        case WG_MAJOR_TYPE_H264:
+            FIXME("Format %u not implemented!\n", format.major_type);
             break;
         case WG_MAJOR_TYPE_UNKNOWN:
             break;
@@ -1815,6 +1817,8 @@ static const char *get_major_type_string(enum wg_major_type type)
             return "unknown";
         case WG_MAJOR_TYPE_WMA:
             return "wma";
+        case WG_MAJOR_TYPE_H264:
+            return "h264";
     }
     assert(0);
     return NULL;
-- 
2.35.1




More information about the wine-devel mailing list