winegstreamer: Let async command handle request token.
[wine.git] / dlls / winegstreamer / media_source.c
blob9c554c7c415a941206356168d80d6eeb531c3b72
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;
34 struct media_source *parent_source;
35 IMFMediaEventQueue *event_queue;
36 IMFStreamDescriptor *descriptor;
38 struct wg_parser_stream *wg_stream;
40 enum
42 STREAM_INACTIVE,
43 STREAM_SHUTDOWN,
44 STREAM_RUNNING,
45 } state;
46 DWORD stream_id;
47 BOOL eos;
50 enum source_async_op
52 SOURCE_ASYNC_START,
53 SOURCE_ASYNC_STOP,
54 SOURCE_ASYNC_REQUEST_SAMPLE,
57 struct source_async_command
59 IUnknown IUnknown_iface;
60 LONG refcount;
61 enum source_async_op op;
62 union
64 struct
66 IMFPresentationDescriptor *descriptor;
67 GUID format;
68 PROPVARIANT position;
69 } start;
70 struct
72 struct media_stream *stream;
73 IUnknown *token;
74 } request_sample;
75 } u;
78 struct media_source
80 IMFMediaSource IMFMediaSource_iface;
81 IMFGetService IMFGetService_iface;
82 IMFRateSupport IMFRateSupport_iface;
83 IMFRateControl IMFRateControl_iface;
84 IMFAsyncCallback async_commands_callback;
85 LONG ref;
86 DWORD async_commands_queue;
87 IMFMediaEventQueue *event_queue;
88 IMFByteStream *byte_stream;
90 struct wg_parser *wg_parser;
92 struct media_stream **streams;
93 ULONG stream_count;
94 IMFPresentationDescriptor *pres_desc;
95 enum
97 SOURCE_OPENING,
98 SOURCE_STOPPED,
99 SOURCE_RUNNING,
100 SOURCE_SHUTDOWN,
101 } state;
103 LONGLONG start_time;
105 HANDLE read_thread;
106 bool read_thread_shutdown;
109 static inline struct media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface)
111 return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface);
114 static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
116 return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
119 static inline struct media_source *impl_from_IMFGetService(IMFGetService *iface)
121 return CONTAINING_RECORD(iface, struct media_source, IMFGetService_iface);
124 static inline struct media_source *impl_from_IMFRateSupport(IMFRateSupport *iface)
126 return CONTAINING_RECORD(iface, struct media_source, IMFRateSupport_iface);
129 static inline struct media_source *impl_from_IMFRateControl(IMFRateControl *iface)
131 return CONTAINING_RECORD(iface, struct media_source, IMFRateControl_iface);
134 static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
136 return CONTAINING_RECORD(iface, struct media_source, async_commands_callback);
139 static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
141 return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface);
144 static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
146 if (IsEqualIID(riid, &IID_IUnknown))
148 *obj = iface;
149 IUnknown_AddRef(iface);
150 return S_OK;
153 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
154 *obj = NULL;
155 return E_NOINTERFACE;
158 static ULONG WINAPI source_async_command_AddRef(IUnknown *iface)
160 struct source_async_command *command = impl_from_async_command_IUnknown(iface);
161 return InterlockedIncrement(&command->refcount);
164 static ULONG WINAPI source_async_command_Release(IUnknown *iface)
166 struct source_async_command *command = impl_from_async_command_IUnknown(iface);
167 ULONG refcount = InterlockedDecrement(&command->refcount);
169 if (!refcount)
171 if (command->op == SOURCE_ASYNC_START)
172 PropVariantClear(&command->u.start.position);
173 else if (command->op == SOURCE_ASYNC_REQUEST_SAMPLE)
175 if (command->u.request_sample.token)
176 IUnknown_Release(command->u.request_sample.token);
178 free(command);
181 return refcount;
184 static const IUnknownVtbl source_async_command_vtbl =
186 source_async_command_QueryInterface,
187 source_async_command_AddRef,
188 source_async_command_Release,
191 static HRESULT source_create_async_op(enum source_async_op op, struct source_async_command **ret)
193 struct source_async_command *command;
195 if (!(command = calloc(1, sizeof(*command))))
196 return E_OUTOFMEMORY;
198 command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
199 command->op = op;
201 *ret = command;
203 return S_OK;
206 static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
208 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
210 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
211 IsEqualIID(riid, &IID_IUnknown))
213 *obj = iface;
214 IMFAsyncCallback_AddRef(iface);
215 return S_OK;
218 WARN("Unsupported %s.\n", debugstr_guid(riid));
219 *obj = NULL;
220 return E_NOINTERFACE;
223 static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
224 DWORD *flags, DWORD *queue)
226 return E_NOTIMPL;
229 static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
231 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
232 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
235 static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
237 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
238 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
241 static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected)
243 ULONG sd_count;
244 IMFStreamDescriptor *ret;
245 unsigned int i;
247 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count)))
248 return NULL;
250 for (i = 0; i < sd_count; i++)
252 DWORD stream_id;
254 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret)))
255 return NULL;
257 if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id)
258 return ret;
260 IMFStreamDescriptor_Release(ret);
262 return NULL;
265 static void start_pipeline(struct media_source *source, struct source_async_command *command)
267 PROPVARIANT *position = &command->u.start.position;
268 BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY;
269 unsigned int i;
271 /* seek to beginning on stop->play */
272 if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY)
274 position->vt = VT_I8;
275 position->hVal.QuadPart = 0;
277 source->start_time = position->hVal.QuadPart;
279 for (i = 0; i < source->stream_count; i++)
281 struct media_stream *stream;
282 IMFStreamDescriptor *sd;
283 IMFMediaTypeHandler *mth;
284 IMFMediaType *current_mt;
285 DWORD stream_id;
286 BOOL was_active;
287 BOOL selected;
289 stream = source->streams[i];
291 IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id);
293 sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected);
294 IMFStreamDescriptor_Release(sd);
296 was_active = stream->state != STREAM_INACTIVE;
298 stream->state = selected ? STREAM_RUNNING : STREAM_INACTIVE;
300 if (selected)
302 struct wg_format format;
304 IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &mth);
305 IMFMediaTypeHandler_GetCurrentMediaType(mth, &current_mt);
307 mf_media_type_to_wg_format(current_mt, &format);
308 unix_funcs->wg_parser_stream_enable(stream->wg_stream, &format);
310 IMFMediaType_Release(current_mt);
311 IMFMediaTypeHandler_Release(mth);
314 if (position->vt != VT_EMPTY)
315 stream->eos = FALSE;
317 if (selected)
319 TRACE("Stream %u (%p) selected\n", i, stream);
320 IMFMediaEventQueue_QueueEventParamUnk(source->event_queue,
321 was_active ? MEUpdatedStream : MENewStream, &GUID_NULL,
322 S_OK, (IUnknown*) &stream->IMFMediaStream_iface);
324 IMFMediaEventQueue_QueueEventParamVar(stream->event_queue,
325 seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position);
329 IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
330 seek_message ? MESourceSeeked : MESourceStarted,
331 &GUID_NULL, S_OK, position);
333 source->state = SOURCE_RUNNING;
335 unix_funcs->wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0,
336 position->hVal.QuadPart, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
337 unix_funcs->wg_parser_end_flush(source->wg_parser);
340 static void stop_pipeline(struct media_source *source)
342 unsigned int i;
344 unix_funcs->wg_parser_begin_flush(source->wg_parser);
346 for (i = 0; i < source->stream_count; i++)
348 struct media_stream *stream = source->streams[i];
349 if (stream->state != STREAM_INACTIVE)
351 IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, &GUID_NULL, S_OK, NULL);
352 unix_funcs->wg_parser_stream_disable(stream->wg_stream);
356 IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL);
358 source->state = SOURCE_STOPPED;
361 static void dispatch_end_of_presentation(struct media_source *source)
363 PROPVARIANT empty = {.vt = VT_EMPTY};
364 unsigned int i;
366 /* A stream has ended, check whether all have */
367 for (i = 0; i < source->stream_count; i++)
369 struct media_stream *stream = source->streams[i];
371 if (stream->state != STREAM_INACTIVE && !stream->eos)
372 return;
375 IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty);
378 static void send_buffer(struct media_stream *stream, const struct wg_parser_event *event, IUnknown *token)
380 IMFMediaBuffer *buffer;
381 IMFSample *sample;
382 HRESULT hr;
383 BYTE *data;
385 if (FAILED(hr = MFCreateSample(&sample)))
387 ERR("Failed to create sample, hr %#x.\n", hr);
388 return;
391 if (FAILED(hr = MFCreateMemoryBuffer(event->u.buffer.size, &buffer)))
393 ERR("Failed to create buffer, hr %#x.\n", hr);
394 IMFSample_Release(sample);
395 return;
398 if (FAILED(hr = IMFSample_AddBuffer(sample, buffer)))
400 ERR("Failed to add buffer, hr %#x.\n", hr);
401 goto out;
404 if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event->u.buffer.size)))
406 ERR("Failed to set size, hr %#x.\n", hr);
407 goto out;
410 if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL)))
412 ERR("Failed to lock buffer, hr %#x.\n", hr);
413 goto out;
416 if (!unix_funcs->wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, event->u.buffer.size))
418 unix_funcs->wg_parser_stream_release_buffer(stream->wg_stream);
419 IMFMediaBuffer_Unlock(buffer);
420 goto out;
422 unix_funcs->wg_parser_stream_release_buffer(stream->wg_stream);
424 if (FAILED(hr = IMFMediaBuffer_Unlock(buffer)))
426 ERR("Failed to unlock buffer, hr %#x.\n", hr);
427 goto out;
430 if (FAILED(hr = IMFSample_SetSampleTime(sample, event->u.buffer.pts - stream->parent_source->start_time)))
432 ERR("Failed to set sample time, hr %#x.\n", hr);
433 goto out;
436 if (FAILED(hr = IMFSample_SetSampleDuration(sample, event->u.buffer.duration)))
438 ERR("Failed to set sample duration, hr %#x.\n", hr);
439 goto out;
442 if (token)
443 IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
445 IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
446 &GUID_NULL, S_OK, (IUnknown *)sample);
448 out:
449 IMFMediaBuffer_Release(buffer);
450 IMFSample_Release(sample);
453 static void wait_on_sample(struct media_stream *stream, IUnknown *token)
455 PROPVARIANT empty_var = {.vt = VT_EMPTY};
456 struct wg_parser_event event;
458 TRACE("%p, %p\n", stream, token);
460 for (;;)
462 if (!unix_funcs->wg_parser_stream_get_event(stream->wg_stream, &event))
463 return;
465 TRACE("Got event of type %#x.\n", event.type);
467 switch (event.type)
469 case WG_PARSER_EVENT_BUFFER:
470 send_buffer(stream, &event, token);
471 return;
473 case WG_PARSER_EVENT_EOS:
474 stream->eos = TRUE;
475 IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var);
476 dispatch_end_of_presentation(stream->parent_source);
477 return;
479 case WG_PARSER_EVENT_SEGMENT:
480 break;
482 case WG_PARSER_EVENT_NONE:
483 assert(0);
488 static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
490 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
491 struct source_async_command *command;
492 IUnknown *state;
493 HRESULT hr;
495 if (source->state == SOURCE_SHUTDOWN)
496 return S_OK;
498 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
499 return hr;
501 command = impl_from_async_command_IUnknown(state);
502 switch (command->op)
504 case SOURCE_ASYNC_START:
505 start_pipeline(source, command);
506 break;
507 case SOURCE_ASYNC_STOP:
508 stop_pipeline(source);
509 break;
510 case SOURCE_ASYNC_REQUEST_SAMPLE:
511 wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token);
512 break;
515 IUnknown_Release(state);
517 return S_OK;
520 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
522 callback_QueryInterface,
523 source_async_commands_callback_AddRef,
524 source_async_commands_callback_Release,
525 callback_GetParameters,
526 source_async_commands_Invoke,
529 static DWORD CALLBACK read_thread(void *arg)
531 struct media_source *source = arg;
532 IMFByteStream *byte_stream = source->byte_stream;
534 TRACE("Starting read thread for media source %p.\n", source);
536 while (!source->read_thread_shutdown)
538 uint64_t offset;
539 ULONG ret_size;
540 uint32_t size;
541 HRESULT hr;
542 void *data;
544 if (!unix_funcs->wg_parser_get_read_request(source->wg_parser, &data, &offset, &size))
545 continue;
547 if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset)))
548 hr = IMFByteStream_Read(byte_stream, data, size, &ret_size);
549 if (SUCCEEDED(hr) && ret_size != size)
550 ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size);
551 unix_funcs->wg_parser_complete_read_request(source->wg_parser, SUCCEEDED(hr));
554 TRACE("Media source is shutting down; exiting.\n");
555 return 0;
558 static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
560 struct media_stream *stream = impl_from_IMFMediaStream(iface);
562 TRACE("(%p)->(%s %p)\n", stream, debugstr_guid(riid), out);
564 if (IsEqualIID(riid, &IID_IMFMediaStream) ||
565 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
566 IsEqualIID(riid, &IID_IUnknown))
568 *out = &stream->IMFMediaStream_iface;
570 else
572 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
573 *out = NULL;
574 return E_NOINTERFACE;
577 IUnknown_AddRef((IUnknown*)*out);
578 return S_OK;
581 static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
583 struct media_stream *stream = impl_from_IMFMediaStream(iface);
584 ULONG ref = InterlockedIncrement(&stream->ref);
586 TRACE("(%p) ref=%u\n", stream, ref);
588 return ref;
591 static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
593 struct media_stream *stream = impl_from_IMFMediaStream(iface);
595 ULONG ref = InterlockedDecrement(&stream->ref);
597 TRACE("(%p) ref=%u\n", stream, ref);
599 if (!ref)
601 if (stream->event_queue)
602 IMFMediaEventQueue_Release(stream->event_queue);
603 free(stream);
606 return ref;
609 static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
611 struct media_stream *stream = impl_from_IMFMediaStream(iface);
613 TRACE("(%p)->(%#x, %p)\n", stream, flags, event);
615 return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
618 static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
620 struct media_stream *stream = impl_from_IMFMediaStream(iface);
622 TRACE("(%p)->(%p, %p)\n", stream, callback, state);
624 return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
627 static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
629 struct media_stream *stream = impl_from_IMFMediaStream(iface);
631 TRACE("(%p)->(%p, %p)\n", stream, result, event);
633 return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
636 static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
637 HRESULT hr, const PROPVARIANT *value)
639 struct media_stream *stream = impl_from_IMFMediaStream(iface);
641 TRACE("(%p)->(%d, %s, %#x, %p)\n", stream, event_type, debugstr_guid(ext_type), hr, value);
643 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
646 static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source)
648 struct media_stream *stream = impl_from_IMFMediaStream(iface);
650 TRACE("(%p)->(%p)\n", stream, source);
652 if (stream->state == STREAM_SHUTDOWN)
653 return MF_E_SHUTDOWN;
655 IMFMediaSource_AddRef(&stream->parent_source->IMFMediaSource_iface);
656 *source = &stream->parent_source->IMFMediaSource_iface;
658 return S_OK;
661 static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
663 struct media_stream *stream = impl_from_IMFMediaStream(iface);
665 TRACE("(%p)->(%p)\n", stream, descriptor);
667 if (stream->state == STREAM_SHUTDOWN)
668 return MF_E_SHUTDOWN;
670 IMFStreamDescriptor_AddRef(stream->descriptor);
671 *descriptor = stream->descriptor;
673 return S_OK;
676 static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
678 struct media_stream *stream = impl_from_IMFMediaStream(iface);
679 struct source_async_command *command;
680 HRESULT hr;
682 TRACE("(%p)->(%p)\n", iface, token);
684 if (stream->state == STREAM_SHUTDOWN)
685 return MF_E_SHUTDOWN;
687 if (stream->state == STREAM_INACTIVE)
689 WARN("Stream isn't active\n");
690 return MF_E_MEDIA_SOURCE_WRONGSTATE;
693 if (stream->eos)
695 return MF_E_END_OF_STREAM;
698 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command)))
700 command->u.request_sample.stream = stream;
701 if (token)
702 IUnknown_AddRef(token);
703 command->u.request_sample.token = token;
705 /* Once pause support is added, this will need to put into a stream queue, and synchronization will need to be added*/
706 hr = MFPutWorkItem(stream->parent_source->async_commands_queue, &stream->parent_source->async_commands_callback, &command->IUnknown_iface);
709 return hr;
712 static const IMFMediaStreamVtbl media_stream_vtbl =
714 media_stream_QueryInterface,
715 media_stream_AddRef,
716 media_stream_Release,
717 media_stream_GetEvent,
718 media_stream_BeginGetEvent,
719 media_stream_EndGetEvent,
720 media_stream_QueueEvent,
721 media_stream_GetMediaSource,
722 media_stream_GetStreamDescriptor,
723 media_stream_RequestSample
726 static HRESULT new_media_stream(struct media_source *source,
727 struct wg_parser_stream *wg_stream, DWORD stream_id, struct media_stream **out_stream)
729 struct media_stream *object = calloc(1, sizeof(*object));
730 HRESULT hr;
732 TRACE("source %p, wg_stream %p, stream_id %u.\n", source, wg_stream, stream_id);
734 object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
735 object->ref = 1;
737 IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
738 object->parent_source = source;
739 object->stream_id = stream_id;
741 object->state = STREAM_INACTIVE;
742 object->eos = FALSE;
743 object->wg_stream = wg_stream;
745 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
746 goto fail;
748 TRACE("->(%p)\n", object);
749 *out_stream = object;
751 return S_OK;
753 fail:
754 WARN("Failed to construct media stream, hr %#x.\n", hr);
756 IMFMediaStream_Release(&object->IMFMediaStream_iface);
757 return hr;
760 static HRESULT media_stream_init_desc(struct media_stream *stream)
762 IMFMediaTypeHandler *type_handler = NULL;
763 IMFMediaType *stream_types[6];
764 struct wg_format format;
765 DWORD type_count = 0;
766 unsigned int i;
767 HRESULT hr;
769 unix_funcs->wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
771 if (format.major_type == WG_MAJOR_TYPE_VIDEO)
773 /* These are the most common native output types of decoders:
774 https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */
775 static const GUID *const video_types[] =
777 &MFVideoFormat_NV12,
778 &MFVideoFormat_YV12,
779 &MFVideoFormat_YUY2,
780 &MFVideoFormat_IYUV,
781 &MFVideoFormat_I420,
784 IMFMediaType *base_type = mf_media_type_from_wg_format(&format);
785 GUID base_subtype;
787 IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype);
789 stream_types[0] = base_type;
790 type_count = 1;
792 for (i = 0; i < ARRAY_SIZE(video_types); i++)
794 IMFMediaType *new_type;
796 if (IsEqualGUID(&base_subtype, video_types[i]))
797 continue;
799 if (FAILED(hr = MFCreateMediaType(&new_type)))
800 goto done;
801 stream_types[type_count++] = new_type;
803 if (FAILED(hr = IMFMediaType_CopyAllItems(base_type, (IMFAttributes *) new_type)))
804 goto done;
805 if (FAILED(hr = IMFMediaType_SetGUID(new_type, &MF_MT_SUBTYPE, video_types[i])))
806 goto done;
809 else if (format.major_type == WG_MAJOR_TYPE_AUDIO)
811 /* Expose at least one PCM and one floating point type for the
812 consumer to pick from. */
813 static const enum wg_audio_format audio_types[] =
815 WG_AUDIO_FORMAT_S16LE,
816 WG_AUDIO_FORMAT_F32LE,
819 stream_types[0] = mf_media_type_from_wg_format(&format);
820 type_count = 1;
822 for (i = 0; i < ARRAY_SIZE(audio_types); i++)
824 struct wg_format new_format;
825 if (format.u.audio.format == audio_types[i])
826 continue;
827 new_format = format;
828 new_format.u.audio.format = audio_types[i];
829 stream_types[type_count++] = mf_media_type_from_wg_format(&new_format);
832 else
834 if ((stream_types[0] = mf_media_type_from_wg_format(&format)))
835 type_count = 1;
838 assert(type_count <= ARRAY_SIZE(stream_types));
840 if (!type_count)
842 ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
843 return E_FAIL;
846 if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, type_count, stream_types, &stream->descriptor)))
847 goto done;
849 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
850 goto done;
852 if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0])))
853 goto done;
855 done:
856 if (type_handler)
857 IMFMediaTypeHandler_Release(type_handler);
858 for (i = 0; i < type_count; i++)
859 IMFMediaType_Release(stream_types[i]);
860 return hr;
863 static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
865 struct media_source *source = impl_from_IMFGetService(iface);
866 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
869 static ULONG WINAPI media_source_get_service_AddRef(IMFGetService *iface)
871 struct media_source *source = impl_from_IMFGetService(iface);
872 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
875 static ULONG WINAPI media_source_get_service_Release(IMFGetService *iface)
877 struct media_source *source = impl_from_IMFGetService(iface);
878 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
881 static HRESULT WINAPI media_source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
883 struct media_source *source = impl_from_IMFGetService(iface);
885 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
887 *obj = NULL;
889 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
891 if (IsEqualIID(riid, &IID_IMFRateSupport))
893 *obj = &source->IMFRateSupport_iface;
895 else if (IsEqualIID(riid, &IID_IMFRateControl))
897 *obj = &source->IMFRateControl_iface;
900 else
901 FIXME("Unsupported service %s.\n", debugstr_guid(service));
903 if (*obj)
904 IUnknown_AddRef((IUnknown *)*obj);
906 return *obj ? S_OK : E_NOINTERFACE;
909 static const IMFGetServiceVtbl media_source_get_service_vtbl =
911 media_source_get_service_QueryInterface,
912 media_source_get_service_AddRef,
913 media_source_get_service_Release,
914 media_source_get_service_GetService,
917 static HRESULT WINAPI media_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
919 struct media_source *source = impl_from_IMFRateSupport(iface);
920 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
923 static ULONG WINAPI media_source_rate_support_AddRef(IMFRateSupport *iface)
925 struct media_source *source = impl_from_IMFRateSupport(iface);
926 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
929 static ULONG WINAPI media_source_rate_support_Release(IMFRateSupport *iface)
931 struct media_source *source = impl_from_IMFRateSupport(iface);
932 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
935 static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
937 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
939 *rate = 0.0f;
941 return S_OK;
944 static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
946 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
948 *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f;
950 return S_OK;
953 static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
954 float *nearest_rate)
956 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_rate);
958 if (nearest_rate)
959 *nearest_rate = rate;
961 return rate >= -1e6f && rate <= 1e6f ? S_OK : MF_E_UNSUPPORTED_RATE;
964 static const IMFRateSupportVtbl media_source_rate_support_vtbl =
966 media_source_rate_support_QueryInterface,
967 media_source_rate_support_AddRef,
968 media_source_rate_support_Release,
969 media_source_rate_support_GetSlowestRate,
970 media_source_rate_support_GetFastestRate,
971 media_source_rate_support_IsRateSupported,
974 static HRESULT WINAPI media_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
976 struct media_source *source = impl_from_IMFRateControl(iface);
977 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
980 static ULONG WINAPI media_source_rate_control_AddRef(IMFRateControl *iface)
982 struct media_source *source = impl_from_IMFRateControl(iface);
983 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
986 static ULONG WINAPI media_source_rate_control_Release(IMFRateControl *iface)
988 struct media_source *source = impl_from_IMFRateControl(iface);
989 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
992 static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
994 FIXME("%p, %d, %f.\n", iface, thin, rate);
996 if (rate < 0.0f)
997 return MF_E_REVERSE_UNSUPPORTED;
999 if (thin)
1000 return MF_E_THINNING_UNSUPPORTED;
1002 if (rate != 1.0f)
1003 return MF_E_UNSUPPORTED_RATE;
1005 return S_OK;
1008 static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
1010 TRACE("%p, %p, %p.\n", iface, thin, rate);
1012 if (thin)
1013 *thin = FALSE;
1015 *rate = 1.0f;
1017 return S_OK;
1020 static const IMFRateControlVtbl media_source_rate_control_vtbl =
1022 media_source_rate_control_QueryInterface,
1023 media_source_rate_control_AddRef,
1024 media_source_rate_control_Release,
1025 media_source_rate_control_SetRate,
1026 media_source_rate_control_GetRate,
1029 static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
1031 struct media_source *source = impl_from_IMFMediaSource(iface);
1033 TRACE("(%p)->(%s %p)\n", source, debugstr_guid(riid), out);
1035 if (IsEqualIID(riid, &IID_IMFMediaSource) ||
1036 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1037 IsEqualIID(riid, &IID_IUnknown))
1039 *out = &source->IMFMediaSource_iface;
1041 else if (IsEqualIID(riid, &IID_IMFGetService))
1043 *out = &source->IMFGetService_iface;
1045 else
1047 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
1048 *out = NULL;
1049 return E_NOINTERFACE;
1052 IUnknown_AddRef((IUnknown*)*out);
1053 return S_OK;
1056 static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface)
1058 struct media_source *source = impl_from_IMFMediaSource(iface);
1059 ULONG ref = InterlockedIncrement(&source->ref);
1061 TRACE("(%p) ref=%u\n", source, ref);
1063 return ref;
1066 static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
1068 struct media_source *source = impl_from_IMFMediaSource(iface);
1069 ULONG ref = InterlockedDecrement(&source->ref);
1071 TRACE("(%p) ref=%u\n", source, ref);
1073 if (!ref)
1075 IMFMediaSource_Shutdown(&source->IMFMediaSource_iface);
1076 IMFMediaEventQueue_Release(source->event_queue);
1077 free(source);
1080 return ref;
1083 static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
1085 struct media_source *source = impl_from_IMFMediaSource(iface);
1087 TRACE("(%p)->(%#x, %p)\n", source, flags, event);
1089 return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
1092 static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
1094 struct media_source *source = impl_from_IMFMediaSource(iface);
1096 TRACE("(%p)->(%p, %p)\n", source, callback, state);
1098 return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
1101 static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1103 struct media_source *source = impl_from_IMFMediaSource(iface);
1105 TRACE("(%p)->(%p, %p)\n", source, result, event);
1107 return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
1110 static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
1111 HRESULT hr, const PROPVARIANT *value)
1113 struct media_source *source = impl_from_IMFMediaSource(iface);
1115 TRACE("(%p)->(%d, %s, %#x, %p)\n", source, event_type, debugstr_guid(ext_type), hr, value);
1117 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
1120 static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
1122 struct media_source *source = impl_from_IMFMediaSource(iface);
1124 TRACE("(%p)->(%p)\n", source, characteristics);
1126 if (source->state == SOURCE_SHUTDOWN)
1127 return MF_E_SHUTDOWN;
1129 *characteristics = MFMEDIASOURCE_CAN_SEEK;
1131 return S_OK;
1134 static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
1136 struct media_source *source = impl_from_IMFMediaSource(iface);
1138 TRACE("(%p)->(%p)\n", source, descriptor);
1140 if (source->state == SOURCE_SHUTDOWN)
1141 return MF_E_SHUTDOWN;
1143 return IMFPresentationDescriptor_Clone(source->pres_desc, descriptor);
1146 static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
1147 const GUID *time_format, const PROPVARIANT *position)
1149 struct media_source *source = impl_from_IMFMediaSource(iface);
1150 struct source_async_command *command;
1151 HRESULT hr;
1153 TRACE("(%p)->(%p, %p, %p)\n", source, descriptor, time_format, position);
1155 if (source->state == SOURCE_SHUTDOWN)
1156 return MF_E_SHUTDOWN;
1158 if (!(IsEqualIID(time_format, &GUID_NULL)))
1159 return MF_E_UNSUPPORTED_TIME_FORMAT;
1161 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command)))
1163 command->u.start.descriptor = descriptor;
1164 command->u.start.format = *time_format;
1165 PropVariantCopy(&command->u.start.position, position);
1167 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
1170 return hr;
1173 static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
1175 struct media_source *source = impl_from_IMFMediaSource(iface);
1176 struct source_async_command *command;
1177 HRESULT hr;
1179 TRACE("(%p)\n", source);
1181 if (source->state == SOURCE_SHUTDOWN)
1182 return MF_E_SHUTDOWN;
1184 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command)))
1185 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
1187 return hr;
1190 static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
1192 struct media_source *source = impl_from_IMFMediaSource(iface);
1194 FIXME("(%p): stub\n", source);
1196 if (source->state == SOURCE_SHUTDOWN)
1197 return MF_E_SHUTDOWN;
1199 return E_NOTIMPL;
1202 static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
1204 struct media_source *source = impl_from_IMFMediaSource(iface);
1205 unsigned int i;
1207 TRACE("(%p)\n", source);
1209 if (source->state == SOURCE_SHUTDOWN)
1210 return MF_E_SHUTDOWN;
1212 source->state = SOURCE_SHUTDOWN;
1214 unix_funcs->wg_parser_disconnect(source->wg_parser);
1216 if (source->read_thread)
1218 source->read_thread_shutdown = true;
1219 WaitForSingleObject(source->read_thread, INFINITE);
1220 CloseHandle(source->read_thread);
1223 if (source->pres_desc)
1224 IMFPresentationDescriptor_Release(source->pres_desc);
1225 if (source->event_queue)
1226 IMFMediaEventQueue_Shutdown(source->event_queue);
1227 if (source->byte_stream)
1228 IMFByteStream_Release(source->byte_stream);
1230 for (i = 0; i < source->stream_count; i++)
1232 struct media_stream *stream = source->streams[i];
1234 stream->state = STREAM_SHUTDOWN;
1236 if (stream->event_queue)
1237 IMFMediaEventQueue_Shutdown(stream->event_queue);
1238 if (stream->descriptor)
1239 IMFStreamDescriptor_Release(stream->descriptor);
1240 if (stream->parent_source)
1241 IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
1243 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1246 unix_funcs->wg_parser_destroy(source->wg_parser);
1248 if (source->stream_count)
1249 free(source->streams);
1251 if (source->async_commands_queue)
1252 MFUnlockWorkQueue(source->async_commands_queue);
1254 return S_OK;
1257 static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
1259 media_source_QueryInterface,
1260 media_source_AddRef,
1261 media_source_Release,
1262 media_source_GetEvent,
1263 media_source_BeginGetEvent,
1264 media_source_EndGetEvent,
1265 media_source_QueueEvent,
1266 media_source_GetCharacteristics,
1267 media_source_CreatePresentationDescriptor,
1268 media_source_Start,
1269 media_source_Stop,
1270 media_source_Pause,
1271 media_source_Shutdown,
1274 static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
1276 IMFStreamDescriptor **descriptors = NULL;
1277 struct media_source *object;
1278 UINT64 total_pres_time = 0;
1279 struct wg_parser *parser;
1280 DWORD bytestream_caps;
1281 uint64_t file_size;
1282 unsigned int i;
1283 HRESULT hr;
1285 if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps)))
1286 return hr;
1288 if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE))
1290 FIXME("Non-seekable bytestreams not supported.\n");
1291 return MF_E_BYTESTREAM_NOT_SEEKABLE;
1294 if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size)))
1296 FIXME("Failed to get byte stream length, hr %#x.\n", hr);
1297 return hr;
1300 if (!(object = calloc(1, sizeof(*object))))
1301 return E_OUTOFMEMORY;
1303 object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
1304 object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl;
1305 object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl;
1306 object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl;
1307 object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
1308 object->ref = 1;
1309 object->byte_stream = bytestream;
1310 IMFByteStream_AddRef(bytestream);
1312 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1313 goto fail;
1315 if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
1316 goto fail;
1318 object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL);
1320 if (!(parser = unix_funcs->wg_decodebin_parser_create()))
1322 hr = E_OUTOFMEMORY;
1323 goto fail;
1325 object->wg_parser = parser;
1327 object->state = SOURCE_OPENING;
1329 if (FAILED(hr = unix_funcs->wg_parser_connect(parser, file_size)))
1330 goto fail;
1332 /* In Media Foundation, sources may read from any media source stream
1333 * without fear of blocking due to buffering limits on another. Trailmakers,
1334 * a Unity3D Engine game, only reads one sample from the audio stream (and
1335 * never deselects it). Remove buffering limits from decodebin in order to
1336 * account for this. Note that this does leak memory, but the same memory
1337 * leak occurs with native. */
1338 unix_funcs->wg_parser_set_unlimited_buffering(parser);
1340 object->stream_count = unix_funcs->wg_parser_get_stream_count(parser);
1342 if (!(object->streams = calloc(object->stream_count, sizeof(*object->streams))))
1344 hr = E_OUTOFMEMORY;
1345 goto fail;
1348 for (i = 0; i < object->stream_count; ++i)
1350 if (FAILED(hr = new_media_stream(object, unix_funcs->wg_parser_get_stream(parser, i), i, &object->streams[i])))
1351 goto fail;
1353 if (FAILED(hr = media_stream_init_desc(object->streams[i])))
1355 ERR("Failed to finish initialization of media stream %p, hr %x.\n", object->streams[i], hr);
1356 IMFMediaStream_Release(&object->streams[i]->IMFMediaStream_iface);
1357 goto fail;
1361 /* init presentation descriptor */
1363 descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *));
1364 for (i = 0; i < object->stream_count; i++)
1366 IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]);
1369 if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc)))
1370 goto fail;
1372 for (i = 0; i < object->stream_count; i++)
1374 IMFPresentationDescriptor_SelectStream(object->pres_desc, i);
1375 IMFStreamDescriptor_Release(descriptors[i]);
1377 free(descriptors);
1378 descriptors = NULL;
1380 for (i = 0; i < object->stream_count; i++)
1381 total_pres_time = max(total_pres_time,
1382 unix_funcs->wg_parser_stream_get_duration(object->streams[i]->wg_stream));
1384 if (object->stream_count)
1385 IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time);
1387 object->state = SOURCE_STOPPED;
1389 *out_media_source = object;
1390 return S_OK;
1392 fail:
1393 WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
1395 free(descriptors);
1396 IMFMediaSource_Release(&object->IMFMediaSource_iface);
1397 return hr;
1400 struct winegstreamer_stream_handler_result
1402 struct list entry;
1403 IMFAsyncResult *result;
1404 MF_OBJECT_TYPE obj_type;
1405 IUnknown *object;
1408 struct winegstreamer_stream_handler
1410 IMFByteStreamHandler IMFByteStreamHandler_iface;
1411 IMFAsyncCallback IMFAsyncCallback_iface;
1412 LONG refcount;
1413 struct list results;
1414 CRITICAL_SECTION cs;
1417 static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
1419 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFByteStreamHandler_iface);
1422 static struct winegstreamer_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
1424 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFAsyncCallback_iface);
1427 static HRESULT WINAPI winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj)
1429 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1431 if (IsEqualIID(riid, &IID_IMFByteStreamHandler) ||
1432 IsEqualIID(riid, &IID_IUnknown))
1434 *obj = iface;
1435 IMFByteStreamHandler_AddRef(iface);
1436 return S_OK;
1439 WARN("Unsupported %s.\n", debugstr_guid(riid));
1440 *obj = NULL;
1441 return E_NOINTERFACE;
1444 static ULONG WINAPI winegstreamer_stream_handler_AddRef(IMFByteStreamHandler *iface)
1446 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1447 ULONG refcount = InterlockedIncrement(&handler->refcount);
1449 TRACE("%p, refcount %u.\n", handler, refcount);
1451 return refcount;
1454 static ULONG WINAPI winegstreamer_stream_handler_Release(IMFByteStreamHandler *iface)
1456 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1457 ULONG refcount = InterlockedDecrement(&handler->refcount);
1458 struct winegstreamer_stream_handler_result *result, *next;
1460 TRACE("%p, refcount %u.\n", iface, refcount);
1462 if (!refcount)
1464 LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct winegstreamer_stream_handler_result, entry)
1466 list_remove(&result->entry);
1467 IMFAsyncResult_Release(result->result);
1468 if (result->object)
1469 IUnknown_Release(result->object);
1470 free(result);
1472 DeleteCriticalSection(&handler->cs);
1473 free(handler);
1476 return refcount;
1479 struct create_object_context
1481 IUnknown IUnknown_iface;
1482 LONG refcount;
1484 IPropertyStore *props;
1485 IMFByteStream *stream;
1486 WCHAR *url;
1487 DWORD flags;
1490 static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
1492 return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
1495 static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
1497 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1499 if (IsEqualIID(riid, &IID_IUnknown))
1501 *obj = iface;
1502 IUnknown_AddRef(iface);
1503 return S_OK;
1506 WARN("Unsupported %s.\n", debugstr_guid(riid));
1507 *obj = NULL;
1508 return E_NOINTERFACE;
1511 static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
1513 struct create_object_context *context = impl_from_IUnknown(iface);
1514 ULONG refcount = InterlockedIncrement(&context->refcount);
1516 TRACE("%p, refcount %u.\n", iface, refcount);
1518 return refcount;
1521 static ULONG WINAPI create_object_context_Release(IUnknown *iface)
1523 struct create_object_context *context = impl_from_IUnknown(iface);
1524 ULONG refcount = InterlockedDecrement(&context->refcount);
1526 TRACE("%p, refcount %u.\n", iface, refcount);
1528 if (!refcount)
1530 if (context->props)
1531 IPropertyStore_Release(context->props);
1532 if (context->stream)
1533 IMFByteStream_Release(context->stream);
1534 free(context->url);
1535 free(context);
1538 return refcount;
1541 static const IUnknownVtbl create_object_context_vtbl =
1543 create_object_context_QueryInterface,
1544 create_object_context_AddRef,
1545 create_object_context_Release,
1548 static HRESULT WINAPI winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
1549 IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
1551 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1552 struct create_object_context *context;
1553 IMFAsyncResult *caller, *item;
1554 HRESULT hr;
1556 TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
1558 if (cancel_cookie)
1559 *cancel_cookie = NULL;
1561 if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
1562 return hr;
1564 if (!(context = calloc(1, sizeof(*context))))
1566 IMFAsyncResult_Release(caller);
1567 return E_OUTOFMEMORY;
1570 context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
1571 context->refcount = 1;
1572 context->props = props;
1573 if (context->props)
1574 IPropertyStore_AddRef(context->props);
1575 context->flags = flags;
1576 context->stream = stream;
1577 if (context->stream)
1578 IMFByteStream_AddRef(context->stream);
1579 if (url)
1580 context->url = wcsdup(url);
1581 if (!context->stream)
1583 IMFAsyncResult_Release(caller);
1584 IUnknown_Release(&context->IUnknown_iface);
1585 return E_OUTOFMEMORY;
1588 hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
1589 IUnknown_Release(&context->IUnknown_iface);
1590 if (SUCCEEDED(hr))
1592 if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
1594 if (cancel_cookie)
1596 *cancel_cookie = (IUnknown *)caller;
1597 IUnknown_AddRef(*cancel_cookie);
1601 IMFAsyncResult_Release(item);
1603 IMFAsyncResult_Release(caller);
1605 return hr;
1608 static HRESULT WINAPI winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
1609 MF_OBJECT_TYPE *obj_type, IUnknown **object)
1611 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1612 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1613 HRESULT hr;
1615 TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
1617 EnterCriticalSection(&this->cs);
1619 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1621 if (result == cur->result)
1623 list_remove(&cur->entry);
1624 found = cur;
1625 break;
1629 LeaveCriticalSection(&this->cs);
1631 if (found)
1633 *obj_type = found->obj_type;
1634 *object = found->object;
1635 hr = IMFAsyncResult_GetStatus(found->result);
1636 IMFAsyncResult_Release(found->result);
1637 free(found);
1639 else
1641 *obj_type = MF_OBJECT_INVALID;
1642 *object = NULL;
1643 hr = MF_E_UNEXPECTED;
1646 return hr;
1649 static HRESULT WINAPI winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie)
1651 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1652 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1654 TRACE("%p, %p.\n", iface, cancel_cookie);
1656 EnterCriticalSection(&this->cs);
1658 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1660 if (cancel_cookie == (IUnknown *)cur->result)
1662 list_remove(&cur->entry);
1663 found = cur;
1664 break;
1668 LeaveCriticalSection(&this->cs);
1670 if (found)
1672 IMFAsyncResult_Release(found->result);
1673 if (found->object)
1674 IUnknown_Release(found->object);
1675 free(found);
1678 return found ? S_OK : MF_E_UNEXPECTED;
1681 static HRESULT WINAPI winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes)
1683 FIXME("stub (%p %p)\n", iface, bytes);
1684 return E_NOTIMPL;
1687 static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl =
1689 winegstreamer_stream_handler_QueryInterface,
1690 winegstreamer_stream_handler_AddRef,
1691 winegstreamer_stream_handler_Release,
1692 winegstreamer_stream_handler_BeginCreateObject,
1693 winegstreamer_stream_handler_EndCreateObject,
1694 winegstreamer_stream_handler_CancelObjectCreation,
1695 winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
1698 static HRESULT WINAPI winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
1700 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1701 IsEqualIID(riid, &IID_IUnknown))
1703 *obj = iface;
1704 IMFAsyncCallback_AddRef(iface);
1705 return S_OK;
1708 WARN("Unsupported %s.\n", debugstr_guid(riid));
1709 *obj = NULL;
1710 return E_NOINTERFACE;
1713 static ULONG WINAPI winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback *iface)
1715 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1716 return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
1719 static ULONG WINAPI winegstreamer_stream_handler_callback_Release(IMFAsyncCallback *iface)
1721 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1722 return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
1725 static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
1727 return E_NOTIMPL;
1730 static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags,
1731 IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type)
1733 TRACE("(%p %s %p %u %p %p %p)\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type);
1735 if (flags & MF_RESOLUTION_MEDIASOURCE)
1737 HRESULT hr;
1738 struct media_source *new_source;
1740 if (FAILED(hr = media_source_constructor(stream, &new_source)))
1741 return hr;
1743 TRACE("->(%p)\n", new_source);
1745 *out_object = (IUnknown*)&new_source->IMFMediaSource_iface;
1746 *out_obj_type = MF_OBJECT_MEDIASOURCE;
1748 return S_OK;
1750 else
1752 FIXME("flags = %08x\n", flags);
1753 return E_NOTIMPL;
1757 static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1759 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1760 struct winegstreamer_stream_handler_result *handler_result;
1761 MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID;
1762 IUnknown *object = NULL, *context_object;
1763 struct create_object_context *context;
1764 IMFAsyncResult *caller;
1765 HRESULT hr;
1767 caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
1769 if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
1771 WARN("Expected context set for callee result.\n");
1772 return hr;
1775 context = impl_from_IUnknown(context_object);
1777 hr = winegstreamer_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type);
1779 if ((handler_result = malloc(sizeof(*handler_result))))
1781 handler_result->result = caller;
1782 IMFAsyncResult_AddRef(handler_result->result);
1783 handler_result->obj_type = obj_type;
1784 handler_result->object = object;
1786 EnterCriticalSection(&handler->cs);
1787 list_add_tail(&handler->results, &handler_result->entry);
1788 LeaveCriticalSection(&handler->cs);
1790 else
1792 if (object)
1793 IUnknown_Release(object);
1794 hr = E_OUTOFMEMORY;
1797 IUnknown_Release(&context->IUnknown_iface);
1799 IMFAsyncResult_SetStatus(caller, hr);
1800 MFInvokeCallback(caller);
1802 return S_OK;
1805 static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl =
1807 winegstreamer_stream_handler_callback_QueryInterface,
1808 winegstreamer_stream_handler_callback_AddRef,
1809 winegstreamer_stream_handler_callback_Release,
1810 winegstreamer_stream_handler_callback_GetParameters,
1811 winegstreamer_stream_handler_callback_Invoke,
1814 HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj)
1816 struct winegstreamer_stream_handler *this;
1817 HRESULT hr;
1819 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1821 if (!(this = calloc(1, sizeof(*this))))
1822 return E_OUTOFMEMORY;
1824 list_init(&this->results);
1825 InitializeCriticalSection(&this->cs);
1827 this->IMFByteStreamHandler_iface.lpVtbl = &winegstreamer_stream_handler_vtbl;
1828 this->IMFAsyncCallback_iface.lpVtbl = &winegstreamer_stream_handler_callback_vtbl;
1829 this->refcount = 1;
1831 hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj);
1832 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
1834 return hr;