[PATCH 5/5] winegstreamer: Support zero-copy in wg_transform_push_data.

Rémi Bernon rbernon at codeweavers.com
Tue Feb 22 16:48:19 CST 2022


This wraps the wg_sample struct in a PE-side struct to add a list entry
without exposing it to the unix-side.

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/winegstreamer/gst_private.h  |  3 ++-
 dlls/winegstreamer/mfplat.c       | 36 ++++++++++++++++++++++++-------
 dlls/winegstreamer/unixlib.h      |  2 ++
 dlls/winegstreamer/wg_transform.c | 15 +++++++++++--
 dlls/winegstreamer/wma_decoder.c  | 13 +++++------
 5 files changed, 52 insertions(+), 17 deletions(-)

diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index f0774d53613..e794b2879de 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -120,8 +120,9 @@ extern HRESULT mfplat_DllRegisterServer(void);
 IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format);
 void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format);
 
-HRESULT mf_create_wg_sample(IMFSample *sample, struct wg_sample **out);
+HRESULT mf_create_wg_sample(IMFSample *sample, struct list *sample_list, struct wg_sample **out);
 void mf_destroy_wg_sample(struct wg_sample *wg_sample);
+void mf_reap_wg_samples(struct list *sample_list, bool force);
 
 HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj);
 
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 2ba1490f20b..9fbf35378a9 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -828,11 +828,17 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format)
         FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type));
 }
 
-HRESULT mf_create_wg_sample(IMFSample *sample, struct wg_sample **out)
+struct wg_sample_entry
+{
+    struct list entry;
+    struct wg_sample sample;
+};
+
+HRESULT mf_create_wg_sample(IMFSample *sample, struct list *sample_list, struct wg_sample **out)
 {
     DWORD current_length, max_length, count;
     IMFMediaBuffer *media_buffer = NULL;
-    struct wg_sample *entry;
+    struct wg_sample_entry *entry;
     BYTE *buffer;
     HRESULT hr;
 
@@ -850,13 +856,14 @@ HRESULT mf_create_wg_sample(IMFSample *sample, struct wg_sample **out)
     if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, &max_length, &current_length)))
         goto failed;
 
-    IMFSample_AddRef((entry->private = sample));
-    entry->data = buffer;
-    entry->size = current_length;
-    entry->max_size = max_length;
+    IMFSample_AddRef((entry->sample.private = sample));
+    entry->sample.data = buffer;
+    entry->sample.size = current_length;
+    entry->sample.max_size = max_length;
+    list_add_tail(sample_list, &entry->entry);
 
     TRACE("Created sample entry %p.\n", entry);
-    *out = entry;
+    *out = &entry->sample;
     return S_OK;
 
 failed:
@@ -868,9 +875,13 @@ failed:
 
 void mf_destroy_wg_sample(struct wg_sample *sample)
 {
+    struct wg_sample_entry *entry = CONTAINING_RECORD(sample, struct wg_sample_entry, sample);
     IMFMediaBuffer *media_buffer;
     HRESULT hr;
 
+    if (sample->refcount)
+        ERR("Sample %p is still in use, trouble ahead!\n", sample->private);
+
     if (FAILED(hr = IMFSample_GetBufferByIndex(sample->private, 0, &media_buffer)))
         WARN("Failed to get first buffer, sample %p\n", sample->private);
     else
@@ -884,5 +895,14 @@ void mf_destroy_wg_sample(struct wg_sample *sample)
     }
 
     IMFSample_Release(sample->private);
-    free(sample);
+    list_remove(&entry->entry);
+    free(entry);
+}
+
+void mf_reap_wg_samples(struct list *sample_list, bool force)
+{
+    struct wg_sample_entry *entry, *next;
+    LIST_FOR_EACH_ENTRY_SAFE(entry, next, sample_list, struct wg_sample_entry, entry)
+        if (!entry->sample.refcount || force)
+            mf_destroy_wg_sample(&entry->sample);
 }
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h
index 0162ed8f550..5666149a6a1 100644
--- a/dlls/winegstreamer/unixlib.h
+++ b/dlls/winegstreamer/unixlib.h
@@ -106,6 +106,8 @@ struct wg_format
 
 struct wg_sample
 {
+    volatile LONG refcount; /* unix refcount */
+    const LONG __pad;
     UINT32 max_size;
     UINT32 size;
     BYTE *data;
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c
index 7a26e0e4774..787157fa1a0 100644
--- a/dlls/winegstreamer/wg_transform.c
+++ b/dlls/winegstreamer/wg_transform.c
@@ -310,6 +310,13 @@ out_free_transform:
     return status;
 }
 
+static void wg_sample_free_notify(void *arg)
+{
+    struct wg_sample *sample = arg;
+    GST_DEBUG("Releasing wg_sample %p", sample);
+    InterlockedDecrement(&sample->refcount);
+}
+
 NTSTATUS wg_transform_push_data(void *args)
 {
     struct wg_transform_push_data_params *params = args;
@@ -318,11 +325,15 @@ NTSTATUS wg_transform_push_data(void *args)
     GstFlowReturn ret;
     GstBuffer *buffer;
 
-    buffer = gst_buffer_new_and_alloc(sample->size);
+    InterlockedIncrement(&sample->refcount);
+    buffer = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, sample->data, sample->max_size,
+            0, sample->size, sample, wg_sample_free_notify);
     if (!buffer)
+    {
+        InterlockedDecrement(&sample->refcount);
         return STATUS_NO_MEMORY;
+    }
 
-    gst_buffer_fill(buffer, 0, sample->data, sample->size);
     if ((ret = gst_pad_push(transform->my_src, buffer)))
         return MF_E_NOTACCEPTING;
 
diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c
index 55b827ed3cd..03cd6ad54c0 100644
--- a/dlls/winegstreamer/wma_decoder.c
+++ b/dlls/winegstreamer/wma_decoder.c
@@ -55,7 +55,7 @@ struct wma_decoder
     IMFMediaType *output_type;
 
     struct wg_transform *wg_transform;
-    struct wg_sample *input_sample;
+    struct list input_samples;
 };
 
 static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface)
@@ -135,8 +135,7 @@ static ULONG WINAPI unknown_Release(IUnknown *iface)
             IMFMediaType_Release(decoder->input_type);
         if (decoder->output_type)
             IMFMediaType_Release(decoder->output_type);
-        if (decoder->input_sample)
-            mf_destroy_wg_sample(decoder->input_sample);
+        mf_reap_wg_samples(&decoder->input_samples, true);
         free(decoder);
     }
 
@@ -537,14 +536,16 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS
     if (!decoder->wg_transform)
         return MF_E_TRANSFORM_TYPE_NOT_SET;
 
-    if (decoder->input_sample)
+    if (!list_empty(&decoder->input_samples))
         return MF_E_NOTACCEPTING;
 
     if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer)))
         return hr;
     IMFMediaBuffer_Release(media_buffer);
 
-    if (FAILED(hr = mf_create_wg_sample(sample, &wg_sample)))
+    mf_reap_wg_samples(&decoder->input_samples, false);
+
+    if (FAILED(hr = mf_create_wg_sample(sample, &decoder->input_samples, &wg_sample)))
         return hr;
 
     if (!(wg_sample->size = (wg_sample->size / info.cbSize) * info.cbSize))
@@ -559,7 +560,6 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS
         return hr;
     }
 
-    decoder->input_sample = wg_sample;
     return S_OK;
 }
 
@@ -847,6 +847,7 @@ HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out)
     decoder->IPropertyBag_iface.lpVtbl = &property_bag_vtbl;
     decoder->refcount = 1;
     decoder->outer = outer ? outer : &decoder->IUnknown_inner;
+    list_init(&decoder->input_samples);
 
     *out = &decoder->IUnknown_inner;
     TRACE("Created decoder %p\n", *out);
-- 
2.34.1




More information about the wine-devel mailing list