[PATCH v2 7/8] winegstreamer: Introduce new wg_transform_read_data entry point.

Rémi Bernon rbernon at codeweavers.com
Wed Feb 23 08:46:38 CST 2022


And use it to implement WMA decoder ProcessOutput.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/mf/tests/mf.c                |  9 +++-
 dlls/winegstreamer/gst_private.h  |  1 +
 dlls/winegstreamer/main.c         | 15 +++++++
 dlls/winegstreamer/mfplat.c       |  1 +
 dlls/winegstreamer/unix_private.h |  1 +
 dlls/winegstreamer/unixlib.h      | 16 +++++++
 dlls/winegstreamer/wg_parser.c    |  2 +
 dlls/winegstreamer/wg_transform.c | 74 ++++++++++++++++++++++++++++++-
 dlls/winegstreamer/wma_decoder.c  |  9 ++--
 9 files changed, 123 insertions(+), 5 deletions(-)

diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index f3c0db7a2c6..e5c0e6051b5 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -6079,9 +6079,17 @@ static void test_wma_decoder(void)
 
         sample = create_sample(wma_encoded_data + i * wma_block_size, wma_block_size);
         hr = IMFTransform_ProcessInput(transform, 0, sample, 0);
+        todo_wine
         ok(hr == S_OK, "ProcessInput returned %#x\n", hr);
         ret = IMFSample_Release(sample);
+        todo_wine
         ok(ret == 1, "Release returned %u\n", ret);
+        if (hr != S_OK)
+        {
+            memset(&output, 0, sizeof(output));
+            output.pSample = sample = create_sample(NULL, output_info.cbSize);
+            break;
+        }
         i++;
 
         status = 0xdeadbeef;
@@ -6139,7 +6147,6 @@ static void test_wma_decoder(void)
     memset(&output, 0, sizeof(output));
     output.pSample = sample;
     hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status);
-    todo_wine
     ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr);
     ok(output.pSample == sample, "got pSample %p\n", output.pSample);
     ok(output.dwStatus == 0 ||
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 7ad3434fd1d..7970980e5ba 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -99,6 +99,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);
+HRESULT 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/main.c b/dlls/winegstreamer/main.c
index f85e9995525..4337bd7e5e1 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -273,6 +273,21 @@ void wg_transform_destroy(struct wg_transform *transform)
     __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform);
 }
 
+HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample)
+{
+    struct wg_transform_read_data_params params =
+    {
+        .transform = transform,
+        .sample = sample,
+    };
+    NTSTATUS status;
+
+    if ((status = __wine_unix_call(unix_handle, unix_wg_transform_read_data, &params)))
+        return HRESULT_FROM_NT(status);
+
+    return params.result;
+}
+
 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved)
 {
     if (reason == DLL_PROCESS_ATTACH)
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index c457a4ee79a..4b4d647170a 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -850,6 +850,7 @@ HRESULT mf_create_wg_sample(IMFSample *sample, struct wg_sample **out)
         goto out_release_buffer;
 
     IMFSample_AddRef((mf_sample->sample = sample));
+    mf_sample->wg_sample.data = buffer;
     mf_sample->wg_sample.size = current_length;
     mf_sample->wg_sample.max_size = max_length;
 
diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h
index d3f32484ee6..d14d0d309f5 100644
--- a/dlls/winegstreamer/unix_private.h
+++ b/dlls/winegstreamer/unix_private.h
@@ -34,5 +34,6 @@ 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_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 5bcad297fa9..8bc8b5f9ec2 100644
--- a/dlls/winegstreamer/unixlib.h
+++ b/dlls/winegstreamer/unixlib.h
@@ -103,10 +103,17 @@ struct wg_format
     } u;
 };
 
+enum wg_sample_flag
+{
+    WG_SAMPLE_FLAG_INCOMPLETE = 1,
+};
+
 struct wg_sample
 {
+    UINT32 flags;
     UINT32 max_size;
     UINT32 size;
+    BYTE *data;
 };
 
 enum wg_parser_event_type
@@ -242,6 +249,13 @@ struct wg_transform_create_params
     const struct wg_format *output_format;
 };
 
+struct wg_transform_read_data_params
+{
+    struct wg_transform *transform;
+    struct wg_sample *sample;
+    HRESULT result;
+};
+
 enum unix_funcs
 {
     unix_wg_parser_create,
@@ -273,6 +287,8 @@ enum unix_funcs
 
     unix_wg_transform_create,
     unix_wg_transform_destroy,
+
+    unix_wg_transform_read_data,
 };
 
 #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index d9bbc60964e..8b7c5278c27 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -1660,4 +1660,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
 
     X(wg_transform_create),
     X(wg_transform_destroy),
+
+    X(wg_transform_read_data),
 };
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c
index ed4f95afde3..5200d836db4 100644
--- a/dlls/winegstreamer/wg_transform.c
+++ b/dlls/winegstreamer/wg_transform.c
@@ -35,7 +35,7 @@
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
 #include "winternl.h"
-#include "dshow.h"
+#include "mferror.h"
 
 #include "unix_private.h"
 
@@ -48,6 +48,7 @@ struct sample_entry
 {
     struct list entry;
     GstSample *sample;
+    gsize buffer_size;
 };
 
 struct wg_transform
@@ -72,6 +73,7 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst
     else
     {
         pthread_mutex_lock(&transform->mutex);
+        entry->buffer_size = gst_buffer_get_size(buffer);
         entry->sample = gst_sample_new(buffer, NULL, NULL, NULL);
         list_add_tail(&transform->samples, &entry->entry);
         pthread_mutex_unlock(&transform->mutex);
@@ -340,3 +342,73 @@ out_free_transform:
     GST_ERROR("Failed to create winegstreamer transform.");
     return status;
 }
+
+static void release_sample_entry(struct wg_sample *sample, struct sample_entry *entry)
+{
+    GstBuffer *buffer = gst_sample_get_buffer(entry->sample);
+
+    if (entry->buffer_size > sample->size)
+    {
+        gst_buffer_resize(buffer, sample->size, -1);
+        entry->buffer_size -= sample->size;
+    }
+    else
+    {
+        gst_sample_unref(entry->sample);
+        list_remove(&entry->entry);
+        free(entry);
+    }
+}
+
+static NTSTATUS copy_from_sample_entry(struct wg_sample *sample, struct sample_entry *entry)
+{
+    GstBuffer *buffer = gst_sample_get_buffer(entry->sample);
+    GstMapInfo info;
+
+    if (!gst_buffer_map(buffer, &info, GST_MAP_READ))
+    {
+        GST_ERROR("Failed to map buffer %p", buffer);
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    if (sample->max_size >= info.size)
+        sample->size = info.size;
+    else
+    {
+        sample->flags |= WG_SAMPLE_FLAG_INCOMPLETE;
+        sample->size = sample->max_size;
+    }
+
+    memcpy(sample->data, info.data, sample->size);
+    gst_buffer_unmap(buffer, &info);
+
+    GST_INFO("Copied %u bytes, flags %#x", sample->size, (UINT32)sample->flags);
+    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;
+    struct sample_entry *entry;
+    struct list *head;
+    NTSTATUS status;
+
+    pthread_mutex_lock(&transform->mutex);
+    if ((head = list_head(&transform->samples)))
+    {
+        params->result = S_OK;
+        entry = LIST_ENTRY(head, struct sample_entry, entry);
+        status = copy_from_sample_entry(sample, entry);
+        release_sample_entry(sample, entry);
+    }
+    else
+    {
+        params->result = MF_E_TRANSFORM_NEED_MORE_INPUT;
+        status = STATUS_SUCCESS;
+    }
+    pthread_mutex_unlock(&transform->mutex);
+
+    return status;
+}
diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c
index 354f363bedf..af7db10b335 100644
--- a/dlls/winegstreamer/wma_decoder.c
+++ b/dlls/winegstreamer/wma_decoder.c
@@ -554,7 +554,7 @@ static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags,
     struct wg_sample *wg_sample;
     HRESULT hr;
 
-    FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status);
+    TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
 
     if (count > 1)
         return E_INVALIDARG;
@@ -579,8 +579,11 @@ 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
-        hr = E_NOTIMPL;
+    else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, wg_sample)))
+    {
+        if (wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE)
+            samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE;
+    }
 
     mf_destroy_wg_sample(wg_sample);
     return hr;
-- 
2.34.1




More information about the wine-devel mailing list