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@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);