From: Anton Baskanov Subject: [PATCH] winegstreamer: Split audio data to fit in the sample buffer. Message-Id: <20201224194930.97337-1-baskanov@gmail.com> Date: Fri, 25 Dec 2020 02:49:30 +0700 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50355 Signed-off-by: Anton Baskanov --- dlls/winegstreamer/gstdemux.c | 142 +++++++++++++++++++++------------- 1 file changed, 88 insertions(+), 54 deletions(-) diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c index 9114e6610a3..8a9c0a84191 100644 --- a/dlls/winegstreamer/gstdemux.c +++ b/dlls/winegstreamer/gstdemux.c @@ -81,6 +81,7 @@ struct gstdemux_source HANDLE caps_event, eos_event; GstSegment *segment; SourceSeeking seek; + DWORD bytes_per_second; }; static inline struct gstdemux *impl_from_strmbase_filter(struct strmbase_filter *iface) @@ -801,6 +802,7 @@ static GstFlowReturn got_data_sink(GstPad *pad, GstObject *parent, GstBuffer *bu BYTE *ptr = NULL; IMediaSample *sample; GstMapInfo info; + gsize position = 0; TRACE("%p %p\n", pad, buf); @@ -809,76 +811,106 @@ static GstFlowReturn got_data_sink(GstPad *pad, GstObject *parent, GstBuffer *bu return GST_FLOW_OK; } - hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0); - - if (hr == VFW_E_NOT_CONNECTED) { - gst_buffer_unref(buf); - return GST_FLOW_NOT_LINKED; - } + gst_buffer_map(buf, &info, GST_MAP_READ); - if (FAILED(hr)) { - gst_buffer_unref(buf); - ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr); - return GST_FLOW_FLUSHING; - } + while (position < info.size) + { + gsize advance; - gst_buffer_map(buf, &info, GST_MAP_READ); + hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0); - hr = IMediaSample_SetActualDataLength(sample, info.size); - if(FAILED(hr)){ - WARN("SetActualDataLength failed: %08x\n", hr); - return GST_FLOW_FLUSHING; - } + if (hr == VFW_E_NOT_CONNECTED) { + gst_buffer_unmap(buf, &info); + gst_buffer_unref(buf); + return GST_FLOW_NOT_LINKED; + } - IMediaSample_GetPointer(sample, &ptr); + if (FAILED(hr)) { + gst_buffer_unmap(buf, &info); + gst_buffer_unref(buf); + ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr); + return GST_FLOW_FLUSHING; + } - memcpy(ptr, info.data, info.size); + advance = min(IMediaSample_GetSize(sample), info.size - position); - gst_buffer_unmap(buf, &info); + hr = IMediaSample_SetActualDataLength(sample, advance); + if(FAILED(hr)){ + gst_buffer_unmap(buf, &info); + gst_buffer_unref(buf); + WARN("SetActualDataLength failed: %08x\n", hr); + return GST_FLOW_FLUSHING; + } - if (GST_BUFFER_PTS_IS_VALID(buf)) { - REFERENCE_TIME rtStart = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, buf->pts); - if (rtStart >= 0) - rtStart /= 100; - - if (GST_BUFFER_DURATION_IS_VALID(buf)) { - REFERENCE_TIME tStart = buf->pts / 100; - REFERENCE_TIME tStop = (buf->pts + buf->duration) / 100; - REFERENCE_TIME rtStop; - rtStop = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, buf->pts + buf->duration); - if (rtStop >= 0) - rtStop /= 100; - TRACE("Current time on %p: %i to %i ms\n", pin, (int)(rtStart / 10000), (int)(rtStop / 10000)); - IMediaSample_SetTime(sample, &rtStart, rtStop >= 0 ? &rtStop : NULL); - IMediaSample_SetMediaTime(sample, &tStart, &tStop); + IMediaSample_GetPointer(sample, &ptr); + + memcpy(ptr, &info.data[position], advance); + + if (GST_BUFFER_PTS_IS_VALID(buf)) { + REFERENCE_TIME rtStart; + GstClockTime ptsStart = buf->pts; + if (position > 0 && pin->bytes_per_second) + ptsStart = buf->pts + gst_util_uint64_scale(position, GST_SECOND, pin->bytes_per_second); + rtStart = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, ptsStart); + if (rtStart >= 0) + rtStart /= 100; + + if (GST_BUFFER_DURATION_IS_VALID(buf)) { + REFERENCE_TIME rtStop; + REFERENCE_TIME tStart; + REFERENCE_TIME tStop; + GstClockTime ptsStop = buf->pts + buf->duration; + if (position + advance < info.size && pin->bytes_per_second) + ptsStop = buf->pts + gst_util_uint64_scale(position + advance, GST_SECOND, pin->bytes_per_second); + tStart = ptsStart / 100; + tStop = ptsStop / 100; + rtStop = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, ptsStop); + if (rtStop >= 0) + rtStop /= 100; + TRACE("Current time on %p: %i to %i ms\n", pin, (int)(rtStart / 10000), (int)(rtStop / 10000)); + IMediaSample_SetTime(sample, &rtStart, rtStop >= 0 ? &rtStop : NULL); + IMediaSample_SetMediaTime(sample, &tStart, &tStop); + } else { + IMediaSample_SetTime(sample, rtStart >= 0 ? &rtStart : NULL, NULL); + IMediaSample_SetMediaTime(sample, NULL, NULL); + } } else { - IMediaSample_SetTime(sample, rtStart >= 0 ? &rtStart : NULL, NULL); + IMediaSample_SetTime(sample, NULL, NULL); IMediaSample_SetMediaTime(sample, NULL, NULL); } - } else { - IMediaSample_SetTime(sample, NULL, NULL); - IMediaSample_SetMediaTime(sample, NULL, NULL); - } - IMediaSample_SetDiscontinuity(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT)); - IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_LIVE)); - IMediaSample_SetSyncPoint(sample, !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT)); + IMediaSample_SetDiscontinuity(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT)); + IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_LIVE)); + IMediaSample_SetSyncPoint(sample, !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT)); - if (!pin->pin.pin.peer) - hr = VFW_E_NOT_CONNECTED; - else - hr = IMemInputPin_Receive(pin->pin.pMemInputPin, sample); + if (!pin->pin.pin.peer) + hr = VFW_E_NOT_CONNECTED; + else + hr = IMemInputPin_Receive(pin->pin.pMemInputPin, sample); - TRACE("sending sample returned: %08x\n", hr); + TRACE("sending sample returned: %08x\n", hr); - gst_buffer_unref(buf); - IMediaSample_Release(sample); + IMediaSample_Release(sample); - if (hr == VFW_E_NOT_CONNECTED) - return GST_FLOW_NOT_LINKED; + if (hr == VFW_E_NOT_CONNECTED) + { + gst_buffer_unmap(buf, &info); + gst_buffer_unref(buf); + return GST_FLOW_NOT_LINKED; + } - if (FAILED(hr)) - return GST_FLOW_FLUSHING; + if (FAILED(hr)) + { + gst_buffer_unmap(buf, &info); + gst_buffer_unref(buf); + return GST_FLOW_FLUSHING; + } + + position += advance; + } + + gst_buffer_unmap(buf, &info); + gst_buffer_unref(buf); return GST_FLOW_OK; } @@ -2104,6 +2136,8 @@ static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface, { WAVEFORMATEX *format = (WAVEFORMATEX *)pin->pin.pin.mt.pbFormat; buffer_size = format->nAvgBytesPerSec; + + pin->bytes_per_second = format->nAvgBytesPerSec; } props->cBuffers = max(props->cBuffers, 1); -- 2.25.1