From: Yuxuan Shui yshui@codeweavers.com
--- dlls/winegstreamer/wg_transform.c | 44 ++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-)
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index 558f6572a1b..50c1958013b 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -53,16 +53,18 @@ struct wg_transform GstQuery *drain_query;
GstAtomicQueue *input_queue; + GstBuffer *current_buffer; MFVideoInfo input_info; MFVideoInfo output_info;
GstAtomicQueue *output_queue; GstSample *output_sample; - bool output_caps_changed; GstCaps *desired_caps; GstCaps *output_caps; GstCaps *input_caps;
+ bool output_caps_changed; + bool has_parser; bool draining; };
@@ -492,8 +494,12 @@ static bool transform_create_decoder_elements(struct wg_transform *transform,
if ((element = find_element(GST_ELEMENT_FACTORY_TYPE_PARSER, transform->input_caps, parsed_caps)) && !append_element(transform->container, element, first, last)) + { + transform->has_parser = true; goto done; - else if (!element) + } + + if (!element) { gst_caps_unref(parsed_caps); parsed_caps = gst_caps_ref(transform->input_caps); @@ -1035,18 +1041,42 @@ error:
static bool get_transform_output(struct wg_transform *transform, struct wg_sample *sample) { - GstBuffer *input_buffer; GstFlowReturn ret;
wg_allocator_provide_sample(transform->allocator, sample);
- while (!(transform->output_sample = gst_atomic_queue_pop(transform->output_queue)) - && (input_buffer = gst_atomic_queue_pop(transform->input_queue))) + while (!(transform->output_sample = gst_atomic_queue_pop(transform->output_queue))) { - if ((ret = gst_pad_push(transform->my_src, input_buffer))) + /* A big buffer could take the transform a long time (longer than a vblank) to + * process, so if we write the entire input buffer in one go, we could block and + * cause application to hitch. So we break the buffer up, write just enough to + * get something back and stop. However, doing so is only safe if we are writing + * into a parser, as it knows to put things back up properly. */ + + gsize target_push_size = 4096, size, maxsize, offset; + GstBuffer *tmp_buffer = NULL; + if (!transform->current_buffer) + transform->current_buffer = gst_atomic_queue_pop(transform->input_queue); + if (!transform->current_buffer) + break; + + size = gst_buffer_get_sizes(transform->current_buffer, &offset, &maxsize); + if (size < target_push_size || !transform->has_parser) + target_push_size = size; + + tmp_buffer = gst_buffer_copy_region(transform->current_buffer, + GST_BUFFER_COPY_METADATA | GST_BUFFER_COPY_MEMORY, 0, target_push_size); + if ((ret = gst_pad_push(transform->my_src, tmp_buffer))) GST_WARNING("Failed to push transform input, error %d", ret);
- complete_drain(transform); + if (target_push_size < size) + gst_buffer_resize(transform->current_buffer, target_push_size, -1); + else + { + gst_buffer_unref(transform->current_buffer); + transform->current_buffer = NULL; + complete_drain(transform); + } }
/* Remove the sample so the allocator cannot use it */