-- v7: winegstreamer: Use an atomic queue for wg_transform input buffers. winegstreamer: Release requested samples if they are too small. mf/tests: Add todo_wine for newer FFmpeg versions.
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/mf/tests/mf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index fd4acf6dfbf..00be50c8494 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -6390,7 +6390,7 @@ static void check_sample_pcm16_(int line, IMFSample *sample, const BYTE *expect_ if (expect - value + 512 > 1024) break; }
- todo_wine_if(todo) + todo_wine_if(todo && i < length / 2) ok_(__FILE__, line)(i == length, "unexpected buffer data\n");
if (output_file) WriteFile(output_file, buffer, length, &length, NULL); @@ -7027,6 +7027,9 @@ static void test_wma_decoder(void) hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status);
winetest_pop_context(); + + /* some FFmpeg version request more input to complete decoding */ + if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT && i == 2) break; } todo_wine ok(wmadec_data_len == 0, "missing %#lx bytes\n", wmadec_data_len);
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/wg_allocator.c | 8 +++++++- dlls/winegstreamer/wg_transform.c | 7 +------ 2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/dlls/winegstreamer/wg_allocator.c b/dlls/winegstreamer/wg_allocator.c index c31751ce83f..5b2c48dcf77 100644 --- a/dlls/winegstreamer/wg_allocator.c +++ b/dlls/winegstreamer/wg_allocator.c @@ -150,6 +150,7 @@ static GstMemory *wg_allocator_alloc(GstAllocator *gst_allocator, gsize size, GstAllocationParams *params) { WgAllocator *allocator = (WgAllocator *)gst_allocator; + struct wg_sample *sample; WgMemory *memory;
GST_LOG("allocator %p, size %#zx, params %p", allocator, size, params); @@ -162,7 +163,12 @@ static GstMemory *wg_allocator_alloc(GstAllocator *gst_allocator, gsize size,
pthread_mutex_lock(&allocator->mutex);
- memory->sample = allocator->request_sample(size, allocator->request_sample_context); + sample = allocator->request_sample(size, allocator->request_sample_context); + if (sample->max_size < size) + InterlockedDecrement(&sample->refcount); + else + memory->sample = sample; + list_add_tail(&allocator->memory_list, &memory->entry);
pthread_mutex_unlock(&allocator->mutex); diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index e05432f6ac7..adefd16c787 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -310,15 +310,10 @@ static bool transform_append_element(struct wg_transform *transform, GstElement static struct wg_sample *transform_request_sample(gsize size, void *context) { struct wg_transform *transform = context; - struct wg_sample *sample;
GST_LOG("size %#zx, context %p", size, transform);
- sample = InterlockedExchangePointer((void **)&transform->output_wg_sample, NULL); - if (!sample || sample->max_size < size) - return NULL; - - return sample; + return InterlockedExchangePointer((void **)&transform->output_wg_sample, NULL); }
NTSTATUS wg_transform_create(void *args)
From: Rémi Bernon rbernon@codeweavers.com
And push them one by one until an output buffer is generated, to avoid generating multiple output buffers without a backing wg_sample.
This makes zero-copy more efficient for games which queue multiple input buffers before checking output, such as Yakuza 4.
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@codeweavers.com --- dlls/winegstreamer/wg_transform.c | 70 +++++++++++++++++-------------- 1 file changed, 39 insertions(+), 31 deletions(-)
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index adefd16c787..070263698fb 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -51,8 +51,10 @@ struct wg_transform GstPad *my_src, *my_sink; GstPad *their_sink, *their_src; GstSegment segment; - GstBufferList *input; + guint input_max_length; + GstAtomicQueue *input_queue; + guint output_plane_align; struct wg_sample *output_wg_sample; GstAtomicQueue *output_queue; @@ -215,9 +217,11 @@ NTSTATUS wg_transform_destroy(void *args) { struct wg_transform *transform = args; GstSample *sample; + GstBuffer *buffer;
- if (transform->input) - gst_buffer_list_unref(transform->input); + while ((buffer = gst_atomic_queue_pop(transform->input_queue))) + gst_buffer_unref(buffer); + gst_atomic_queue_unref(transform->input_queue);
gst_element_set_state(transform->container, GST_STATE_NULL);
@@ -336,7 +340,7 @@ NTSTATUS wg_transform_create(void *args) return STATUS_NO_MEMORY; if (!(transform->container = gst_bin_new("wg_transform"))) goto out; - if (!(transform->input = gst_buffer_list_new())) + if (!(transform->input_queue = gst_atomic_queue_new(8))) goto out; if (!(transform->output_queue = gst_atomic_queue_new(8))) goto out; @@ -503,8 +507,8 @@ out: wg_allocator_destroy(transform->allocator); if (transform->output_queue) gst_atomic_queue_unref(transform->output_queue); - if (transform->input) - gst_buffer_list_unref(transform->input); + if (transform->input_queue) + gst_atomic_queue_unref(transform->input_queue); if (transform->container) { gst_element_set_state(transform->container, GST_STATE_NULL); @@ -530,7 +534,7 @@ NTSTATUS wg_transform_push_data(void *args) GstBuffer *buffer; guint length;
- length = gst_buffer_list_length(transform->input); + length = gst_atomic_queue_length(transform->input_queue); if (length >= transform->input_max_length) { GST_INFO("Refusing %u bytes, %u buffers already queued", sample->size, length); @@ -556,7 +560,7 @@ NTSTATUS wg_transform_push_data(void *args) GST_BUFFER_DURATION(buffer) = sample->duration * 100; if (!(sample->flags & WG_SAMPLE_FLAG_SYNC_POINT)) GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT); - gst_buffer_list_insert(transform->input, -1, buffer); + gst_atomic_queue_push(transform->input_queue, buffer);
params->result = S_OK; return STATUS_SUCCESS; @@ -705,48 +709,52 @@ static NTSTATUS read_transform_output_data(GstBuffer *buffer, GstCaps *caps, gsi return STATUS_SUCCESS; }
-NTSTATUS wg_transform_read_data(void *args) +static bool get_transform_output(struct wg_transform *transform, struct wg_sample *sample) { - struct wg_transform_read_data_params *params = args; - struct wg_transform *transform = params->transform; - struct wg_sample *sample = params->sample; - struct wg_format *format = params->format; GstFlowReturn ret = GST_FLOW_OK; - GstBuffer *output_buffer; - GstBufferList *input; - GstCaps *output_caps; - bool discard_data; - NTSTATUS status; + GstBuffer *input_buffer;
/* Provide the sample for transform_request_sample to pick it up */ InterlockedIncrement(&sample->refcount); InterlockedExchangePointer((void **)&transform->output_wg_sample, sample);
- if (!gst_buffer_list_length(transform->input)) - GST_DEBUG("Not input buffer queued"); - else if ((input = gst_buffer_list_new())) + while (!(transform->output_sample = gst_atomic_queue_pop(transform->output_queue))) { - ret = gst_pad_push_list(transform->my_src, transform->input); - transform->input = input; - } - else - { - GST_ERROR("Failed to allocate new input queue"); - ret = GST_FLOW_ERROR; + if (!(input_buffer = gst_atomic_queue_pop(transform->input_queue))) + break; + + if ((ret = gst_pad_push(transform->my_src, input_buffer))) + { + GST_ERROR("Failed to push transform input, error %d", ret); + break; + } }
/* Remove the sample so transform_request_sample cannot use it */ if (InterlockedExchangePointer((void **)&transform->output_wg_sample, NULL)) InterlockedDecrement(&sample->refcount);
- if (ret) + return ret == GST_FLOW_OK; +} + +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 wg_format *format = params->format; + GstBuffer *output_buffer; + GstCaps *output_caps; + bool discard_data; + NTSTATUS status; + + if (!transform->output_sample && !get_transform_output(transform, sample)) { - GST_ERROR("Failed to push transform input, error %d", ret); wg_allocator_release_sample(transform->allocator, sample, false); return STATUS_UNSUCCESSFUL; }
- if (!transform->output_sample && !(transform->output_sample = gst_atomic_queue_pop(transform->output_queue))) + if (!transform->output_sample) { sample->size = 0; params->result = MF_E_TRANSFORM_NEED_MORE_INPUT;
This merge request was approved by Alexandre Julliard.