[PATCH v3 6/7] winegstreamer: Support wg_transform output format change events.

Rémi Bernon wine at gitlab.winehq.org
Mon May 23 11:38:25 CDT 2022


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

Using a separate peek_data entry point, which pushes the input buffer
list and returns the current output sample format if requested.

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                    |  4 ---
 dlls/winegstreamer/gst_private.h      |  3 +-
 dlls/winegstreamer/h264_decoder.c     | 19 +++++++++++--
 dlls/winegstreamer/main.c             | 23 +++++++++++----
 dlls/winegstreamer/quartz_transform.c | 12 ++++----
 dlls/winegstreamer/unix_private.h     |  2 +-
 dlls/winegstreamer/unixlib.h          | 40 ++++++++++++++++++++++++++-
 dlls/winegstreamer/wg_format.c        | 31 ---------------------
 dlls/winegstreamer/wg_parser.c        |  1 +
 dlls/winegstreamer/wg_transform.c     | 32 +++++++++++++++------
 dlls/winegstreamer/wma_decoder.c      | 11 ++++++--
 11 files changed, 116 insertions(+), 62 deletions(-)

diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 9de7308f9ff..419faa61e2b 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -7187,20 +7187,16 @@ static void test_h264_decoder(void)
     ok(i == 2, "got %lu iterations\n", i);
     todo_wine
     ok(h264_encoded_data_len == 1180, "got h264_encoded_data_len %lu\n", h264_encoded_data_len);
-    todo_wine
     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);
-    todo_wine
     ok(length == 0, "got length %lu\n", length);
     ret = IMFSample_Release(output.pSample);
     ok(ret == 0, "Release returned %lu\n", ret);
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 2a4b16079c1..c92d452fbd9 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -97,7 +97,8 @@ 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);
 HRESULT wg_transform_push_data(struct wg_transform *transform, struct wg_sample *sample);
-HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample);
+HRESULT wg_transform_peek_data(struct wg_transform *transform, struct wg_format *format);
+bool wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample);
 
 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 912a5bdf0b1..db4c74d561e 100644
--- a/dlls/winegstreamer/h264_decoder.c
+++ b/dlls/winegstreamer/h264_decoder.c
@@ -50,6 +50,7 @@ struct h264_decoder
     IMFMediaType *input_type;
     IMFMediaType *output_type;
 
+    struct wg_format wg_format;
     struct wg_transform *wg_transform;
 };
 
@@ -543,6 +544,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
     struct h264_decoder *decoder = impl_from_IMFTransform(iface);
     MFT_OUTPUT_STREAM_INFO info;
     struct wg_sample *wg_sample;
+    struct wg_format wg_format;
     HRESULT hr;
 
     TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
@@ -565,8 +567,21 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
 
     if (wg_sample->max_size < info.cbSize)
         hr = MF_E_BUFFERTOOSMALL;
-    else
-        hr = wg_transform_read_data(decoder->wg_transform, wg_sample);
+    else if (SUCCEEDED(hr = wg_transform_peek_data(decoder->wg_transform, &wg_format)))
+    {
+        if (!wg_format_compare(&decoder->wg_format, &wg_format))
+        {
+            decoder->wg_format = wg_format;
+            samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
+            *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE;
+            hr = MF_E_TRANSFORM_STREAM_CHANGE;
+        }
+        else if (!wg_transform_read_data(decoder->wg_transform, wg_sample))
+        {
+            ERR("Failed to read transform data\n");
+            hr = E_FAIL;
+        }
+    }
 
     mf_destroy_wg_sample(wg_sample);
     return hr;
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c
index c3adbb82d61..b3fea9e760c 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -329,23 +329,36 @@ HRESULT wg_transform_push_data(struct wg_transform *transform, struct wg_sample
     return params.result;
 }
 
-HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample)
+HRESULT wg_transform_peek_data(struct wg_transform *transform, struct wg_format *format)
 {
-    struct wg_transform_read_data_params params =
+    struct wg_transform_peek_data_params params =
     {
         .transform = transform,
-        .sample = sample,
+        .format = format,
     };
     NTSTATUS status;
 
-    TRACE("transform %p, sample %p.\n", transform, sample);
+    TRACE("transform %p, format %p.\n", transform, format);
 
-    if ((status = __wine_unix_call(unix_handle, unix_wg_transform_read_data, &params)))
+    if ((status = __wine_unix_call(unix_handle, unix_wg_transform_peek_data, &params)))
         return HRESULT_FROM_NT(status);
 
     return params.result;
 }
 
+bool wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample)
+{
+    struct wg_transform_read_data_params params =
+    {
+        .transform = transform,
+        .sample = sample,
+    };
+
+    TRACE("transform %p, sample %p.\n", transform, sample);
+
+    return !__wine_unix_call(unix_handle, unix_wg_transform_read_data, &params);
+}
+
 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
 {
     if (reason == DLL_PROCESS_ATTACH)
diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c
index 447f331d474..5c9ff508846 100644
--- a/dlls/winegstreamer/quartz_transform.c
+++ b/dlls/winegstreamer/quartz_transform.c
@@ -342,16 +342,14 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa
             return hr;
         }
 
-        hr = wg_transform_read_data(filter->transform, &output_wg_sample);
-        if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
-        {
-            IMediaSample_Release(output_sample);
-            break;
-        }
+        hr = wg_transform_peek_data(filter->transform, NULL);
+        if (SUCCEEDED(hr) && !wg_transform_read_data(filter->transform, &output_wg_sample))
+            hr = E_FAIL;
+
         if (FAILED(hr))
         {
             IMediaSample_Release(output_sample);
-            return hr;
+            return hr == MF_E_TRANSFORM_NEED_MORE_INPUT ? S_OK : hr;
         }
 
         hr = IMediaSample_SetActualDataLength(output_sample, output_wg_sample.size);
diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h
index 7bce8263aaf..10992992f2b 100644
--- a/dlls/winegstreamer/unix_private.h
+++ b/dlls/winegstreamer/unix_private.h
@@ -29,12 +29,12 @@ extern bool init_gstreamer(void) DECLSPEC_HIDDEN;
 extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN;
 
 extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN;
-extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN;
 extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN;
 
 extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN;
 extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN;
 extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN;
+extern NTSTATUS wg_transform_peek_data(void *args) DECLSPEC_HIDDEN;
 extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN;
 
 #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h
index 5911278530d..4a72ef4bd0e 100644
--- a/dlls/winegstreamer/unixlib.h
+++ b/dlls/winegstreamer/unixlib.h
@@ -23,6 +23,8 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <assert.h>
+
 #include "windef.h"
 #include "winternl.h"
 #include "wtypes.h"
@@ -114,6 +116,35 @@ struct wg_format
     } u;
 };
 
+static inline bool wg_format_compare(const struct wg_format *a, const struct wg_format *b)
+{
+    if (a->major_type != b->major_type)
+        return false;
+
+    switch (a->major_type)
+    {
+        case WG_MAJOR_TYPE_MPEG1_AUDIO:
+        case WG_MAJOR_TYPE_WMA:
+        case WG_MAJOR_TYPE_H264:
+        case WG_MAJOR_TYPE_UNKNOWN:
+            return false;
+
+        case WG_MAJOR_TYPE_AUDIO:
+            return a->u.audio.format == b->u.audio.format
+                    && a->u.audio.channels == b->u.audio.channels
+                    && a->u.audio.rate == b->u.audio.rate;
+
+        case WG_MAJOR_TYPE_VIDEO:
+            /* Do not compare FPS. */
+            return a->u.video.format == b->u.video.format
+                    && a->u.video.width == b->u.video.width
+                    && abs(a->u.video.height) == abs(b->u.video.height);
+    }
+
+    assert(0);
+    return false;
+}
+
 enum wg_sample_flag
 {
     WG_SAMPLE_FLAG_INCOMPLETE = 1,
@@ -253,11 +284,17 @@ struct wg_transform_push_data_params
     HRESULT result;
 };
 
+struct wg_transform_peek_data_params
+{
+    struct wg_transform *transform;
+    struct wg_format *format;
+    HRESULT result;
+};
+
 struct wg_transform_read_data_params
 {
     struct wg_transform *transform;
     struct wg_sample *sample;
-    HRESULT result;
 };
 
 enum unix_funcs
@@ -290,6 +327,7 @@ enum unix_funcs
     unix_wg_transform_destroy,
 
     unix_wg_transform_push_data,
+    unix_wg_transform_peek_data,
     unix_wg_transform_read_data,
 };
 
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c
index 4cebeac9182..a1ef9fb327b 100644
--- a/dlls/winegstreamer/wg_format.c
+++ b/dlls/winegstreamer/wg_format.c
@@ -527,34 +527,3 @@ GstCaps *wg_format_to_caps(const struct wg_format *format)
     assert(0);
     return NULL;
 }
-
-bool wg_format_compare(const struct wg_format *a, const struct wg_format *b)
-{
-    if (a->major_type != b->major_type)
-        return false;
-
-    switch (a->major_type)
-    {
-        case WG_MAJOR_TYPE_MPEG1_AUDIO:
-        case WG_MAJOR_TYPE_WMA:
-        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:
-            return a->u.audio.format == b->u.audio.format
-                    && a->u.audio.channels == b->u.audio.channels
-                    && a->u.audio.rate == b->u.audio.rate;
-
-        case WG_MAJOR_TYPE_VIDEO:
-            /* Do not compare FPS. */
-            return a->u.video.format == b->u.video.format
-                    && a->u.video.width == b->u.video.width
-                    && abs(a->u.video.height) == abs(b->u.video.height);
-    }
-
-    assert(0);
-    return false;
-}
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index 7d55897aa0a..954fdd3dc3d 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -1627,5 +1627,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     X(wg_transform_destroy),
 
     X(wg_transform_push_data),
+    X(wg_transform_peek_data),
     X(wg_transform_read_data),
 };
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c
index f8211001be9..a4125a7d822 100644
--- a/dlls/winegstreamer/wg_transform.c
+++ b/dlls/winegstreamer/wg_transform.c
@@ -471,15 +471,13 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, struct wg_sample *
     return STATUS_SUCCESS;
 }
 
-NTSTATUS wg_transform_read_data(void *args)
+NTSTATUS wg_transform_peek_data(void *args)
 {
-    struct wg_transform_read_data_params *params = args;
+    struct wg_transform_peek_data_params *params = args;
     struct wg_transform *transform = params->transform;
-    struct wg_sample *sample = params->sample;
+    struct wg_format *format = params->format;
     GstBufferList *input = transform->input;
-    GstBuffer *output_buffer;
     GstFlowReturn ret;
-    NTSTATUS status;
 
     if (!gst_buffer_list_length(transform->input))
         GST_DEBUG("Not input buffer queued");
@@ -497,12 +495,31 @@ NTSTATUS wg_transform_read_data(void *args)
 
     if (!transform->output_sample && !(transform->output_sample = gst_atomic_queue_pop(transform->output_queue)))
     {
-        sample->size = 0;
         params->result = MF_E_TRANSFORM_NEED_MORE_INPUT;
-        GST_INFO("Cannot read %u bytes, no output available", sample->max_size);
+        GST_INFO("No output sample available");
         return STATUS_SUCCESS;
     }
 
+    if (format)
+        wg_format_from_caps(format, gst_sample_get_caps(transform->output_sample));
+
+    params->result = S_OK;
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS wg_transform_read_data(void *args)
+{
+    struct wg_transform_read_data_params *params = args;
+    struct wg_transform *transform = params->transform;
+    struct wg_sample *sample = params->sample;
+    GstBuffer *output_buffer;
+    NTSTATUS status;
+
+    if (!transform->output_sample)
+    {
+        GST_ERROR("No output sample available");
+        return STATUS_UNSUCCESSFUL;
+    }
     output_buffer = gst_sample_get_buffer(transform->output_sample);
 
     if ((status = read_transform_output_data(output_buffer, sample)))
@@ -514,6 +531,5 @@ NTSTATUS wg_transform_read_data(void *args)
         transform->output_sample = NULL;
     }
 
-    params->result = S_OK;
     return STATUS_SUCCESS;
 }
diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c
index 71369add244..c7466b74471 100644
--- a/dlls/winegstreamer/wma_decoder.c
+++ b/dlls/winegstreamer/wma_decoder.c
@@ -580,10 +580,17 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
     wg_sample->size = 0;
     if (wg_sample->max_size < info.cbSize)
         hr = MF_E_BUFFERTOOSMALL;
-    else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, wg_sample)))
+    else if (SUCCEEDED(hr = wg_transform_peek_data(decoder->wg_transform, NULL)))
     {
-        if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE)
+        if (!wg_transform_read_data(decoder->wg_transform, wg_sample))
+        {
+            ERR("Failed to read transform data\n");
+            hr = E_FAIL;
+        }
+        else if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE)
+        {
             samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE;
+        }
     }
 
     mf_destroy_wg_sample(wg_sample);
-- 
GitLab


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



More information about the wine-devel mailing list