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"
26 #include "wine/list.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
32 IMFMediaStream IMFMediaStream_iface
;
34 struct media_source
*parent_source
;
35 IMFMediaEventQueue
*event_queue
;
36 IMFStreamDescriptor
*descriptor
;
38 struct wg_parser_stream
*wg_stream
;
54 SOURCE_ASYNC_REQUEST_SAMPLE
,
57 struct source_async_command
59 IUnknown IUnknown_iface
;
61 enum source_async_op op
;
66 IMFPresentationDescriptor
*descriptor
;
72 struct media_stream
*stream
;
80 IMFMediaSource IMFMediaSource_iface
;
81 IMFAsyncCallback async_commands_callback
;
83 DWORD async_commands_queue
;
84 IMFMediaEventQueue
*event_queue
;
85 IMFByteStream
*byte_stream
;
87 struct wg_parser
*wg_parser
;
89 struct media_stream
**streams
;
91 IMFPresentationDescriptor
*pres_desc
;
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
))
131 IUnknown_AddRef(iface
);
135 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
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
);
153 if (command
->op
== SOURCE_ASYNC_START
)
154 PropVariantClear(&command
->u
.start
.position
);
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
;
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
))
191 IMFAsyncCallback_AddRef(iface
);
195 WARN("Unsupported %s.\n", debugstr_guid(riid
));
197 return E_NOINTERFACE
;
200 static HRESULT WINAPI
callback_GetParameters(IMFAsyncCallback
*iface
,
201 DWORD
*flags
, DWORD
*queue
)
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
)
221 IMFStreamDescriptor
*ret
;
224 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc
, &sd_count
)))
227 for (i
= 0; i
< sd_count
; i
++)
231 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc
, i
, selected
, &ret
)))
234 if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret
, &stream_id
)) && stream_id
== id
)
237 IMFStreamDescriptor_Release(ret
);
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
;
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
;
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
;
279 struct wg_format format
;
281 IMFStreamDescriptor_GetMediaTypeHandler(stream
->descriptor
, &mth
);
282 IMFMediaTypeHandler_GetCurrentMediaType(mth
, ¤t_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
)
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
)
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
};
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
)
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
;
362 if (FAILED(hr
= MFCreateSample(&sample
)))
364 ERR("Failed to create sample, hr %#x.\n", hr
);
368 if (FAILED(hr
= MFCreateMemoryBuffer(event
->u
.buffer
.size
, &buffer
)))
370 ERR("Failed to create buffer, hr %#x.\n", hr
);
371 IMFSample_Release(sample
);
375 if (FAILED(hr
= IMFSample_AddBuffer(sample
, buffer
)))
377 ERR("Failed to add buffer, hr %#x.\n", hr
);
381 if (FAILED(hr
= IMFMediaBuffer_SetCurrentLength(buffer
, event
->u
.buffer
.size
)))
383 ERR("Failed to set size, hr %#x.\n", hr
);
387 if (FAILED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, NULL
, NULL
)))
389 ERR("Failed to lock buffer, hr %#x.\n", hr
);
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
);
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
);
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
);
413 if (FAILED(hr
= IMFSample_SetSampleDuration(sample
, event
->u
.buffer
.duration
)))
415 ERR("Failed to set sample duration, hr %#x.\n", hr
);
420 IMFSample_SetUnknown(sample
, &MFSampleExtension_Token
, token
);
422 IMFMediaEventQueue_QueueEventParamUnk(stream
->event_queue
, MEMediaSample
,
423 &GUID_NULL
, S_OK
, (IUnknown
*)sample
);
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
);
439 if (!unix_funcs
->wg_parser_stream_get_event(stream
->wg_stream
, &event
))
442 TRACE("Got event of type %#x.\n", event
.type
);
446 case WG_PARSER_EVENT_BUFFER
:
447 send_buffer(stream
, &event
, token
);
450 case WG_PARSER_EVENT_EOS
:
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
);
458 case WG_PARSER_EVENT_SEGMENT
:
461 case WG_PARSER_EVENT_NONE
:
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
;
474 if (source
->state
== SOURCE_SHUTDOWN
)
477 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
480 command
= impl_from_async_command_IUnknown(state
);
483 case SOURCE_ASYNC_START
:
484 start_pipeline(source
, command
);
486 case SOURCE_ASYNC_STOP
:
487 stop_pipeline(source
);
489 case SOURCE_ASYNC_REQUEST_SAMPLE
:
490 wait_on_sample(command
->u
.request_sample
.stream
, command
->u
.request_sample
.token
);
494 IUnknown_Release(state
);
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
)
523 if (!unix_funcs
->wg_parser_get_read_request(source
->wg_parser
, &data
, &offset
, &size
))
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");
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
;
551 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
553 return E_NOINTERFACE
;
556 IUnknown_AddRef((IUnknown
*)*out
);
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
);
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
);
580 if (stream
->event_queue
)
581 IMFMediaEventQueue_Release(stream
->event_queue
);
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
;
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
;
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
;
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
;
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
;
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
);
691 static const IMFMediaStreamVtbl media_stream_vtbl
=
693 media_stream_QueryInterface
,
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
));
711 TRACE("source %p, wg_stream %p, stream_id %u.\n", source
, wg_stream
, stream_id
);
713 object
->IMFMediaStream_iface
.lpVtbl
= &media_stream_vtbl
;
716 IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
717 object
->parent_source
= source
;
718 object
->stream_id
= stream_id
;
720 object
->state
= STREAM_INACTIVE
;
722 object
->wg_stream
= wg_stream
;
724 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
727 TRACE("->(%p)\n", object
);
728 *out_stream
= object
;
733 WARN("Failed to construct media stream, hr %#x.\n", hr
);
735 IMFMediaStream_Release(&object
->IMFMediaStream_iface
);
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;
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
[] =
764 IMFMediaType
*base_type
= mf_media_type_from_wg_format(&format
);
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
;
774 for (i
= 0; i
< ARRAY_SIZE(video_types
); i
++)
776 IMFMediaType
*new_type
;
778 if (IsEqualGUID(&base_subtype
, video_types
[i
]))
781 if (FAILED(hr
= MFCreateMediaType(&new_type
)))
783 stream_types
[type_count
++] = new_type
;
785 if (FAILED(hr
= IMFMediaType_CopyAllItems(base_type
, (IMFAttributes
*) new_type
)))
787 if (FAILED(hr
= IMFMediaType_SetGUID(new_type
, &MF_MT_SUBTYPE
, video_types
[i
])))
793 stream_type
= mf_media_type_from_wg_format(&format
);
796 stream_types
= &stream_type
;
803 ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
807 if (FAILED(hr
= MFCreateStreamDescriptor(stream
->stream_id
, type_count
, stream_types
, &stream
->descriptor
)))
810 if (FAILED(hr
= IMFStreamDescriptor_GetMediaTypeHandler(stream
->descriptor
, &type_handler
)))
813 if (FAILED(hr
= IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, stream_types
[0])))
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
)
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
;
840 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
842 return E_NOINTERFACE
;
845 IUnknown_AddRef((IUnknown
*)*out
);
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
);
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
);
868 IMFMediaSource_Shutdown(&source
->IMFMediaSource_iface
);
869 IMFMediaEventQueue_Release(source
->event_queue
);
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
;
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
;
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
);
966 static HRESULT WINAPI
media_source_Stop(IMFMediaSource
*iface
)
968 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
969 struct source_async_command
*command
;
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
);
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
;
995 static HRESULT WINAPI
media_source_Shutdown(IMFMediaSource
*iface
)
997 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
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
);
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
,
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
;
1078 if (FAILED(hr
= IMFByteStream_GetCapabilities(bytestream
, &bytestream_caps
)))
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
);
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
;
1099 object
->byte_stream
= bytestream
;
1100 IMFByteStream_AddRef(bytestream
);
1102 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1105 if (FAILED(hr
= MFAllocateWorkQueue(&object
->async_commands_queue
)))
1108 object
->read_thread
= CreateThread(NULL
, 0, read_thread
, object
, 0, NULL
);
1110 if (!(parser
= unix_funcs
->wg_decodebin_parser_create()))
1115 object
->wg_parser
= parser
;
1117 object
->state
= SOURCE_OPENING
;
1119 if (FAILED(hr
= unix_funcs
->wg_parser_connect(parser
, file_size
)))
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
))))
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
])))
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
);
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
)))
1162 for (i
= 0; i
< object
->stream_count
; i
++)
1164 IMFPresentationDescriptor_SelectStream(object
->pres_desc
, i
);
1165 IMFStreamDescriptor_Release(descriptors
[i
]);
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
;
1183 WARN("Failed to construct MFMediaSource, hr %#x.\n", hr
);
1186 IMFMediaSource_Release(&object
->IMFMediaSource_iface
);
1190 struct winegstreamer_stream_handler_result
1193 IMFAsyncResult
*result
;
1194 MF_OBJECT_TYPE obj_type
;
1198 struct winegstreamer_stream_handler
1200 IMFByteStreamHandler IMFByteStreamHandler_iface
;
1201 IMFAsyncCallback IMFAsyncCallback_iface
;
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
))
1225 IMFByteStreamHandler_AddRef(iface
);
1229 WARN("Unsupported %s.\n", debugstr_guid(riid
));
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
);
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
);
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
);
1259 IUnknown_Release(result
->object
);
1262 DeleteCriticalSection(&handler
->cs
);
1269 struct create_object_context
1271 IUnknown IUnknown_iface
;
1274 IPropertyStore
*props
;
1275 IMFByteStream
*stream
;
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
))
1292 IUnknown_AddRef(iface
);
1296 WARN("Unsupported %s.\n", debugstr_guid(riid
));
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
);
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
);
1321 IPropertyStore_Release(context
->props
);
1322 if (context
->stream
)
1323 IMFByteStream_Release(context
->stream
);
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
;
1346 TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface
, debugstr_w(url
), flags
, props
, cancel_cookie
, callback
, state
);
1349 *cancel_cookie
= NULL
;
1351 if (FAILED(hr
= MFCreateAsyncResult(NULL
, callback
, state
, &caller
)))
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
;
1364 IPropertyStore_AddRef(context
->props
);
1365 context
->flags
= flags
;
1366 context
->stream
= stream
;
1367 if (context
->stream
)
1368 IMFByteStream_AddRef(context
->stream
);
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
);
1382 if (SUCCEEDED(hr
= MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO
, item
)))
1386 *cancel_cookie
= (IUnknown
*)caller
;
1387 IUnknown_AddRef(*cancel_cookie
);
1391 IMFAsyncResult_Release(item
);
1393 IMFAsyncResult_Release(caller
);
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
;
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
);
1419 LeaveCriticalSection(&this->cs
);
1423 *obj_type
= found
->obj_type
;
1424 *object
= found
->object
;
1425 hr
= IMFAsyncResult_GetStatus(found
->result
);
1426 IMFAsyncResult_Release(found
->result
);
1431 *obj_type
= MF_OBJECT_INVALID
;
1433 hr
= MF_E_UNEXPECTED
;
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
);
1458 LeaveCriticalSection(&this->cs
);
1462 IMFAsyncResult_Release(found
->result
);
1464 IUnknown_Release(found
->object
);
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
);
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
))
1494 IMFAsyncCallback_AddRef(iface
);
1498 WARN("Unsupported %s.\n", debugstr_guid(riid
));
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
)
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
)
1528 struct media_source
*new_source
;
1530 if (FAILED(hr
= media_source_constructor(stream
, &new_source
)))
1533 TRACE("->(%p)\n", new_source
);
1535 *out_object
= (IUnknown
*)&new_source
->IMFMediaSource_iface
;
1536 *out_obj_type
= MF_OBJECT_MEDIASOURCE
;
1542 FIXME("flags = %08x\n", flags
);
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
;
1557 caller
= (IMFAsyncResult
*)IMFAsyncResult_GetStateNoAddRef(result
);
1559 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &context_object
)))
1561 WARN("Expected context set for callee result.\n");
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
);
1583 IUnknown_Release(object
);
1587 IUnknown_Release(&context
->IUnknown_iface
);
1589 IMFAsyncResult_SetStatus(caller
, hr
);
1590 MFInvokeCallback(caller
);
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;
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
;
1621 hr
= IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface
, riid
, obj
);
1622 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface
);