mfplat: Implement GetScanline0AndPitch() for d3d11 buffers.
[wine/zf.git] / dlls / winegstreamer / media_source.c
blob589e894db2ed73a59d3a176afcb2c591244c25db
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 IMFAsyncCallback async_commands_callback;
82 LONG ref;
83 DWORD async_commands_queue;
84 IMFMediaEventQueue *event_queue;
85 IMFByteStream *byte_stream;
87 struct wg_parser *wg_parser;
89 struct media_stream **streams;
90 ULONG stream_count;
91 IMFPresentationDescriptor *pres_desc;
92 enum
94 SOURCE_OPENING,
95 SOURCE_STOPPED,
96 SOURCE_RUNNING,
97 SOURCE_SHUTDOWN,
98 } state;
100 LONGLONG start_time;
102 HANDLE read_thread;
103 bool read_thread_shutdown;
106 static inline struct media_stream *impl_from_IMFMediaStream(IMFMediaStream *iface)
108 return CONTAINING_RECORD(iface, struct media_stream, IMFMediaStream_iface);
111 static inline struct media_source *impl_from_IMFMediaSource(IMFMediaSource *iface)
113 return CONTAINING_RECORD(iface, struct media_source, IMFMediaSource_iface);
116 static inline struct media_source *impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback *iface)
118 return CONTAINING_RECORD(iface, struct media_source, async_commands_callback);
121 static inline struct source_async_command *impl_from_async_command_IUnknown(IUnknown *iface)
123 return CONTAINING_RECORD(iface, struct source_async_command, IUnknown_iface);
126 static HRESULT WINAPI source_async_command_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
128 if (IsEqualIID(riid, &IID_IUnknown))
130 *obj = iface;
131 IUnknown_AddRef(iface);
132 return S_OK;
135 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
136 *obj = NULL;
137 return E_NOINTERFACE;
140 static ULONG WINAPI source_async_command_AddRef(IUnknown *iface)
142 struct source_async_command *command = impl_from_async_command_IUnknown(iface);
143 return InterlockedIncrement(&command->refcount);
146 static ULONG WINAPI source_async_command_Release(IUnknown *iface)
148 struct source_async_command *command = impl_from_async_command_IUnknown(iface);
149 ULONG refcount = InterlockedDecrement(&command->refcount);
151 if (!refcount)
153 if (command->op == SOURCE_ASYNC_START)
154 PropVariantClear(&command->u.start.position);
155 free(command);
158 return refcount;
161 static const IUnknownVtbl source_async_command_vtbl =
163 source_async_command_QueryInterface,
164 source_async_command_AddRef,
165 source_async_command_Release,
168 static HRESULT source_create_async_op(enum source_async_op op, struct source_async_command **ret)
170 struct source_async_command *command;
172 if (!(command = calloc(1, sizeof(*command))))
173 return E_OUTOFMEMORY;
175 command->IUnknown_iface.lpVtbl = &source_async_command_vtbl;
176 command->op = op;
178 *ret = command;
180 return S_OK;
183 static HRESULT WINAPI callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
185 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
187 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
188 IsEqualIID(riid, &IID_IUnknown))
190 *obj = iface;
191 IMFAsyncCallback_AddRef(iface);
192 return S_OK;
195 WARN("Unsupported %s.\n", debugstr_guid(riid));
196 *obj = NULL;
197 return E_NOINTERFACE;
200 static HRESULT WINAPI callback_GetParameters(IMFAsyncCallback *iface,
201 DWORD *flags, DWORD *queue)
203 return E_NOTIMPL;
206 static ULONG WINAPI source_async_commands_callback_AddRef(IMFAsyncCallback *iface)
208 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
209 return IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
212 static ULONG WINAPI source_async_commands_callback_Release(IMFAsyncCallback *iface)
214 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
215 return IMFMediaSource_Release(&source->IMFMediaSource_iface);
218 static IMFStreamDescriptor *stream_descriptor_from_id(IMFPresentationDescriptor *pres_desc, DWORD id, BOOL *selected)
220 ULONG sd_count;
221 IMFStreamDescriptor *ret;
222 unsigned int i;
224 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc, &sd_count)))
225 return NULL;
227 for (i = 0; i < sd_count; i++)
229 DWORD stream_id;
231 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc, i, selected, &ret)))
232 return NULL;
234 if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret, &stream_id)) && stream_id == id)
235 return ret;
237 IMFStreamDescriptor_Release(ret);
239 return NULL;
242 static void start_pipeline(struct media_source *source, struct source_async_command *command)
244 PROPVARIANT *position = &command->u.start.position;
245 BOOL seek_message = source->state != SOURCE_STOPPED && position->vt != VT_EMPTY;
246 unsigned int i;
248 /* seek to beginning on stop->play */
249 if (source->state == SOURCE_STOPPED && position->vt == VT_EMPTY)
251 position->vt = VT_I8;
252 position->hVal.QuadPart = 0;
254 source->start_time = position->hVal.QuadPart;
256 for (i = 0; i < source->stream_count; i++)
258 struct media_stream *stream;
259 IMFStreamDescriptor *sd;
260 IMFMediaTypeHandler *mth;
261 IMFMediaType *current_mt;
262 DWORD stream_id;
263 BOOL was_active;
264 BOOL selected;
266 stream = source->streams[i];
268 IMFStreamDescriptor_GetStreamIdentifier(stream->descriptor, &stream_id);
270 sd = stream_descriptor_from_id(command->u.start.descriptor, stream_id, &selected);
271 IMFStreamDescriptor_Release(sd);
273 was_active = stream->state != STREAM_INACTIVE;
275 stream->state = selected ? STREAM_RUNNING : STREAM_INACTIVE;
277 if (selected)
279 struct wg_format format;
281 IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &mth);
282 IMFMediaTypeHandler_GetCurrentMediaType(mth, &current_mt);
284 mf_media_type_to_wg_format(current_mt, &format);
285 unix_funcs->wg_parser_stream_enable(stream->wg_stream, &format);
287 IMFMediaType_Release(current_mt);
288 IMFMediaTypeHandler_Release(mth);
291 if (position->vt != VT_EMPTY)
292 stream->eos = FALSE;
294 if (selected)
296 TRACE("Stream %u (%p) selected\n", i, stream);
297 IMFMediaEventQueue_QueueEventParamUnk(source->event_queue,
298 was_active ? MEUpdatedStream : MENewStream, &GUID_NULL,
299 S_OK, (IUnknown*) &stream->IMFMediaStream_iface);
301 IMFMediaEventQueue_QueueEventParamVar(stream->event_queue,
302 seek_message ? MEStreamSeeked : MEStreamStarted, &GUID_NULL, S_OK, position);
306 IMFMediaEventQueue_QueueEventParamVar(source->event_queue,
307 seek_message ? MESourceSeeked : MESourceStarted,
308 &GUID_NULL, S_OK, position);
310 source->state = SOURCE_RUNNING;
312 unix_funcs->wg_parser_stream_seek(source->streams[0]->wg_stream, 1.0,
313 position->hVal.QuadPart, 0, AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning);
314 unix_funcs->wg_parser_end_flush(source->wg_parser);
317 static void stop_pipeline(struct media_source *source)
319 unsigned int i;
321 unix_funcs->wg_parser_begin_flush(source->wg_parser);
323 for (i = 0; i < source->stream_count; i++)
325 struct media_stream *stream = source->streams[i];
326 if (stream->state != STREAM_INACTIVE)
328 IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEStreamStopped, &GUID_NULL, S_OK, NULL);
329 unix_funcs->wg_parser_stream_disable(stream->wg_stream);
333 IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MESourceStopped, &GUID_NULL, S_OK, NULL);
335 source->state = SOURCE_STOPPED;
338 static void dispatch_end_of_presentation(struct media_source *source)
340 PROPVARIANT empty = {.vt = VT_EMPTY};
341 unsigned int i;
343 /* A stream has ended, check whether all have */
344 for (i = 0; i < source->stream_count; i++)
346 struct media_stream *stream = source->streams[i];
348 if (stream->state != STREAM_INACTIVE && !stream->eos)
349 return;
352 IMFMediaEventQueue_QueueEventParamVar(source->event_queue, MEEndOfPresentation, &GUID_NULL, S_OK, &empty);
355 static void send_buffer(struct media_stream *stream, const struct wg_parser_event *event, IUnknown *token)
357 IMFMediaBuffer *buffer;
358 IMFSample *sample;
359 HRESULT hr;
360 BYTE *data;
362 if (FAILED(hr = MFCreateSample(&sample)))
364 ERR("Failed to create sample, hr %#x.\n", hr);
365 return;
368 if (FAILED(hr = MFCreateMemoryBuffer(event->u.buffer.size, &buffer)))
370 ERR("Failed to create buffer, hr %#x.\n", hr);
371 IMFSample_Release(sample);
372 return;
375 if (FAILED(hr = IMFSample_AddBuffer(sample, buffer)))
377 ERR("Failed to add buffer, hr %#x.\n", hr);
378 goto out;
381 if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event->u.buffer.size)))
383 ERR("Failed to set size, hr %#x.\n", hr);
384 goto out;
387 if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL)))
389 ERR("Failed to lock buffer, hr %#x.\n", hr);
390 goto out;
393 if (!unix_funcs->wg_parser_stream_copy_buffer(stream->wg_stream, data, 0, event->u.buffer.size))
395 unix_funcs->wg_parser_stream_release_buffer(stream->wg_stream);
396 IMFMediaBuffer_Unlock(buffer);
397 goto out;
399 unix_funcs->wg_parser_stream_release_buffer(stream->wg_stream);
401 if (FAILED(hr = IMFMediaBuffer_Unlock(buffer)))
403 ERR("Failed to unlock buffer, hr %#x.\n", hr);
404 goto out;
407 if (FAILED(hr = IMFSample_SetSampleTime(sample, event->u.buffer.pts - stream->parent_source->start_time)))
409 ERR("Failed to set sample time, hr %#x.\n", hr);
410 goto out;
413 if (FAILED(hr = IMFSample_SetSampleDuration(sample, event->u.buffer.duration)))
415 ERR("Failed to set sample duration, hr %#x.\n", hr);
416 goto out;
419 if (token)
420 IMFSample_SetUnknown(sample, &MFSampleExtension_Token, token);
422 IMFMediaEventQueue_QueueEventParamUnk(stream->event_queue, MEMediaSample,
423 &GUID_NULL, S_OK, (IUnknown *)sample);
425 out:
426 IMFMediaBuffer_Release(buffer);
427 IMFSample_Release(sample);
430 static void wait_on_sample(struct media_stream *stream, IUnknown *token)
432 PROPVARIANT empty_var = {.vt = VT_EMPTY};
433 struct wg_parser_event event;
435 TRACE("%p, %p\n", stream, token);
437 for (;;)
439 if (!unix_funcs->wg_parser_stream_get_event(stream->wg_stream, &event))
440 return;
442 TRACE("Got event of type %#x.\n", event.type);
444 switch (event.type)
446 case WG_PARSER_EVENT_BUFFER:
447 send_buffer(stream, &event, token);
448 return;
450 case WG_PARSER_EVENT_EOS:
451 stream->eos = TRUE;
452 if (token)
453 IUnknown_Release(token);
454 IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, MEEndOfStream, &GUID_NULL, S_OK, &empty_var);
455 dispatch_end_of_presentation(stream->parent_source);
456 return;
458 case WG_PARSER_EVENT_SEGMENT:
459 break;
461 case WG_PARSER_EVENT_NONE:
462 assert(0);
467 static HRESULT WINAPI source_async_commands_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
469 struct media_source *source = impl_from_async_commands_callback_IMFAsyncCallback(iface);
470 struct source_async_command *command;
471 IUnknown *state;
472 HRESULT hr;
474 if (source->state == SOURCE_SHUTDOWN)
475 return S_OK;
477 if (FAILED(hr = IMFAsyncResult_GetState(result, &state)))
478 return hr;
480 command = impl_from_async_command_IUnknown(state);
481 switch (command->op)
483 case SOURCE_ASYNC_START:
484 start_pipeline(source, command);
485 break;
486 case SOURCE_ASYNC_STOP:
487 stop_pipeline(source);
488 break;
489 case SOURCE_ASYNC_REQUEST_SAMPLE:
490 wait_on_sample(command->u.request_sample.stream, command->u.request_sample.token);
491 break;
494 IUnknown_Release(state);
496 return S_OK;
499 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl =
501 callback_QueryInterface,
502 source_async_commands_callback_AddRef,
503 source_async_commands_callback_Release,
504 callback_GetParameters,
505 source_async_commands_Invoke,
508 static DWORD CALLBACK read_thread(void *arg)
510 struct media_source *source = arg;
511 IMFByteStream *byte_stream = source->byte_stream;
513 TRACE("Starting read thread for media source %p.\n", source);
515 while (!source->read_thread_shutdown)
517 uint64_t offset;
518 ULONG ret_size;
519 uint32_t size;
520 HRESULT hr;
521 void *data;
523 if (!unix_funcs->wg_parser_get_read_request(source->wg_parser, &data, &offset, &size))
524 continue;
526 if (SUCCEEDED(hr = IMFByteStream_SetCurrentPosition(byte_stream, offset)))
527 hr = IMFByteStream_Read(byte_stream, data, size, &ret_size);
528 if (SUCCEEDED(hr) && ret_size != size)
529 ERR("Unexpected short read: requested %u bytes, got %u.\n", size, ret_size);
530 unix_funcs->wg_parser_complete_read_request(source->wg_parser, SUCCEEDED(hr));
533 TRACE("Media source is shutting down; exiting.\n");
534 return 0;
537 static HRESULT WINAPI media_stream_QueryInterface(IMFMediaStream *iface, REFIID riid, void **out)
539 struct media_stream *stream = impl_from_IMFMediaStream(iface);
541 TRACE("(%p)->(%s %p)\n", stream, debugstr_guid(riid), out);
543 if (IsEqualIID(riid, &IID_IMFMediaStream) ||
544 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
545 IsEqualIID(riid, &IID_IUnknown))
547 *out = &stream->IMFMediaStream_iface;
549 else
551 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
552 *out = NULL;
553 return E_NOINTERFACE;
556 IUnknown_AddRef((IUnknown*)*out);
557 return S_OK;
560 static ULONG WINAPI media_stream_AddRef(IMFMediaStream *iface)
562 struct media_stream *stream = impl_from_IMFMediaStream(iface);
563 ULONG ref = InterlockedIncrement(&stream->ref);
565 TRACE("(%p) ref=%u\n", stream, ref);
567 return ref;
570 static ULONG WINAPI media_stream_Release(IMFMediaStream *iface)
572 struct media_stream *stream = impl_from_IMFMediaStream(iface);
574 ULONG ref = InterlockedDecrement(&stream->ref);
576 TRACE("(%p) ref=%u\n", stream, ref);
578 if (!ref)
580 if (stream->event_queue)
581 IMFMediaEventQueue_Release(stream->event_queue);
582 free(stream);
585 return ref;
588 static HRESULT WINAPI media_stream_GetEvent(IMFMediaStream *iface, DWORD flags, IMFMediaEvent **event)
590 struct media_stream *stream = impl_from_IMFMediaStream(iface);
592 TRACE("(%p)->(%#x, %p)\n", stream, flags, event);
594 return IMFMediaEventQueue_GetEvent(stream->event_queue, flags, event);
597 static HRESULT WINAPI media_stream_BeginGetEvent(IMFMediaStream *iface, IMFAsyncCallback *callback, IUnknown *state)
599 struct media_stream *stream = impl_from_IMFMediaStream(iface);
601 TRACE("(%p)->(%p, %p)\n", stream, callback, state);
603 return IMFMediaEventQueue_BeginGetEvent(stream->event_queue, callback, state);
606 static HRESULT WINAPI media_stream_EndGetEvent(IMFMediaStream *iface, IMFAsyncResult *result, IMFMediaEvent **event)
608 struct media_stream *stream = impl_from_IMFMediaStream(iface);
610 TRACE("(%p)->(%p, %p)\n", stream, result, event);
612 return IMFMediaEventQueue_EndGetEvent(stream->event_queue, result, event);
615 static HRESULT WINAPI media_stream_QueueEvent(IMFMediaStream *iface, MediaEventType event_type, REFGUID ext_type,
616 HRESULT hr, const PROPVARIANT *value)
618 struct media_stream *stream = impl_from_IMFMediaStream(iface);
620 TRACE("(%p)->(%d, %s, %#x, %p)\n", stream, event_type, debugstr_guid(ext_type), hr, value);
622 return IMFMediaEventQueue_QueueEventParamVar(stream->event_queue, event_type, ext_type, hr, value);
625 static HRESULT WINAPI media_stream_GetMediaSource(IMFMediaStream *iface, IMFMediaSource **source)
627 struct media_stream *stream = impl_from_IMFMediaStream(iface);
629 TRACE("(%p)->(%p)\n", stream, source);
631 if (stream->state == STREAM_SHUTDOWN)
632 return MF_E_SHUTDOWN;
634 IMFMediaSource_AddRef(&stream->parent_source->IMFMediaSource_iface);
635 *source = &stream->parent_source->IMFMediaSource_iface;
637 return S_OK;
640 static HRESULT WINAPI media_stream_GetStreamDescriptor(IMFMediaStream* iface, IMFStreamDescriptor **descriptor)
642 struct media_stream *stream = impl_from_IMFMediaStream(iface);
644 TRACE("(%p)->(%p)\n", stream, descriptor);
646 if (stream->state == STREAM_SHUTDOWN)
647 return MF_E_SHUTDOWN;
649 IMFStreamDescriptor_AddRef(stream->descriptor);
650 *descriptor = stream->descriptor;
652 return S_OK;
655 static HRESULT WINAPI media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
657 struct media_stream *stream = impl_from_IMFMediaStream(iface);
658 struct source_async_command *command;
659 HRESULT hr;
661 TRACE("(%p)->(%p)\n", iface, token);
663 if (stream->state == STREAM_SHUTDOWN)
664 return MF_E_SHUTDOWN;
666 if (stream->state == STREAM_INACTIVE)
668 WARN("Stream isn't active\n");
669 return MF_E_MEDIA_SOURCE_WRONGSTATE;
672 if (stream->eos)
674 return MF_E_END_OF_STREAM;
677 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE, &command)))
679 command->u.request_sample.stream = stream;
680 if (token)
681 IUnknown_AddRef(token);
682 command->u.request_sample.token = token;
684 /* Once pause support is added, this will need to put into a stream queue, and synchronization will need to be added*/
685 hr = MFPutWorkItem(stream->parent_source->async_commands_queue, &stream->parent_source->async_commands_callback, &command->IUnknown_iface);
688 return hr;
691 static const IMFMediaStreamVtbl media_stream_vtbl =
693 media_stream_QueryInterface,
694 media_stream_AddRef,
695 media_stream_Release,
696 media_stream_GetEvent,
697 media_stream_BeginGetEvent,
698 media_stream_EndGetEvent,
699 media_stream_QueueEvent,
700 media_stream_GetMediaSource,
701 media_stream_GetStreamDescriptor,
702 media_stream_RequestSample
705 static HRESULT new_media_stream(struct media_source *source,
706 struct wg_parser_stream *wg_stream, DWORD stream_id, struct media_stream **out_stream)
708 struct media_stream *object = calloc(1, sizeof(*object));
709 HRESULT hr;
711 TRACE("source %p, wg_stream %p, stream_id %u.\n", source, wg_stream, stream_id);
713 object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
714 object->ref = 1;
716 IMFMediaSource_AddRef(&source->IMFMediaSource_iface);
717 object->parent_source = source;
718 object->stream_id = stream_id;
720 object->state = STREAM_INACTIVE;
721 object->eos = FALSE;
722 object->wg_stream = wg_stream;
724 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
725 goto fail;
727 TRACE("->(%p)\n", object);
728 *out_stream = object;
730 return S_OK;
732 fail:
733 WARN("Failed to construct media stream, hr %#x.\n", hr);
735 IMFMediaStream_Release(&object->IMFMediaStream_iface);
736 return hr;
739 static HRESULT media_stream_init_desc(struct media_stream *stream)
741 IMFMediaTypeHandler *type_handler = NULL;
742 IMFMediaType **stream_types = NULL;
743 IMFMediaType *stream_type = NULL;
744 struct wg_format format;
745 DWORD type_count = 0;
746 unsigned int i;
747 HRESULT hr;
749 unix_funcs->wg_parser_stream_get_preferred_format(stream->wg_stream, &format);
751 if (format.major_type == WG_MAJOR_TYPE_VIDEO)
753 /* These are the most common native output types of decoders:
754 https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */
755 static const GUID *const video_types[] =
757 &MFVideoFormat_NV12,
758 &MFVideoFormat_YV12,
759 &MFVideoFormat_YUY2,
760 &MFVideoFormat_IYUV,
761 &MFVideoFormat_I420,
764 IMFMediaType *base_type = mf_media_type_from_wg_format(&format);
765 GUID base_subtype;
767 IMFMediaType_GetGUID(base_type, &MF_MT_SUBTYPE, &base_subtype);
769 stream_types = malloc(sizeof(IMFMediaType *) * (ARRAY_SIZE(video_types) + 1));
771 stream_types[0] = base_type;
772 type_count = 1;
774 for (i = 0; i < ARRAY_SIZE(video_types); i++)
776 IMFMediaType *new_type;
778 if (IsEqualGUID(&base_subtype, video_types[i]))
779 continue;
781 if (FAILED(hr = MFCreateMediaType(&new_type)))
782 goto done;
783 stream_types[type_count++] = new_type;
785 if (FAILED(hr = IMFMediaType_CopyAllItems(base_type, (IMFAttributes *) new_type)))
786 goto done;
787 if (FAILED(hr = IMFMediaType_SetGUID(new_type, &MF_MT_SUBTYPE, video_types[i])))
788 goto done;
791 else
793 stream_type = mf_media_type_from_wg_format(&format);
794 if (stream_type)
796 stream_types = &stream_type;
797 type_count = 1;
801 if (!type_count)
803 ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
804 return E_FAIL;
807 if (FAILED(hr = MFCreateStreamDescriptor(stream->stream_id, type_count, stream_types, &stream->descriptor)))
808 goto done;
810 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
811 goto done;
813 if (FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_types[0])))
814 goto done;
816 done:
817 if (type_handler)
818 IMFMediaTypeHandler_Release(type_handler);
819 for (i = 0; i < type_count; i++)
820 IMFMediaType_Release(stream_types[i]);
821 if (stream_types != &stream_type)
822 free(stream_types);
823 return hr;
826 static HRESULT WINAPI media_source_QueryInterface(IMFMediaSource *iface, REFIID riid, void **out)
828 struct media_source *source = impl_from_IMFMediaSource(iface);
830 TRACE("(%p)->(%s %p)\n", source, debugstr_guid(riid), out);
832 if (IsEqualIID(riid, &IID_IMFMediaSource) ||
833 IsEqualIID(riid, &IID_IMFMediaEventGenerator) ||
834 IsEqualIID(riid, &IID_IUnknown))
836 *out = &source->IMFMediaSource_iface;
838 else
840 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
841 *out = NULL;
842 return E_NOINTERFACE;
845 IUnknown_AddRef((IUnknown*)*out);
846 return S_OK;
849 static ULONG WINAPI media_source_AddRef(IMFMediaSource *iface)
851 struct media_source *source = impl_from_IMFMediaSource(iface);
852 ULONG ref = InterlockedIncrement(&source->ref);
854 TRACE("(%p) ref=%u\n", source, ref);
856 return ref;
859 static ULONG WINAPI media_source_Release(IMFMediaSource *iface)
861 struct media_source *source = impl_from_IMFMediaSource(iface);
862 ULONG ref = InterlockedDecrement(&source->ref);
864 TRACE("(%p) ref=%u\n", source, ref);
866 if (!ref)
868 IMFMediaSource_Shutdown(&source->IMFMediaSource_iface);
869 IMFMediaEventQueue_Release(source->event_queue);
870 free(source);
873 return ref;
876 static HRESULT WINAPI media_source_GetEvent(IMFMediaSource *iface, DWORD flags, IMFMediaEvent **event)
878 struct media_source *source = impl_from_IMFMediaSource(iface);
880 TRACE("(%p)->(%#x, %p)\n", source, flags, event);
882 return IMFMediaEventQueue_GetEvent(source->event_queue, flags, event);
885 static HRESULT WINAPI media_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
887 struct media_source *source = impl_from_IMFMediaSource(iface);
889 TRACE("(%p)->(%p, %p)\n", source, callback, state);
891 return IMFMediaEventQueue_BeginGetEvent(source->event_queue, callback, state);
894 static HRESULT WINAPI media_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncResult *result, IMFMediaEvent **event)
896 struct media_source *source = impl_from_IMFMediaSource(iface);
898 TRACE("(%p)->(%p, %p)\n", source, result, event);
900 return IMFMediaEventQueue_EndGetEvent(source->event_queue, result, event);
903 static HRESULT WINAPI media_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
904 HRESULT hr, const PROPVARIANT *value)
906 struct media_source *source = impl_from_IMFMediaSource(iface);
908 TRACE("(%p)->(%d, %s, %#x, %p)\n", source, event_type, debugstr_guid(ext_type), hr, value);
910 return IMFMediaEventQueue_QueueEventParamVar(source->event_queue, event_type, ext_type, hr, value);
913 static HRESULT WINAPI media_source_GetCharacteristics(IMFMediaSource *iface, DWORD *characteristics)
915 struct media_source *source = impl_from_IMFMediaSource(iface);
917 TRACE("(%p)->(%p)\n", source, characteristics);
919 if (source->state == SOURCE_SHUTDOWN)
920 return MF_E_SHUTDOWN;
922 *characteristics = MFMEDIASOURCE_CAN_SEEK;
924 return S_OK;
927 static HRESULT WINAPI media_source_CreatePresentationDescriptor(IMFMediaSource *iface, IMFPresentationDescriptor **descriptor)
929 struct media_source *source = impl_from_IMFMediaSource(iface);
931 TRACE("(%p)->(%p)\n", source, descriptor);
933 if (source->state == SOURCE_SHUTDOWN)
934 return MF_E_SHUTDOWN;
936 return IMFPresentationDescriptor_Clone(source->pres_desc, descriptor);
939 static HRESULT WINAPI media_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *descriptor,
940 const GUID *time_format, const PROPVARIANT *position)
942 struct media_source *source = impl_from_IMFMediaSource(iface);
943 struct source_async_command *command;
944 HRESULT hr;
946 TRACE("(%p)->(%p, %p, %p)\n", source, descriptor, time_format, position);
948 if (source->state == SOURCE_SHUTDOWN)
949 return MF_E_SHUTDOWN;
951 if (!(IsEqualIID(time_format, &GUID_NULL)))
952 return MF_E_UNSUPPORTED_TIME_FORMAT;
954 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_START, &command)))
956 command->u.start.descriptor = descriptor;
957 command->u.start.format = *time_format;
958 PropVariantCopy(&command->u.start.position, position);
960 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
963 return hr;
966 static HRESULT WINAPI media_source_Stop(IMFMediaSource *iface)
968 struct media_source *source = impl_from_IMFMediaSource(iface);
969 struct source_async_command *command;
970 HRESULT hr;
972 TRACE("(%p)\n", source);
974 if (source->state == SOURCE_SHUTDOWN)
975 return MF_E_SHUTDOWN;
977 if (SUCCEEDED(hr = source_create_async_op(SOURCE_ASYNC_STOP, &command)))
978 hr = MFPutWorkItem(source->async_commands_queue, &source->async_commands_callback, &command->IUnknown_iface);
980 return hr;
983 static HRESULT WINAPI media_source_Pause(IMFMediaSource *iface)
985 struct media_source *source = impl_from_IMFMediaSource(iface);
987 FIXME("(%p): stub\n", source);
989 if (source->state == SOURCE_SHUTDOWN)
990 return MF_E_SHUTDOWN;
992 return E_NOTIMPL;
995 static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
997 struct media_source *source = impl_from_IMFMediaSource(iface);
998 unsigned int i;
1000 TRACE("(%p)\n", source);
1002 if (source->state == SOURCE_SHUTDOWN)
1003 return MF_E_SHUTDOWN;
1005 source->state = SOURCE_SHUTDOWN;
1007 unix_funcs->wg_parser_disconnect(source->wg_parser);
1009 if (source->pres_desc)
1010 IMFPresentationDescriptor_Release(source->pres_desc);
1011 if (source->event_queue)
1012 IMFMediaEventQueue_Shutdown(source->event_queue);
1013 if (source->byte_stream)
1014 IMFByteStream_Release(source->byte_stream);
1016 for (i = 0; i < source->stream_count; i++)
1018 struct media_stream *stream = source->streams[i];
1020 stream->state = STREAM_SHUTDOWN;
1022 if (stream->event_queue)
1023 IMFMediaEventQueue_Shutdown(stream->event_queue);
1024 if (stream->descriptor)
1025 IMFStreamDescriptor_Release(stream->descriptor);
1026 if (stream->parent_source)
1027 IMFMediaSource_Release(&stream->parent_source->IMFMediaSource_iface);
1029 IMFMediaStream_Release(&stream->IMFMediaStream_iface);
1032 if (source->read_thread)
1034 source->read_thread_shutdown = true;
1035 WaitForSingleObject(source->read_thread, INFINITE);
1036 CloseHandle(source->read_thread);
1039 unix_funcs->wg_parser_destroy(source->wg_parser);
1041 if (source->stream_count)
1042 free(source->streams);
1044 if (source->async_commands_queue)
1045 MFUnlockWorkQueue(source->async_commands_queue);
1047 return S_OK;
1050 static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
1052 media_source_QueryInterface,
1053 media_source_AddRef,
1054 media_source_Release,
1055 media_source_GetEvent,
1056 media_source_BeginGetEvent,
1057 media_source_EndGetEvent,
1058 media_source_QueueEvent,
1059 media_source_GetCharacteristics,
1060 media_source_CreatePresentationDescriptor,
1061 media_source_Start,
1062 media_source_Stop,
1063 media_source_Pause,
1064 media_source_Shutdown,
1067 static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source)
1069 IMFStreamDescriptor **descriptors = NULL;
1070 struct media_source *object;
1071 UINT64 total_pres_time = 0;
1072 struct wg_parser *parser;
1073 DWORD bytestream_caps;
1074 uint64_t file_size;
1075 unsigned int i;
1076 HRESULT hr;
1078 if (FAILED(hr = IMFByteStream_GetCapabilities(bytestream, &bytestream_caps)))
1079 return hr;
1081 if (!(bytestream_caps & MFBYTESTREAM_IS_SEEKABLE))
1083 FIXME("Non-seekable bytestreams not supported.\n");
1084 return MF_E_BYTESTREAM_NOT_SEEKABLE;
1087 if (FAILED(hr = IMFByteStream_GetLength(bytestream, &file_size)))
1089 FIXME("Failed to get byte stream length, hr %#x.\n", hr);
1090 return hr;
1093 if (!(object = calloc(1, sizeof(*object))))
1094 return E_OUTOFMEMORY;
1096 object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
1097 object->async_commands_callback.lpVtbl = &source_async_commands_callback_vtbl;
1098 object->ref = 1;
1099 object->byte_stream = bytestream;
1100 IMFByteStream_AddRef(bytestream);
1102 if (FAILED(hr = MFCreateEventQueue(&object->event_queue)))
1103 goto fail;
1105 if (FAILED(hr = MFAllocateWorkQueue(&object->async_commands_queue)))
1106 goto fail;
1108 object->read_thread = CreateThread(NULL, 0, read_thread, object, 0, NULL);
1110 if (!(parser = unix_funcs->wg_decodebin_parser_create()))
1112 hr = E_OUTOFMEMORY;
1113 goto fail;
1115 object->wg_parser = parser;
1117 object->state = SOURCE_OPENING;
1119 if (FAILED(hr = unix_funcs->wg_parser_connect(parser, file_size)))
1120 goto fail;
1122 /* In Media Foundation, sources may read from any media source stream
1123 * without fear of blocking due to buffering limits on another. Trailmakers,
1124 * a Unity3D Engine game, only reads one sample from the audio stream (and
1125 * never deselects it). Remove buffering limits from decodebin in order to
1126 * account for this. Note that this does leak memory, but the same memory
1127 * leak occurs with native. */
1128 unix_funcs->wg_parser_set_unlimited_buffering(parser);
1130 object->stream_count = unix_funcs->wg_parser_get_stream_count(parser);
1132 if (!(object->streams = calloc(object->stream_count, sizeof(*object->streams))))
1134 hr = E_OUTOFMEMORY;
1135 goto fail;
1138 for (i = 0; i < object->stream_count; ++i)
1140 if (FAILED(hr = new_media_stream(object, unix_funcs->wg_parser_get_stream(parser, i), i, &object->streams[i])))
1141 goto fail;
1143 if (FAILED(hr = media_stream_init_desc(object->streams[i])))
1145 ERR("Failed to finish initialization of media stream %p, hr %x.\n", object->streams[i], hr);
1146 IMFMediaStream_Release(&object->streams[i]->IMFMediaStream_iface);
1147 goto fail;
1151 /* init presentation descriptor */
1153 descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *));
1154 for (i = 0; i < object->stream_count; i++)
1156 IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]);
1159 if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc)))
1160 goto fail;
1162 for (i = 0; i < object->stream_count; i++)
1164 IMFPresentationDescriptor_SelectStream(object->pres_desc, i);
1165 IMFStreamDescriptor_Release(descriptors[i]);
1167 free(descriptors);
1168 descriptors = NULL;
1170 for (i = 0; i < object->stream_count; i++)
1171 total_pres_time = max(total_pres_time,
1172 unix_funcs->wg_parser_stream_get_duration(object->streams[i]->wg_stream));
1174 if (object->stream_count)
1175 IMFPresentationDescriptor_SetUINT64(object->pres_desc, &MF_PD_DURATION, total_pres_time);
1177 object->state = SOURCE_STOPPED;
1179 *out_media_source = object;
1180 return S_OK;
1182 fail:
1183 WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
1185 free(descriptors);
1186 IMFMediaSource_Release(&object->IMFMediaSource_iface);
1187 return hr;
1190 struct winegstreamer_stream_handler_result
1192 struct list entry;
1193 IMFAsyncResult *result;
1194 MF_OBJECT_TYPE obj_type;
1195 IUnknown *object;
1198 struct winegstreamer_stream_handler
1200 IMFByteStreamHandler IMFByteStreamHandler_iface;
1201 IMFAsyncCallback IMFAsyncCallback_iface;
1202 LONG refcount;
1203 struct list results;
1204 CRITICAL_SECTION cs;
1207 static struct winegstreamer_stream_handler *impl_from_IMFByteStreamHandler(IMFByteStreamHandler *iface)
1209 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFByteStreamHandler_iface);
1212 static struct winegstreamer_stream_handler *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
1214 return CONTAINING_RECORD(iface, struct winegstreamer_stream_handler, IMFAsyncCallback_iface);
1217 static HRESULT WINAPI winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler *iface, REFIID riid, void **obj)
1219 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1221 if (IsEqualIID(riid, &IID_IMFByteStreamHandler) ||
1222 IsEqualIID(riid, &IID_IUnknown))
1224 *obj = iface;
1225 IMFByteStreamHandler_AddRef(iface);
1226 return S_OK;
1229 WARN("Unsupported %s.\n", debugstr_guid(riid));
1230 *obj = NULL;
1231 return E_NOINTERFACE;
1234 static ULONG WINAPI winegstreamer_stream_handler_AddRef(IMFByteStreamHandler *iface)
1236 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1237 ULONG refcount = InterlockedIncrement(&handler->refcount);
1239 TRACE("%p, refcount %u.\n", handler, refcount);
1241 return refcount;
1244 static ULONG WINAPI winegstreamer_stream_handler_Release(IMFByteStreamHandler *iface)
1246 struct winegstreamer_stream_handler *handler = impl_from_IMFByteStreamHandler(iface);
1247 ULONG refcount = InterlockedDecrement(&handler->refcount);
1248 struct winegstreamer_stream_handler_result *result, *next;
1250 TRACE("%p, refcount %u.\n", iface, refcount);
1252 if (!refcount)
1254 LIST_FOR_EACH_ENTRY_SAFE(result, next, &handler->results, struct winegstreamer_stream_handler_result, entry)
1256 list_remove(&result->entry);
1257 IMFAsyncResult_Release(result->result);
1258 if (result->object)
1259 IUnknown_Release(result->object);
1260 free(result);
1262 DeleteCriticalSection(&handler->cs);
1263 free(handler);
1266 return refcount;
1269 struct create_object_context
1271 IUnknown IUnknown_iface;
1272 LONG refcount;
1274 IPropertyStore *props;
1275 IMFByteStream *stream;
1276 WCHAR *url;
1277 DWORD flags;
1280 static struct create_object_context *impl_from_IUnknown(IUnknown *iface)
1282 return CONTAINING_RECORD(iface, struct create_object_context, IUnknown_iface);
1285 static HRESULT WINAPI create_object_context_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
1287 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1289 if (IsEqualIID(riid, &IID_IUnknown))
1291 *obj = iface;
1292 IUnknown_AddRef(iface);
1293 return S_OK;
1296 WARN("Unsupported %s.\n", debugstr_guid(riid));
1297 *obj = NULL;
1298 return E_NOINTERFACE;
1301 static ULONG WINAPI create_object_context_AddRef(IUnknown *iface)
1303 struct create_object_context *context = impl_from_IUnknown(iface);
1304 ULONG refcount = InterlockedIncrement(&context->refcount);
1306 TRACE("%p, refcount %u.\n", iface, refcount);
1308 return refcount;
1311 static ULONG WINAPI create_object_context_Release(IUnknown *iface)
1313 struct create_object_context *context = impl_from_IUnknown(iface);
1314 ULONG refcount = InterlockedDecrement(&context->refcount);
1316 TRACE("%p, refcount %u.\n", iface, refcount);
1318 if (!refcount)
1320 if (context->props)
1321 IPropertyStore_Release(context->props);
1322 if (context->stream)
1323 IMFByteStream_Release(context->stream);
1324 free(context->url);
1325 free(context);
1328 return refcount;
1331 static const IUnknownVtbl create_object_context_vtbl =
1333 create_object_context_QueryInterface,
1334 create_object_context_AddRef,
1335 create_object_context_Release,
1338 static HRESULT WINAPI winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler *iface, IMFByteStream *stream, const WCHAR *url, DWORD flags,
1339 IPropertyStore *props, IUnknown **cancel_cookie, IMFAsyncCallback *callback, IUnknown *state)
1341 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1342 struct create_object_context *context;
1343 IMFAsyncResult *caller, *item;
1344 HRESULT hr;
1346 TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
1348 if (cancel_cookie)
1349 *cancel_cookie = NULL;
1351 if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
1352 return hr;
1354 if (!(context = calloc(1, sizeof(*context))))
1356 IMFAsyncResult_Release(caller);
1357 return E_OUTOFMEMORY;
1360 context->IUnknown_iface.lpVtbl = &create_object_context_vtbl;
1361 context->refcount = 1;
1362 context->props = props;
1363 if (context->props)
1364 IPropertyStore_AddRef(context->props);
1365 context->flags = flags;
1366 context->stream = stream;
1367 if (context->stream)
1368 IMFByteStream_AddRef(context->stream);
1369 if (url)
1370 context->url = wcsdup(url);
1371 if (!context->stream)
1373 IMFAsyncResult_Release(caller);
1374 IUnknown_Release(&context->IUnknown_iface);
1375 return E_OUTOFMEMORY;
1378 hr = MFCreateAsyncResult(&context->IUnknown_iface, &this->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
1379 IUnknown_Release(&context->IUnknown_iface);
1380 if (SUCCEEDED(hr))
1382 if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
1384 if (cancel_cookie)
1386 *cancel_cookie = (IUnknown *)caller;
1387 IUnknown_AddRef(*cancel_cookie);
1391 IMFAsyncResult_Release(item);
1393 IMFAsyncResult_Release(caller);
1395 return hr;
1398 static HRESULT WINAPI winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler *iface, IMFAsyncResult *result,
1399 MF_OBJECT_TYPE *obj_type, IUnknown **object)
1401 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1402 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1403 HRESULT hr;
1405 TRACE("%p, %p, %p, %p.\n", iface, result, obj_type, object);
1407 EnterCriticalSection(&this->cs);
1409 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1411 if (result == cur->result)
1413 list_remove(&cur->entry);
1414 found = cur;
1415 break;
1419 LeaveCriticalSection(&this->cs);
1421 if (found)
1423 *obj_type = found->obj_type;
1424 *object = found->object;
1425 hr = IMFAsyncResult_GetStatus(found->result);
1426 IMFAsyncResult_Release(found->result);
1427 free(found);
1429 else
1431 *obj_type = MF_OBJECT_INVALID;
1432 *object = NULL;
1433 hr = MF_E_UNEXPECTED;
1436 return hr;
1439 static HRESULT WINAPI winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler *iface, IUnknown *cancel_cookie)
1441 struct winegstreamer_stream_handler *this = impl_from_IMFByteStreamHandler(iface);
1442 struct winegstreamer_stream_handler_result *found = NULL, *cur;
1444 TRACE("%p, %p.\n", iface, cancel_cookie);
1446 EnterCriticalSection(&this->cs);
1448 LIST_FOR_EACH_ENTRY(cur, &this->results, struct winegstreamer_stream_handler_result, entry)
1450 if (cancel_cookie == (IUnknown *)cur->result)
1452 list_remove(&cur->entry);
1453 found = cur;
1454 break;
1458 LeaveCriticalSection(&this->cs);
1460 if (found)
1462 IMFAsyncResult_Release(found->result);
1463 if (found->object)
1464 IUnknown_Release(found->object);
1465 free(found);
1468 return found ? S_OK : MF_E_UNEXPECTED;
1471 static HRESULT WINAPI winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler *iface, QWORD *bytes)
1473 FIXME("stub (%p %p)\n", iface, bytes);
1474 return E_NOTIMPL;
1477 static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl =
1479 winegstreamer_stream_handler_QueryInterface,
1480 winegstreamer_stream_handler_AddRef,
1481 winegstreamer_stream_handler_Release,
1482 winegstreamer_stream_handler_BeginCreateObject,
1483 winegstreamer_stream_handler_EndCreateObject,
1484 winegstreamer_stream_handler_CancelObjectCreation,
1485 winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution,
1488 static HRESULT WINAPI winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
1490 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1491 IsEqualIID(riid, &IID_IUnknown))
1493 *obj = iface;
1494 IMFAsyncCallback_AddRef(iface);
1495 return S_OK;
1498 WARN("Unsupported %s.\n", debugstr_guid(riid));
1499 *obj = NULL;
1500 return E_NOINTERFACE;
1503 static ULONG WINAPI winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback *iface)
1505 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1506 return IMFByteStreamHandler_AddRef(&handler->IMFByteStreamHandler_iface);
1509 static ULONG WINAPI winegstreamer_stream_handler_callback_Release(IMFAsyncCallback *iface)
1511 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1512 return IMFByteStreamHandler_Release(&handler->IMFByteStreamHandler_iface);
1515 static HRESULT WINAPI winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
1517 return E_NOTIMPL;
1520 static HRESULT winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler *This, WCHAR *url, IMFByteStream *stream, DWORD flags,
1521 IPropertyStore *props, IUnknown **out_object, MF_OBJECT_TYPE *out_obj_type)
1523 TRACE("(%p %s %p %u %p %p %p)\n", This, debugstr_w(url), stream, flags, props, out_object, out_obj_type);
1525 if (flags & MF_RESOLUTION_MEDIASOURCE)
1527 HRESULT hr;
1528 struct media_source *new_source;
1530 if (FAILED(hr = media_source_constructor(stream, &new_source)))
1531 return hr;
1533 TRACE("->(%p)\n", new_source);
1535 *out_object = (IUnknown*)&new_source->IMFMediaSource_iface;
1536 *out_obj_type = MF_OBJECT_MEDIASOURCE;
1538 return S_OK;
1540 else
1542 FIXME("flags = %08x\n", flags);
1543 return E_NOTIMPL;
1547 static HRESULT WINAPI winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1549 struct winegstreamer_stream_handler *handler = impl_from_IMFAsyncCallback(iface);
1550 struct winegstreamer_stream_handler_result *handler_result;
1551 MF_OBJECT_TYPE obj_type = MF_OBJECT_INVALID;
1552 IUnknown *object = NULL, *context_object;
1553 struct create_object_context *context;
1554 IMFAsyncResult *caller;
1555 HRESULT hr;
1557 caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
1559 if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
1561 WARN("Expected context set for callee result.\n");
1562 return hr;
1565 context = impl_from_IUnknown(context_object);
1567 hr = winegstreamer_stream_handler_create_object(handler, context->url, context->stream, context->flags, context->props, &object, &obj_type);
1569 if ((handler_result = malloc(sizeof(*handler_result))))
1571 handler_result->result = caller;
1572 IMFAsyncResult_AddRef(handler_result->result);
1573 handler_result->obj_type = obj_type;
1574 handler_result->object = object;
1576 EnterCriticalSection(&handler->cs);
1577 list_add_tail(&handler->results, &handler_result->entry);
1578 LeaveCriticalSection(&handler->cs);
1580 else
1582 if (object)
1583 IUnknown_Release(object);
1584 hr = E_OUTOFMEMORY;
1587 IUnknown_Release(&context->IUnknown_iface);
1589 IMFAsyncResult_SetStatus(caller, hr);
1590 MFInvokeCallback(caller);
1592 return S_OK;
1595 static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl =
1597 winegstreamer_stream_handler_callback_QueryInterface,
1598 winegstreamer_stream_handler_callback_AddRef,
1599 winegstreamer_stream_handler_callback_Release,
1600 winegstreamer_stream_handler_callback_GetParameters,
1601 winegstreamer_stream_handler_callback_Invoke,
1604 HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj)
1606 struct winegstreamer_stream_handler *this;
1607 HRESULT hr;
1609 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1611 if (!(this = calloc(1, sizeof(*this))))
1612 return E_OUTOFMEMORY;
1614 list_init(&this->results);
1615 InitializeCriticalSection(&this->cs);
1617 this->IMFByteStreamHandler_iface.lpVtbl = &winegstreamer_stream_handler_vtbl;
1618 this->IMFAsyncCallback_iface.lpVtbl = &winegstreamer_stream_handler_callback_vtbl;
1619 this->refcount = 1;
1621 hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj);
1622 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
1624 return hr;