wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / winegstreamer / media_source.c
blobeb5b9e366ecc416438c5bdba2edd1f48fba4b2d9
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 free(command);
176 return refcount;
179 static const IUnknownVtbl source_async_command_vtbl =
181 source_async_command_QueryInterface,
182 source_async_command_AddRef,
183 source_async_command_Release,
186 static HRESULT source_create_async_op(enum source_async_op op, struct source_async_command **ret)
188 struct source_async_command *command;
190 if (!(command = calloc(1, sizeof(*command))))
191 return E_OUTOFMEMORY;
193 command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
194 command->op = op;
196 *ret = command;
198 return S_OK;
201 static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
203 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
205 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
206 IsEqualIID(riid, &IID_IUnknown))
208 *obj = iface;
209 IMFAsyncCallback_AddRef(iface);
210 return S_OK;
213 WARN("Unsupported %s.\n", debugstr_guid(riid));
214 *obj = NULL;
215 return E_NOINTERFACE;
218 static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
219 DWORD *flags, DWORD *queue)
221 return E_NOTIMPL;
224 static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
226 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
227 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
230 static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
232 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
233 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
236 static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected)
238 ULONG sd_count;
239 IMFStreamDescriptor *ret;
240 unsigned int i;
242 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count)))
243 return NULL;
245 for (i = 0; i < sd_count; i++)
247 DWORD stream_id;
249 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret)))
250 return NULL;
252 if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id)
253 return ret;
255 IMFStreamDescriptor_Release(ret);
257 return NULL;
260 static void start_pipeline(struct media_source *source, struct source_async_command *command)
262 PROPVARIANT *position = &command->u.start.position;
263 BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY;
264 unsigned int i;
266 /* seek to beginning on stop->play */
267 if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY)
269 position->vt = VT_I8;
270 position->hVal.QuadPart = 0;
272 source->start_time = position->hVal.QuadPart;
274 for (i = 0; i < source->stream_count; i++)
276 struct media_stream *stream;
277 IMFStreamDescriptor *sd;
278 IMFMediaTypeHandler *mth;
279 IMFMediaType *current_mt;
280 DWORD stream_id;
281 BOOL was_active;
282 BOOL selected;
284 stream = source->streams[i];
286 IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id);
288 sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected);
289 IMFStreamDescriptor_Release(sd);
291 was_active = stream->state != STREAM_INACTIVE;
293 stream->state = selected ? STREAM_RUNNING : STREAM_INACTIVE;
295 if (selected)
297 struct wg_format format;
299 IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &mth);
300 IMFMediaTypeHandler_GetCurrentMediaType(mth, &current_mt);
302 mf_media_type_to_wg_format(current_mt, &format);
303 unix_funcs->wg_parser_stream_enable(stream->wg_stream, &format);
305 IMFMediaType_Release(current_mt);
306 IMFMediaTypeHandler_Release(mth);
309 if (position->vt != VT_EMPTY)
310 stream->eos = FALSE;
312 if (selected)
314 TRACE("Stream %u (%p) selected\n", i, stream);
315 IMFMediaEventQueue_QueueEventParamUnk(source->event_queue,
316 was_active ? MEUpdatedStream : MENewStream, &GUID_NULL,
317 S_OK, (IUnknown*) &stream->IMFMediaStream_iface);
319 IMFMediaEventQueue_QueueEventParamVar(stream->event_queue,
320 seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position);
324 IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
325 seek_message ? MESourceSeeked : MESourceStarted,
326 &GUID_NULL, S_OK, position);
328 source->state = SOURCE_RUNNING;
330 unix_funcs->wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0,
331 position->hVal.QuadPart, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
332 unix_funcs->wg_parser_end_flush(source->wg_parser);
335 static void stop_pipeline(struct media_source *source)
337 unsigned int i;
339 unix_funcs->wg_parser_begin_flush(source->wg_parser);
341 for (i = 0; i < source->stream_count; i++)
343 struct media_stream *stream = source->streams[i];
344 if (stream->state != STREAM_INACTIVE)
346 IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, &GUID_NULL, S_OK, NULL);
347 unix_funcs->wg_parser_stream_disable(stream->wg_stream);
351 IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL);
353 source->state = SOURCE_STOPPED;
356 static void dispatch_end_of_presentation(struct media_source *source)
358 PROPVARIANT empty = {.vt = VT_EMPTY};
359 unsigned int i;
361 /* A stream has ended, check whether all have */
362 for (i = 0; i < source->stream_count; i++)
364 struct media_stream *stream = source->streams[i];
366 if (stream->state != STREAM_INACTIVE && !stream->eos)
367 return;
370 IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty);
373 static void send_buffer(struct media_stream *stream, const struct wg_parser_event *event, IUnknown *token)
375 IMFMediaBuffer *buffer;
376 IMFSample *sample;
377 HRESULT hr;
378 BYTE *data;
380 if (FAILED(hr = MFCreateSample(&sample)))
382 ERR("Failed to create sample, hr %#x.\n", hr);
383 return;
386 if (FAILED(hr = MFCreateMemoryBuffer(event->u.buffer.size, &buffer)))
388 ERR("Failed to create buffer, hr %#x.\n", hr);
389 IMFSample_Release(sample);
390 return;
393 if (FAILED(hr = IMFSample_AddBuffer(sample, buffer)))
395 ERR("Failed to add buffer, hr %#x.\n", hr);
396 goto out;
399 if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event->u.buffer.size)))
401 ERR("Failed to set size, hr %#x.\n", hr);
402 goto out;
405 if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL)))
407 ERR("Failed to lock buffer, hr %#x.\n", hr);
408 goto out;
411 if (!unix_funcs->wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, event->u.buffer.size))
413 unix_funcs->wg_parser_stream_release_buffer(stream->wg_stream);
414 IMFMediaBuffer_Unlock(buffer);
415 goto out;
417 unix_funcs->wg_parser_stream_release_buffer(stream->wg_stream);
419 if (FAILED(hr = IMFMediaBuffer_Unlock(buffer)))
421 ERR("Failed to unlock buffer, hr %#x.\n", hr);
422 goto out;
425 if (FAILED(hr = IMFSample_SetSampleTime(sample, event->u.buffer.pts - stream->parent_source->start_time)))
427 ERR("Failed to set sample time, hr %#x.\n", hr);
428 goto out;
431 if (FAILED(hr = IMFSample_SetSampleDuration(sample, event->u.buffer.duration)))
433 ERR("Failed to set sample duration, hr %#x.\n", hr);
434 goto out;
437 if (token)
438 IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
440 IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
441 &GUID_NULL, S_OK, (IUnknown *)sample);
443 out:
444 IMFMediaBuffer_Release(buffer);
445 IMFSample_Release(sample);
448 static void wait_on_sample(struct media_stream *stream, IUnknown *token)
450 PROPVARIANT empty_var = {.vt = VT_EMPTY};
451 struct wg_parser_event event;
453 TRACE("%p, %p\n", stream, token);
455 for (;;)
457 if (!unix_funcs->wg_parser_stream_get_event(stream->wg_stream, &event))
458 return;
460 TRACE("Got event of type %#x.\n", event.type);
462 switch (event.type)
464 case WG_PARSER_EVENT_BUFFER:
465 send_buffer(stream, &event, token);
466 return;
468 case WG_PARSER_EVENT_EOS:
469 stream->eos = TRUE;
470 if (token)
471 IUnknown_Release(token);
472 IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var);
473 dispatch_end_of_presentation(stream->parent_source);
474 return;
476 case WG_PARSER_EVENT_SEGMENT:
477 break;
479 case WG_PARSER_EVENT_NONE:
480 assert(0);
485 static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
487 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
488 struct source_async_command *command;
489 IUnknown *state;
490 HRESULT hr;
492 if (source->state == SOURCE_SHUTDOWN)
493 return S_OK;
495 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
496 return hr;
498 command = impl_from_async_command_IUnknown(state);
499 switch (command->op)
501 case SOURCE_ASYNC_START:
502 start_pipeline(source, command);
503 break;
504 case SOURCE_ASYNC_STOP:
505 stop_pipeline(source);
506 break;
507 case SOURCE_ASYNC_REQUEST_SAMPLE:
508 wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token);
509 break;
512 IUnknown_Release(state);
514 return S_OK;
517 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
519 callback_QueryInterface,
520 source_async_commands_callback_AddRef,
521 source_async_commands_callback_Release,
522 callback_GetParameters,
523 source_async_commands_Invoke,
526 static DWORD CALLBACK read_thread(void *arg)
528 struct media_source *source = arg;
529 IMFByteStream *byte_stream = source->byte_stream;
531 TRACE("Starting read thread for media source %p.\n", source);
533 while (!source->read_thread_shutdown)
535 uint64_t offset;
536 ULONG ret_size;
537 uint32_t size;
538 HRESULT hr;
539 void *data;
541 if (!unix_funcs->wg_parser_get_read_request(source->wg_parser, &data, &offset, &size))
542 continue;
544 if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset)))
545 hr = IMFByteStream_Read(byte_stream, data, size, &ret_size);
546 if (SUCCEEDED(hr) && ret_size != size)
547 ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size);
548 unix_funcs->wg_parser_complete_read_request(source->wg_parser, SUCCEEDED(hr));
551 TRACE("Media source is shutting down; exiting.\n");
552 return 0;
555 static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
557 struct media_stream *stream = impl_from_IMFMediaStream(iface);
559 TRACE("(%p)->(%s %p)\n", stream, debugstr_guid(riid), out);
561 if (IsEqualIID(riid, &IID_IMFMediaStream) ||
562 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
563 IsEqualIID(riid, &IID_IUnknown))
565 *out = &stream->IMFMediaStream_iface;
567 else
569 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
570 *out = NULL;
571 return E_NOINTERFACE;
574 IUnknown_AddRef((IUnknown*)*out);
575 return S_OK;
578 static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
580 struct media_stream *stream = impl_from_IMFMediaStream(iface);
581 ULONG ref = InterlockedIncrement(&stream->ref);
583 TRACE("(%p) ref=%u\n", stream, ref);
585 return ref;
588 static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
590 struct media_stream *stream = impl_from_IMFMediaStream(iface);
592 ULONG ref = InterlockedDecrement(&stream->ref);
594 TRACE("(%p) ref=%u\n", stream, ref);
596 if (!ref)
598 if (stream->event_queue)
599 IMFMediaEventQueue_Release(stream->event_queue);
600 free(stream);
603 return ref;
606 static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
608 struct media_stream *stream = impl_from_IMFMediaStream(iface);
610 TRACE("(%p)->(%#x, %p)\n", stream, flags, event);
612 return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
615 static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
617 struct media_stream *stream = impl_from_IMFMediaStream(iface);
619 TRACE("(%p)->(%p, %p)\n", stream, callback, state);
621 return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
624 static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
626 struct media_stream *stream = impl_from_IMFMediaStream(iface);
628 TRACE("(%p)->(%p, %p)\n", stream, result, event);
630 return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
633 static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
634 HRESULT hr, const PROPVARIANT *value)
636 struct media_stream *stream = impl_from_IMFMediaStream(iface);
638 TRACE("(%p)->(%d, %s, %#x, %p)\n", stream, event_type, debugstr_guid(ext_type), hr, value);
640 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
643 static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source)
645 struct media_stream *stream = impl_from_IMFMediaStream(iface);
647 TRACE("(%p)->(%p)\n", stream, source);
649 if (stream->state == STREAM_SHUTDOWN)
650 return MF_E_SHUTDOWN;
652 IMFMediaSource_AddRef(&stream->parent_source->IMFMediaSource_iface);
653 *source = &stream->parent_source->IMFMediaSource_iface;
655 return S_OK;
658 static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
660 struct media_stream *stream = impl_from_IMFMediaStream(iface);
662 TRACE("(%p)->(%p)\n", stream, descriptor);
664 if (stream->state == STREAM_SHUTDOWN)
665 return MF_E_SHUTDOWN;
667 IMFStreamDescriptor_AddRef(stream->descriptor);
668 *descriptor = stream->descriptor;
670 return S_OK;
673 static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
675 struct media_stream *stream = impl_from_IMFMediaStream(iface);
676 struct source_async_command *command;
677 HRESULT hr;
679 TRACE("(%p)->(%p)\n", iface, token);
681 if (stream->state == STREAM_SHUTDOWN)
682 return MF_E_SHUTDOWN;
684 if (stream->state == STREAM_INACTIVE)
686 WARN("Stream isn't active\n");
687 return MF_E_MEDIA_SOURCE_WRONGSTATE;
690 if (stream->eos)
692 return MF_E_END_OF_STREAM;
695 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command)))
697 command->u.request_sample.stream = stream;
698 if (token)
699 IUnknown_AddRef(token);
700 command->u.request_sample.token = token;
702 /* Once pause support is added, this will need to put into a stream queue, and synchronization will need to be added*/
703 hr = MFPutWorkItem(stream->parent_source->async_commands_queue, &stream->parent_source->async_commands_callback, &command->IUnknown_iface);
706 return hr;
709 static const IMFMediaStreamVtbl media_stream_vtbl =
711 media_stream_QueryInterface,
712 media_stream_AddRef,
713 media_stream_Release,
714 media_stream_GetEvent,
715 media_stream_BeginGetEvent,
716 media_stream_EndGetEvent,
717 media_stream_QueueEvent,
718 media_stream_GetMediaSource,
719 media_stream_GetStreamDescriptor,
720 media_stream_RequestSample
723 static HRESULT new_media_stream(struct media_source *source,
724 struct wg_parser_stream *wg_stream, DWORD stream_id, struct media_stream **out_stream)
726 struct media_stream *object = calloc(1, sizeof(*object));
727 HRESULT hr;
729 TRACE("source %p, wg_stream %p, stream_id %u.\n", source, wg_stream, stream_id);
731 object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
732 object->ref = 1;
734 IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
735 object->parent_source = source;
736 object->stream_id = stream_id;
738 object->state = STREAM_INACTIVE;
739 object->eos = FALSE;
740 object->wg_stream = wg_stream;
742 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
743 goto fail;
745 TRACE("->(%p)\n", object);
746 *out_stream = object;
748 return S_OK;
750 fail:
751 WARN("Failed to construct media stream, hr %#x.\n", hr);
753 IMFMediaStream_Release(&object->IMFMediaStream_iface);
754 return hr;
757 static HRESULT media_stream_init_desc(struct media_stream *stream)
759 IMFMediaTypeHandler *type_handler = NULL;
760 IMFMediaType **stream_types = NULL;
761 IMFMediaType *stream_type = NULL;
762 struct wg_format format;
763 DWORD type_count = 0;
764 unsigned int i;
765 HRESULT hr;
767 unix_funcs->wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
769 if (format.major_type == WG_MAJOR_TYPE_VIDEO)
771 /* These are the most common native output types of decoders:
772 https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */
773 static const GUID *const video_types[] =
775 &MFVideoFormat_NV12,
776 &MFVideoFormat_YV12,
777 &MFVideoFormat_YUY2,
778 &MFVideoFormat_IYUV,
779 &MFVideoFormat_I420,
782 IMFMediaType *base_type = mf_media_type_from_wg_format(&format);
783 GUID base_subtype;
785 IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype);
787 stream_types = malloc(sizeof(IMFMediaType *) * (ARRAY_SIZE(video_types) + 1));
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
811 stream_type = mf_media_type_from_wg_format(&format);
812 if (stream_type)
814 stream_types = &stream_type;
815 type_count = 1;
819 if (!type_count)
821 ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
822 return E_FAIL;
825 if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, type_count, stream_types, &stream->descriptor)))
826 goto done;
828 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
829 goto done;
831 if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0])))
832 goto done;
834 done:
835 if (type_handler)
836 IMFMediaTypeHandler_Release(type_handler);
837 for (i = 0; i < type_count; i++)
838 IMFMediaType_Release(stream_types[i]);
839 if (stream_types != &stream_type)
840 free(stream_types);
841 return hr;
844 static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
846 struct media_source *source = impl_from_IMFGetService(iface);
847 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
850 static ULONG WINAPI media_source_get_service_AddRef(IMFGetService *iface)
852 struct media_source *source = impl_from_IMFGetService(iface);
853 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
856 static ULONG WINAPI media_source_get_service_Release(IMFGetService *iface)
858 struct media_source *source = impl_from_IMFGetService(iface);
859 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
862 static HRESULT WINAPI media_source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
864 struct media_source *source = impl_from_IMFGetService(iface);
866 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
868 *obj = NULL;
870 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
872 if (IsEqualIID(riid, &IID_IMFRateSupport))
874 *obj = &source->IMFRateSupport_iface;
876 else if (IsEqualIID(riid, &IID_IMFRateControl))
878 *obj = &source->IMFRateControl_iface;
881 else
882 FIXME("Unsupported service %s.\n", debugstr_guid(service));
884 if (*obj)
885 IUnknown_AddRef((IUnknown *)*obj);
887 return *obj ? S_OK : E_NOINTERFACE;
890 static const IMFGetServiceVtbl media_source_get_service_vtbl =
892 media_source_get_service_QueryInterface,
893 media_source_get_service_AddRef,
894 media_source_get_service_Release,
895 media_source_get_service_GetService,
898 static HRESULT WINAPI media_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
900 struct media_source *source = impl_from_IMFRateSupport(iface);
901 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
904 static ULONG WINAPI media_source_rate_support_AddRef(IMFRateSupport *iface)
906 struct media_source *source = impl_from_IMFRateSupport(iface);
907 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
910 static ULONG WINAPI media_source_rate_support_Release(IMFRateSupport *iface)
912 struct media_source *source = impl_from_IMFRateSupport(iface);
913 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
916 static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
918 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
920 if (direction == MFRATE_REVERSE)
921 return MF_E_REVERSE_UNSUPPORTED;
923 if (thin)
924 return MF_E_THINNING_UNSUPPORTED;
926 *rate = 1.0f;
928 return S_OK;
931 static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
933 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
935 if (direction == MFRATE_REVERSE)
936 return MF_E_REVERSE_UNSUPPORTED;
938 if (thin)
939 return MF_E_THINNING_UNSUPPORTED;
941 *rate = 1.0f;
943 return S_OK;
946 static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate, float *nearest_support_rate)
948 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_support_rate);
950 if (rate < 0.0f)
951 return MF_E_REVERSE_UNSUPPORTED;
953 if (thin)
954 return MF_E_THINNING_UNSUPPORTED;
956 if (nearest_support_rate)
957 *nearest_support_rate = 1.0f;
959 return rate == 1.0f ? S_OK : MF_E_UNSUPPORTED_RATE;
962 static const IMFRateSupportVtbl media_source_rate_support_vtbl =
964 media_source_rate_support_QueryInterface,
965 media_source_rate_support_AddRef,
966 media_source_rate_support_Release,
967 media_source_rate_support_GetSlowestRate,
968 media_source_rate_support_GetFastestRate,
969 media_source_rate_support_IsRateSupported,
972 static HRESULT WINAPI media_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
974 struct media_source *source = impl_from_IMFRateControl(iface);
975 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
978 static ULONG WINAPI media_source_rate_control_AddRef(IMFRateControl *iface)
980 struct media_source *source = impl_from_IMFRateControl(iface);
981 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
984 static ULONG WINAPI media_source_rate_control_Release(IMFRateControl *iface)
986 struct media_source *source = impl_from_IMFRateControl(iface);
987 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
990 static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
992 FIXME("%p, %d, %f.\n", iface, thin, rate);
994 if (rate < 0.0f)
995 return MF_E_REVERSE_UNSUPPORTED;
997 if (thin)
998 return MF_E_THINNING_UNSUPPORTED;
1000 if (rate != 1.0f)
1001 return MF_E_UNSUPPORTED_RATE;
1003 return S_OK;
1006 static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
1008 TRACE("%p, %p, %p.\n", iface, thin, rate);
1010 if (thin)
1011 *thin = FALSE;
1013 *rate = 1.0f;
1015 return S_OK;
1018 static const IMFRateControlVtbl media_source_rate_control_vtbl =
1020 media_source_rate_control_QueryInterface,
1021 media_source_rate_control_AddRef,
1022 media_source_rate_control_Release,
1023 media_source_rate_control_SetRate,
1024 media_source_rate_control_GetRate,
1027 static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
1029 struct media_source *source = impl_from_IMFMediaSource(iface);
1031 TRACE("(%p)->(%s %p)\n", source, debugstr_guid(riid), out);
1033 if (IsEqualIID(riid, &IID_IMFMediaSource) ||
1034 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1035 IsEqualIID(riid, &IID_IUnknown))
1037 *out = &source->IMFMediaSource_iface;
1039 else if (IsEqualIID(riid, &IID_IMFGetService))
1041 *out = &source->IMFGetService_iface;
1043 else
1045 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
1046 *out = NULL;
1047 return E_NOINTERFACE;
1050 IUnknown_AddRef((IUnknown*)*out);
1051 return S_OK;
1054 static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface)
1056 struct media_source *source = impl_from_IMFMediaSource(iface);
1057 ULONG ref = InterlockedIncrement(&source->ref);
1059 TRACE("(%p) ref=%u\n", source, ref);
1061 return ref;
1064 static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
1066 struct media_source *source = impl_from_IMFMediaSource(iface);
1067 ULONG ref = InterlockedDecrement(&source->ref);
1069 TRACE("(%p) ref=%u\n", source, ref);
1071 if (!ref)
1073 IMFMediaSource_Shutdown(&source->IMFMediaSource_iface);
1074 IMFMediaEventQueue_Release(source->event_queue);
1075 free(source);
1078 return ref;
1081 static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
1083 struct media_source *source = impl_from_IMFMediaSource(iface);
1085 TRACE("(%p)->(%#x, %p)\n", source, flags, event);
1087 return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
1090 static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
1092 struct media_source *source = impl_from_IMFMediaSource(iface);
1094 TRACE("(%p)->(%p, %p)\n", source, callback, state);
1096 return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
1099 static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1101 struct media_source *source = impl_from_IMFMediaSource(iface);
1103 TRACE("(%p)->(%p, %p)\n", source, result, event);
1105 return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
1108 static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
1109 HRESULT hr, const PROPVARIANT *value)
1111 struct media_source *source = impl_from_IMFMediaSource(iface);
1113 TRACE("(%p)->(%d, %s, %#x, %p)\n", source, event_type, debugstr_guid(ext_type), hr, value);
1115 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
1118 static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
1120 struct media_source *source = impl_from_IMFMediaSource(iface);
1122 TRACE("(%p)->(%p)\n", source, characteristics);
1124 if (source->state == SOURCE_SHUTDOWN)
1125 return MF_E_SHUTDOWN;
1127 *characteristics = MFMEDIASOURCE_CAN_SEEK;
1129 return S_OK;
1132 static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
1134 struct media_source *source = impl_from_IMFMediaSource(iface);
1136 TRACE("(%p)->(%p)\n", source, descriptor);
1138 if (source->state == SOURCE_SHUTDOWN)
1139 return MF_E_SHUTDOWN;
1141 return IMFPresentationDescriptor_Clone(source->pres_desc, descriptor);
1144 static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
1145 const GUID *time_format, const PROPVARIANT *position)
1147 struct media_source *source = impl_from_IMFMediaSource(iface);
1148 struct source_async_command *command;
1149 HRESULT hr;
1151 TRACE("(%p)->(%p, %p, %p)\n", source, descriptor, time_format, position);
1153 if (source->state == SOURCE_SHUTDOWN)
1154 return MF_E_SHUTDOWN;
1156 if (!(IsEqualIID(time_format, &GUID_NULL)))
1157 return MF_E_UNSUPPORTED_TIME_FORMAT;
1159 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command)))
1161 command->u.start.descriptor = descriptor;
1162 command->u.start.format = *time_format;
1163 PropVariantCopy(&command->u.start.position, position);
1165 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
1168 return hr;
1171 static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
1173 struct media_source *source = impl_from_IMFMediaSource(iface);
1174 struct source_async_command *command;
1175 HRESULT hr;
1177 TRACE("(%p)\n", source);
1179 if (source->state == SOURCE_SHUTDOWN)
1180 return MF_E_SHUTDOWN;
1182 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command)))
1183 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
1185 return hr;
1188 static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
1190 struct media_source *source = impl_from_IMFMediaSource(iface);
1192 FIXME("(%p): stub\n", source);
1194 if (source->state == SOURCE_SHUTDOWN)
1195 return MF_E_SHUTDOWN;
1197 return E_NOTIMPL;
1200 static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
1202 struct media_source *source = impl_from_IMFMediaSource(iface);
1203 unsigned int i;
1205 TRACE("(%p)\n", source);
1207 if (source->state == SOURCE_SHUTDOWN)
1208 return MF_E_SHUTDOWN;
1210 source->state = SOURCE_SHUTDOWN;
1212 unix_funcs->wg_parser_disconnect(source->wg_parser);
1214 if (source->pres_desc)
1215 IMFPresentationDescriptor_Release(source->pres_desc);
1216 if (source->event_queue)
1217 IMFMediaEventQueue_Shutdown(source->event_queue);
1218 if (source->byte_stream)
1219 IMFByteStream_Release(source->byte_stream);
1221 for (i = 0; i < source->stream_count; i++)
1223 struct media_stream *stream = source->streams[i];
1225 stream->state = STREAM_SHUTDOWN;
1227 if (stream->event_queue)
1228 IMFMediaEventQueue_Shutdown(stream->event_queue);
1229 if (stream->descriptor)
1230 IMFStreamDescriptor_Release(stream->descriptor);
1231 if (stream->parent_source)
1232 IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
1234 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1237 if (source->read_thread)
1239 source->read_thread_shutdown = true;
1240 WaitForSingleObject(source->read_thread, INFINITE);
1241 CloseHandle(source->read_thread);
1244 unix_funcs->wg_parser_destroy(source->wg_parser);
1246 if (source->stream_count)
1247 free(source->streams);
1249 if (source->async_commands_queue)
1250 MFUnlockWorkQueue(source->async_commands_queue);
1252 return S_OK;
1255 static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
1257 media_source_QueryInterface,
1258 media_source_AddRef,
1259 media_source_Release,
1260 media_source_GetEvent,
1261 media_source_BeginGetEvent,
1262 media_source_EndGetEvent,
1263 media_source_QueueEvent,
1264 media_source_GetCharacteristics,
1265 media_source_CreatePresentationDescriptor,
1266 media_source_Start,
1267 media_source_Stop,
1268 media_source_Pause,
1269 media_source_Shutdown,
1272 static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
1274 IMFStreamDescriptor **descriptors = NULL;
1275 struct media_source *object;
1276 UINT64 total_pres_time = 0;
1277 struct wg_parser *parser;
1278 DWORD bytestream_caps;
1279 uint64_t file_size;
1280 unsigned int i;
1281 HRESULT hr;
1283 if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps)))
1284 return hr;
1286 if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE))
1288 FIXME("Non-seekable bytestreams not supported.\n");
1289 return MF_E_BYTESTREAM_NOT_SEEKABLE;
1292 if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size)))
1294 FIXME("Failed to get byte stream length, hr %#x.\n", hr);
1295 return hr;
1298 if (!(object = calloc(1, sizeof(*object))))
1299 return E_OUTOFMEMORY;
1301 object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
1302 object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl;
1303 object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl;
1304 object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl;
1305 object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
1306 object->ref = 1;
1307 object->byte_stream = bytestream;
1308 IMFByteStream_AddRef(bytestream);
1310 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1311 goto fail;
1313 if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
1314 goto fail;
1316 object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL);
1318 if (!(parser = unix_funcs->wg_decodebin_parser_create()))
1320 hr = E_OUTOFMEMORY;
1321 goto fail;
1323 object->wg_parser = parser;
1325 object->state = SOURCE_OPENING;
1327 if (FAILED(hr = unix_funcs->wg_parser_connect(parser, file_size)))
1328 goto fail;
1330 /* In Media Foundation, sources may read from any media source stream
1331 * without fear of blocking due to buffering limits on another. Trailmakers,
1332 * a Unity3D Engine game, only reads one sample from the audio stream (and
1333 * never deselects it). Remove buffering limits from decodebin in order to
1334 * account for this. Note that this does leak memory, but the same memory
1335 * leak occurs with native. */
1336 unix_funcs->wg_parser_set_unlimited_buffering(parser);
1338 object->stream_count = unix_funcs->wg_parser_get_stream_count(parser);
1340 if (!(object->streams = calloc(object->stream_count, sizeof(*object->streams))))
1342 hr = E_OUTOFMEMORY;
1343 goto fail;
1346 for (i = 0; i < object->stream_count; ++i)
1348 if (FAILED(hr = new_media_stream(object, unix_funcs->wg_parser_get_stream(parser, i), i, &object->streams[i])))
1349 goto fail;
1351 if (FAILED(hr = media_stream_init_desc(object->streams[i])))
1353 ERR("Failed to finish initialization of media stream %p, hr %x.\n", object->streams[i], hr);
1354 IMFMediaStream_Release(&object->streams[i]->IMFMediaStream_iface);
1355 goto fail;
1359 /* init presentation descriptor */
1361 descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *));
1362 for (i = 0; i < object->stream_count; i++)
1364 IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]);
1367 if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc)))
1368 goto fail;
1370 for (i = 0; i < object->stream_count; i++)
1372 IMFPresentationDescriptor_SelectStream(object->pres_desc, i);
1373 IMFStreamDescriptor_Release(descriptors[i]);
1375 free(descriptors);
1376 descriptors = NULL;
1378 for (i = 0; i < object->stream_count; i++)
1379 total_pres_time = max(total_pres_time,
1380 unix_funcs->wg_parser_stream_get_duration(object->streams[i]->wg_stream));
1382 if (object->stream_count)
1383 IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time);
1385 object->state = SOURCE_STOPPED;
1387 *out_media_source = object;
1388 return S_OK;
1390 fail:
1391 WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
1393 free(descriptors);
1394 IMFMediaSource_Release(&object->IMFMediaSource_iface);
1395 return hr;
1398 struct winegstreamer_stream_handler_result
1400 struct list entry;
1401 IMFAsyncResult *result;
1402 MF_OBJECT_TYPE obj_type;
1403 IUnknown *object;
1406 struct winegstreamer_stream_handler
1408 IMFByteStreamHandler IMFByteStreamHandler_iface;
1409 IMFAsyncCallback IMFAsyncCallback_iface;
1410 LONG refcount;
1411 struct list results;
1412 CRITICAL_SECTION cs;
1415 static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
1417 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFByteStreamHandler_iface);
1420 static struct winegstreamer_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
1422 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFAsyncCallback_iface);
1425 static HRESULT WINAPI winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj)
1427 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1429 if (IsEqualIID(riid, &IID_IMFByteStreamHandler) ||
1430 IsEqualIID(riid, &IID_IUnknown))
1432 *obj = iface;
1433 IMFByteStreamHandler_AddRef(iface);
1434 return S_OK;
1437 WARN("Unsupported %s.\n", debugstr_guid(riid));
1438 *obj = NULL;
1439 return E_NOINTERFACE;
1442 static ULONG WINAPI winegstreamer_stream_handler_AddRef(IMFByteStreamHandler *iface)
1444 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1445 ULONG refcount = InterlockedIncrement(&handler->refcount);
1447 TRACE("%p, refcount %u.\n", handler, refcount);
1449 return refcount;
1452 static ULONG WINAPI winegstreamer_stream_handler_Release(IMFByteStreamHandler *iface)
1454 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1455 ULONG refcount = InterlockedDecrement(&handler->refcount);
1456 struct winegstreamer_stream_handler_result *result, *next;
1458 TRACE("%p, refcount %u.\n", iface, refcount);
1460 if (!refcount)
1462 LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct winegstreamer_stream_handler_result, entry)
1464 list_remove(&result->entry);
1465 IMFAsyncResult_Release(result->result);
1466 if (result->object)
1467 IUnknown_Release(result->object);
1468 free(result);
1470 DeleteCriticalSection(&handler->cs);
1471 free(handler);
1474 return refcount;
1477 struct create_object_context
1479 IUnknown IUnknown_iface;
1480 LONG refcount;
1482 IPropertyStore *props;
1483 IMFByteStream *stream;
1484 WCHAR *url;
1485 DWORD flags;
1488 static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
1490 return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
1493 static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
1495 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1497 if (IsEqualIID(riid, &IID_IUnknown))
1499 *obj = iface;
1500 IUnknown_AddRef(iface);
1501 return S_OK;
1504 WARN("Unsupported %s.\n", debugstr_guid(riid));
1505 *obj = NULL;
1506 return E_NOINTERFACE;
1509 static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
1511 struct create_object_context *context = impl_from_IUnknown(iface);
1512 ULONG refcount = InterlockedIncrement(&context->refcount);
1514 TRACE("%p, refcount %u.\n", iface, refcount);
1516 return refcount;
1519 static ULONG WINAPI create_object_context_Release(IUnknown *iface)
1521 struct create_object_context *context = impl_from_IUnknown(iface);
1522 ULONG refcount = InterlockedDecrement(&context->refcount);
1524 TRACE("%p, refcount %u.\n", iface, refcount);
1526 if (!refcount)
1528 if (context->props)
1529 IPropertyStore_Release(context->props);
1530 if (context->stream)
1531 IMFByteStream_Release(context->stream);
1532 free(context->url);
1533 free(context);
1536 return refcount;
1539 static const IUnknownVtbl create_object_context_vtbl =
1541 create_object_context_QueryInterface,
1542 create_object_context_AddRef,
1543 create_object_context_Release,
1546 static HRESULT WINAPI winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
1547 IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
1549 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1550 struct create_object_context *context;
1551 IMFAsyncResult *caller, *item;
1552 HRESULT hr;
1554 TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
1556 if (cancel_cookie)
1557 *cancel_cookie = NULL;
1559 if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
1560 return hr;
1562 if (!(context = calloc(1, sizeof(*context))))
1564 IMFAsyncResult_Release(caller);
1565 return E_OUTOFMEMORY;
1568 context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
1569 context->refcount = 1;
1570 context->props = props;
1571 if (context->props)
1572 IPropertyStore_AddRef(context->props);
1573 context->flags = flags;
1574 context->stream = stream;
1575 if (context->stream)
1576 IMFByteStream_AddRef(context->stream);
1577 if (url)
1578 context->url = wcsdup(url);
1579 if (!context->stream)
1581 IMFAsyncResult_Release(caller);
1582 IUnknown_Release(&context->IUnknown_iface);
1583 return E_OUTOFMEMORY;
1586 hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
1587 IUnknown_Release(&context->IUnknown_iface);
1588 if (SUCCEEDED(hr))
1590 if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
1592 if (cancel_cookie)
1594 *cancel_cookie = (IUnknown *)caller;
1595 IUnknown_AddRef(*cancel_cookie);
1599 IMFAsyncResult_Release(item);
1601 IMFAsyncResult_Release(caller);
1603 return hr;
1606 static HRESULT WINAPI winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
1607 MF_OBJECT_TYPE *obj_type, IUnknown **object)
1609 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1610 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1611 HRESULT hr;
1613 TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
1615 EnterCriticalSection(&this->cs);
1617 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1619 if (result == cur->result)
1621 list_remove(&cur->entry);
1622 found = cur;
1623 break;
1627 LeaveCriticalSection(&this->cs);
1629 if (found)
1631 *obj_type = found->obj_type;
1632 *object = found->object;
1633 hr = IMFAsyncResult_GetStatus(found->result);
1634 IMFAsyncResult_Release(found->result);
1635 free(found);
1637 else
1639 *obj_type = MF_OBJECT_INVALID;
1640 *object = NULL;
1641 hr = MF_E_UNEXPECTED;
1644 return hr;
1647 static HRESULT WINAPI winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie)
1649 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1650 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1652 TRACE("%p, %p.\n", iface, cancel_cookie);
1654 EnterCriticalSection(&this->cs);
1656 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1658 if (cancel_cookie == (IUnknown *)cur->result)
1660 list_remove(&cur->entry);
1661 found = cur;
1662 break;
1666 LeaveCriticalSection(&this->cs);
1668 if (found)
1670 IMFAsyncResult_Release(found->result);
1671 if (found->object)
1672 IUnknown_Release(found->object);
1673 free(found);
1676 return found ? S_OK : MF_E_UNEXPECTED;
1679 static HRESULT WINAPI winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes)
1681 FIXME("stub (%p %p)\n", iface, bytes);
1682 return E_NOTIMPL;
1685 static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl =
1687 winegstreamer_stream_handler_QueryInterface,
1688 winegstreamer_stream_handler_AddRef,
1689 winegstreamer_stream_handler_Release,
1690 winegstreamer_stream_handler_BeginCreateObject,
1691 winegstreamer_stream_handler_EndCreateObject,
1692 winegstreamer_stream_handler_CancelObjectCreation,
1693 winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
1696 static HRESULT WINAPI winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
1698 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1699 IsEqualIID(riid, &IID_IUnknown))
1701 *obj = iface;
1702 IMFAsyncCallback_AddRef(iface);
1703 return S_OK;
1706 WARN("Unsupported %s.\n", debugstr_guid(riid));
1707 *obj = NULL;
1708 return E_NOINTERFACE;
1711 static ULONG WINAPI winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback *iface)
1713 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1714 return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
1717 static ULONG WINAPI winegstreamer_stream_handler_callback_Release(IMFAsyncCallback *iface)
1719 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1720 return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
1723 static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
1725 return E_NOTIMPL;
1728 static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags,
1729 IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type)
1731 TRACE("(%p %s %p %u %p %p %p)\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type);
1733 if (flags & MF_RESOLUTION_MEDIASOURCE)
1735 HRESULT hr;
1736 struct media_source *new_source;
1738 if (FAILED(hr = media_source_constructor(stream, &new_source)))
1739 return hr;
1741 TRACE("->(%p)\n", new_source);
1743 *out_object = (IUnknown*)&new_source->IMFMediaSource_iface;
1744 *out_obj_type = MF_OBJECT_MEDIASOURCE;
1746 return S_OK;
1748 else
1750 FIXME("flags = %08x\n", flags);
1751 return E_NOTIMPL;
1755 static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1757 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1758 struct winegstreamer_stream_handler_result *handler_result;
1759 MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID;
1760 IUnknown *object = NULL, *context_object;
1761 struct create_object_context *context;
1762 IMFAsyncResult *caller;
1763 HRESULT hr;
1765 caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
1767 if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
1769 WARN("Expected context set for callee result.\n");
1770 return hr;
1773 context = impl_from_IUnknown(context_object);
1775 hr = winegstreamer_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type);
1777 if ((handler_result = malloc(sizeof(*handler_result))))
1779 handler_result->result = caller;
1780 IMFAsyncResult_AddRef(handler_result->result);
1781 handler_result->obj_type = obj_type;
1782 handler_result->object = object;
1784 EnterCriticalSection(&handler->cs);
1785 list_add_tail(&handler->results, &handler_result->entry);
1786 LeaveCriticalSection(&handler->cs);
1788 else
1790 if (object)
1791 IUnknown_Release(object);
1792 hr = E_OUTOFMEMORY;
1795 IUnknown_Release(&context->IUnknown_iface);
1797 IMFAsyncResult_SetStatus(caller, hr);
1798 MFInvokeCallback(caller);
1800 return S_OK;
1803 static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl =
1805 winegstreamer_stream_handler_callback_QueryInterface,
1806 winegstreamer_stream_handler_callback_AddRef,
1807 winegstreamer_stream_handler_callback_Release,
1808 winegstreamer_stream_handler_callback_GetParameters,
1809 winegstreamer_stream_handler_callback_Invoke,
1812 HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj)
1814 struct winegstreamer_stream_handler *this;
1815 HRESULT hr;
1817 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1819 if (!(this = calloc(1, sizeof(*this))))
1820 return E_OUTOFMEMORY;
1822 list_init(&this->results);
1823 InitializeCriticalSection(&this->cs);
1825 this->IMFByteStreamHandler_iface.lpVtbl = &winegstreamer_stream_handler_vtbl;
1826 this->IMFAsyncCallback_iface.lpVtbl = &winegstreamer_stream_handler_callback_vtbl;
1827 this->refcount = 1;
1829 hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj);
1830 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
1832 return hr;