winegstreamer: Fix typo.
[wine.git] / dlls / winegstreamer / media_source.c
blob412715854547327c29c6d246fcf3a5e0b41bf958
1 /* GStreamer Media Source
3 * Copyright 2020 Derek Lesho
4 * Copyright 2020 Zebediah Figura for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "gst_private.h"
23 #include "mfapi.h"
24 #include "mferror.h"
26 #include "wine/list.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
30 struct media_stream
32 IMFMediaStream IMFMediaStream_iface;
33 LONG ref;
35 IMFMediaSource *media_source;
36 IMFMediaEventQueue *event_queue;
37 IMFStreamDescriptor *descriptor;
39 struct wg_parser_stream *wg_stream;
41 IUnknown **token_queue;
42 LONG token_queue_count;
43 LONG token_queue_cap;
45 DWORD stream_id;
46 BOOL active;
47 BOOL eos;
50 enum source_async_op
52 SOURCE_ASYNC_START,
53 SOURCE_ASYNC_PAUSE,
54 SOURCE_ASYNC_STOP,
55 SOURCE_ASYNC_REQUEST_SAMPLE,
58 struct source_async_command
60 IUnknown IUnknown_iface;
61 LONG refcount;
62 enum source_async_op op;
63 union
65 struct
67 IMFPresentationDescriptor *descriptor;
68 GUID format;
69 PROPVARIANT position;
70 } start;
71 struct
73 struct media_stream *stream;
74 IUnknown *token;
75 } request_sample;
76 } u;
79 struct media_source
81 IMFMediaSource IMFMediaSource_iface;
82 IMFGetService IMFGetService_iface;
83 IMFRateSupport IMFRateSupport_iface;
84 IMFRateControl IMFRateControl_iface;
85 IMFAsyncCallback async_commands_callback;
86 LONG ref;
87 DWORD async_commands_queue;
88 IMFMediaEventQueue *event_queue;
89 IMFByteStream *byte_stream;
91 CRITICAL_SECTION cs;
93 struct wg_parser *wg_parser;
94 UINT64 duration;
96 IMFStreamDescriptor **descriptors;
97 struct media_stream **streams;
98 ULONG stream_count;
100 enum
102 SOURCE_OPENING,
103 SOURCE_STOPPED,
104 SOURCE_PAUSED,
105 SOURCE_RUNNING,
106 SOURCE_SHUTDOWN,
107 } state;
108 float rate;
110 HANDLE read_thread;
111 bool read_thread_shutdown;
114 static inline struct media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface)
116 return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface);
119 static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
121 return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
124 static inline struct media_source *impl_from_IMFGetService(IMFGetService *iface)
126 return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface);
129 static inline struct media_source *impl_from_IMFRateSupport(IMFRateSupport *iface)
131 return CONTAINING_RECORD(iface, struct media_source, IMFRateSupport_iface);
134 static inline struct media_source *impl_from_IMFRateControl(IMFRateControl *iface)
136 return CONTAINING_RECORD(iface, struct media_source, IMFRateControl_iface);
139 static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
141 return CONTAINING_RECORD(iface, struct media_source, async_commands_callback);
144 static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
146 return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface);
149 static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
151 if (IsEqualIID(riid, &IID_IUnknown))
153 *obj = iface;
154 IUnknown_AddRef(iface);
155 return S_OK;
158 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
159 *obj = NULL;
160 return E_NOINTERFACE;
163 static ULONG WINAPI source_async_command_AddRef(IUnknown *iface)
165 struct source_async_command *command = impl_from_async_command_IUnknown(iface);
166 return InterlockedIncrement(&command->refcount);
169 static ULONG WINAPI source_async_command_Release(IUnknown *iface)
171 struct source_async_command *command = impl_from_async_command_IUnknown(iface);
172 ULONG refcount = InterlockedDecrement(&command->refcount);
174 if (!refcount)
176 if (command->op == SOURCE_ASYNC_START)
177 PropVariantClear(&command->u.start.position);
178 else if (command->op == SOURCE_ASYNC_REQUEST_SAMPLE)
180 if (command->u.request_sample.token)
181 IUnknown_Release(command->u.request_sample.token);
183 free(command);
186 return refcount;
189 static const IUnknownVtbl source_async_command_vtbl =
191 source_async_command_QueryInterface,
192 source_async_command_AddRef,
193 source_async_command_Release,
196 static HRESULT source_create_async_op(enum source_async_op op, IUnknown **out)
198 struct source_async_command *command;
200 if (!(command = calloc(1, sizeof(*command))))
201 return E_OUTOFMEMORY;
203 command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
204 command->refcount = 1;
205 command->op = op;
207 *out = &command->IUnknown_iface;
208 return S_OK;
211 static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
213 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
215 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
216 IsEqualIID(riid, &IID_IUnknown))
218 *obj = iface;
219 IMFAsyncCallback_AddRef(iface);
220 return S_OK;
223 WARN("Unsupported %s.\n", debugstr_guid(riid));
224 *obj = NULL;
225 return E_NOINTERFACE;
228 static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
229 DWORD *flags, DWORD *queue)
231 return E_NOTIMPL;
234 static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
236 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
237 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
240 static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
242 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
243 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
246 static HRESULT stream_descriptor_get_media_type(IMFStreamDescriptor *descriptor, IMFMediaType **media_type)
248 IMFMediaTypeHandler *handler;
249 HRESULT hr;
251 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler)))
252 return hr;
253 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
254 IMFMediaTypeHandler_Release(handler);
256 return hr;
259 static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, struct wg_format *format)
261 IMFMediaType *media_type;
262 HRESULT hr;
264 if (FAILED(hr = stream_descriptor_get_media_type(descriptor, &media_type)))
265 return hr;
266 mf_media_type_to_wg_format(media_type, format);
267 IMFMediaType_Release(media_type);
269 return hr;
272 static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected)
274 ULONG sd_count;
275 IMFStreamDescriptor *ret;
276 unsigned int i;
278 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count)))
279 return NULL;
281 for (i = 0; i < sd_count; i++)
283 DWORD stream_id;
285 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret)))
286 return NULL;
288 if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id)
289 return ret;
291 IMFStreamDescriptor_Release(ret);
293 return NULL;
296 static BOOL enqueue_token(struct media_stream *stream, IUnknown *token)
298 if (stream->token_queue_count == stream->token_queue_cap)
300 IUnknown **buf;
301 stream->token_queue_cap = stream->token_queue_cap * 2 + 1;
302 buf = realloc(stream->token_queue, stream->token_queue_cap * sizeof(*buf));
303 if (buf)
304 stream->token_queue = buf;
305 else
307 stream->token_queue_cap = stream->token_queue_count;
308 return FALSE;
311 stream->token_queue[stream->token_queue_count++] = token;
312 return TRUE;
315 static void flush_token_queue(struct media_stream *stream, BOOL send)
317 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
318 LONG i;
320 for (i = 0; i < stream->token_queue_count; i++)
322 if (send)
324 IUnknown *op;
325 HRESULT hr;
327 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op)))
329 struct source_async_command *command = impl_from_async_command_IUnknown(op);
330 command->u.request_sample.stream = stream;
331 command->u.request_sample.token = stream->token_queue[i];
333 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
334 IUnknown_Release(op);
336 if (FAILED(hr))
337 WARN("Could not enqueue sample request, hr %#lx\n", hr);
339 else if (stream->token_queue[i])
340 IUnknown_Release(stream->token_queue[i]);
342 free(stream->token_queue);
343 stream->token_queue = NULL;
344 stream->token_queue_count = 0;
345 stream->token_queue_cap = 0;
348 static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL seeking, const PROPVARIANT *position)
350 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
351 struct wg_format format;
352 HRESULT hr;
354 TRACE("source %p, stream %p\n", source, stream);
356 if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format)))
357 WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr);
358 wg_parser_stream_enable(stream->wg_stream, &format);
360 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, active ? MEUpdatedStream : MENewStream,
361 &GUID_NULL, S_OK, (IUnknown *)&stream->IMFMediaStream_iface)))
362 WARN("Failed to send source stream event, hr %#lx\n", hr);
363 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, seeking ? MEStreamSeeked : MEStreamStarted,
364 &GUID_NULL, S_OK, position);
367 static HRESULT media_source_start(struct media_source *source, IMFPresentationDescriptor *descriptor,
368 GUID *format, PROPVARIANT *position)
370 BOOL starting = source->state == SOURCE_STOPPED, seek_message = !starting && position->vt != VT_EMPTY;
371 unsigned int i;
372 HRESULT hr;
374 TRACE("source %p, descriptor %p, format %s, position %s\n", source, descriptor,
375 debugstr_guid(format), wine_dbgstr_variant((VARIANT *)position));
377 if (source->state == SOURCE_SHUTDOWN)
378 return MF_E_SHUTDOWN;
380 /* seek to beginning on stop->play */
381 if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY)
383 position->vt = VT_I8;
384 position->hVal.QuadPart = 0;
387 for (i = 0; i < source->stream_count; i++)
389 struct media_stream *stream;
390 BOOL was_active, selected;
391 IMFStreamDescriptor *sd;
392 DWORD stream_id;
394 stream = source->streams[i];
395 was_active = !starting && stream->active;
397 IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id);
398 sd = stream_descriptor_from_id(descriptor, stream_id, &selected);
399 IMFStreamDescriptor_Release(sd);
401 if (position->vt != VT_EMPTY)
402 stream->eos = FALSE;
404 if (!(stream->active = selected))
405 wg_parser_stream_disable(stream->wg_stream);
406 else if (FAILED(hr = media_stream_start(stream, was_active, seek_message, position)))
407 WARN("Failed to start media stream, hr %#lx\n", hr);
410 source->state = SOURCE_RUNNING;
412 if (position->vt == VT_I8)
413 wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, position->hVal.QuadPart, 0,
414 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
416 for (i = 0; i < source->stream_count; i++)
417 flush_token_queue(source->streams[i], position->vt == VT_EMPTY);
419 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
420 seek_message ? MESourceSeeked : MESourceStarted, &GUID_NULL, S_OK, position);
423 static HRESULT media_source_pause(struct media_source *source)
425 unsigned int i;
426 HRESULT hr;
428 TRACE("source %p\n", source);
430 if (source->state == SOURCE_SHUTDOWN)
431 return MF_E_SHUTDOWN;
433 for (i = 0; i < source->stream_count; i++)
435 struct media_stream *stream = source->streams[i];
436 if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused,
437 &GUID_NULL, S_OK, NULL)))
438 WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr);
441 source->state = SOURCE_PAUSED;
442 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL);
445 static HRESULT media_source_stop(struct media_source *source)
447 unsigned int i;
448 HRESULT hr;
450 TRACE("source %p\n", source);
452 if (source->state == SOURCE_SHUTDOWN)
453 return MF_E_SHUTDOWN;
455 for (i = 0; i < source->stream_count; i++)
457 struct media_stream *stream = source->streams[i];
458 if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped,
459 &GUID_NULL, S_OK, NULL)))
460 WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr);
463 source->state = SOURCE_STOPPED;
465 for (i = 0; i < source->stream_count; i++)
466 flush_token_queue(source->streams[i], FALSE);
468 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL);
471 static HRESULT media_stream_send_sample(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token)
473 IMFSample *sample = NULL;
474 IMFMediaBuffer *buffer;
475 HRESULT hr;
476 BYTE *data;
478 if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer->size, &buffer)))
479 return hr;
480 if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer->size)))
481 goto out;
482 if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL)))
483 goto out;
485 if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, wg_buffer->size))
487 wg_parser_stream_release_buffer(stream->wg_stream);
488 IMFMediaBuffer_Unlock(buffer);
489 goto out;
491 wg_parser_stream_release_buffer(stream->wg_stream);
493 if (FAILED(hr = IMFMediaBuffer_Unlock(buffer)))
494 goto out;
496 if (FAILED(hr = MFCreateSample(&sample)))
497 goto out;
498 if (FAILED(hr = IMFSample_AddBuffer(sample, buffer)))
499 goto out;
500 if (FAILED(hr = IMFSample_SetSampleTime(sample, wg_buffer->pts)))
501 goto out;
502 if (FAILED(hr = IMFSample_SetSampleDuration(sample, wg_buffer->duration)))
503 goto out;
504 if (token && FAILED(hr = IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token)))
505 goto out;
507 hr = IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
508 &GUID_NULL, S_OK, (IUnknown *)sample);
510 out:
511 if (sample)
512 IMFSample_Release(sample);
513 IMFMediaBuffer_Release(buffer);
514 return hr;
517 static HRESULT media_stream_send_eos(struct media_source *source, struct media_stream *stream)
519 PROPVARIANT empty = {.vt = VT_EMPTY};
520 HRESULT hr;
521 UINT i;
523 TRACE("source %p, stream %p\n", source, stream);
525 stream->eos = TRUE;
526 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty)))
527 WARN("Failed to queue MEEndOfStream event, hr %#lx\n", hr);
529 for (i = 0; i < source->stream_count; i++)
531 struct media_stream *stream = source->streams[i];
532 if (stream->active && !stream->eos)
533 return S_OK;
536 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty)))
537 WARN("Failed to queue MEEndOfPresentation event, hr %#lx\n", hr);
538 return S_OK;
541 static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token)
543 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
544 struct wg_parser_buffer buffer;
546 TRACE("%p, %p\n", stream, token);
548 if (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer))
549 return media_stream_send_sample(stream, &buffer, token);
551 return media_stream_send_eos(source, stream);
554 static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
556 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
557 struct source_async_command *command;
558 IUnknown *state;
559 HRESULT hr;
561 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
562 return hr;
564 EnterCriticalSection(&source->cs);
566 command = impl_from_async_command_IUnknown(state);
567 switch (command->op)
569 case SOURCE_ASYNC_START:
571 IMFPresentationDescriptor *descriptor = command->u.start.descriptor;
572 GUID format = command->u.start.format;
573 PROPVARIANT position = command->u.start.position;
575 if (FAILED(hr = media_source_start(source, descriptor, &format, &position)))
576 WARN("Failed to start source %p, hr %#lx\n", source, hr);
577 break;
579 case SOURCE_ASYNC_PAUSE:
580 if (FAILED(hr = media_source_pause(source)))
581 WARN("Failed to pause source %p, hr %#lx\n", source, hr);
582 break;
583 case SOURCE_ASYNC_STOP:
584 if (FAILED(hr = media_source_stop(source)))
585 WARN("Failed to stop source %p, hr %#lx\n", source, hr);
586 break;
587 case SOURCE_ASYNC_REQUEST_SAMPLE:
588 if (source->state == SOURCE_PAUSED)
589 enqueue_token(command->u.request_sample.stream, command->u.request_sample.token);
590 else if (source->state == SOURCE_RUNNING)
592 if (FAILED(hr = wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token)))
593 WARN("Failed to request sample, hr %#lx\n", hr);
595 break;
598 LeaveCriticalSection(&source->cs);
600 IUnknown_Release(state);
602 return S_OK;
605 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
607 callback_QueryInterface,
608 source_async_commands_callback_AddRef,
609 source_async_commands_callback_Release,
610 callback_GetParameters,
611 source_async_commands_Invoke,
614 static DWORD CALLBACK read_thread(void *arg)
616 struct media_source *source = arg;
617 IMFByteStream *byte_stream = source->byte_stream;
618 size_t buffer_size = 4096;
619 uint64_t file_size;
620 void *data;
622 if (!(data = malloc(buffer_size)))
623 return 0;
625 IMFByteStream_GetLength(byte_stream, &file_size);
627 TRACE("Starting read thread for media source %p.\n", source);
629 while (!source->read_thread_shutdown)
631 uint64_t offset;
632 ULONG ret_size;
633 uint32_t size;
634 HRESULT hr;
636 if (!wg_parser_get_next_read_offset(source->wg_parser, &offset, &size))
637 continue;
639 if (offset >= file_size)
640 size = 0;
641 else if (offset + size >= file_size)
642 size = file_size - offset;
644 /* Some IMFByteStreams (including the standard file-based stream) return
645 * an error when reading past the file size. */
646 if (!size)
648 wg_parser_push_data(source->wg_parser, data, 0);
649 continue;
652 if (!array_reserve(&data, &buffer_size, size, 1))
654 free(data);
655 return 0;
658 ret_size = 0;
660 if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset)))
661 hr = IMFByteStream_Read(byte_stream, data, size, &ret_size);
662 if (FAILED(hr))
663 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr);
664 else if (ret_size != size)
665 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size);
666 wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size);
669 free(data);
670 TRACE("Media source is shutting down; exiting.\n");
671 return 0;
674 static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
676 struct media_stream *stream = impl_from_IMFMediaStream(iface);
678 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
680 if (IsEqualIID(riid, &IID_IMFMediaStream) ||
681 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
682 IsEqualIID(riid, &IID_IUnknown))
684 *out = &stream->IMFMediaStream_iface;
686 else
688 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
689 *out = NULL;
690 return E_NOINTERFACE;
693 IUnknown_AddRef((IUnknown*)*out);
694 return S_OK;
697 static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
699 struct media_stream *stream = impl_from_IMFMediaStream(iface);
700 ULONG ref = InterlockedIncrement(&stream->ref);
702 TRACE("%p, refcount %lu.\n", iface, ref);
704 return ref;
707 static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
709 struct media_stream *stream = impl_from_IMFMediaStream(iface);
710 ULONG ref = InterlockedDecrement(&stream->ref);
712 TRACE("%p, refcount %lu.\n", iface, ref);
714 if (!ref)
716 IMFMediaSource_Release(stream->media_source);
717 IMFStreamDescriptor_Release(stream->descriptor);
718 IMFMediaEventQueue_Release(stream->event_queue);
719 flush_token_queue(stream, FALSE);
720 free(stream);
723 return ref;
726 static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
728 struct media_stream *stream = impl_from_IMFMediaStream(iface);
730 TRACE("%p, %#lx, %p.\n", iface, flags, event);
732 return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
735 static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
737 struct media_stream *stream = impl_from_IMFMediaStream(iface);
739 TRACE("%p, %p, %p.\n", iface, callback, state);
741 return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
744 static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
746 struct media_stream *stream = impl_from_IMFMediaStream(iface);
748 TRACE("%p, %p, %p.\n", stream, result, event);
750 return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
753 static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
754 HRESULT hr, const PROPVARIANT *value)
756 struct media_stream *stream = impl_from_IMFMediaStream(iface);
758 TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
760 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
763 static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **out)
765 struct media_stream *stream = impl_from_IMFMediaStream(iface);
766 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
767 HRESULT hr = S_OK;
769 TRACE("%p, %p.\n", iface, out);
771 EnterCriticalSection(&source->cs);
773 if (source->state == SOURCE_SHUTDOWN)
774 hr = MF_E_SHUTDOWN;
775 else
777 IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
778 *out = &source->IMFMediaSource_iface;
781 LeaveCriticalSection(&source->cs);
783 return hr;
786 static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
788 struct media_stream *stream = impl_from_IMFMediaStream(iface);
789 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
790 HRESULT hr = S_OK;
792 TRACE("%p, %p.\n", iface, descriptor);
794 EnterCriticalSection(&source->cs);
796 if (source->state == SOURCE_SHUTDOWN)
797 hr = MF_E_SHUTDOWN;
798 else
800 IMFStreamDescriptor_AddRef(stream->descriptor);
801 *descriptor = stream->descriptor;
804 LeaveCriticalSection(&source->cs);
806 return hr;
809 static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
811 struct media_stream *stream = impl_from_IMFMediaStream(iface);
812 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
813 IUnknown *op;
814 HRESULT hr;
816 TRACE("%p, %p.\n", iface, token);
818 EnterCriticalSection(&source->cs);
820 if (source->state == SOURCE_SHUTDOWN)
821 hr = MF_E_SHUTDOWN;
822 else if (!stream->active)
823 hr = MF_E_MEDIA_SOURCE_WRONGSTATE;
824 else if (stream->eos)
825 hr = MF_E_END_OF_STREAM;
826 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op)))
828 struct source_async_command *command = impl_from_async_command_IUnknown(op);
829 command->u.request_sample.stream = stream;
830 if (token)
831 IUnknown_AddRef(token);
832 command->u.request_sample.token = token;
834 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
835 IUnknown_Release(op);
838 LeaveCriticalSection(&source->cs);
840 return hr;
843 static const IMFMediaStreamVtbl media_stream_vtbl =
845 media_stream_QueryInterface,
846 media_stream_AddRef,
847 media_stream_Release,
848 media_stream_GetEvent,
849 media_stream_BeginGetEvent,
850 media_stream_EndGetEvent,
851 media_stream_QueueEvent,
852 media_stream_GetMediaSource,
853 media_stream_GetStreamDescriptor,
854 media_stream_RequestSample
857 static HRESULT media_stream_create(IMFMediaSource *source, DWORD id,
858 struct media_stream **out)
860 struct wg_parser *wg_parser = impl_from_IMFMediaSource(source)->wg_parser;
861 struct media_stream *object;
862 HRESULT hr;
864 TRACE("source %p, id %lu.\n", source, id);
866 if (!(object = calloc(1, sizeof(*object))))
867 return E_OUTOFMEMORY;
869 object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
870 object->ref = 1;
872 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
874 free(object);
875 return hr;
878 IMFMediaSource_AddRef(source);
879 object->media_source = source;
880 object->stream_id = id;
882 object->active = TRUE;
883 object->eos = FALSE;
884 object->wg_stream = wg_parser_get_stream(wg_parser, id);
886 TRACE("Created stream object %p.\n", object);
888 *out = object;
889 return S_OK;
892 static HRESULT media_stream_init_desc(struct media_stream *stream)
894 IMFMediaTypeHandler *type_handler = NULL;
895 IMFMediaType *stream_types[6];
896 struct wg_format format;
897 DWORD type_count = 0;
898 unsigned int i;
899 HRESULT hr;
901 wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
903 if (format.major_type == WG_MAJOR_TYPE_VIDEO)
905 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
906 * YUV color space, and it's generally much less expensive for
907 * videoconvert to do YUV -> YUV transformations. */
908 static const enum wg_video_format video_formats[] =
910 WG_VIDEO_FORMAT_NV12,
911 WG_VIDEO_FORMAT_YV12,
912 WG_VIDEO_FORMAT_YUY2,
913 WG_VIDEO_FORMAT_I420,
916 IMFMediaType *base_type = mf_media_type_from_wg_format(&format);
917 GUID base_subtype;
919 if (!base_type)
921 hr = MF_E_INVALIDMEDIATYPE;
922 goto done;
925 IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype);
927 stream_types[0] = base_type;
928 type_count = 1;
930 for (i = 0; i < ARRAY_SIZE(video_formats); ++i)
932 struct wg_format new_format = format;
933 IMFMediaType *new_type;
935 new_format.u.video.format = video_formats[i];
937 if (!(new_type = mf_media_type_from_wg_format(&new_format)))
939 hr = E_OUTOFMEMORY;
940 goto done;
942 stream_types[type_count++] = new_type;
944 if (video_formats[i] == WG_VIDEO_FORMAT_I420)
946 IMFMediaType *iyuv_type;
948 if (FAILED(hr = MFCreateMediaType(&iyuv_type)))
949 goto done;
950 if (FAILED(hr = IMFMediaType_CopyAllItems(new_type, (IMFAttributes *)iyuv_type)))
951 goto done;
952 if (FAILED(hr = IMFMediaType_SetGUID(iyuv_type, &MF_MT_SUBTYPE, &MFVideoFormat_IYUV)))
953 goto done;
954 stream_types[type_count++] = iyuv_type;
958 else if (format.major_type == WG_MAJOR_TYPE_AUDIO)
960 /* Expose at least one PCM and one floating point type for the
961 consumer to pick from. */
962 static const enum wg_audio_format audio_types[] =
964 WG_AUDIO_FORMAT_S16LE,
965 WG_AUDIO_FORMAT_F32LE,
968 if ((stream_types[0] = mf_media_type_from_wg_format(&format)))
969 type_count = 1;
971 for (i = 0; i < ARRAY_SIZE(audio_types); i++)
973 struct wg_format new_format;
974 if (format.u.audio.format == audio_types[i])
975 continue;
976 new_format = format;
977 new_format.u.audio.format = audio_types[i];
978 if ((stream_types[type_count] = mf_media_type_from_wg_format(&new_format)))
979 type_count++;
982 else
984 if ((stream_types[0] = mf_media_type_from_wg_format(&format)))
985 type_count = 1;
988 assert(type_count <= ARRAY_SIZE(stream_types));
990 if (!type_count)
992 ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
993 return E_FAIL;
996 if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, type_count, stream_types, &stream->descriptor)))
997 goto done;
999 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
1001 IMFStreamDescriptor_Release(stream->descriptor);
1002 goto done;
1005 if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0])))
1007 IMFStreamDescriptor_Release(stream->descriptor);
1008 goto done;
1011 done:
1012 if (type_handler)
1013 IMFMediaTypeHandler_Release(type_handler);
1014 for (i = 0; i < type_count; i++)
1015 IMFMediaType_Release(stream_types[i]);
1016 return hr;
1019 static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1021 struct media_source *source = impl_from_IMFGetService(iface);
1022 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1025 static ULONG WINAPI media_source_get_service_AddRef(IMFGetService *iface)
1027 struct media_source *source = impl_from_IMFGetService(iface);
1028 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1031 static ULONG WINAPI media_source_get_service_Release(IMFGetService *iface)
1033 struct media_source *source = impl_from_IMFGetService(iface);
1034 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1037 static HRESULT WINAPI media_source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1039 struct media_source *source = impl_from_IMFGetService(iface);
1041 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1043 *obj = NULL;
1045 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1047 if (IsEqualIID(riid, &IID_IMFRateSupport))
1049 *obj = &source->IMFRateSupport_iface;
1051 else if (IsEqualIID(riid, &IID_IMFRateControl))
1053 *obj = &source->IMFRateControl_iface;
1056 else
1057 FIXME("Unsupported service %s.\n", debugstr_guid(service));
1059 if (*obj)
1060 IUnknown_AddRef((IUnknown *)*obj);
1062 return *obj ? S_OK : E_NOINTERFACE;
1065 static const IMFGetServiceVtbl media_source_get_service_vtbl =
1067 media_source_get_service_QueryInterface,
1068 media_source_get_service_AddRef,
1069 media_source_get_service_Release,
1070 media_source_get_service_GetService,
1073 static HRESULT WINAPI media_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1075 struct media_source *source = impl_from_IMFRateSupport(iface);
1076 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1079 static ULONG WINAPI media_source_rate_support_AddRef(IMFRateSupport *iface)
1081 struct media_source *source = impl_from_IMFRateSupport(iface);
1082 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1085 static ULONG WINAPI media_source_rate_support_Release(IMFRateSupport *iface)
1087 struct media_source *source = impl_from_IMFRateSupport(iface);
1088 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1091 static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
1093 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1095 *rate = 0.0f;
1097 return S_OK;
1100 static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
1102 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1104 *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f;
1106 return S_OK;
1109 static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1110 float *nearest_rate)
1112 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_rate);
1114 if (nearest_rate)
1115 *nearest_rate = rate;
1117 return rate >= -1e6f && rate <= 1e6f ? S_OK : MF_E_UNSUPPORTED_RATE;
1120 static const IMFRateSupportVtbl media_source_rate_support_vtbl =
1122 media_source_rate_support_QueryInterface,
1123 media_source_rate_support_AddRef,
1124 media_source_rate_support_Release,
1125 media_source_rate_support_GetSlowestRate,
1126 media_source_rate_support_GetFastestRate,
1127 media_source_rate_support_IsRateSupported,
1130 static HRESULT WINAPI media_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
1132 struct media_source *source = impl_from_IMFRateControl(iface);
1133 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1136 static ULONG WINAPI media_source_rate_control_AddRef(IMFRateControl *iface)
1138 struct media_source *source = impl_from_IMFRateControl(iface);
1139 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1142 static ULONG WINAPI media_source_rate_control_Release(IMFRateControl *iface)
1144 struct media_source *source = impl_from_IMFRateControl(iface);
1145 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1148 static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
1150 struct media_source *source = impl_from_IMFRateControl(iface);
1151 HRESULT hr;
1153 FIXME("%p, %d, %f.\n", iface, thin, rate);
1155 if (rate < 0.0f)
1156 return MF_E_REVERSE_UNSUPPORTED;
1158 if (thin)
1159 return MF_E_THINNING_UNSUPPORTED;
1161 if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL)))
1162 return hr;
1164 EnterCriticalSection(&source->cs);
1165 source->rate = rate;
1166 LeaveCriticalSection(&source->cs);
1168 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL);
1171 static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
1173 struct media_source *source = impl_from_IMFRateControl(iface);
1175 TRACE("%p, %p, %p.\n", iface, thin, rate);
1177 if (thin)
1178 *thin = FALSE;
1180 EnterCriticalSection(&source->cs);
1181 *rate = source->rate;
1182 LeaveCriticalSection(&source->cs);
1184 return S_OK;
1187 static const IMFRateControlVtbl media_source_rate_control_vtbl =
1189 media_source_rate_control_QueryInterface,
1190 media_source_rate_control_AddRef,
1191 media_source_rate_control_Release,
1192 media_source_rate_control_SetRate,
1193 media_source_rate_control_GetRate,
1196 static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
1198 struct media_source *source = impl_from_IMFMediaSource(iface);
1200 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1202 if (IsEqualIID(riid, &IID_IMFMediaSource) ||
1203 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1204 IsEqualIID(riid, &IID_IUnknown))
1206 *out = &source->IMFMediaSource_iface;
1208 else if (IsEqualIID(riid, &IID_IMFGetService))
1210 *out = &source->IMFGetService_iface;
1212 else
1214 FIXME("%s, %p.\n", debugstr_guid(riid), out);
1215 *out = NULL;
1216 return E_NOINTERFACE;
1219 IUnknown_AddRef((IUnknown*)*out);
1220 return S_OK;
1223 static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface)
1225 struct media_source *source = impl_from_IMFMediaSource(iface);
1226 ULONG ref = InterlockedIncrement(&source->ref);
1228 TRACE("%p, refcount %lu.\n", iface, ref);
1230 return ref;
1233 static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
1235 struct media_source *source = impl_from_IMFMediaSource(iface);
1236 ULONG ref = InterlockedDecrement(&source->ref);
1238 TRACE("%p, refcount %lu.\n", iface, ref);
1240 if (!ref)
1242 IMFMediaSource_Shutdown(iface);
1243 IMFMediaEventQueue_Release(source->event_queue);
1244 IMFByteStream_Release(source->byte_stream);
1245 wg_parser_destroy(source->wg_parser);
1246 source->cs.DebugInfo->Spare[0] = 0;
1247 DeleteCriticalSection(&source->cs);
1248 free(source);
1251 return ref;
1254 static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
1256 struct media_source *source = impl_from_IMFMediaSource(iface);
1258 TRACE("%p, %#lx, %p.\n", iface, flags, event);
1260 return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
1263 static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
1265 struct media_source *source = impl_from_IMFMediaSource(iface);
1267 TRACE("%p, %p, %p.\n", iface, callback, state);
1269 return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
1272 static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1274 struct media_source *source = impl_from_IMFMediaSource(iface);
1276 TRACE("%p, %p, %p.\n", iface, result, event);
1278 return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
1281 static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
1282 HRESULT hr, const PROPVARIANT *value)
1284 struct media_source *source = impl_from_IMFMediaSource(iface);
1286 TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1288 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
1291 static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
1293 struct media_source *source = impl_from_IMFMediaSource(iface);
1294 HRESULT hr = S_OK;
1296 TRACE("%p, %p.\n", iface, characteristics);
1298 EnterCriticalSection(&source->cs);
1300 if (source->state == SOURCE_SHUTDOWN)
1301 hr = MF_E_SHUTDOWN;
1302 else
1303 *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE;
1305 LeaveCriticalSection(&source->cs);
1307 return hr;
1310 static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
1312 struct media_source *source = impl_from_IMFMediaSource(iface);
1313 HRESULT hr;
1314 UINT i;
1316 TRACE("%p, %p.\n", iface, descriptor);
1318 EnterCriticalSection(&source->cs);
1320 if (source->state == SOURCE_SHUTDOWN)
1321 hr = MF_E_SHUTDOWN;
1322 else if (SUCCEEDED(hr = MFCreatePresentationDescriptor(source->stream_count, source->descriptors, descriptor)))
1324 if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_DURATION, source->duration)))
1325 WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr);
1327 for (i = 0; i < source->stream_count; ++i)
1329 if (FAILED(hr = IMFPresentationDescriptor_SelectStream(*descriptor, i)))
1330 WARN("Failed to select stream %u, hr %#lx\n", i, hr);
1333 hr = S_OK;
1336 LeaveCriticalSection(&source->cs);
1338 return hr;
1341 static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
1342 const GUID *time_format, const PROPVARIANT *position)
1344 struct media_source *source = impl_from_IMFMediaSource(iface);
1345 IUnknown *op;
1346 HRESULT hr;
1348 TRACE("%p, %p, %p, %p.\n", iface, descriptor, time_format, position);
1350 EnterCriticalSection(&source->cs);
1352 if (source->state == SOURCE_SHUTDOWN)
1353 hr = MF_E_SHUTDOWN;
1354 else if (!(IsEqualIID(time_format, &GUID_NULL)))
1355 hr = MF_E_UNSUPPORTED_TIME_FORMAT;
1356 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &op)))
1358 struct source_async_command *command = impl_from_async_command_IUnknown(op);
1359 command->u.start.descriptor = descriptor;
1360 command->u.start.format = *time_format;
1361 PropVariantCopy(&command->u.start.position, position);
1363 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1364 IUnknown_Release(op);
1367 LeaveCriticalSection(&source->cs);
1369 return hr;
1372 static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
1374 struct media_source *source = impl_from_IMFMediaSource(iface);
1375 IUnknown *op;
1376 HRESULT hr;
1378 TRACE("%p.\n", iface);
1380 EnterCriticalSection(&source->cs);
1382 if (source->state == SOURCE_SHUTDOWN)
1383 hr = MF_E_SHUTDOWN;
1384 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &op)))
1386 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1387 IUnknown_Release(op);
1390 LeaveCriticalSection(&source->cs);
1392 return hr;
1395 static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
1397 struct media_source *source = impl_from_IMFMediaSource(iface);
1398 IUnknown *op;
1399 HRESULT hr;
1401 TRACE("%p.\n", iface);
1403 EnterCriticalSection(&source->cs);
1405 if (source->state == SOURCE_SHUTDOWN)
1406 hr = MF_E_SHUTDOWN;
1407 else if (source->state != SOURCE_RUNNING)
1408 hr = MF_E_INVALID_STATE_TRANSITION;
1409 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &op)))
1411 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1412 IUnknown_Release(op);
1415 LeaveCriticalSection(&source->cs);
1417 return S_OK;
1420 static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
1422 struct media_source *source = impl_from_IMFMediaSource(iface);
1424 TRACE("%p.\n", iface);
1426 EnterCriticalSection(&source->cs);
1428 if (source->state == SOURCE_SHUTDOWN)
1430 LeaveCriticalSection(&source->cs);
1431 return MF_E_SHUTDOWN;
1434 source->state = SOURCE_SHUTDOWN;
1436 wg_parser_disconnect(source->wg_parser);
1438 source->read_thread_shutdown = true;
1439 WaitForSingleObject(source->read_thread, INFINITE);
1440 CloseHandle(source->read_thread);
1442 IMFMediaEventQueue_Shutdown(source->event_queue);
1443 IMFByteStream_Close(source->byte_stream);
1445 while (source->stream_count--)
1447 struct media_stream *stream = source->streams[source->stream_count];
1448 IMFStreamDescriptor_Release(source->descriptors[source->stream_count]);
1449 IMFMediaEventQueue_Shutdown(stream->event_queue);
1450 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1452 free(source->descriptors);
1453 free(source->streams);
1455 MFUnlockWorkQueue(source->async_commands_queue);
1457 LeaveCriticalSection(&source->cs);
1459 return S_OK;
1462 static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
1464 media_source_QueryInterface,
1465 media_source_AddRef,
1466 media_source_Release,
1467 media_source_GetEvent,
1468 media_source_BeginGetEvent,
1469 media_source_EndGetEvent,
1470 media_source_QueueEvent,
1471 media_source_GetCharacteristics,
1472 media_source_CreatePresentationDescriptor,
1473 media_source_Start,
1474 media_source_Stop,
1475 media_source_Pause,
1476 media_source_Shutdown,
1479 static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
1481 unsigned int stream_count = UINT_MAX;
1482 struct media_source *object;
1483 struct wg_parser *parser;
1484 DWORD bytestream_caps;
1485 uint64_t file_size;
1486 unsigned int i;
1487 HRESULT hr;
1489 if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps)))
1490 return hr;
1492 if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE))
1494 FIXME("Non-seekable bytestreams not supported.\n");
1495 return MF_E_BYTESTREAM_NOT_SEEKABLE;
1498 if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size)))
1500 FIXME("Failed to get byte stream length, hr %#lx.\n", hr);
1501 return hr;
1504 if (!(object = calloc(1, sizeof(*object))))
1505 return E_OUTOFMEMORY;
1507 object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
1508 object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl;
1509 object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl;
1510 object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl;
1511 object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
1512 object->ref = 1;
1513 object->byte_stream = bytestream;
1514 IMFByteStream_AddRef(bytestream);
1515 object->rate = 1.0f;
1516 InitializeCriticalSection(&object->cs);
1517 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
1519 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1520 goto fail;
1522 if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
1523 goto fail;
1525 /* In Media Foundation, sources may read from any media source stream
1526 * without fear of blocking due to buffering limits on another. Trailmakers,
1527 * a Unity3D Engine game, only reads one sample from the audio stream (and
1528 * never deselects it). Remove buffering limits from decodebin in order to
1529 * account for this. Note that this does leak memory, but the same memory
1530 * leak occurs with native. */
1531 if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, true)))
1533 hr = E_OUTOFMEMORY;
1534 goto fail;
1536 object->wg_parser = parser;
1538 object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL);
1540 object->state = SOURCE_OPENING;
1542 if (FAILED(hr = wg_parser_connect(parser, file_size)))
1543 goto fail;
1545 stream_count = wg_parser_get_stream_count(parser);
1547 if (!(object->descriptors = calloc(stream_count, sizeof(*object->descriptors)))
1548 || !(object->streams = calloc(stream_count, sizeof(*object->streams))))
1550 free(object->descriptors);
1551 hr = E_OUTOFMEMORY;
1552 goto fail;
1555 for (i = 0; i < stream_count; ++i)
1557 struct media_stream *stream;
1559 if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, i, &stream)))
1560 goto fail;
1561 if (FAILED(hr = media_stream_init_desc(stream)))
1563 ERR("Failed to finish initialization of media stream %p, hr %#lx.\n", stream, hr);
1564 IMFMediaSource_Release(stream->media_source);
1565 IMFMediaEventQueue_Release(stream->event_queue);
1566 free(stream);
1567 goto fail;
1570 object->duration = max(object->duration, wg_parser_stream_get_duration(stream->wg_stream));
1571 IMFStreamDescriptor_AddRef(stream->descriptor);
1572 object->descriptors[i] = stream->descriptor;
1573 object->streams[i] = stream;
1574 object->stream_count++;
1577 /* init presentation descriptor */
1579 for (i = 0; i < object->stream_count; i++)
1581 static const struct
1583 enum wg_parser_tag tag;
1584 const GUID *mf_attr;
1586 tags[] =
1588 {WG_PARSER_TAG_LANGUAGE, &MF_SD_LANGUAGE},
1589 {WG_PARSER_TAG_NAME, &MF_SD_STREAM_NAME},
1591 unsigned int j;
1592 WCHAR *strW;
1593 DWORD len;
1594 char *str;
1596 for (j = 0; j < ARRAY_SIZE(tags); ++j)
1598 if (!(str = wg_parser_stream_get_tag(object->streams[i]->wg_stream, tags[j].tag)))
1599 continue;
1600 if (!(len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
1602 free(str);
1603 continue;
1605 strW = malloc(len * sizeof(*strW));
1606 if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len))
1607 IMFStreamDescriptor_SetString(object->descriptors[i], tags[j].mf_attr, strW);
1608 free(strW);
1609 free(str);
1613 object->state = SOURCE_STOPPED;
1615 *out_media_source = object;
1616 return S_OK;
1618 fail:
1619 WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr);
1621 while (object->streams && object->stream_count--)
1623 struct media_stream *stream = object->streams[object->stream_count];
1624 IMFStreamDescriptor_Release(object->descriptors[object->stream_count]);
1625 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1627 free(object->descriptors);
1628 free(object->streams);
1630 if (stream_count != UINT_MAX)
1631 wg_parser_disconnect(object->wg_parser);
1632 if (object->read_thread)
1634 object->read_thread_shutdown = true;
1635 WaitForSingleObject(object->read_thread, INFINITE);
1636 CloseHandle(object->read_thread);
1638 if (object->wg_parser)
1639 wg_parser_destroy(object->wg_parser);
1640 if (object->async_commands_queue)
1641 MFUnlockWorkQueue(object->async_commands_queue);
1642 if (object->event_queue)
1643 IMFMediaEventQueue_Release(object->event_queue);
1644 IMFByteStream_Release(object->byte_stream);
1645 free(object);
1646 return hr;
1649 struct winegstreamer_stream_handler_result
1651 struct list entry;
1652 IMFAsyncResult *result;
1653 MF_OBJECT_TYPE obj_type;
1654 IUnknown *object;
1657 struct winegstreamer_stream_handler
1659 IMFByteStreamHandler IMFByteStreamHandler_iface;
1660 IMFAsyncCallback IMFAsyncCallback_iface;
1661 LONG refcount;
1662 struct list results;
1663 CRITICAL_SECTION cs;
1666 static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
1668 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFByteStreamHandler_iface);
1671 static struct winegstreamer_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
1673 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFAsyncCallback_iface);
1676 static HRESULT WINAPI winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj)
1678 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1680 if (IsEqualIID(riid, &IID_IMFByteStreamHandler) ||
1681 IsEqualIID(riid, &IID_IUnknown))
1683 *obj = iface;
1684 IMFByteStreamHandler_AddRef(iface);
1685 return S_OK;
1688 WARN("Unsupported %s.\n", debugstr_guid(riid));
1689 *obj = NULL;
1690 return E_NOINTERFACE;
1693 static ULONG WINAPI winegstreamer_stream_handler_AddRef(IMFByteStreamHandler *iface)
1695 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1696 ULONG refcount = InterlockedIncrement(&handler->refcount);
1698 TRACE("%p, refcount %lu.\n", handler, refcount);
1700 return refcount;
1703 static ULONG WINAPI winegstreamer_stream_handler_Release(IMFByteStreamHandler *iface)
1705 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1706 ULONG refcount = InterlockedDecrement(&handler->refcount);
1707 struct winegstreamer_stream_handler_result *result, *next;
1709 TRACE("%p, refcount %lu.\n", iface, refcount);
1711 if (!refcount)
1713 LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct winegstreamer_stream_handler_result, entry)
1715 list_remove(&result->entry);
1716 IMFAsyncResult_Release(result->result);
1717 if (result->object)
1718 IUnknown_Release(result->object);
1719 free(result);
1721 DeleteCriticalSection(&handler->cs);
1722 free(handler);
1725 return refcount;
1728 struct create_object_context
1730 IUnknown IUnknown_iface;
1731 LONG refcount;
1733 IPropertyStore *props;
1734 IMFByteStream *stream;
1735 WCHAR *url;
1736 DWORD flags;
1739 static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
1741 return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
1744 static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
1746 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1748 if (IsEqualIID(riid, &IID_IUnknown))
1750 *obj = iface;
1751 IUnknown_AddRef(iface);
1752 return S_OK;
1755 WARN("Unsupported %s.\n", debugstr_guid(riid));
1756 *obj = NULL;
1757 return E_NOINTERFACE;
1760 static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
1762 struct create_object_context *context = impl_from_IUnknown(iface);
1763 ULONG refcount = InterlockedIncrement(&context->refcount);
1765 TRACE("%p, refcount %lu.\n", iface, refcount);
1767 return refcount;
1770 static ULONG WINAPI create_object_context_Release(IUnknown *iface)
1772 struct create_object_context *context = impl_from_IUnknown(iface);
1773 ULONG refcount = InterlockedDecrement(&context->refcount);
1775 TRACE("%p, refcount %lu.\n", iface, refcount);
1777 if (!refcount)
1779 if (context->props)
1780 IPropertyStore_Release(context->props);
1781 if (context->stream)
1782 IMFByteStream_Release(context->stream);
1783 free(context->url);
1784 free(context);
1787 return refcount;
1790 static const IUnknownVtbl create_object_context_vtbl =
1792 create_object_context_QueryInterface,
1793 create_object_context_AddRef,
1794 create_object_context_Release,
1797 static HRESULT WINAPI winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
1798 IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
1800 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1801 struct create_object_context *context;
1802 IMFAsyncResult *caller, *item;
1803 HRESULT hr;
1805 TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
1807 if (cancel_cookie)
1808 *cancel_cookie = NULL;
1810 if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
1811 return hr;
1813 if (!(context = calloc(1, sizeof(*context))))
1815 IMFAsyncResult_Release(caller);
1816 return E_OUTOFMEMORY;
1819 context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
1820 context->refcount = 1;
1821 context->props = props;
1822 if (context->props)
1823 IPropertyStore_AddRef(context->props);
1824 context->flags = flags;
1825 context->stream = stream;
1826 if (context->stream)
1827 IMFByteStream_AddRef(context->stream);
1828 if (url)
1829 context->url = wcsdup(url);
1830 if (!context->stream)
1832 IMFAsyncResult_Release(caller);
1833 IUnknown_Release(&context->IUnknown_iface);
1834 return E_OUTOFMEMORY;
1837 hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
1838 IUnknown_Release(&context->IUnknown_iface);
1839 if (SUCCEEDED(hr))
1841 if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
1843 if (cancel_cookie)
1845 *cancel_cookie = (IUnknown *)caller;
1846 IUnknown_AddRef(*cancel_cookie);
1850 IMFAsyncResult_Release(item);
1852 IMFAsyncResult_Release(caller);
1854 return hr;
1857 static HRESULT WINAPI winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
1858 MF_OBJECT_TYPE *obj_type, IUnknown **object)
1860 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1861 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1862 HRESULT hr;
1864 TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
1866 EnterCriticalSection(&this->cs);
1868 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1870 if (result == cur->result)
1872 list_remove(&cur->entry);
1873 found = cur;
1874 break;
1878 LeaveCriticalSection(&this->cs);
1880 if (found)
1882 *obj_type = found->obj_type;
1883 *object = found->object;
1884 hr = IMFAsyncResult_GetStatus(found->result);
1885 IMFAsyncResult_Release(found->result);
1886 free(found);
1888 else
1890 *obj_type = MF_OBJECT_INVALID;
1891 *object = NULL;
1892 hr = MF_E_UNEXPECTED;
1895 return hr;
1898 static HRESULT WINAPI winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie)
1900 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1901 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1903 TRACE("%p, %p.\n", iface, cancel_cookie);
1905 EnterCriticalSection(&this->cs);
1907 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1909 if (cancel_cookie == (IUnknown *)cur->result)
1911 list_remove(&cur->entry);
1912 found = cur;
1913 break;
1917 LeaveCriticalSection(&this->cs);
1919 if (found)
1921 IMFAsyncResult_Release(found->result);
1922 if (found->object)
1923 IUnknown_Release(found->object);
1924 free(found);
1927 return found ? S_OK : MF_E_UNEXPECTED;
1930 static HRESULT WINAPI winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes)
1932 FIXME("stub (%p %p)\n", iface, bytes);
1933 return E_NOTIMPL;
1936 static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl =
1938 winegstreamer_stream_handler_QueryInterface,
1939 winegstreamer_stream_handler_AddRef,
1940 winegstreamer_stream_handler_Release,
1941 winegstreamer_stream_handler_BeginCreateObject,
1942 winegstreamer_stream_handler_EndCreateObject,
1943 winegstreamer_stream_handler_CancelObjectCreation,
1944 winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
1947 static HRESULT WINAPI winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
1949 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1950 IsEqualIID(riid, &IID_IUnknown))
1952 *obj = iface;
1953 IMFAsyncCallback_AddRef(iface);
1954 return S_OK;
1957 WARN("Unsupported %s.\n", debugstr_guid(riid));
1958 *obj = NULL;
1959 return E_NOINTERFACE;
1962 static ULONG WINAPI winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback *iface)
1964 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1965 return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
1968 static ULONG WINAPI winegstreamer_stream_handler_callback_Release(IMFAsyncCallback *iface)
1970 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1971 return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
1974 static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
1976 return E_NOTIMPL;
1979 static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags,
1980 IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type)
1982 TRACE("%p, %s, %p, %#lx, %p, %p, %p.\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type);
1984 if (flags & MF_RESOLUTION_MEDIASOURCE)
1986 HRESULT hr;
1987 struct media_source *new_source;
1989 if (FAILED(hr = media_source_constructor(stream, &new_source)))
1990 return hr;
1992 TRACE("->(%p)\n", new_source);
1994 *out_object = (IUnknown*)&new_source->IMFMediaSource_iface;
1995 *out_obj_type = MF_OBJECT_MEDIASOURCE;
1997 return S_OK;
1999 else
2001 FIXME("Unhandled flags %#lx.\n", flags);
2002 return E_NOTIMPL;
2006 static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2008 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
2009 struct winegstreamer_stream_handler_result *handler_result;
2010 MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID;
2011 IUnknown *object = NULL, *context_object;
2012 struct create_object_context *context;
2013 IMFAsyncResult *caller;
2014 HRESULT hr;
2016 caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
2018 if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
2020 WARN("Expected context set for callee result.\n");
2021 return hr;
2024 context = impl_from_IUnknown(context_object);
2026 hr = winegstreamer_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type);
2028 if ((handler_result = malloc(sizeof(*handler_result))))
2030 handler_result->result = caller;
2031 IMFAsyncResult_AddRef(handler_result->result);
2032 handler_result->obj_type = obj_type;
2033 handler_result->object = object;
2035 EnterCriticalSection(&handler->cs);
2036 list_add_tail(&handler->results, &handler_result->entry);
2037 LeaveCriticalSection(&handler->cs);
2039 else
2041 if (object)
2042 IUnknown_Release(object);
2043 hr = E_OUTOFMEMORY;
2046 IUnknown_Release(&context->IUnknown_iface);
2048 IMFAsyncResult_SetStatus(caller, hr);
2049 MFInvokeCallback(caller);
2051 return S_OK;
2054 static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl =
2056 winegstreamer_stream_handler_callback_QueryInterface,
2057 winegstreamer_stream_handler_callback_AddRef,
2058 winegstreamer_stream_handler_callback_Release,
2059 winegstreamer_stream_handler_callback_GetParameters,
2060 winegstreamer_stream_handler_callback_Invoke,
2063 HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj)
2065 struct winegstreamer_stream_handler *this;
2066 HRESULT hr;
2068 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
2070 if (!(this = calloc(1, sizeof(*this))))
2071 return E_OUTOFMEMORY;
2073 list_init(&this->results);
2074 InitializeCriticalSection(&this->cs);
2076 this->IMFByteStreamHandler_iface.lpVtbl = &winegstreamer_stream_handler_vtbl;
2077 this->IMFAsyncCallback_iface.lpVtbl = &winegstreamer_stream_handler_callback_vtbl;
2078 this->refcount = 1;
2080 hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj);
2081 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
2083 return hr;