winegstreamer: Simplify media source creation flags handling.
[wine.git] / dlls / winegstreamer / media_source.c
blob0fb41c0e8db206486f10bfb08e5f2d04155a516e
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)
178 IMFPresentationDescriptor_Release(command->u.start.descriptor);
179 PropVariantClear(&command->u.start.position);
181 else if (command->op == SOURCE_ASYNC_REQUEST_SAMPLE)
183 if (command->u.request_sample.token)
184 IUnknown_Release(command->u.request_sample.token);
186 free(command);
189 return refcount;
192 static const IUnknownVtbl source_async_command_vtbl =
194 source_async_command_QueryInterface,
195 source_async_command_AddRef,
196 source_async_command_Release,
199 static HRESULT source_create_async_op(enum source_async_op op, IUnknown **out)
201 struct source_async_command *command;
203 if (!(command = calloc(1, sizeof(*command))))
204 return E_OUTOFMEMORY;
206 command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
207 command->refcount = 1;
208 command->op = op;
210 *out = &command->IUnknown_iface;
211 return S_OK;
214 static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
216 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
218 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
219 IsEqualIID(riid, &IID_IUnknown))
221 *obj = iface;
222 IMFAsyncCallback_AddRef(iface);
223 return S_OK;
226 WARN("Unsupported %s.\n", debugstr_guid(riid));
227 *obj = NULL;
228 return E_NOINTERFACE;
231 static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
232 DWORD *flags, DWORD *queue)
234 return E_NOTIMPL;
237 static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
239 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
240 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
243 static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
245 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
246 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
249 static HRESULT stream_descriptor_get_media_type(IMFStreamDescriptor *descriptor, IMFMediaType **media_type)
251 IMFMediaTypeHandler *handler;
252 HRESULT hr;
254 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler)))
255 return hr;
256 hr = IMFMediaTypeHandler_GetCurrentMediaType(handler, media_type);
257 IMFMediaTypeHandler_Release(handler);
259 return hr;
262 static HRESULT wg_format_from_stream_descriptor(IMFStreamDescriptor *descriptor, struct wg_format *format)
264 IMFMediaType *media_type;
265 HRESULT hr;
267 if (FAILED(hr = stream_descriptor_get_media_type(descriptor, &media_type)))
268 return hr;
269 mf_media_type_to_wg_format(media_type, format);
270 IMFMediaType_Release(media_type);
272 return hr;
275 static HRESULT stream_descriptor_set_tag(IMFStreamDescriptor *descriptor, struct wg_parser_stream *stream,
276 const GUID *attr, enum wg_parser_tag tag)
278 WCHAR *strW;
279 HRESULT hr;
280 DWORD len;
281 char *str;
283 if (!(str = wg_parser_stream_get_tag(stream, tag))
284 || !(len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)))
285 hr = S_OK;
286 else if (!(strW = malloc(len * sizeof(*strW))))
287 hr = E_OUTOFMEMORY;
288 else
290 if (MultiByteToWideChar(CP_UTF8, 0, str, -1, strW, len))
291 hr = IMFStreamDescriptor_SetString(descriptor, attr, strW);
292 else
293 hr = E_FAIL;
294 free(strW);
297 free(str);
298 return hr;
301 static HRESULT init_video_media_types(struct wg_format *format, IMFMediaType *types[6], DWORD *types_count)
303 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
304 * YUV color space, and it's generally much less expensive for
305 * videoconvert to do YUV -> YUV transformations. */
306 static const enum wg_video_format video_formats[] =
308 WG_VIDEO_FORMAT_NV12,
309 WG_VIDEO_FORMAT_YV12,
310 WG_VIDEO_FORMAT_YUY2,
311 WG_VIDEO_FORMAT_I420,
313 UINT count = *types_count, i;
314 GUID base_subtype;
315 HRESULT hr;
317 if (FAILED(hr = IMFMediaType_GetGUID(types[0], &MF_MT_SUBTYPE, &base_subtype)))
318 return hr;
320 for (i = 0; i < ARRAY_SIZE(video_formats); ++i)
322 struct wg_format new_format = *format;
323 IMFMediaType *new_type;
325 new_format.u.video.format = video_formats[i];
327 if (!(new_type = mf_media_type_from_wg_format(&new_format)))
329 hr = E_OUTOFMEMORY;
330 goto done;
332 types[count++] = new_type;
334 if (video_formats[i] == WG_VIDEO_FORMAT_I420)
336 IMFMediaType *iyuv_type;
338 if (FAILED(hr = MFCreateMediaType(&iyuv_type)))
339 goto done;
340 if (FAILED(hr = IMFMediaType_CopyAllItems(new_type, (IMFAttributes *)iyuv_type)))
341 goto done;
342 if (FAILED(hr = IMFMediaType_SetGUID(iyuv_type, &MF_MT_SUBTYPE, &MFVideoFormat_IYUV)))
343 goto done;
344 types[count++] = iyuv_type;
348 done:
349 *types_count = count;
350 return hr;
353 static HRESULT init_audio_media_types(struct wg_format *format, IMFMediaType *types[6], DWORD *types_count)
355 /* Expose at least one PCM and one floating point type for the
356 consumer to pick from. */
357 static const enum wg_audio_format audio_types[] =
359 WG_AUDIO_FORMAT_S16LE,
360 WG_AUDIO_FORMAT_F32LE,
362 UINT count = *types_count, i;
364 for (i = 0; i < ARRAY_SIZE(audio_types); i++)
366 struct wg_format new_format = *format;
367 if (new_format.u.audio.format == audio_types[i])
368 continue;
369 new_format.u.audio.format = audio_types[i];
370 if ((types[count] = mf_media_type_from_wg_format(&new_format)))
371 count++;
374 *types_count = count;
375 return S_OK;
378 static HRESULT stream_descriptor_create(UINT32 id, struct wg_format *format, IMFStreamDescriptor **out)
380 IMFStreamDescriptor *descriptor;
381 IMFMediaTypeHandler *handler;
382 IMFMediaType *types[6];
383 DWORD count = 0;
384 HRESULT hr;
386 if (!(types[0] = mf_media_type_from_wg_format(format)))
387 return MF_E_INVALIDMEDIATYPE;
388 count = 1;
390 if (format->major_type == WG_MAJOR_TYPE_VIDEO)
392 if (FAILED(hr = init_video_media_types(format, types, &count)))
393 goto done;
395 else if (format->major_type == WG_MAJOR_TYPE_AUDIO)
397 if (FAILED(hr = init_audio_media_types(format, types, &count)))
398 goto done;
401 assert(count <= ARRAY_SIZE(types));
403 if (FAILED(hr = MFCreateStreamDescriptor(id, count, types, &descriptor)))
404 goto done;
406 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(descriptor, &handler)))
407 IMFStreamDescriptor_Release(descriptor);
408 else
410 hr = IMFMediaTypeHandler_SetCurrentMediaType(handler, types[0]);
411 IMFMediaTypeHandler_Release(handler);
414 done:
415 while (count--)
416 IMFMediaType_Release(types[count]);
417 *out = SUCCEEDED(hr) ? descriptor : NULL;
418 return hr;
421 static BOOL enqueue_token(struct media_stream *stream, IUnknown *token)
423 if (stream->token_queue_count == stream->token_queue_cap)
425 IUnknown **buf;
426 stream->token_queue_cap = stream->token_queue_cap * 2 + 1;
427 buf = realloc(stream->token_queue, stream->token_queue_cap * sizeof(*buf));
428 if (buf)
429 stream->token_queue = buf;
430 else
432 stream->token_queue_cap = stream->token_queue_count;
433 return FALSE;
436 stream->token_queue[stream->token_queue_count++] = token;
437 return TRUE;
440 static void flush_token_queue(struct media_stream *stream, BOOL send)
442 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
443 LONG i;
445 for (i = 0; i < stream->token_queue_count; i++)
447 if (send)
449 IUnknown *op;
450 HRESULT hr;
452 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op)))
454 struct source_async_command *command = impl_from_async_command_IUnknown(op);
455 command->u.request_sample.stream = stream;
456 command->u.request_sample.token = stream->token_queue[i];
458 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
459 IUnknown_Release(op);
461 if (FAILED(hr))
462 WARN("Could not enqueue sample request, hr %#lx\n", hr);
464 else if (stream->token_queue[i])
465 IUnknown_Release(stream->token_queue[i]);
467 free(stream->token_queue);
468 stream->token_queue = NULL;
469 stream->token_queue_count = 0;
470 stream->token_queue_cap = 0;
473 static HRESULT media_stream_start(struct media_stream *stream, BOOL active, BOOL seeking, const PROPVARIANT *position)
475 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
476 struct wg_format format;
477 HRESULT hr;
479 TRACE("source %p, stream %p\n", source, stream);
481 if (FAILED(hr = wg_format_from_stream_descriptor(stream->descriptor, &format)))
482 WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr);
483 wg_parser_stream_enable(stream->wg_stream, &format);
485 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamUnk(source->event_queue, active ? MEUpdatedStream : MENewStream,
486 &GUID_NULL, S_OK, (IUnknown *)&stream->IMFMediaStream_iface)))
487 WARN("Failed to send source stream event, hr %#lx\n", hr);
488 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, seeking ? MEStreamSeeked : MEStreamStarted,
489 &GUID_NULL, S_OK, position);
492 static HRESULT media_source_start(struct media_source *source, IMFPresentationDescriptor *descriptor,
493 GUID *format, PROPVARIANT *position)
495 BOOL starting = source->state == SOURCE_STOPPED, seek_message = !starting && position->vt != VT_EMPTY;
496 IMFStreamDescriptor **descriptors;
497 DWORD i, count;
498 HRESULT hr;
500 TRACE("source %p, descriptor %p, format %s, position %s\n", source, descriptor,
501 debugstr_guid(format), wine_dbgstr_variant((VARIANT *)position));
503 if (source->state == SOURCE_SHUTDOWN)
504 return MF_E_SHUTDOWN;
506 /* seek to beginning on stop->play */
507 if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY)
509 position->vt = VT_I8;
510 position->hVal.QuadPart = 0;
513 if (!(descriptors = calloc(source->stream_count, sizeof(*descriptors))))
514 return E_OUTOFMEMORY;
516 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor, &count)))
517 WARN("Failed to get presentation descriptor stream count, hr %#lx\n", hr);
519 for (i = 0; i < count; i++)
521 IMFStreamDescriptor *stream_descriptor;
522 BOOL selected;
523 DWORD id;
525 if (FAILED(hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor, i,
526 &selected, &stream_descriptor)))
527 WARN("Failed to get presentation stream descriptor, hr %#lx\n", hr);
528 else
530 if (FAILED(hr = IMFStreamDescriptor_GetStreamIdentifier(stream_descriptor, &id)))
531 WARN("Failed to get stream descriptor id, hr %#lx\n", hr);
532 else if (id >= source->stream_count)
533 WARN("Invalid stream descriptor id %lu, hr %#lx\n", id, hr);
534 else if (selected)
535 IMFStreamDescriptor_AddRef((descriptors[id] = stream_descriptor));
537 IMFStreamDescriptor_Release(stream_descriptor);
541 for (i = 0; i < source->stream_count; i++)
543 struct media_stream *stream = source->streams[i];
544 BOOL was_active = !starting && stream->active;
546 if (position->vt != VT_EMPTY)
547 stream->eos = FALSE;
549 if (!(stream->active = !!descriptors[i]))
550 wg_parser_stream_disable(stream->wg_stream);
551 else
553 if (FAILED(hr = media_stream_start(stream, was_active, seek_message, position)))
554 WARN("Failed to start media stream, hr %#lx\n", hr);
555 IMFStreamDescriptor_Release(descriptors[i]);
559 free(descriptors);
561 source->state = SOURCE_RUNNING;
563 if (position->vt == VT_I8)
564 wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0, position->hVal.QuadPart, 0,
565 AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
567 for (i = 0; i < source->stream_count; i++)
568 flush_token_queue(source->streams[i], position->vt == VT_EMPTY);
570 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
571 seek_message ? MESourceSeeked : MESourceStarted, &GUID_NULL, S_OK, position);
574 static HRESULT media_source_pause(struct media_source *source)
576 unsigned int i;
577 HRESULT hr;
579 TRACE("source %p\n", source);
581 if (source->state == SOURCE_SHUTDOWN)
582 return MF_E_SHUTDOWN;
584 for (i = 0; i < source->stream_count; i++)
586 struct media_stream *stream = source->streams[i];
587 if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamPaused,
588 &GUID_NULL, S_OK, NULL)))
589 WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr);
592 source->state = SOURCE_PAUSED;
593 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourcePaused, &GUID_NULL, S_OK, NULL);
596 static HRESULT media_source_stop(struct media_source *source)
598 unsigned int i;
599 HRESULT hr;
601 TRACE("source %p\n", source);
603 if (source->state == SOURCE_SHUTDOWN)
604 return MF_E_SHUTDOWN;
606 for (i = 0; i < source->stream_count; i++)
608 struct media_stream *stream = source->streams[i];
609 if (stream->active && FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped,
610 &GUID_NULL, S_OK, NULL)))
611 WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr);
614 source->state = SOURCE_STOPPED;
616 for (i = 0; i < source->stream_count; i++)
617 flush_token_queue(source->streams[i], FALSE);
619 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL);
622 static HRESULT media_stream_send_sample(struct media_stream *stream, const struct wg_parser_buffer *wg_buffer, IUnknown *token)
624 IMFSample *sample = NULL;
625 IMFMediaBuffer *buffer;
626 HRESULT hr;
627 BYTE *data;
629 if (FAILED(hr = MFCreateMemoryBuffer(wg_buffer->size, &buffer)))
630 return hr;
631 if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, wg_buffer->size)))
632 goto out;
633 if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL)))
634 goto out;
636 if (!wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, wg_buffer->size))
638 wg_parser_stream_release_buffer(stream->wg_stream);
639 IMFMediaBuffer_Unlock(buffer);
640 goto out;
642 wg_parser_stream_release_buffer(stream->wg_stream);
644 if (FAILED(hr = IMFMediaBuffer_Unlock(buffer)))
645 goto out;
647 if (FAILED(hr = MFCreateSample(&sample)))
648 goto out;
649 if (FAILED(hr = IMFSample_AddBuffer(sample, buffer)))
650 goto out;
651 if (FAILED(hr = IMFSample_SetSampleTime(sample, wg_buffer->pts)))
652 goto out;
653 if (FAILED(hr = IMFSample_SetSampleDuration(sample, wg_buffer->duration)))
654 goto out;
655 if (token && FAILED(hr = IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token)))
656 goto out;
658 hr = IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
659 &GUID_NULL, S_OK, (IUnknown *)sample);
661 out:
662 if (sample)
663 IMFSample_Release(sample);
664 IMFMediaBuffer_Release(buffer);
665 return hr;
668 static HRESULT media_stream_send_eos(struct media_source *source, struct media_stream *stream)
670 PROPVARIANT empty = {.vt = VT_EMPTY};
671 HRESULT hr;
672 UINT i;
674 TRACE("source %p, stream %p\n", source, stream);
676 stream->eos = TRUE;
677 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty)))
678 WARN("Failed to queue MEEndOfStream event, hr %#lx\n", hr);
680 for (i = 0; i < source->stream_count; i++)
682 struct media_stream *stream = source->streams[i];
683 if (stream->active && !stream->eos)
684 return S_OK;
687 if (FAILED(hr = IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty)))
688 WARN("Failed to queue MEEndOfPresentation event, hr %#lx\n", hr);
689 return S_OK;
692 static HRESULT wait_on_sample(struct media_stream *stream, IUnknown *token)
694 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
695 struct wg_parser_buffer buffer;
697 TRACE("%p, %p\n", stream, token);
699 if (wg_parser_stream_get_buffer(source->wg_parser, stream->wg_stream, &buffer))
700 return media_stream_send_sample(stream, &buffer, token);
702 return media_stream_send_eos(source, stream);
705 static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
707 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
708 struct source_async_command *command;
709 IUnknown *state;
710 HRESULT hr;
712 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
713 return hr;
715 EnterCriticalSection(&source->cs);
717 command = impl_from_async_command_IUnknown(state);
718 switch (command->op)
720 case SOURCE_ASYNC_START:
722 IMFPresentationDescriptor *descriptor = command->u.start.descriptor;
723 GUID format = command->u.start.format;
724 PROPVARIANT position = command->u.start.position;
726 if (FAILED(hr = media_source_start(source, descriptor, &format, &position)))
727 WARN("Failed to start source %p, hr %#lx\n", source, hr);
728 break;
730 case SOURCE_ASYNC_PAUSE:
731 if (FAILED(hr = media_source_pause(source)))
732 WARN("Failed to pause source %p, hr %#lx\n", source, hr);
733 break;
734 case SOURCE_ASYNC_STOP:
735 if (FAILED(hr = media_source_stop(source)))
736 WARN("Failed to stop source %p, hr %#lx\n", source, hr);
737 break;
738 case SOURCE_ASYNC_REQUEST_SAMPLE:
739 if (source->state == SOURCE_PAUSED)
740 enqueue_token(command->u.request_sample.stream, command->u.request_sample.token);
741 else if (source->state == SOURCE_RUNNING)
743 if (FAILED(hr = wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token)))
744 WARN("Failed to request sample, hr %#lx\n", hr);
746 break;
749 LeaveCriticalSection(&source->cs);
751 IUnknown_Release(state);
753 return S_OK;
756 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
758 callback_QueryInterface,
759 source_async_commands_callback_AddRef,
760 source_async_commands_callback_Release,
761 callback_GetParameters,
762 source_async_commands_Invoke,
765 static DWORD CALLBACK read_thread(void *arg)
767 struct media_source *source = arg;
768 IMFByteStream *byte_stream = source->byte_stream;
769 size_t buffer_size = 4096;
770 QWORD file_size;
771 void *data;
773 if (!(data = malloc(buffer_size)))
774 return 0;
776 IMFByteStream_GetLength(byte_stream, &file_size);
778 TRACE("Starting read thread for media source %p.\n", source);
780 while (!source->read_thread_shutdown)
782 uint64_t offset;
783 ULONG ret_size;
784 uint32_t size;
785 HRESULT hr;
787 if (!wg_parser_get_next_read_offset(source->wg_parser, &offset, &size))
788 continue;
790 if (offset >= file_size)
791 size = 0;
792 else if (offset + size >= file_size)
793 size = file_size - offset;
795 /* Some IMFByteStreams (including the standard file-based stream) return
796 * an error when reading past the file size. */
797 if (!size)
799 wg_parser_push_data(source->wg_parser, data, 0);
800 continue;
803 if (!array_reserve(&data, &buffer_size, size, 1))
805 free(data);
806 return 0;
809 ret_size = 0;
811 if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset)))
812 hr = IMFByteStream_Read(byte_stream, data, size, &ret_size);
813 if (FAILED(hr))
814 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr);
815 else if (ret_size != size)
816 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size);
817 wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size);
820 free(data);
821 TRACE("Media source is shutting down; exiting.\n");
822 return 0;
825 static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
827 struct media_stream *stream = impl_from_IMFMediaStream(iface);
829 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
831 if (IsEqualIID(riid, &IID_IMFMediaStream) ||
832 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
833 IsEqualIID(riid, &IID_IUnknown))
835 *out = &stream->IMFMediaStream_iface;
837 else
839 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
840 *out = NULL;
841 return E_NOINTERFACE;
844 IUnknown_AddRef((IUnknown*)*out);
845 return S_OK;
848 static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
850 struct media_stream *stream = impl_from_IMFMediaStream(iface);
851 ULONG ref = InterlockedIncrement(&stream->ref);
853 TRACE("%p, refcount %lu.\n", iface, ref);
855 return ref;
858 static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
860 struct media_stream *stream = impl_from_IMFMediaStream(iface);
861 ULONG ref = InterlockedDecrement(&stream->ref);
863 TRACE("%p, refcount %lu.\n", iface, ref);
865 if (!ref)
867 IMFMediaSource_Release(stream->media_source);
868 IMFStreamDescriptor_Release(stream->descriptor);
869 IMFMediaEventQueue_Release(stream->event_queue);
870 flush_token_queue(stream, FALSE);
871 free(stream);
874 return ref;
877 static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
879 struct media_stream *stream = impl_from_IMFMediaStream(iface);
881 TRACE("%p, %#lx, %p.\n", iface, flags, event);
883 return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
886 static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
888 struct media_stream *stream = impl_from_IMFMediaStream(iface);
890 TRACE("%p, %p, %p.\n", iface, callback, state);
892 return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
895 static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
897 struct media_stream *stream = impl_from_IMFMediaStream(iface);
899 TRACE("%p, %p, %p.\n", stream, result, event);
901 return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
904 static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
905 HRESULT hr, const PROPVARIANT *value)
907 struct media_stream *stream = impl_from_IMFMediaStream(iface);
909 TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
911 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
914 static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **out)
916 struct media_stream *stream = impl_from_IMFMediaStream(iface);
917 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
918 HRESULT hr = S_OK;
920 TRACE("%p, %p.\n", iface, out);
922 EnterCriticalSection(&source->cs);
924 if (source->state == SOURCE_SHUTDOWN)
925 hr = MF_E_SHUTDOWN;
926 else
928 IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
929 *out = &source->IMFMediaSource_iface;
932 LeaveCriticalSection(&source->cs);
934 return hr;
937 static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
939 struct media_stream *stream = impl_from_IMFMediaStream(iface);
940 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
941 HRESULT hr = S_OK;
943 TRACE("%p, %p.\n", iface, descriptor);
945 EnterCriticalSection(&source->cs);
947 if (source->state == SOURCE_SHUTDOWN)
948 hr = MF_E_SHUTDOWN;
949 else
951 IMFStreamDescriptor_AddRef(stream->descriptor);
952 *descriptor = stream->descriptor;
955 LeaveCriticalSection(&source->cs);
957 return hr;
960 static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
962 struct media_stream *stream = impl_from_IMFMediaStream(iface);
963 struct media_source *source = impl_from_IMFMediaSource(stream->media_source);
964 IUnknown *op;
965 HRESULT hr;
967 TRACE("%p, %p.\n", iface, token);
969 EnterCriticalSection(&source->cs);
971 if (source->state == SOURCE_SHUTDOWN)
972 hr = MF_E_SHUTDOWN;
973 else if (!stream->active)
974 hr = MF_E_MEDIA_SOURCE_WRONGSTATE;
975 else if (stream->eos)
976 hr = MF_E_END_OF_STREAM;
977 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &op)))
979 struct source_async_command *command = impl_from_async_command_IUnknown(op);
980 command->u.request_sample.stream = stream;
981 if (token)
982 IUnknown_AddRef(token);
983 command->u.request_sample.token = token;
985 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
986 IUnknown_Release(op);
989 LeaveCriticalSection(&source->cs);
991 return hr;
994 static const IMFMediaStreamVtbl media_stream_vtbl =
996 media_stream_QueryInterface,
997 media_stream_AddRef,
998 media_stream_Release,
999 media_stream_GetEvent,
1000 media_stream_BeginGetEvent,
1001 media_stream_EndGetEvent,
1002 media_stream_QueueEvent,
1003 media_stream_GetMediaSource,
1004 media_stream_GetStreamDescriptor,
1005 media_stream_RequestSample
1008 static HRESULT media_stream_create(IMFMediaSource *source, IMFStreamDescriptor *descriptor,
1009 struct wg_parser_stream *wg_stream, struct media_stream **out)
1011 struct media_stream *object;
1012 HRESULT hr;
1014 TRACE("source %p, descriptor %p, wg_stream %p.\n", source, descriptor, wg_stream);
1016 if (!(object = calloc(1, sizeof(*object))))
1017 return E_OUTOFMEMORY;
1019 object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
1020 object->ref = 1;
1022 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1024 free(object);
1025 return hr;
1028 IMFMediaSource_AddRef(source);
1029 object->media_source = source;
1030 IMFStreamDescriptor_AddRef(descriptor);
1031 object->descriptor = descriptor;
1033 object->active = TRUE;
1034 object->eos = FALSE;
1035 object->wg_stream = wg_stream;
1037 TRACE("Created stream object %p.\n", object);
1039 *out = object;
1040 return S_OK;
1043 static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1045 struct media_source *source = impl_from_IMFGetService(iface);
1046 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1049 static ULONG WINAPI media_source_get_service_AddRef(IMFGetService *iface)
1051 struct media_source *source = impl_from_IMFGetService(iface);
1052 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1055 static ULONG WINAPI media_source_get_service_Release(IMFGetService *iface)
1057 struct media_source *source = impl_from_IMFGetService(iface);
1058 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1061 static HRESULT WINAPI media_source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1063 struct media_source *source = impl_from_IMFGetService(iface);
1065 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1067 *obj = NULL;
1069 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
1071 if (IsEqualIID(riid, &IID_IMFRateSupport))
1073 *obj = &source->IMFRateSupport_iface;
1075 else if (IsEqualIID(riid, &IID_IMFRateControl))
1077 *obj = &source->IMFRateControl_iface;
1080 else
1081 FIXME("Unsupported service %s.\n", debugstr_guid(service));
1083 if (*obj)
1084 IUnknown_AddRef((IUnknown *)*obj);
1086 return *obj ? S_OK : E_NOINTERFACE;
1089 static const IMFGetServiceVtbl media_source_get_service_vtbl =
1091 media_source_get_service_QueryInterface,
1092 media_source_get_service_AddRef,
1093 media_source_get_service_Release,
1094 media_source_get_service_GetService,
1097 static HRESULT WINAPI media_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
1099 struct media_source *source = impl_from_IMFRateSupport(iface);
1100 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1103 static ULONG WINAPI media_source_rate_support_AddRef(IMFRateSupport *iface)
1105 struct media_source *source = impl_from_IMFRateSupport(iface);
1106 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1109 static ULONG WINAPI media_source_rate_support_Release(IMFRateSupport *iface)
1111 struct media_source *source = impl_from_IMFRateSupport(iface);
1112 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1115 static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
1117 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1119 *rate = 0.0f;
1121 return S_OK;
1124 static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
1126 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
1128 *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f;
1130 return S_OK;
1133 static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
1134 float *nearest_rate)
1136 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_rate);
1138 if (nearest_rate)
1139 *nearest_rate = rate;
1141 return rate >= -1e6f && rate <= 1e6f ? S_OK : MF_E_UNSUPPORTED_RATE;
1144 static const IMFRateSupportVtbl media_source_rate_support_vtbl =
1146 media_source_rate_support_QueryInterface,
1147 media_source_rate_support_AddRef,
1148 media_source_rate_support_Release,
1149 media_source_rate_support_GetSlowestRate,
1150 media_source_rate_support_GetFastestRate,
1151 media_source_rate_support_IsRateSupported,
1154 static HRESULT WINAPI media_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
1156 struct media_source *source = impl_from_IMFRateControl(iface);
1157 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1160 static ULONG WINAPI media_source_rate_control_AddRef(IMFRateControl *iface)
1162 struct media_source *source = impl_from_IMFRateControl(iface);
1163 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1166 static ULONG WINAPI media_source_rate_control_Release(IMFRateControl *iface)
1168 struct media_source *source = impl_from_IMFRateControl(iface);
1169 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1172 static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
1174 struct media_source *source = impl_from_IMFRateControl(iface);
1175 HRESULT hr;
1177 FIXME("%p, %d, %f.\n", iface, thin, rate);
1179 if (rate < 0.0f)
1180 return MF_E_REVERSE_UNSUPPORTED;
1182 if (thin)
1183 return MF_E_THINNING_UNSUPPORTED;
1185 if (FAILED(hr = IMFRateSupport_IsRateSupported(&source->IMFRateSupport_iface, thin, rate, NULL)))
1186 return hr;
1188 EnterCriticalSection(&source->cs);
1189 source->rate = rate;
1190 LeaveCriticalSection(&source->cs);
1192 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceRateChanged, &GUID_NULL, S_OK, NULL);
1195 static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
1197 struct media_source *source = impl_from_IMFRateControl(iface);
1199 TRACE("%p, %p, %p.\n", iface, thin, rate);
1201 if (thin)
1202 *thin = FALSE;
1204 EnterCriticalSection(&source->cs);
1205 *rate = source->rate;
1206 LeaveCriticalSection(&source->cs);
1208 return S_OK;
1211 static const IMFRateControlVtbl media_source_rate_control_vtbl =
1213 media_source_rate_control_QueryInterface,
1214 media_source_rate_control_AddRef,
1215 media_source_rate_control_Release,
1216 media_source_rate_control_SetRate,
1217 media_source_rate_control_GetRate,
1220 static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
1222 struct media_source *source = impl_from_IMFMediaSource(iface);
1224 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1226 if (IsEqualIID(riid, &IID_IMFMediaSource) ||
1227 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1228 IsEqualIID(riid, &IID_IUnknown))
1230 *out = &source->IMFMediaSource_iface;
1232 else if (IsEqualIID(riid, &IID_IMFGetService))
1234 *out = &source->IMFGetService_iface;
1236 else
1238 FIXME("%s, %p.\n", debugstr_guid(riid), out);
1239 *out = NULL;
1240 return E_NOINTERFACE;
1243 IUnknown_AddRef((IUnknown*)*out);
1244 return S_OK;
1247 static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface)
1249 struct media_source *source = impl_from_IMFMediaSource(iface);
1250 ULONG ref = InterlockedIncrement(&source->ref);
1252 TRACE("%p, refcount %lu.\n", iface, ref);
1254 return ref;
1257 static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
1259 struct media_source *source = impl_from_IMFMediaSource(iface);
1260 ULONG ref = InterlockedDecrement(&source->ref);
1262 TRACE("%p, refcount %lu.\n", iface, ref);
1264 if (!ref)
1266 IMFMediaSource_Shutdown(iface);
1267 IMFMediaEventQueue_Release(source->event_queue);
1268 IMFByteStream_Release(source->byte_stream);
1269 wg_parser_destroy(source->wg_parser);
1270 source->cs.DebugInfo->Spare[0] = 0;
1271 DeleteCriticalSection(&source->cs);
1272 free(source);
1275 return ref;
1278 static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
1280 struct media_source *source = impl_from_IMFMediaSource(iface);
1282 TRACE("%p, %#lx, %p.\n", iface, flags, event);
1284 return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
1287 static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
1289 struct media_source *source = impl_from_IMFMediaSource(iface);
1291 TRACE("%p, %p, %p.\n", iface, callback, state);
1293 return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
1296 static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1298 struct media_source *source = impl_from_IMFMediaSource(iface);
1300 TRACE("%p, %p, %p.\n", iface, result, event);
1302 return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
1305 static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
1306 HRESULT hr, const PROPVARIANT *value)
1308 struct media_source *source = impl_from_IMFMediaSource(iface);
1310 TRACE("%p, %lu, %s, %#lx, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1312 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
1315 static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
1317 struct media_source *source = impl_from_IMFMediaSource(iface);
1318 HRESULT hr = S_OK;
1320 TRACE("%p, %p.\n", iface, characteristics);
1322 EnterCriticalSection(&source->cs);
1324 if (source->state == SOURCE_SHUTDOWN)
1325 hr = MF_E_SHUTDOWN;
1326 else
1327 *characteristics = MFMEDIASOURCE_CAN_SEEK | MFMEDIASOURCE_CAN_PAUSE;
1329 LeaveCriticalSection(&source->cs);
1331 return hr;
1334 static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
1336 struct media_source *source = impl_from_IMFMediaSource(iface);
1337 HRESULT hr;
1338 UINT i;
1340 TRACE("%p, %p.\n", iface, descriptor);
1342 EnterCriticalSection(&source->cs);
1344 if (source->state == SOURCE_SHUTDOWN)
1345 hr = MF_E_SHUTDOWN;
1346 else if (SUCCEEDED(hr = MFCreatePresentationDescriptor(source->stream_count, source->descriptors, descriptor)))
1348 if (FAILED(hr = IMFPresentationDescriptor_SetUINT64(*descriptor, &MF_PD_DURATION, source->duration)))
1349 WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr);
1351 for (i = 0; i < source->stream_count; ++i)
1353 if (FAILED(hr = IMFPresentationDescriptor_SelectStream(*descriptor, i)))
1354 WARN("Failed to select stream %u, hr %#lx\n", i, hr);
1357 hr = S_OK;
1360 LeaveCriticalSection(&source->cs);
1362 return hr;
1365 static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
1366 const GUID *time_format, const PROPVARIANT *position)
1368 struct media_source *source = impl_from_IMFMediaSource(iface);
1369 IUnknown *op;
1370 HRESULT hr;
1372 TRACE("%p, %p, %p, %p.\n", iface, descriptor, time_format, position);
1374 EnterCriticalSection(&source->cs);
1376 if (source->state == SOURCE_SHUTDOWN)
1377 hr = MF_E_SHUTDOWN;
1378 else if (!(IsEqualIID(time_format, &GUID_NULL)))
1379 hr = MF_E_UNSUPPORTED_TIME_FORMAT;
1380 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &op)))
1382 struct source_async_command *command = impl_from_async_command_IUnknown(op);
1383 command->u.start.descriptor = descriptor;
1384 IMFPresentationDescriptor_AddRef(descriptor);
1385 command->u.start.format = *time_format;
1386 PropVariantCopy(&command->u.start.position, position);
1388 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1389 IUnknown_Release(op);
1392 LeaveCriticalSection(&source->cs);
1394 return hr;
1397 static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
1399 struct media_source *source = impl_from_IMFMediaSource(iface);
1400 IUnknown *op;
1401 HRESULT hr;
1403 TRACE("%p.\n", iface);
1405 EnterCriticalSection(&source->cs);
1407 if (source->state == SOURCE_SHUTDOWN)
1408 hr = MF_E_SHUTDOWN;
1409 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &op)))
1411 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1412 IUnknown_Release(op);
1415 LeaveCriticalSection(&source->cs);
1417 return hr;
1420 static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
1422 struct media_source *source = impl_from_IMFMediaSource(iface);
1423 IUnknown *op;
1424 HRESULT hr;
1426 TRACE("%p.\n", iface);
1428 EnterCriticalSection(&source->cs);
1430 if (source->state == SOURCE_SHUTDOWN)
1431 hr = MF_E_SHUTDOWN;
1432 else if (source->state != SOURCE_RUNNING)
1433 hr = MF_E_INVALID_STATE_TRANSITION;
1434 else if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_PAUSE, &op)))
1436 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, op);
1437 IUnknown_Release(op);
1440 LeaveCriticalSection(&source->cs);
1442 return S_OK;
1445 static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
1447 struct media_source *source = impl_from_IMFMediaSource(iface);
1449 TRACE("%p.\n", iface);
1451 EnterCriticalSection(&source->cs);
1453 if (source->state == SOURCE_SHUTDOWN)
1455 LeaveCriticalSection(&source->cs);
1456 return MF_E_SHUTDOWN;
1459 source->state = SOURCE_SHUTDOWN;
1461 wg_parser_disconnect(source->wg_parser);
1463 source->read_thread_shutdown = true;
1464 WaitForSingleObject(source->read_thread, INFINITE);
1465 CloseHandle(source->read_thread);
1467 IMFMediaEventQueue_Shutdown(source->event_queue);
1468 IMFByteStream_Close(source->byte_stream);
1470 while (source->stream_count--)
1472 struct media_stream *stream = source->streams[source->stream_count];
1473 IMFStreamDescriptor_Release(source->descriptors[source->stream_count]);
1474 IMFMediaEventQueue_Shutdown(stream->event_queue);
1475 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1477 free(source->descriptors);
1478 free(source->streams);
1480 MFUnlockWorkQueue(source->async_commands_queue);
1482 LeaveCriticalSection(&source->cs);
1484 return S_OK;
1487 static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
1489 media_source_QueryInterface,
1490 media_source_AddRef,
1491 media_source_Release,
1492 media_source_GetEvent,
1493 media_source_BeginGetEvent,
1494 media_source_EndGetEvent,
1495 media_source_QueueEvent,
1496 media_source_GetCharacteristics,
1497 media_source_CreatePresentationDescriptor,
1498 media_source_Start,
1499 media_source_Stop,
1500 media_source_Pause,
1501 media_source_Shutdown,
1504 static void media_source_init_descriptors(struct media_source *source)
1506 HRESULT hr = S_OK;
1507 UINT i;
1509 for (i = 0; i < source->stream_count; i++)
1511 struct media_stream *stream = source->streams[i];
1512 IMFStreamDescriptor *descriptor = stream->descriptor;
1514 if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream,
1515 &MF_SD_LANGUAGE, WG_PARSER_TAG_LANGUAGE)))
1516 WARN("Failed to set stream descriptor language, hr %#lx\n", hr);
1517 if (FAILED(hr = stream_descriptor_set_tag(descriptor, stream->wg_stream,
1518 &MF_SD_STREAM_NAME, WG_PARSER_TAG_NAME)))
1519 WARN("Failed to set stream descriptor name, hr %#lx\n", hr);
1523 static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
1525 unsigned int stream_count = UINT_MAX;
1526 struct media_source *object;
1527 struct wg_parser *parser;
1528 DWORD bytestream_caps;
1529 QWORD file_size;
1530 unsigned int i;
1531 HRESULT hr;
1533 if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps)))
1534 return hr;
1536 if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE))
1538 FIXME("Non-seekable bytestreams not supported.\n");
1539 return MF_E_BYTESTREAM_NOT_SEEKABLE;
1542 if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size)))
1544 FIXME("Failed to get byte stream length, hr %#lx.\n", hr);
1545 return hr;
1548 if (!(object = calloc(1, sizeof(*object))))
1549 return E_OUTOFMEMORY;
1551 object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
1552 object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl;
1553 object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl;
1554 object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl;
1555 object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
1556 object->ref = 1;
1557 object->byte_stream = bytestream;
1558 IMFByteStream_AddRef(bytestream);
1559 object->rate = 1.0f;
1560 InitializeCriticalSection(&object->cs);
1561 object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": cs");
1563 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1564 goto fail;
1566 if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
1567 goto fail;
1569 /* In Media Foundation, sources may read from any media source stream
1570 * without fear of blocking due to buffering limits on another. Trailmakers,
1571 * a Unity3D Engine game, only reads one sample from the audio stream (and
1572 * never deselects it). Remove buffering limits from decodebin in order to
1573 * account for this. Note that this does leak memory, but the same memory
1574 * leak occurs with native. */
1575 if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, true)))
1577 hr = E_OUTOFMEMORY;
1578 goto fail;
1580 object->wg_parser = parser;
1582 object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL);
1584 object->state = SOURCE_OPENING;
1586 if (FAILED(hr = wg_parser_connect(parser, file_size)))
1587 goto fail;
1589 stream_count = wg_parser_get_stream_count(parser);
1591 if (!(object->descriptors = calloc(stream_count, sizeof(*object->descriptors)))
1592 || !(object->streams = calloc(stream_count, sizeof(*object->streams))))
1594 free(object->descriptors);
1595 hr = E_OUTOFMEMORY;
1596 goto fail;
1599 for (i = 0; i < stream_count; ++i)
1601 struct wg_parser_stream *wg_stream = wg_parser_get_stream(object->wg_parser, i);
1602 IMFStreamDescriptor *descriptor;
1603 struct media_stream *stream;
1604 struct wg_format format;
1606 wg_parser_stream_get_preferred_format(wg_stream, &format);
1607 if (FAILED(hr = stream_descriptor_create(i, &format, &descriptor)))
1608 goto fail;
1609 if (FAILED(hr = media_stream_create(&object->IMFMediaSource_iface, descriptor, wg_stream, &stream)))
1611 IMFStreamDescriptor_Release(descriptor);
1612 goto fail;
1615 object->duration = max(object->duration, wg_parser_stream_get_duration(wg_stream));
1616 IMFStreamDescriptor_AddRef(descriptor);
1617 object->descriptors[i] = descriptor;
1618 object->streams[i] = stream;
1619 object->stream_count++;
1622 media_source_init_descriptors(object);
1623 object->state = SOURCE_STOPPED;
1625 *out_media_source = object;
1626 return S_OK;
1628 fail:
1629 WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr);
1631 while (object->streams && object->stream_count--)
1633 struct media_stream *stream = object->streams[object->stream_count];
1634 IMFStreamDescriptor_Release(object->descriptors[object->stream_count]);
1635 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1637 free(object->descriptors);
1638 free(object->streams);
1640 if (stream_count != UINT_MAX)
1641 wg_parser_disconnect(object->wg_parser);
1642 if (object->read_thread)
1644 object->read_thread_shutdown = true;
1645 WaitForSingleObject(object->read_thread, INFINITE);
1646 CloseHandle(object->read_thread);
1648 if (object->wg_parser)
1649 wg_parser_destroy(object->wg_parser);
1650 if (object->async_commands_queue)
1651 MFUnlockWorkQueue(object->async_commands_queue);
1652 if (object->event_queue)
1653 IMFMediaEventQueue_Release(object->event_queue);
1654 IMFByteStream_Release(object->byte_stream);
1655 free(object);
1656 return hr;
1659 struct result_entry
1661 struct list entry;
1662 IMFAsyncResult *result;
1663 MF_OBJECT_TYPE type;
1664 IUnknown *object;
1667 static HRESULT result_entry_create(IMFAsyncResult *result, MF_OBJECT_TYPE type,
1668 IUnknown *object, struct result_entry **out)
1670 struct result_entry *entry;
1672 if (!(entry = malloc(sizeof(*entry))))
1673 return E_OUTOFMEMORY;
1675 entry->result = result;
1676 IMFAsyncResult_AddRef(entry->result);
1677 entry->object = object;
1678 IUnknown_AddRef(entry->object);
1679 entry->type = type;
1681 *out = entry;
1682 return S_OK;
1685 static void result_entry_destroy(struct result_entry *entry)
1687 IMFAsyncResult_Release(entry->result);
1688 IUnknown_Release(entry->object);
1689 free(entry);
1692 struct stream_handler
1694 IMFByteStreamHandler IMFByteStreamHandler_iface;
1695 IMFAsyncCallback IMFAsyncCallback_iface;
1696 LONG refcount;
1697 struct list results;
1698 CRITICAL_SECTION cs;
1701 static struct result_entry *handler_find_result_entry(struct stream_handler *handler, IMFAsyncResult *result)
1703 struct result_entry *entry;
1705 EnterCriticalSection(&handler->cs);
1706 LIST_FOR_EACH_ENTRY(entry, &handler->results, struct result_entry, entry)
1708 if (result == entry->result)
1710 list_remove(&entry->entry);
1711 LeaveCriticalSection(&handler->cs);
1712 return entry;
1715 LeaveCriticalSection(&handler->cs);
1717 return NULL;
1720 static struct stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
1722 return CONTAINING_RECORD(iface, struct stream_handler, IMFByteStreamHandler_iface);
1725 static struct stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
1727 return CONTAINING_RECORD(iface, struct stream_handler, IMFAsyncCallback_iface);
1730 static HRESULT WINAPI stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj)
1732 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1734 if (IsEqualIID(riid, &IID_IMFByteStreamHandler) ||
1735 IsEqualIID(riid, &IID_IUnknown))
1737 *obj = iface;
1738 IMFByteStreamHandler_AddRef(iface);
1739 return S_OK;
1742 WARN("Unsupported %s.\n", debugstr_guid(riid));
1743 *obj = NULL;
1744 return E_NOINTERFACE;
1747 static ULONG WINAPI stream_handler_AddRef(IMFByteStreamHandler *iface)
1749 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1750 ULONG refcount = InterlockedIncrement(&handler->refcount);
1752 TRACE("%p, refcount %lu.\n", handler, refcount);
1754 return refcount;
1757 static ULONG WINAPI stream_handler_Release(IMFByteStreamHandler *iface)
1759 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1760 ULONG refcount = InterlockedDecrement(&handler->refcount);
1761 struct result_entry *result, *next;
1763 TRACE("%p, refcount %lu.\n", iface, refcount);
1765 if (!refcount)
1767 LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct result_entry, entry)
1768 result_entry_destroy(result);
1769 DeleteCriticalSection(&handler->cs);
1770 free(handler);
1773 return refcount;
1776 struct create_object_context
1778 IUnknown IUnknown_iface;
1779 LONG refcount;
1781 IMFByteStream *stream;
1782 WCHAR *url;
1785 static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
1787 return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
1790 static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
1792 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1794 if (IsEqualIID(riid, &IID_IUnknown))
1796 *obj = iface;
1797 IUnknown_AddRef(iface);
1798 return S_OK;
1801 WARN("Unsupported %s.\n", debugstr_guid(riid));
1802 *obj = NULL;
1803 return E_NOINTERFACE;
1806 static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
1808 struct create_object_context *context = impl_from_IUnknown(iface);
1809 ULONG refcount = InterlockedIncrement(&context->refcount);
1811 TRACE("%p, refcount %lu.\n", iface, refcount);
1813 return refcount;
1816 static ULONG WINAPI create_object_context_Release(IUnknown *iface)
1818 struct create_object_context *context = impl_from_IUnknown(iface);
1819 ULONG refcount = InterlockedDecrement(&context->refcount);
1821 TRACE("%p, refcount %lu.\n", iface, refcount);
1823 if (!refcount)
1825 IMFByteStream_Release(context->stream);
1826 free(context->url);
1827 free(context);
1830 return refcount;
1833 static const IUnknownVtbl create_object_context_vtbl =
1835 create_object_context_QueryInterface,
1836 create_object_context_AddRef,
1837 create_object_context_Release,
1840 static HRESULT WINAPI stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
1841 IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
1843 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1844 struct create_object_context *context;
1845 IMFAsyncResult *caller, *item;
1846 HRESULT hr;
1848 TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
1850 if (cancel_cookie)
1851 *cancel_cookie = NULL;
1853 if (!stream)
1854 return E_INVALIDARG;
1855 if (flags != MF_RESOLUTION_MEDIASOURCE)
1856 FIXME("Unimplemented flags %#lx\n", flags);
1858 if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
1859 return hr;
1861 if (!(context = calloc(1, sizeof(*context))))
1863 IMFAsyncResult_Release(caller);
1864 return E_OUTOFMEMORY;
1867 context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
1868 context->refcount = 1;
1869 context->stream = stream;
1870 IMFByteStream_AddRef(context->stream);
1871 if (url)
1872 context->url = wcsdup(url);
1874 hr = MFCreateAsyncResult(&context->IUnknown_iface, &handler->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
1875 IUnknown_Release(&context->IUnknown_iface);
1876 if (SUCCEEDED(hr))
1878 if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
1880 if (cancel_cookie)
1882 *cancel_cookie = (IUnknown *)caller;
1883 IUnknown_AddRef(*cancel_cookie);
1887 IMFAsyncResult_Release(item);
1889 IMFAsyncResult_Release(caller);
1891 return hr;
1894 static HRESULT WINAPI stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
1895 MF_OBJECT_TYPE *type, IUnknown **object)
1897 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1898 struct result_entry *entry;
1899 HRESULT hr;
1901 TRACE("%p, %p, %p, %p.\n", iface, result, type, object);
1903 if (!(entry = handler_find_result_entry(handler, result)))
1905 *type = MF_OBJECT_INVALID;
1906 *object = NULL;
1907 return MF_E_UNEXPECTED;
1910 hr = IMFAsyncResult_GetStatus(entry->result);
1911 *type = entry->type;
1912 *object = entry->object;
1913 IUnknown_AddRef(*object);
1914 result_entry_destroy(entry);
1915 return hr;
1918 static HRESULT WINAPI stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cookie)
1920 struct stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1921 IMFAsyncResult *result = (IMFAsyncResult *)cookie;
1922 struct result_entry *entry;
1924 TRACE("%p, %p.\n", iface, cookie);
1926 if (!(entry = handler_find_result_entry(handler, result)))
1927 return MF_E_UNEXPECTED;
1929 result_entry_destroy(entry);
1930 return S_OK;
1933 static HRESULT WINAPI stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes)
1935 FIXME("stub (%p %p)\n", iface, bytes);
1936 return E_NOTIMPL;
1939 static const IMFByteStreamHandlerVtbl stream_handler_vtbl =
1941 stream_handler_QueryInterface,
1942 stream_handler_AddRef,
1943 stream_handler_Release,
1944 stream_handler_BeginCreateObject,
1945 stream_handler_EndCreateObject,
1946 stream_handler_CancelObjectCreation,
1947 stream_handler_GetMaxNumberOfBytesRequiredForResolution,
1950 static HRESULT WINAPI stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
1952 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1953 IsEqualIID(riid, &IID_IUnknown))
1955 *obj = iface;
1956 IMFAsyncCallback_AddRef(iface);
1957 return S_OK;
1960 WARN("Unsupported %s.\n", debugstr_guid(riid));
1961 *obj = NULL;
1962 return E_NOINTERFACE;
1965 static ULONG WINAPI stream_handler_callback_AddRef(IMFAsyncCallback *iface)
1967 struct stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1968 return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
1971 static ULONG WINAPI stream_handler_callback_Release(IMFAsyncCallback *iface)
1973 struct stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1974 return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
1977 static HRESULT WINAPI stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
1979 return E_NOTIMPL;
1982 static HRESULT stream_handler_create_object(struct stream_handler *handler, WCHAR *url, IMFByteStream *stream,
1983 IUnknown **out_object)
1985 HRESULT hr;
1986 struct media_source *new_source;
1988 TRACE("%p, %s, %p, %p.\n", handler, debugstr_w(url), stream, out_object);
1990 if (FAILED(hr = media_source_constructor(stream, &new_source)))
1991 return hr;
1993 TRACE("->(%p)\n", new_source);
1995 *out_object = (IUnknown*)&new_source->IMFMediaSource_iface;
1997 return S_OK;
2000 static HRESULT WINAPI stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
2002 struct stream_handler *handler = impl_from_IMFAsyncCallback(iface);
2003 IUnknown *object = NULL, *context_object;
2004 struct create_object_context *context;
2005 struct result_entry *entry;
2006 IMFAsyncResult *caller;
2007 HRESULT hr;
2009 caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
2011 if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
2013 WARN("Expected context set for callee result.\n");
2014 return hr;
2017 context = impl_from_IUnknown(context_object);
2019 if (FAILED(hr = stream_handler_create_object(handler, context->url, context->stream, &object)))
2020 WARN("Failed to create object, hr %#lx\n", hr);
2021 else
2023 if (FAILED(hr = result_entry_create(caller, MF_OBJECT_MEDIASOURCE, object, &entry)))
2024 WARN("Failed to create handler result, hr %#lx\n", hr);
2025 else
2027 EnterCriticalSection(&handler->cs);
2028 list_add_tail(&handler->results, &entry->entry);
2029 LeaveCriticalSection(&handler->cs);
2032 IUnknown_Release(object);
2035 IUnknown_Release(&context->IUnknown_iface);
2037 IMFAsyncResult_SetStatus(caller, hr);
2038 MFInvokeCallback(caller);
2040 return S_OK;
2043 static const IMFAsyncCallbackVtbl stream_handler_callback_vtbl =
2045 stream_handler_callback_QueryInterface,
2046 stream_handler_callback_AddRef,
2047 stream_handler_callback_Release,
2048 stream_handler_callback_GetParameters,
2049 stream_handler_callback_Invoke,
2052 HRESULT gstreamer_byte_stream_handler_create(REFIID riid, void **obj)
2054 struct stream_handler *handler;
2055 HRESULT hr;
2057 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
2059 if (!(handler = calloc(1, sizeof(*handler))))
2060 return E_OUTOFMEMORY;
2062 list_init(&handler->results);
2063 InitializeCriticalSection(&handler->cs);
2065 handler->IMFByteStreamHandler_iface.lpVtbl = &stream_handler_vtbl;
2066 handler->IMFAsyncCallback_iface.lpVtbl = &stream_handler_callback_vtbl;
2067 handler->refcount = 1;
2069 hr = IMFByteStreamHandler_QueryInterface(&handler->IMFByteStreamHandler_iface, riid, obj);
2070 IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
2072 return hr;