[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, ¤t_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