winegstreamer: Allocate source media buffers in the PE components.
[wine.git] / dlls / winegstreamer / media_source.c
blob825bad8da2768d73f3507c1c1eabbcf9cea28599
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;
533 uint32_t buffer_size = 0;
534 uint64_t file_size;
535 void *data = NULL;
537 IMFByteStream_GetLength(byte_stream, &file_size);
539 TRACE("Starting read thread for media source %p.\n", source);
541 while (!source->read_thread_shutdown)
543 uint64_t offset;
544 ULONG ret_size;
545 uint32_t size;
546 HRESULT hr;
548 if (!unix_funcs->wg_parser_get_next_read_offset(source->wg_parser, &offset, &size))
549 continue;
551 if (offset >= file_size)
552 size = 0;
553 else if (offset + size >= file_size)
554 size = file_size - offset;
556 if (size > buffer_size)
558 buffer_size = size;
559 data = realloc(data, size);
562 ret_size = 0;
564 if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset)))
565 hr = IMFByteStream_Read(byte_stream, data, size, &ret_size);
566 if (FAILED(hr))
567 ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr);
568 else if (ret_size != size)
569 ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size);
570 unix_funcs->wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size);
573 free(data);
574 TRACE("Media source is shutting down; exiting.\n");
575 return 0;
578 static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
580 struct media_stream *stream = impl_from_IMFMediaStream(iface);
582 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
584 if (IsEqualIID(riid, &IID_IMFMediaStream) ||
585 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
586 IsEqualIID(riid, &IID_IUnknown))
588 *out = &stream->IMFMediaStream_iface;
590 else
592 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
593 *out = NULL;
594 return E_NOINTERFACE;
597 IUnknown_AddRef((IUnknown*)*out);
598 return S_OK;
601 static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
603 struct media_stream *stream = impl_from_IMFMediaStream(iface);
604 ULONG ref = InterlockedIncrement(&stream->ref);
606 TRACE("%p, refcount %u.\n", iface, ref);
608 return ref;
611 static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
613 struct media_stream *stream = impl_from_IMFMediaStream(iface);
614 ULONG ref = InterlockedDecrement(&stream->ref);
616 TRACE("%p, refcount %u.\n", iface, ref);
618 if (!ref)
620 if (stream->event_queue)
621 IMFMediaEventQueue_Release(stream->event_queue);
622 free(stream);
625 return ref;
628 static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
630 struct media_stream *stream = impl_from_IMFMediaStream(iface);
632 TRACE("%p, %#x, %p.\n", iface, flags, event);
634 return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
637 static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
639 struct media_stream *stream = impl_from_IMFMediaStream(iface);
641 TRACE("%p, %p, %p.\n", iface, callback, state);
643 return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
646 static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
648 struct media_stream *stream = impl_from_IMFMediaStream(iface);
650 TRACE("%p, %p, %p.\n", stream, result, event);
652 return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
655 static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
656 HRESULT hr, const PROPVARIANT *value)
658 struct media_stream *stream = impl_from_IMFMediaStream(iface);
660 TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
662 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
665 static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source)
667 struct media_stream *stream = impl_from_IMFMediaStream(iface);
669 TRACE("%p, %p.\n", iface, source);
671 if (stream->state == STREAM_SHUTDOWN)
672 return MF_E_SHUTDOWN;
674 IMFMediaSource_AddRef(&stream->parent_source->IMFMediaSource_iface);
675 *source = &stream->parent_source->IMFMediaSource_iface;
677 return S_OK;
680 static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
682 struct media_stream *stream = impl_from_IMFMediaStream(iface);
684 TRACE("%p, %p.\n", iface, descriptor);
686 if (stream->state == STREAM_SHUTDOWN)
687 return MF_E_SHUTDOWN;
689 IMFStreamDescriptor_AddRef(stream->descriptor);
690 *descriptor = stream->descriptor;
692 return S_OK;
695 static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
697 struct media_stream *stream = impl_from_IMFMediaStream(iface);
698 struct source_async_command *command;
699 HRESULT hr;
701 TRACE("%p, %p.\n", iface, token);
703 if (stream->state == STREAM_SHUTDOWN)
704 return MF_E_SHUTDOWN;
706 if (stream->state == STREAM_INACTIVE)
708 WARN("Stream isn't active\n");
709 return MF_E_MEDIA_SOURCE_WRONGSTATE;
712 if (stream->eos)
714 return MF_E_END_OF_STREAM;
717 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command)))
719 command->u.request_sample.stream = stream;
720 if (token)
721 IUnknown_AddRef(token);
722 command->u.request_sample.token = token;
724 /* Once pause support is added, this will need to put into a stream queue, and synchronization will need to be added*/
725 hr = MFPutWorkItem(stream->parent_source->async_commands_queue, &stream->parent_source->async_commands_callback, &command->IUnknown_iface);
728 return hr;
731 static const IMFMediaStreamVtbl media_stream_vtbl =
733 media_stream_QueryInterface,
734 media_stream_AddRef,
735 media_stream_Release,
736 media_stream_GetEvent,
737 media_stream_BeginGetEvent,
738 media_stream_EndGetEvent,
739 media_stream_QueueEvent,
740 media_stream_GetMediaSource,
741 media_stream_GetStreamDescriptor,
742 media_stream_RequestSample
745 static HRESULT new_media_stream(struct media_source *source,
746 struct wg_parser_stream *wg_stream, DWORD stream_id, struct media_stream **out_stream)
748 struct media_stream *object = calloc(1, sizeof(*object));
749 HRESULT hr;
751 TRACE("source %p, wg_stream %p, stream_id %u.\n", source, wg_stream, stream_id);
753 object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
754 object->ref = 1;
756 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
758 free(object);
759 return hr;
762 IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
763 object->parent_source = source;
764 object->stream_id = stream_id;
766 object->state = STREAM_INACTIVE;
767 object->eos = FALSE;
768 object->wg_stream = wg_stream;
770 TRACE("Created stream object %p.\n", object);
772 *out_stream = object;
774 return S_OK;
777 static HRESULT media_stream_init_desc(struct media_stream *stream)
779 IMFMediaTypeHandler *type_handler = NULL;
780 IMFMediaType *stream_types[6];
781 struct wg_format format;
782 DWORD type_count = 0;
783 unsigned int i;
784 HRESULT hr;
786 unix_funcs->wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
788 if (format.major_type == WG_MAJOR_TYPE_VIDEO)
790 /* These are the most common native output types of decoders:
791 https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */
792 static const GUID *const video_types[] =
794 &MFVideoFormat_NV12,
795 &MFVideoFormat_YV12,
796 &MFVideoFormat_YUY2,
797 &MFVideoFormat_IYUV,
798 &MFVideoFormat_I420,
801 IMFMediaType *base_type = mf_media_type_from_wg_format(&format);
802 GUID base_subtype;
804 IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype);
806 stream_types[0] = base_type;
807 type_count = 1;
809 for (i = 0; i < ARRAY_SIZE(video_types); i++)
811 IMFMediaType *new_type;
813 if (IsEqualGUID(&base_subtype, video_types[i]))
814 continue;
816 if (FAILED(hr = MFCreateMediaType(&new_type)))
817 goto done;
818 stream_types[type_count++] = new_type;
820 if (FAILED(hr = IMFMediaType_CopyAllItems(base_type, (IMFAttributes *) new_type)))
821 goto done;
822 if (FAILED(hr = IMFMediaType_SetGUID(new_type, &MF_MT_SUBTYPE, video_types[i])))
823 goto done;
826 else if (format.major_type == WG_MAJOR_TYPE_AUDIO)
828 /* Expose at least one PCM and one floating point type for the
829 consumer to pick from. */
830 static const enum wg_audio_format audio_types[] =
832 WG_AUDIO_FORMAT_S16LE,
833 WG_AUDIO_FORMAT_F32LE,
836 stream_types[0] = mf_media_type_from_wg_format(&format);
837 type_count = 1;
839 for (i = 0; i < ARRAY_SIZE(audio_types); i++)
841 struct wg_format new_format;
842 if (format.u.audio.format == audio_types[i])
843 continue;
844 new_format = format;
845 new_format.u.audio.format = audio_types[i];
846 stream_types[type_count++] = mf_media_type_from_wg_format(&new_format);
849 else
851 if ((stream_types[0] = mf_media_type_from_wg_format(&format)))
852 type_count = 1;
855 assert(type_count <= ARRAY_SIZE(stream_types));
857 if (!type_count)
859 ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
860 return E_FAIL;
863 if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, type_count, stream_types, &stream->descriptor)))
864 goto done;
866 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
868 IMFStreamDescriptor_Release(stream->descriptor);
869 goto done;
872 if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0])))
874 IMFStreamDescriptor_Release(stream->descriptor);
875 goto done;
878 done:
879 if (type_handler)
880 IMFMediaTypeHandler_Release(type_handler);
881 for (i = 0; i < type_count; i++)
882 IMFMediaType_Release(stream_types[i]);
883 return hr;
886 static HRESULT WINAPI media_source_get_service_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
888 struct media_source *source = impl_from_IMFGetService(iface);
889 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
892 static ULONG WINAPI media_source_get_service_AddRef(IMFGetService *iface)
894 struct media_source *source = impl_from_IMFGetService(iface);
895 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
898 static ULONG WINAPI media_source_get_service_Release(IMFGetService *iface)
900 struct media_source *source = impl_from_IMFGetService(iface);
901 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
904 static HRESULT WINAPI media_source_get_service_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
906 struct media_source *source = impl_from_IMFGetService(iface);
908 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
910 *obj = NULL;
912 if (IsEqualGUID(service, &MF_RATE_CONTROL_SERVICE))
914 if (IsEqualIID(riid, &IID_IMFRateSupport))
916 *obj = &source->IMFRateSupport_iface;
918 else if (IsEqualIID(riid, &IID_IMFRateControl))
920 *obj = &source->IMFRateControl_iface;
923 else
924 FIXME("Unsupported service %s.\n", debugstr_guid(service));
926 if (*obj)
927 IUnknown_AddRef((IUnknown *)*obj);
929 return *obj ? S_OK : E_NOINTERFACE;
932 static const IMFGetServiceVtbl media_source_get_service_vtbl =
934 media_source_get_service_QueryInterface,
935 media_source_get_service_AddRef,
936 media_source_get_service_Release,
937 media_source_get_service_GetService,
940 static HRESULT WINAPI media_source_rate_support_QueryInterface(IMFRateSupport *iface, REFIID riid, void **obj)
942 struct media_source *source = impl_from_IMFRateSupport(iface);
943 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
946 static ULONG WINAPI media_source_rate_support_AddRef(IMFRateSupport *iface)
948 struct media_source *source = impl_from_IMFRateSupport(iface);
949 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
952 static ULONG WINAPI media_source_rate_support_Release(IMFRateSupport *iface)
954 struct media_source *source = impl_from_IMFRateSupport(iface);
955 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
958 static HRESULT WINAPI media_source_rate_support_GetSlowestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
960 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
962 *rate = 0.0f;
964 return S_OK;
967 static HRESULT WINAPI media_source_rate_support_GetFastestRate(IMFRateSupport *iface, MFRATE_DIRECTION direction, BOOL thin, float *rate)
969 TRACE("%p, %d, %d, %p.\n", iface, direction, thin, rate);
971 *rate = direction == MFRATE_FORWARD ? 1e6f : -1e6f;
973 return S_OK;
976 static HRESULT WINAPI media_source_rate_support_IsRateSupported(IMFRateSupport *iface, BOOL thin, float rate,
977 float *nearest_rate)
979 TRACE("%p, %d, %f, %p.\n", iface, thin, rate, nearest_rate);
981 if (nearest_rate)
982 *nearest_rate = rate;
984 return rate >= -1e6f && rate <= 1e6f ? S_OK : MF_E_UNSUPPORTED_RATE;
987 static const IMFRateSupportVtbl media_source_rate_support_vtbl =
989 media_source_rate_support_QueryInterface,
990 media_source_rate_support_AddRef,
991 media_source_rate_support_Release,
992 media_source_rate_support_GetSlowestRate,
993 media_source_rate_support_GetFastestRate,
994 media_source_rate_support_IsRateSupported,
997 static HRESULT WINAPI media_source_rate_control_QueryInterface(IMFRateControl *iface, REFIID riid, void **obj)
999 struct media_source *source = impl_from_IMFRateControl(iface);
1000 return IMFMediaSource_QueryInterface(&source->IMFMediaSource_iface, riid, obj);
1003 static ULONG WINAPI media_source_rate_control_AddRef(IMFRateControl *iface)
1005 struct media_source *source = impl_from_IMFRateControl(iface);
1006 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
1009 static ULONG WINAPI media_source_rate_control_Release(IMFRateControl *iface)
1011 struct media_source *source = impl_from_IMFRateControl(iface);
1012 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
1015 static HRESULT WINAPI media_source_rate_control_SetRate(IMFRateControl *iface, BOOL thin, float rate)
1017 FIXME("%p, %d, %f.\n", iface, thin, rate);
1019 if (rate < 0.0f)
1020 return MF_E_REVERSE_UNSUPPORTED;
1022 if (thin)
1023 return MF_E_THINNING_UNSUPPORTED;
1025 if (rate != 1.0f)
1026 return MF_E_UNSUPPORTED_RATE;
1028 return S_OK;
1031 static HRESULT WINAPI media_source_rate_control_GetRate(IMFRateControl *iface, BOOL *thin, float *rate)
1033 TRACE("%p, %p, %p.\n", iface, thin, rate);
1035 if (thin)
1036 *thin = FALSE;
1038 *rate = 1.0f;
1040 return S_OK;
1043 static const IMFRateControlVtbl media_source_rate_control_vtbl =
1045 media_source_rate_control_QueryInterface,
1046 media_source_rate_control_AddRef,
1047 media_source_rate_control_Release,
1048 media_source_rate_control_SetRate,
1049 media_source_rate_control_GetRate,
1052 static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
1054 struct media_source *source = impl_from_IMFMediaSource(iface);
1056 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
1058 if (IsEqualIID(riid, &IID_IMFMediaSource) ||
1059 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
1060 IsEqualIID(riid, &IID_IUnknown))
1062 *out = &source->IMFMediaSource_iface;
1064 else if (IsEqualIID(riid, &IID_IMFGetService))
1066 *out = &source->IMFGetService_iface;
1068 else
1070 FIXME("%s, %p.\n", debugstr_guid(riid), out);
1071 *out = NULL;
1072 return E_NOINTERFACE;
1075 IUnknown_AddRef((IUnknown*)*out);
1076 return S_OK;
1079 static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface)
1081 struct media_source *source = impl_from_IMFMediaSource(iface);
1082 ULONG ref = InterlockedIncrement(&source->ref);
1084 TRACE("%p, refcount %u.\n", iface, ref);
1086 return ref;
1089 static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
1091 struct media_source *source = impl_from_IMFMediaSource(iface);
1092 ULONG ref = InterlockedDecrement(&source->ref);
1094 TRACE("%p, refcount %u.\n", iface, ref);
1096 if (!ref)
1098 IMFMediaSource_Shutdown(&source->IMFMediaSource_iface);
1099 IMFMediaEventQueue_Release(source->event_queue);
1100 free(source);
1103 return ref;
1106 static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
1108 struct media_source *source = impl_from_IMFMediaSource(iface);
1110 TRACE("%p, %#x, %p.\n", iface, flags, event);
1112 return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
1115 static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
1117 struct media_source *source = impl_from_IMFMediaSource(iface);
1119 TRACE("%p, %p, %p.\n", iface, callback, state);
1121 return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
1124 static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
1126 struct media_source *source = impl_from_IMFMediaSource(iface);
1128 TRACE("%p, %p, %p.\n", iface, result, event);
1130 return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
1133 static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
1134 HRESULT hr, const PROPVARIANT *value)
1136 struct media_source *source = impl_from_IMFMediaSource(iface);
1138 TRACE("%p, %d, %s, %#x, %p.\n", iface, event_type, debugstr_guid(ext_type), hr, value);
1140 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
1143 static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
1145 struct media_source *source = impl_from_IMFMediaSource(iface);
1147 TRACE("%p, %p.\n", iface, characteristics);
1149 if (source->state == SOURCE_SHUTDOWN)
1150 return MF_E_SHUTDOWN;
1152 *characteristics = MFMEDIASOURCE_CAN_SEEK;
1154 return S_OK;
1157 static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
1159 struct media_source *source = impl_from_IMFMediaSource(iface);
1161 TRACE("%p, %p.\n", iface, descriptor);
1163 if (source->state == SOURCE_SHUTDOWN)
1164 return MF_E_SHUTDOWN;
1166 return IMFPresentationDescriptor_Clone(source->pres_desc, descriptor);
1169 static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
1170 const GUID *time_format, const PROPVARIANT *position)
1172 struct media_source *source = impl_from_IMFMediaSource(iface);
1173 struct source_async_command *command;
1174 HRESULT hr;
1176 TRACE("%p, %p, %p, %p.\n", iface, descriptor, time_format, position);
1178 if (source->state == SOURCE_SHUTDOWN)
1179 return MF_E_SHUTDOWN;
1181 if (!(IsEqualIID(time_format, &GUID_NULL)))
1182 return MF_E_UNSUPPORTED_TIME_FORMAT;
1184 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command)))
1186 command->u.start.descriptor = descriptor;
1187 command->u.start.format = *time_format;
1188 PropVariantCopy(&command->u.start.position, position);
1190 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
1193 return hr;
1196 static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
1198 struct media_source *source = impl_from_IMFMediaSource(iface);
1199 struct source_async_command *command;
1200 HRESULT hr;
1202 TRACE("%p.\n", iface);
1204 if (source->state == SOURCE_SHUTDOWN)
1205 return MF_E_SHUTDOWN;
1207 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command)))
1208 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
1210 return hr;
1213 static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
1215 struct media_source *source = impl_from_IMFMediaSource(iface);
1217 FIXME("%p: stub\n", iface);
1219 if (source->state == SOURCE_SHUTDOWN)
1220 return MF_E_SHUTDOWN;
1222 return E_NOTIMPL;
1225 static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
1227 struct media_source *source = impl_from_IMFMediaSource(iface);
1228 unsigned int i;
1230 TRACE("%p.\n", iface);
1232 if (source->state == SOURCE_SHUTDOWN)
1233 return MF_E_SHUTDOWN;
1235 source->state = SOURCE_SHUTDOWN;
1237 unix_funcs->wg_parser_disconnect(source->wg_parser);
1239 source->read_thread_shutdown = true;
1240 WaitForSingleObject(source->read_thread, INFINITE);
1241 CloseHandle(source->read_thread);
1243 IMFPresentationDescriptor_Release(source->pres_desc);
1244 IMFMediaEventQueue_Shutdown(source->event_queue);
1245 IMFByteStream_Release(source->byte_stream);
1247 for (i = 0; i < source->stream_count; i++)
1249 struct media_stream *stream = source->streams[i];
1251 stream->state = STREAM_SHUTDOWN;
1253 IMFMediaEventQueue_Shutdown(stream->event_queue);
1254 IMFStreamDescriptor_Release(stream->descriptor);
1255 IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
1257 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1260 unix_funcs->wg_parser_destroy(source->wg_parser);
1262 free(source->streams);
1264 MFUnlockWorkQueue(source->async_commands_queue);
1266 return S_OK;
1269 static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
1271 media_source_QueryInterface,
1272 media_source_AddRef,
1273 media_source_Release,
1274 media_source_GetEvent,
1275 media_source_BeginGetEvent,
1276 media_source_EndGetEvent,
1277 media_source_QueueEvent,
1278 media_source_GetCharacteristics,
1279 media_source_CreatePresentationDescriptor,
1280 media_source_Start,
1281 media_source_Stop,
1282 media_source_Pause,
1283 media_source_Shutdown,
1286 static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
1288 IMFStreamDescriptor **descriptors = NULL;
1289 unsigned int stream_count = UINT_MAX;
1290 struct media_source *object;
1291 UINT64 total_pres_time = 0;
1292 struct wg_parser *parser;
1293 DWORD bytestream_caps;
1294 uint64_t file_size;
1295 unsigned int i;
1296 HRESULT hr;
1298 if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps)))
1299 return hr;
1301 if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE))
1303 FIXME("Non-seekable bytestreams not supported.\n");
1304 return MF_E_BYTESTREAM_NOT_SEEKABLE;
1307 if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size)))
1309 FIXME("Failed to get byte stream length, hr %#x.\n", hr);
1310 return hr;
1313 if (!(object = calloc(1, sizeof(*object))))
1314 return E_OUTOFMEMORY;
1316 object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
1317 object->IMFGetService_iface.lpVtbl = &media_source_get_service_vtbl;
1318 object->IMFRateSupport_iface.lpVtbl = &media_source_rate_support_vtbl;
1319 object->IMFRateControl_iface.lpVtbl = &media_source_rate_control_vtbl;
1320 object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
1321 object->ref = 1;
1322 object->byte_stream = bytestream;
1323 IMFByteStream_AddRef(bytestream);
1325 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1326 goto fail;
1328 if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
1329 goto fail;
1331 if (!(parser = unix_funcs->wg_decodebin_parser_create()))
1333 hr = E_OUTOFMEMORY;
1334 goto fail;
1336 object->wg_parser = parser;
1338 object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL);
1340 object->state = SOURCE_OPENING;
1342 if (FAILED(hr = unix_funcs->wg_parser_connect(parser, file_size)))
1343 goto fail;
1345 /* In Media Foundation, sources may read from any media source stream
1346 * without fear of blocking due to buffering limits on another. Trailmakers,
1347 * a Unity3D Engine game, only reads one sample from the audio stream (and
1348 * never deselects it). Remove buffering limits from decodebin in order to
1349 * account for this. Note that this does leak memory, but the same memory
1350 * leak occurs with native. */
1351 unix_funcs->wg_parser_set_unlimited_buffering(parser);
1353 stream_count = unix_funcs->wg_parser_get_stream_count(parser);
1355 if (!(object->streams = calloc(stream_count, sizeof(*object->streams))))
1357 hr = E_OUTOFMEMORY;
1358 goto fail;
1361 for (i = 0; i < stream_count; ++i)
1363 if (FAILED(hr = new_media_stream(object, unix_funcs->wg_parser_get_stream(parser, i), i, &object->streams[i])))
1364 goto fail;
1366 if (FAILED(hr = media_stream_init_desc(object->streams[i])))
1368 ERR("Failed to finish initialization of media stream %p, hr %x.\n", object->streams[i], hr);
1369 IMFMediaSource_Release(&object->streams[i]->parent_source->IMFMediaSource_iface);
1370 IMFMediaEventQueue_Release(object->streams[i]->event_queue);
1371 free(object->streams[i]);
1372 goto fail;
1375 object->stream_count++;
1378 /* init presentation descriptor */
1380 descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *));
1381 for (i = 0; i < object->stream_count; i++)
1383 IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]);
1386 if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc)))
1387 goto fail;
1389 for (i = 0; i < object->stream_count; i++)
1391 IMFPresentationDescriptor_SelectStream(object->pres_desc, i);
1392 IMFStreamDescriptor_Release(descriptors[i]);
1394 free(descriptors);
1395 descriptors = NULL;
1397 for (i = 0; i < object->stream_count; i++)
1398 total_pres_time = max(total_pres_time,
1399 unix_funcs->wg_parser_stream_get_duration(object->streams[i]->wg_stream));
1401 if (object->stream_count)
1402 IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time);
1404 object->state = SOURCE_STOPPED;
1406 *out_media_source = object;
1407 return S_OK;
1409 fail:
1410 WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
1412 if (descriptors)
1414 for (i = 0; i < object->stream_count; i++)
1415 IMFStreamDescriptor_Release(descriptors[i]);
1416 free(descriptors);
1418 for (i = 0; i < object->stream_count; i++)
1420 struct media_stream *stream = object->streams[i];
1422 IMFMediaEventQueue_Release(stream->event_queue);
1423 IMFStreamDescriptor_Release(stream->descriptor);
1424 IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
1426 free(stream);
1428 free(object->streams);
1429 if (stream_count != UINT_MAX)
1430 unix_funcs->wg_parser_disconnect(object->wg_parser);
1431 if (object->read_thread)
1433 object->read_thread_shutdown = true;
1434 WaitForSingleObject(object->read_thread, INFINITE);
1435 CloseHandle(object->read_thread);
1437 if (object->wg_parser)
1438 unix_funcs->wg_parser_destroy(object->wg_parser);
1439 if (object->async_commands_queue)
1440 MFUnlockWorkQueue(object->async_commands_queue);
1441 if (object->event_queue)
1442 IMFMediaEventQueue_Release(object->event_queue);
1443 IMFByteStream_Release(object->byte_stream);
1444 free(object);
1445 return hr;
1448 struct winegstreamer_stream_handler_result
1450 struct list entry;
1451 IMFAsyncResult *result;
1452 MF_OBJECT_TYPE obj_type;
1453 IUnknown *object;
1456 struct winegstreamer_stream_handler
1458 IMFByteStreamHandler IMFByteStreamHandler_iface;
1459 IMFAsyncCallback IMFAsyncCallback_iface;
1460 LONG refcount;
1461 struct list results;
1462 CRITICAL_SECTION cs;
1465 static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
1467 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFByteStreamHandler_iface);
1470 static struct winegstreamer_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
1472 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFAsyncCallback_iface);
1475 static HRESULT WINAPI winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj)
1477 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1479 if (IsEqualIID(riid, &IID_IMFByteStreamHandler) ||
1480 IsEqualIID(riid, &IID_IUnknown))
1482 *obj = iface;
1483 IMFByteStreamHandler_AddRef(iface);
1484 return S_OK;
1487 WARN("Unsupported %s.\n", debugstr_guid(riid));
1488 *obj = NULL;
1489 return E_NOINTERFACE;
1492 static ULONG WINAPI winegstreamer_stream_handler_AddRef(IMFByteStreamHandler *iface)
1494 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1495 ULONG refcount = InterlockedIncrement(&handler->refcount);
1497 TRACE("%p, refcount %u.\n", handler, refcount);
1499 return refcount;
1502 static ULONG WINAPI winegstreamer_stream_handler_Release(IMFByteStreamHandler *iface)
1504 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1505 ULONG refcount = InterlockedDecrement(&handler->refcount);
1506 struct winegstreamer_stream_handler_result *result, *next;
1508 TRACE("%p, refcount %u.\n", iface, refcount);
1510 if (!refcount)
1512 LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct winegstreamer_stream_handler_result, entry)
1514 list_remove(&result->entry);
1515 IMFAsyncResult_Release(result->result);
1516 if (result->object)
1517 IUnknown_Release(result->object);
1518 free(result);
1520 DeleteCriticalSection(&handler->cs);
1521 free(handler);
1524 return refcount;
1527 struct create_object_context
1529 IUnknown IUnknown_iface;
1530 LONG refcount;
1532 IPropertyStore *props;
1533 IMFByteStream *stream;
1534 WCHAR *url;
1535 DWORD flags;
1538 static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
1540 return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
1543 static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
1545 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1547 if (IsEqualIID(riid, &IID_IUnknown))
1549 *obj = iface;
1550 IUnknown_AddRef(iface);
1551 return S_OK;
1554 WARN("Unsupported %s.\n", debugstr_guid(riid));
1555 *obj = NULL;
1556 return E_NOINTERFACE;
1559 static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
1561 struct create_object_context *context = impl_from_IUnknown(iface);
1562 ULONG refcount = InterlockedIncrement(&context->refcount);
1564 TRACE("%p, refcount %u.\n", iface, refcount);
1566 return refcount;
1569 static ULONG WINAPI create_object_context_Release(IUnknown *iface)
1571 struct create_object_context *context = impl_from_IUnknown(iface);
1572 ULONG refcount = InterlockedDecrement(&context->refcount);
1574 TRACE("%p, refcount %u.\n", iface, refcount);
1576 if (!refcount)
1578 if (context->props)
1579 IPropertyStore_Release(context->props);
1580 if (context->stream)
1581 IMFByteStream_Release(context->stream);
1582 free(context->url);
1583 free(context);
1586 return refcount;
1589 static const IUnknownVtbl create_object_context_vtbl =
1591 create_object_context_QueryInterface,
1592 create_object_context_AddRef,
1593 create_object_context_Release,
1596 static HRESULT WINAPI winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
1597 IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
1599 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1600 struct create_object_context *context;
1601 IMFAsyncResult *caller, *item;
1602 HRESULT hr;
1604 TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
1606 if (cancel_cookie)
1607 *cancel_cookie = NULL;
1609 if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
1610 return hr;
1612 if (!(context = calloc(1, sizeof(*context))))
1614 IMFAsyncResult_Release(caller);
1615 return E_OUTOFMEMORY;
1618 context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
1619 context->refcount = 1;
1620 context->props = props;
1621 if (context->props)
1622 IPropertyStore_AddRef(context->props);
1623 context->flags = flags;
1624 context->stream = stream;
1625 if (context->stream)
1626 IMFByteStream_AddRef(context->stream);
1627 if (url)
1628 context->url = wcsdup(url);
1629 if (!context->stream)
1631 IMFAsyncResult_Release(caller);
1632 IUnknown_Release(&context->IUnknown_iface);
1633 return E_OUTOFMEMORY;
1636 hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
1637 IUnknown_Release(&context->IUnknown_iface);
1638 if (SUCCEEDED(hr))
1640 if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
1642 if (cancel_cookie)
1644 *cancel_cookie = (IUnknown *)caller;
1645 IUnknown_AddRef(*cancel_cookie);
1649 IMFAsyncResult_Release(item);
1651 IMFAsyncResult_Release(caller);
1653 return hr;
1656 static HRESULT WINAPI winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
1657 MF_OBJECT_TYPE *obj_type, IUnknown **object)
1659 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1660 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1661 HRESULT hr;
1663 TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
1665 EnterCriticalSection(&this->cs);
1667 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1669 if (result == cur->result)
1671 list_remove(&cur->entry);
1672 found = cur;
1673 break;
1677 LeaveCriticalSection(&this->cs);
1679 if (found)
1681 *obj_type = found->obj_type;
1682 *object = found->object;
1683 hr = IMFAsyncResult_GetStatus(found->result);
1684 IMFAsyncResult_Release(found->result);
1685 free(found);
1687 else
1689 *obj_type = MF_OBJECT_INVALID;
1690 *object = NULL;
1691 hr = MF_E_UNEXPECTED;
1694 return hr;
1697 static HRESULT WINAPI winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie)
1699 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1700 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1702 TRACE("%p, %p.\n", iface, cancel_cookie);
1704 EnterCriticalSection(&this->cs);
1706 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1708 if (cancel_cookie == (IUnknown *)cur->result)
1710 list_remove(&cur->entry);
1711 found = cur;
1712 break;
1716 LeaveCriticalSection(&this->cs);
1718 if (found)
1720 IMFAsyncResult_Release(found->result);
1721 if (found->object)
1722 IUnknown_Release(found->object);
1723 free(found);
1726 return found ? S_OK : MF_E_UNEXPECTED;
1729 static HRESULT WINAPI winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes)
1731 FIXME("stub (%p %p)\n", iface, bytes);
1732 return E_NOTIMPL;
1735 static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl =
1737 winegstreamer_stream_handler_QueryInterface,
1738 winegstreamer_stream_handler_AddRef,
1739 winegstreamer_stream_handler_Release,
1740 winegstreamer_stream_handler_BeginCreateObject,
1741 winegstreamer_stream_handler_EndCreateObject,
1742 winegstreamer_stream_handler_CancelObjectCreation,
1743 winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
1746 static HRESULT WINAPI winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
1748 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1749 IsEqualIID(riid, &IID_IUnknown))
1751 *obj = iface;
1752 IMFAsyncCallback_AddRef(iface);
1753 return S_OK;
1756 WARN("Unsupported %s.\n", debugstr_guid(riid));
1757 *obj = NULL;
1758 return E_NOINTERFACE;
1761 static ULONG WINAPI winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback *iface)
1763 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1764 return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
1767 static ULONG WINAPI winegstreamer_stream_handler_callback_Release(IMFAsyncCallback *iface)
1769 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1770 return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
1773 static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
1775 return E_NOTIMPL;
1778 static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags,
1779 IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type)
1781 TRACE("%p, %s, %p, %u, %p, %p, %p.\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type);
1783 if (flags & MF_RESOLUTION_MEDIASOURCE)
1785 HRESULT hr;
1786 struct media_source *new_source;
1788 if (FAILED(hr = media_source_constructor(stream, &new_source)))
1789 return hr;
1791 TRACE("->(%p)\n", new_source);
1793 *out_object = (IUnknown*)&new_source->IMFMediaSource_iface;
1794 *out_obj_type = MF_OBJECT_MEDIASOURCE;
1796 return S_OK;
1798 else
1800 FIXME("flags = %08x\n", flags);
1801 return E_NOTIMPL;
1805 static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1807 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1808 struct winegstreamer_stream_handler_result *handler_result;
1809 MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID;
1810 IUnknown *object = NULL, *context_object;
1811 struct create_object_context *context;
1812 IMFAsyncResult *caller;
1813 HRESULT hr;
1815 caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
1817 if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
1819 WARN("Expected context set for callee result.\n");
1820 return hr;
1823 context = impl_from_IUnknown(context_object);
1825 hr = winegstreamer_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type);
1827 if ((handler_result = malloc(sizeof(*handler_result))))
1829 handler_result->result = caller;
1830 IMFAsyncResult_AddRef(handler_result->result);
1831 handler_result->obj_type = obj_type;
1832 handler_result->object = object;
1834 EnterCriticalSection(&handler->cs);
1835 list_add_tail(&handler->results, &handler_result->entry);
1836 LeaveCriticalSection(&handler->cs);
1838 else
1840 if (object)
1841 IUnknown_Release(object);
1842 hr = E_OUTOFMEMORY;
1845 IUnknown_Release(&context->IUnknown_iface);
1847 IMFAsyncResult_SetStatus(caller, hr);
1848 MFInvokeCallback(caller);
1850 return S_OK;
1853 static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl =
1855 winegstreamer_stream_handler_callback_QueryInterface,
1856 winegstreamer_stream_handler_callback_AddRef,
1857 winegstreamer_stream_handler_callback_Release,
1858 winegstreamer_stream_handler_callback_GetParameters,
1859 winegstreamer_stream_handler_callback_Invoke,
1862 HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj)
1864 struct winegstreamer_stream_handler *this;
1865 HRESULT hr;
1867 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1869 if (!(this = calloc(1, sizeof(*this))))
1870 return E_OUTOFMEMORY;
1872 list_init(&this->results);
1873 InitializeCriticalSection(&this->cs);
1875 this->IMFByteStreamHandler_iface.lpVtbl = &winegstreamer_stream_handler_vtbl;
1876 this->IMFAsyncCallback_iface.lpVtbl = &winegstreamer_stream_handler_callback_vtbl;
1877 this->refcount = 1;
1879 hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj);
1880 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
1882 return hr;