[PATCH v3 3/6] winegstreamer: Implement H264 SetOutputType by reconfiguring the pipeline.

Rémi Bernon wine at gitlab.winehq.org
Thu Jun 23 12:12:40 CDT 2022


From: Rémi Bernon <rbernon at codeweavers.com>

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/mf/tests/mf.c                | 11 ++---
 dlls/winegstreamer/gst_private.h  |  1 +
 dlls/winegstreamer/h264_decoder.c | 23 +++++++++-
 dlls/winegstreamer/main.c         | 13 ++++++
 dlls/winegstreamer/unix_private.h |  1 +
 dlls/winegstreamer/unixlib.h      |  7 ++++
 dlls/winegstreamer/wg_parser.c    |  1 +
 dlls/winegstreamer/wg_transform.c | 70 +++++++++++++++++++++++++++++++
 8 files changed, 119 insertions(+), 8 deletions(-)

diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 5f26b1a6238..afe85ddbf3c 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -7333,7 +7333,7 @@ static void test_h264_decoder(void)
     todo_wine
     ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr);
 
-    if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
+    while (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
     {
         hr = IMFTransform_ProcessInput(transform, 0, sample, 0);
         ok(hr == S_OK, "ProcessInput returned %#lx\n", hr);
@@ -7341,16 +7341,14 @@ static void test_h264_decoder(void)
         ok(ret <= 1, "Release returned %lu\n", ret);
         sample = next_h264_sample(&h264_encoded_data, &h264_encoded_data_len);
         hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status);
-        todo_wine
+        todo_wine_if(hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
         ok(hr == MF_E_TRANSFORM_STREAM_CHANGE, "ProcessOutput returned %#lx\n", hr);
     }
 
     ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID);
     ok(!!output.pSample, "got pSample %p\n", output.pSample);
-    todo_wine
     ok(output.dwStatus == MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE, "got dwStatus %#lx\n", output.dwStatus);
     ok(!output.pEvents, "got pEvents %p\n", output.pEvents);
-    todo_wine
     ok(status == MFT_PROCESS_OUTPUT_STATUS_NEW_STREAMS, "got status %#lx\n", status);
     hr = IMFSample_GetTotalLength(output.pSample, &length);
     ok(hr == S_OK, "GetTotalLength returned %#lx\n", hr);
@@ -7373,17 +7371,16 @@ static void test_h264_decoder(void)
     memset(&output, 0, sizeof(output));
     output.pSample = create_sample(NULL, actual_width * actual_height * 2);
     hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status);
-    todo_wine
     ok(hr == S_OK, "ProcessOutput returned %#lx\n", hr);
     ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID);
     ok(!!output.pSample, "got pSample %p\n", output.pSample);
     ok(output.dwStatus == 0, "got dwStatus %#lx\n", output.dwStatus);
     ok(!output.pEvents, "got pEvents %p\n", output.pEvents);
     ok(status == 0, "got status %#lx\n", status);
-    if (hr != S_OK) goto skip_i420_tests;
 
     hr = IMFSample_GetSampleTime(output.pSample, &time);
     ok(hr == S_OK, "GetSampleTime returned %#lx\n", hr);
+    todo_wine_if(time == 1334666)  /* when VA-API plugin is used */
     ok(time - 333666 <= 2, "got time %I64d\n", time);
 
     duration = 0xdeadbeef;
@@ -7419,7 +7416,6 @@ static void test_h264_decoder(void)
 
     check_sample(output.pSample, i420_frame_data, output_file);
 
-skip_i420_tests:
     ret = IMFSample_Release(output.pSample);
     ok(ret == 0, "Release returned %lu\n", ret);
 
@@ -7430,6 +7426,7 @@ skip_i420_tests:
     memset(&output, 0, sizeof(output));
     output.pSample = create_sample(NULL, actual_width * actual_height * 2);
     hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status);
+    todo_wine_if(hr == S_OK)  /* when VA-API plugin is used */
     ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#lx\n", hr);
     ok(output.dwStreamID == 0, "got dwStreamID %lu\n", output.dwStreamID);
     ok(!!output.pSample, "got pSample %p\n", output.pSample);
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 8348d2e8360..14a52df5921 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -102,6 +102,7 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate,
 struct wg_transform *wg_transform_create(const struct wg_format *input_format,
         const struct wg_format *output_format);
 void wg_transform_destroy(struct wg_transform *transform);
+bool wg_transform_set_format(struct wg_transform *transform, struct wg_format *format);
 
 unsigned int wg_format_get_max_size(const struct wg_format *format);
 
diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c
index 012a7060f29..1a9dcbd561c 100644
--- a/dlls/winegstreamer/h264_decoder.c
+++ b/dlls/winegstreamer/h264_decoder.c
@@ -467,7 +467,28 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF
         IMFMediaType_Release(decoder->output_type);
     IMFMediaType_AddRef((decoder->output_type = type));
 
-    if (FAILED(hr = try_create_wg_transform(decoder)))
+    if (decoder->wg_transform)
+    {
+        struct wg_format output_format;
+        mf_media_type_to_wg_format(decoder->output_type, &output_format);
+
+        /* Don't force any specific size, H264 streams already have the metadata for it
+         * and will generate a MF_E_TRANSFORM_STREAM_CHANGE result later.
+         */
+        output_format.u.video.width = 0;
+        output_format.u.video.height = 0;
+        output_format.u.video.fps_d = 0;
+        output_format.u.video.fps_n = 0;
+
+        if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN
+                || !wg_transform_set_format(decoder->wg_transform, &output_format))
+        {
+            IMFMediaType_Release(decoder->output_type);
+            decoder->output_type = NULL;
+            return MF_E_INVALIDMEDIATYPE;
+        }
+    }
+    else if (FAILED(hr = try_create_wg_transform(decoder)))
     {
         IMFMediaType_Release(decoder->output_type);
         decoder->output_type = NULL;
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c
index fc7b9d73285..fb2e8865089 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -348,6 +348,19 @@ HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample
     return params.result;
 }
 
+bool wg_transform_set_format(struct wg_transform *transform, struct wg_format *format)
+{
+    struct wg_transform_set_format_params params =
+    {
+        .transform = transform,
+        .format = format,
+    };
+
+    TRACE("transform %p, format %p.\n", transform, format);
+
+    return !__wine_unix_call(unix_handle, unix_wg_transform_set_format, &params);
+}
+
 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
 {
     if (reason == DLL_PROCESS_ATTACH)
diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h
index e9f472986ae..3a6b162c500 100644
--- a/dlls/winegstreamer/unix_private.h
+++ b/dlls/winegstreamer/unix_private.h
@@ -34,6 +34,7 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE
 
 extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN;
 extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN;
+extern NTSTATUS wg_transform_set_format(void *args) DECLSPEC_HIDDEN;
 extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN;
 extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN;
 
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h
index 860a8ab2a52..ed02f025b05 100644
--- a/dlls/winegstreamer/unixlib.h
+++ b/dlls/winegstreamer/unixlib.h
@@ -263,6 +263,12 @@ struct wg_transform_read_data_params
     HRESULT result;
 };
 
+struct wg_transform_set_format_params
+{
+    struct wg_transform *transform;
+    const struct wg_format *format;
+};
+
 enum unix_funcs
 {
     unix_wg_parser_create,
@@ -291,6 +297,7 @@ enum unix_funcs
 
     unix_wg_transform_create,
     unix_wg_transform_destroy,
+    unix_wg_transform_set_format,
 
     unix_wg_transform_push_data,
     unix_wg_transform_read_data,
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index 7d55897aa0a..a4aa945a708 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -1625,6 +1625,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
 
     X(wg_transform_create),
     X(wg_transform_destroy),
+    X(wg_transform_set_format),
 
     X(wg_transform_push_data),
     X(wg_transform_read_data),
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c
index b0048fad644..b90fde70519 100644
--- a/dlls/winegstreamer/wg_transform.c
+++ b/dlls/winegstreamer/wg_transform.c
@@ -173,6 +173,31 @@ static gboolean transform_sink_query_cb(GstPad *pad, GstObject *parent, GstQuery
             g_object_unref(pool);
             return true;
         }
+
+        case GST_QUERY_CAPS:
+        {
+            GstCaps *caps, *filter, *temp;
+            gchar *str;
+
+            gst_query_parse_caps(query, &filter);
+            caps = gst_caps_ref(transform->output_caps);
+
+            if (filter)
+            {
+                temp = gst_caps_intersect(caps, filter);
+                gst_caps_unref(caps);
+                caps = temp;
+            }
+
+            str = gst_caps_to_string(caps);
+            GST_INFO("Returning caps %s", str);
+            g_free(str);
+
+            gst_query_set_caps_result(query, caps);
+            gst_caps_unref(caps);
+            return true;
+        }
+
         default:
             GST_WARNING("Ignoring \"%s\" query.", gst_query_type_get_name(query->type));
             break;
@@ -525,6 +550,51 @@ out:
     return status;
 }
 
+NTSTATUS wg_transform_set_format(void *args)
+{
+    struct wg_transform_set_format_params *params = args;
+    struct wg_transform *transform = params->transform;
+    GstSample *sample;
+    GstEvent *event;
+    GstCaps *caps;
+    gchar *str;
+
+    if (!(caps = wg_format_to_caps(params->format)))
+    {
+        GST_ERROR("Failed to convert format to caps.");
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    if (gst_caps_is_always_compatible(transform->output_caps, caps))
+    {
+        gst_caps_unref(caps);
+        return STATUS_SUCCESS;
+    }
+
+    gst_caps_unref(transform->output_caps);
+    transform->output_caps = caps;
+
+    if (!gst_pad_set_caps(transform->my_sink, caps)
+            || !(event = gst_event_new_reconfigure())
+            || !gst_pad_push_event(transform->my_sink, event))
+    {
+        GST_ERROR("Failed to reconfigure transform.");
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    str = gst_caps_to_string(caps);
+    GST_INFO("Configured new caps %s.", str);
+    g_free(str);
+
+    if (transform->output_sample)
+        gst_sample_unref(transform->output_sample);
+    while ((sample = gst_atomic_queue_pop(transform->output_queue)))
+        gst_sample_unref(sample);
+    transform->output_sample = NULL;
+
+    return STATUS_SUCCESS;
+}
+
 static void wg_sample_free_notify(void *arg)
 {
     struct wg_sample *sample = arg;
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/302



More information about the wine-devel mailing list