Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/winegstreamer/gst_private.h | 8 ++-
dlls/winegstreamer/wm_asyncreader.c | 17 ++++--
dlls/winegstreamer/wm_reader.c | 84 ++++++++++++++++++++++++-----
3 files changed, 91 insertions(+), 18 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index e1dec7b755c..f1862515ebc 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -120,10 +120,11 @@ struct wm_stream
{
struct wm_reader *reader;
struct wg_parser_stream *wg_stream;
- WORD index;
- bool eos;
struct wg_format format;
WMT_STREAM_SELECTION selection;
+ WORD index;
+ bool eos;
+ bool allocate_output;
};
struct wm_reader
@@ -148,6 +149,8 @@ struct wm_reader
struct wm_stream *streams;
WORD stream_count;
+ IWMReaderCallbackAdvanced *callback_advanced;
+
const struct wm_reader_ops *ops;
};
@@ -174,6 +177,7 @@ void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops);
HRESULT wm_reader_open_file(struct wm_reader *reader, const WCHAR *filename);
HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream);
void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration);
+HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output, BOOL allocate);
HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output,
IWMOutputMediaProps *props);
HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count,
diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c
index 35ed8221aa0..e0547dfda60 100644
--- a/dlls/winegstreamer/wm_asyncreader.c
+++ b/dlls/winegstreamer/wm_asyncreader.c
@@ -57,10 +57,16 @@ static REFERENCE_TIME get_current_time(const struct async_reader *reader)
static void open_stream(struct async_reader *reader, IWMReaderCallback *callback, void *context)
{
static const DWORD zero;
+ HRESULT hr;
IWMReaderCallback_AddRef(reader->callback = callback);
reader->context = context;
IWMReaderCallback_OnStatus(callback, WMT_OPENED, S_OK, WMT_TYPE_DWORD, (BYTE *)&zero, context);
+
+ if (FAILED(hr = IWMReaderCallback_QueryInterface(callback,
+ &IID_IWMReaderCallbackAdvanced, (void **)&reader->reader.callback_advanced)))
+ reader->reader.callback_advanced = NULL;
+ TRACE("Querying for IWMReaderCallbackAdvanced returned %#x.\n", hr);
}
static DWORD WINAPI stream_thread(void *arg)
@@ -497,11 +503,14 @@ static HRESULT WINAPI WMReaderAdvanced_GetReceiveStreamSamples(IWMReaderAdvanced
return E_NOTIMPL;
}
-static HRESULT WINAPI WMReaderAdvanced_SetAllocateForOutput(IWMReaderAdvanced6 *iface, DWORD output_num, BOOL allocate)
+static HRESULT WINAPI WMReaderAdvanced_SetAllocateForOutput(IWMReaderAdvanced6 *iface,
+ DWORD output, BOOL allocate)
{
- struct async_reader *This = impl_from_IWMReaderAdvanced6(iface);
- FIXME("(%p)->(%d %x)\n", This, output_num, allocate);
- return E_NOTIMPL;
+ struct async_reader *reader = impl_from_IWMReaderAdvanced6(iface);
+
+ TRACE("reader %p, output %u, allocate %d.\n", reader, output, allocate);
+
+ return wm_reader_set_allocate_for_output(&reader->reader, output, allocate);
}
static HRESULT WINAPI WMReaderAdvanced_GetAllocateForOutput(IWMReaderAdvanced6 *iface, DWORD output_num, BOOL *allocate)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c
index 3ca43fb127e..09059c3a32b 100644
--- a/dlls/winegstreamer/wm_reader.c
+++ b/dlls/winegstreamer/wm_reader.c
@@ -1554,6 +1554,10 @@ HRESULT wm_reader_close(struct wm_reader *reader)
CloseHandle(reader->read_thread);
reader->read_thread = NULL;
+ if (reader->callback_advanced)
+ IWMReaderCallbackAdvanced_Release(reader->callback_advanced);
+ reader->callback_advanced = NULL;
+
wg_parser_destroy(reader->wg_parser);
reader->wg_parser = NULL;
@@ -1758,9 +1762,9 @@ static const char *get_major_type_string(enum wg_major_type type)
HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags)
{
+ IWMReaderCallbackAdvanced *callback_advanced = stream->reader->callback_advanced;
struct wg_parser_stream *wg_stream = stream->wg_stream;
struct wg_parser_event event;
- struct buffer *object;
if (stream->selection == WMT_OFF)
return NS_E_INVALID_REQUEST;
@@ -1768,6 +1772,9 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
if (stream->eos)
return NS_E_NO_MORE_SAMPLES;
+ if (!stream->allocate_output)
+ callback_advanced = NULL;
+
for (;;)
{
if (!wg_parser_stream_get_event(wg_stream, &event))
@@ -1782,24 +1789,59 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
switch (event.type)
{
case WG_PARSER_EVENT_BUFFER:
- /* FIXME: Should these be pooled? */
- if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size]))))
+ {
+ DWORD size, capacity;
+ INSSBuffer *sample;
+ HRESULT hr;
+ BYTE *data;
+
+ if (callback_advanced)
{
- wg_parser_stream_release_buffer(wg_stream);
- return E_OUTOFMEMORY;
+ if (FAILED(hr = IWMReaderCallbackAdvanced_AllocateForOutput(callback_advanced,
+ stream->index, event.u.buffer.size, &sample, NULL)))
+ {
+ ERR("Failed to allocate sample of %u bytes, hr %#x.\n", event.u.buffer.size, hr);
+ wg_parser_stream_release_buffer(wg_stream);
+ return hr;
+ }
+ }
+ else
+ {
+ struct buffer *object;
+
+ /* FIXME: Should these be pooled? */
+ if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size]))))
+ {
+ wg_parser_stream_release_buffer(wg_stream);
+ return E_OUTOFMEMORY;
+ }
+
+ object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
+ object->refcount = 1;
+ object->capacity = event.u.buffer.size;
+
+ TRACE("Created buffer %p.\n", object);
+ sample = &object->INSSBuffer_iface;
}
- object->INSSBuffer_iface.lpVtbl = &buffer_vtbl;
- object->refcount = 1;
- object->capacity = object->size = event.u.buffer.size;
+ if (FAILED(hr = INSSBuffer_GetBufferAndLength(sample, &data, &size)))
+ ERR("Failed to get data pointer, hr %#x.\n", hr);
+ if (FAILED(hr = INSSBuffer_GetMaxLength(sample, &capacity)))
+ ERR("Failed to get capacity, hr %#x.\n", hr);
+ if (event.u.buffer.size > capacity)
+ ERR("Returned capacity %u is less than requested capacity %u.\n",
+ capacity, event.u.buffer.size);
- if (!wg_parser_stream_copy_buffer(wg_stream, object->data, 0, object->size))
+ if (!wg_parser_stream_copy_buffer(wg_stream, data, 0, event.u.buffer.size))
{
/* The GStreamer pin has been flushed. */
- free(object);
+ INSSBuffer_Release(sample);
break;
}
+ if (FAILED(hr = INSSBuffer_SetLength(sample, event.u.buffer.size)))
+ ERR("Failed to set size %u, hr %#x.\n", event.u.buffer.size, hr);
+
wg_parser_stream_release_buffer(wg_stream);
if (!event.u.buffer.has_pts)
@@ -1815,9 +1857,9 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
if (!event.u.buffer.delta)
*flags |= WM_SF_CLEANPOINT;
- TRACE("Created buffer %p.\n", object);
- *ret_sample = &object->INSSBuffer_iface;
+ *ret_sample = sample;
return S_OK;
+ }
case WG_PARSER_EVENT_EOS:
stream->eos = true;
@@ -1913,6 +1955,24 @@ HRESULT wm_reader_get_stream_selection(struct wm_reader *reader,
return S_OK;
}
+HRESULT wm_reader_set_allocate_for_output(struct wm_reader *reader, DWORD output, BOOL allocate)
+{
+ struct wm_stream *stream;
+
+ EnterCriticalSection(&reader->cs);
+
+ if (!(stream = get_stream_by_output_number(reader, output)))
+ {
+ LeaveCriticalSection(&reader->cs);
+ return E_INVALIDARG;
+ }
+
+ stream->allocate_output = !!allocate;
+
+ LeaveCriticalSection(&reader->cs);
+ return S_OK;
+}
+
void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops)
{
reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl;
--
2.33.0