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 0e0c639d504..810a800f016 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1532,6 +1532,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; @@ -1736,9 +1740,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; @@ -1746,6 +1750,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)) @@ -1760,24 +1767,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) @@ -1793,9 +1835,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; @@ -1891,6 +1933,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;