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