From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/quartz_parser.c | 177 +++++------------------------ dlls/winegstreamer/unixlib.h | 1 + dlls/winegstreamer/wg_sample.c | 71 ++++++++++++ dlls/winegstreamer/wg_transform.c | 2 + 5 files changed, 102 insertions(+), 150 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 8fb1bdf9576..fff849fd71e 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -122,6 +122,7 @@ 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 wg_sample_wrap_mf(IMFSample *mf_sample, struct wg_sample **out); +HRESULT wg_sample_wrap_qz(IMediaSample *qz_sample, struct wg_sample **out); HRESULT wg_sample_wrap_wm(INSSBuffer *wm_sample, QWORD pts, QWORD duration, DWORD flags, struct wg_sample **out); void wg_sample_unwrap(struct wg_sample *wg_sample); diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 34848c0b503..81f6b795bd3 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -651,127 +651,14 @@ bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) return false; }
-/* - * scale_uint64() is based on gst_util_scale_int() from GStreamer, which is - * covered by the following license: - * - * GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen omega@cse.ogi.edu - * 2000 Wim Taymans wtay@chello.be - * 2002 Thomas Vander Stichele thomas@apestaart.org - * 2004 Wim Taymans wim@fluendo.com - * 2015 Jan Schmidt jan@centricular.com - * - * gstutils.c: Utility functions - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -static uint64_t scale_uint64(uint64_t value, uint32_t numerator, uint32_t denominator) -{ - ULARGE_INTEGER i, high, low; - - if (!value) - return 0; - - i.QuadPart = value; - low.QuadPart = (ULONGLONG)i.u.LowPart * numerator; - high.QuadPart = (ULONGLONG)i.u.HighPart * numerator + low.u.HighPart; - low.u.HighPart = 0; - - if (high.u.HighPart >= denominator) - return ULLONG_MAX; - - low.QuadPart += (high.QuadPart % denominator) << 32; - return ((high.QuadPart / denominator) << 32) + (low.QuadPart / denominator); -} - -/* Fill and send a single IMediaSample. */ -static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample, - const struct wg_parser_buffer *buffer, uint32_t offset, uint32_t size, DWORD bytes_per_second) -{ - HRESULT hr; - BYTE *ptr = NULL; - - TRACE("offset %u, size %u, sample size %lu.\n", offset, size, IMediaSample_GetSize(sample)); - - hr = IMediaSample_SetActualDataLength(sample, size); - if(FAILED(hr)){ - ERR("Failed to set sample size, hr %#lx.\n", hr); - return hr; - } - - IMediaSample_GetPointer(sample, &ptr); - - if (!wg_parser_stream_copy_buffer(pin->wg_stream, ptr, offset, size)) - { - /* The GStreamer pin has been flushed. */ - return S_OK; - } - - if (buffer->has_pts) - { - REFERENCE_TIME start_pts = buffer->pts; - - if (offset) - start_pts += scale_uint64(offset, 10000000, bytes_per_second); - start_pts -= pin->seek.llCurrent; - start_pts *= pin->seek.dRate; - - if (buffer->has_duration) - { - REFERENCE_TIME end_pts = buffer->pts + buffer->duration; - - if (offset + size < buffer->size) - end_pts = buffer->pts + scale_uint64(offset + size, 10000000, bytes_per_second); - end_pts -= pin->seek.llCurrent; - end_pts *= pin->seek.dRate; - - IMediaSample_SetTime(sample, &start_pts, &end_pts); - IMediaSample_SetMediaTime(sample, &start_pts, &end_pts); - } - else - { - IMediaSample_SetTime(sample, &start_pts, NULL); - IMediaSample_SetMediaTime(sample, NULL, NULL); - } - } - else - { - IMediaSample_SetTime(sample, NULL, NULL); - IMediaSample_SetMediaTime(sample, NULL, NULL); - } - - IMediaSample_SetDiscontinuity(sample, !offset && buffer->discontinuity); - IMediaSample_SetPreroll(sample, buffer->preroll); - IMediaSample_SetSyncPoint(sample, !buffer->delta); - - if (!pin->pin.pin.peer) - return VFW_E_NOT_CONNECTED; - - hr = IMemInputPin_Receive(pin->pin.pMemInputPin, sample); - TRACE("Receive() returned hr %#lx.\n", hr); - return hr; -} - /* Send a single GStreamer buffer (splitting it into multiple IMediaSamples if * necessary). */ static void send_buffer(struct parser_source *pin, const struct wg_parser_buffer *buffer) { - HRESULT hr; + bool success, incomplete = true; + struct wg_sample *wg_sample; IMediaSample *sample; + HRESULT hr = S_OK;
if (pin->need_segment) { @@ -781,50 +668,40 @@ static void send_buffer(struct parser_source *pin, const struct wg_parser_buffer pin->need_segment = false; }
- if (IsEqualGUID(&pin->pin.pin.mt.formattype, &FORMAT_WaveFormatEx) - && (IsEqualGUID(&pin->pin.pin.mt.subtype, &MEDIASUBTYPE_PCM) - || IsEqualGUID(&pin->pin.pin.mt.subtype, &MEDIASUBTYPE_IEEE_FLOAT))) + while (SUCCEEDED(hr) && incomplete) { - WAVEFORMATEX *format = (WAVEFORMATEX *)pin->pin.pin.mt.pbFormat; - uint32_t offset = 0; - - while (offset < buffer->size) + if (FAILED(hr = IMemAllocator_GetBuffer(pin->pin.pAllocator, &sample, NULL, NULL, 0))) { - uint32_t advance; - - if (FAILED(hr = IMemAllocator_GetBuffer(pin->pin.pAllocator, &sample, NULL, NULL, 0))) - { - ERR("Failed to get a sample, hr %#lx.\n", hr); - break; - } - - advance = min(IMediaSample_GetSize(sample), buffer->size - offset); - - hr = send_sample(pin, sample, buffer, offset, advance, format->nAvgBytesPerSec); - + ERR("Failed to get a sample, hr %#lx.\n", hr); + break; + } + if (FAILED(hr = wg_sample_wrap_qz(sample, &wg_sample))) + { + ERR("Failed to create sample, hr %#lx.\n", hr); IMediaSample_Release(sample); - - if (FAILED(hr)) - break; - - offset += advance; + break; } - } - else - { - if (FAILED(hr = IMemAllocator_GetBuffer(pin->pin.pAllocator, &sample, NULL, NULL, 0))) + + if ((success = wg_parser_stream_read_data(pin->wg_stream, wg_sample))) { - ERR("Failed to get a sample, hr %#lx.\n", hr); + /* update pts and duration to current seeking time and rate */ + wg_sample->pts -= pin->seek.llCurrent; + wg_sample->pts *= pin->seek.dRate; + wg_sample->duration *= pin->seek.dRate; + incomplete = wg_sample->flags & WG_SAMPLE_FLAG_INCOMPLETE; } + wg_sample_unwrap(wg_sample); + + if (!success || !pin->pin.pin.peer) + hr = E_FAIL; else { - hr = send_sample(pin, sample, buffer, 0, buffer->size, 0); - - IMediaSample_Release(sample); + hr = IMemInputPin_Receive(pin->pin.pMemInputPin, sample); + TRACE("Receive() returned hr %#lx.\n", hr); } - }
- wg_parser_stream_release_buffer(pin->wg_stream); + IMediaSample_Release(sample); + } }
static DWORD CALLBACK stream_thread(void *arg) diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h index 7e639abfd3c..e5135d67e74 100644 --- a/dlls/winegstreamer/unixlib.h +++ b/dlls/winegstreamer/unixlib.h @@ -122,6 +122,7 @@ enum wg_sample_flag WG_SAMPLE_FLAG_HAS_DURATION = 4, WG_SAMPLE_FLAG_SYNC_POINT = 8, WG_SAMPLE_FLAG_DISCONTINUITY = 0x10, + WG_SAMPLE_FLAG_PREROLL = 0x20, };
struct wg_sample diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c index fd757fa44f6..1a0e7ca9209 100644 --- a/dlls/winegstreamer/wg_sample.c +++ b/dlls/winegstreamer/wg_sample.c @@ -25,6 +25,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat); WINE_DECLARE_DEBUG_CHANNEL(wmvcore); +WINE_DECLARE_DEBUG_CHANNEL(quartz);
struct sample { @@ -33,6 +34,7 @@ struct sample { WG_SAMPLE_TYPE_MF = 1, WG_SAMPLE_TYPE_WM = 2, + WG_SAMPLE_TYPE_QZ = 3, } type;
union @@ -46,6 +48,10 @@ struct sample { INSSBuffer *sample; } wm; + struct + { + IMediaSample *sample; + } qz; } u; };
@@ -130,6 +136,32 @@ HRESULT wg_sample_wrap_wm(INSSBuffer *wm_sample, QWORD pts, QWORD duration, DWOR return S_OK; }
+HRESULT wg_sample_wrap_qz(IMediaSample *qz_sample, struct wg_sample **out) +{ + DWORD current_length, max_length; + struct sample *sample; + BYTE *buffer; + HRESULT hr; + + if (FAILED(hr = IMediaSample_GetPointer(qz_sample, &buffer))) + return hr; + current_length = IMediaSample_GetActualDataLength(qz_sample); + max_length = IMediaSample_GetSize(qz_sample); + + if (!(sample = calloc(1, sizeof(*sample)))) + return E_OUTOFMEMORY; + + IMediaSample_AddRef((sample->u.qz.sample = qz_sample)); + sample->wg_sample.data = buffer; + sample->wg_sample.size = current_length; + sample->wg_sample.max_size = max_length; + sample->type = WG_SAMPLE_TYPE_QZ; + + TRACE_(quartz)("Created wg_sample %p for sample %p.\n", &sample->wg_sample, qz_sample); + *out = &sample->wg_sample; + return S_OK; +} + void wg_sample_unwrap(struct wg_sample *wg_sample) { struct sample *sample = CONTAINING_RECORD(wg_sample, struct sample, wg_sample); @@ -160,6 +192,45 @@ void wg_sample_unwrap(struct wg_sample *wg_sample) INSSBuffer_Release(sample->u.wm.sample); break;
+ case WG_SAMPLE_TYPE_QZ: + { + REFERENCE_TIME start_pts = wg_sample->pts, end_pts = start_pts + wg_sample->duration; + BOOL value; + + TRACE_(quartz)("wg_sample %p\n", wg_sample); + + IMediaSample_SetActualDataLength(sample->u.qz.sample, wg_sample->size); + + if (wg_sample->flags & WG_SAMPLE_FLAG_HAS_PTS) + { + if (wg_sample->flags & WG_SAMPLE_FLAG_HAS_DURATION) + { + IMediaSample_SetTime(sample->u.qz.sample, &start_pts, &end_pts); + IMediaSample_SetMediaTime(sample->u.qz.sample, &start_pts, &end_pts); + } + else + { + IMediaSample_SetTime(sample->u.qz.sample, &start_pts, NULL); + IMediaSample_SetMediaTime(sample->u.qz.sample, NULL, NULL); + } + } + else + { + IMediaSample_SetTime(sample->u.qz.sample, NULL, NULL); + IMediaSample_SetMediaTime(sample->u.qz.sample, NULL, NULL); + } + + value = !!(wg_sample->flags & WG_SAMPLE_FLAG_DISCONTINUITY); + IMediaSample_SetDiscontinuity(sample->u.qz.sample, value); + value = !!(wg_sample->flags & WG_SAMPLE_FLAG_DISCONTINUITY); + IMediaSample_SetPreroll(sample->u.qz.sample, value); + value = !!(wg_sample->flags & WG_SAMPLE_FLAG_DISCONTINUITY); + IMediaSample_SetSyncPoint(sample->u.qz.sample, value); + + IMediaSample_Release(sample->u.qz.sample); + break; + } + default: FIXME("Unknown wg_sample %p, type %u\n", wg_sample, sample->type); break; diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c index bd53c13e84b..37f9cadde76 100644 --- a/dlls/winegstreamer/wg_transform.c +++ b/dlls/winegstreamer/wg_transform.c @@ -652,6 +652,8 @@ NTSTATUS wg_sample_read_from_buffer(GstBuffer *buffer, GstCaps *caps, gsize plan sample->flags |= WG_SAMPLE_FLAG_SYNC_POINT; if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT)) sample->flags |= WG_SAMPLE_FLAG_DISCONTINUITY; + if (GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_LIVE)) + sample->flags |= WG_SAMPLE_FLAG_PREROLL;
GST_INFO("Copied %u bytes, sample %p, flags %#x", sample->size, sample, sample->flags); return STATUS_SUCCESS;