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
);
173 else if (command
->op
== SOURCE_ASYNC_REQUEST_SAMPLE
)
175 if (command
->u
.request_sample
.token
)
176 IUnknown_Release(command
->u
.request_sample
.token
);
184 static const IUnknownVtbl source_async_command_vtbl
=
186 source_async_command_QueryInterface
,
187 source_async_command_AddRef
,
188 source_async_command_Release
,
191 static HRESULT
source_create_async_op(enum source_async_op op
, struct source_async_command
**ret
)
193 struct source_async_command
*command
;
195 if (!(command
= calloc(1, sizeof(*command
))))
196 return E_OUTOFMEMORY
;
198 command
->IUnknown_iface
.lpVtbl
= &source_async_command_vtbl
;
206 static HRESULT WINAPI
callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
208 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
210 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
211 IsEqualIID(riid
, &IID_IUnknown
))
214 IMFAsyncCallback_AddRef(iface
);
218 WARN("Unsupported %s.\n", debugstr_guid(riid
));
220 return E_NOINTERFACE
;
223 static HRESULT WINAPI
callback_GetParameters(IMFAsyncCallback
*iface
,
224 DWORD
*flags
, DWORD
*queue
)
229 static ULONG WINAPI
source_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
231 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
232 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
235 static ULONG WINAPI
source_async_commands_callback_Release(IMFAsyncCallback
*iface
)
237 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
238 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
241 static IMFStreamDescriptor
*stream_descriptor_from_id(IMFPresentationDescriptor
*pres_desc
, DWORD id
, BOOL
*selected
)
244 IMFStreamDescriptor
*ret
;
247 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc
, &sd_count
)))
250 for (i
= 0; i
< sd_count
; i
++)
254 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc
, i
, selected
, &ret
)))
257 if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret
, &stream_id
)) && stream_id
== id
)
260 IMFStreamDescriptor_Release(ret
);
265 static void start_pipeline(struct media_source
*source
, struct source_async_command
*command
)
267 PROPVARIANT
*position
= &command
->u
.start
.position
;
268 BOOL seek_message
= source
->state
!= SOURCE_STOPPED
&& position
->vt
!= VT_EMPTY
;
271 /* seek to beginning on stop->play */
272 if (source
->state
== SOURCE_STOPPED
&& position
->vt
== VT_EMPTY
)
274 position
->vt
= VT_I8
;
275 position
->hVal
.QuadPart
= 0;
277 source
->start_time
= position
->hVal
.QuadPart
;
279 for (i
= 0; i
< source
->stream_count
; i
++)
281 struct media_stream
*stream
;
282 IMFStreamDescriptor
*sd
;
283 IMFMediaTypeHandler
*mth
;
284 IMFMediaType
*current_mt
;
289 stream
= source
->streams
[i
];
291 IMFStreamDescriptor_GetStreamIdentifier(stream
->descriptor
, &stream_id
);
293 sd
= stream_descriptor_from_id(command
->u
.start
.descriptor
, stream_id
, &selected
);
294 IMFStreamDescriptor_Release(sd
);
296 was_active
= stream
->state
!= STREAM_INACTIVE
;
298 stream
->state
= selected
? STREAM_RUNNING
: STREAM_INACTIVE
;
302 struct wg_format format
;
304 IMFStreamDescriptor_GetMediaTypeHandler(stream
->descriptor
, &mth
);
305 IMFMediaTypeHandler_GetCurrentMediaType(mth
, ¤t_mt
);
307 mf_media_type_to_wg_format(current_mt
, &format
);
308 unix_funcs
->wg_parser_stream_enable(stream
->wg_stream
, &format
);
310 IMFMediaType_Release(current_mt
);
311 IMFMediaTypeHandler_Release(mth
);
314 if (position
->vt
!= VT_EMPTY
)
319 TRACE("Stream %u (%p) selected\n", i
, stream
);
320 IMFMediaEventQueue_QueueEventParamUnk(source
->event_queue
,
321 was_active
? MEUpdatedStream
: MENewStream
, &GUID_NULL
,
322 S_OK
, (IUnknown
*) &stream
->IMFMediaStream_iface
);
324 IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
,
325 seek_message
? MEStreamSeeked
: MEStreamStarted
, &GUID_NULL
, S_OK
, position
);
329 IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
,
330 seek_message
? MESourceSeeked
: MESourceStarted
,
331 &GUID_NULL
, S_OK
, position
);
333 source
->state
= SOURCE_RUNNING
;
335 unix_funcs
->wg_parser_stream_seek(source
->streams
[0]->wg_stream
, 1.0,
336 position
->hVal
.QuadPart
, 0, AM_SEEKING_AbsolutePositioning
, AM_SEEKING_NoPositioning
);
337 unix_funcs
->wg_parser_end_flush(source
->wg_parser
);
340 static void stop_pipeline(struct media_source
*source
)
344 unix_funcs
->wg_parser_begin_flush(source
->wg_parser
);
346 for (i
= 0; i
< source
->stream_count
; i
++)
348 struct media_stream
*stream
= source
->streams
[i
];
349 if (stream
->state
!= STREAM_INACTIVE
)
351 IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEStreamStopped
, &GUID_NULL
, S_OK
, NULL
);
352 unix_funcs
->wg_parser_stream_disable(stream
->wg_stream
);
356 IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourceStopped
, &GUID_NULL
, S_OK
, NULL
);
358 source
->state
= SOURCE_STOPPED
;
361 static void dispatch_end_of_presentation(struct media_source
*source
)
363 PROPVARIANT empty
= {.vt
= VT_EMPTY
};
366 /* A stream has ended, check whether all have */
367 for (i
= 0; i
< source
->stream_count
; i
++)
369 struct media_stream
*stream
= source
->streams
[i
];
371 if (stream
->state
!= STREAM_INACTIVE
&& !stream
->eos
)
375 IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, &empty
);
378 static void send_buffer(struct media_stream
*stream
, const struct wg_parser_event
*event
, IUnknown
*token
)
380 IMFMediaBuffer
*buffer
;
385 if (FAILED(hr
= MFCreateSample(&sample
)))
387 ERR("Failed to create sample, hr %#x.\n", hr
);
391 if (FAILED(hr
= MFCreateMemoryBuffer(event
->u
.buffer
.size
, &buffer
)))
393 ERR("Failed to create buffer, hr %#x.\n", hr
);
394 IMFSample_Release(sample
);
398 if (FAILED(hr
= IMFSample_AddBuffer(sample
, buffer
)))
400 ERR("Failed to add buffer, hr %#x.\n", hr
);
404 if (FAILED(hr
= IMFMediaBuffer_SetCurrentLength(buffer
, event
->u
.buffer
.size
)))
406 ERR("Failed to set size, hr %#x.\n", hr
);
410 if (FAILED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, NULL
, NULL
)))
412 ERR("Failed to lock buffer, hr %#x.\n", hr
);
416 if (!unix_funcs
->wg_parser_stream_copy_buffer(stream
->wg_stream
, data
, 0, event
->u
.buffer
.size
))
418 unix_funcs
->wg_parser_stream_release_buffer(stream
->wg_stream
);
419 IMFMediaBuffer_Unlock(buffer
);
422 unix_funcs
->wg_parser_stream_release_buffer(stream
->wg_stream
);
424 if (FAILED(hr
= IMFMediaBuffer_Unlock(buffer
)))
426 ERR("Failed to unlock buffer, hr %#x.\n", hr
);
430 if (FAILED(hr
= IMFSample_SetSampleTime(sample
, event
->u
.buffer
.pts
- stream
->parent_source
->start_time
)))
432 ERR("Failed to set sample time, hr %#x.\n", hr
);
436 if (FAILED(hr
= IMFSample_SetSampleDuration(sample
, event
->u
.buffer
.duration
)))
438 ERR("Failed to set sample duration, hr %#x.\n", hr
);
443 IMFSample_SetUnknown(sample
, &MFSampleExtension_Token
, token
);
445 IMFMediaEventQueue_QueueEventParamUnk(stream
->event_queue
, MEMediaSample
,
446 &GUID_NULL
, S_OK
, (IUnknown
*)sample
);
449 IMFMediaBuffer_Release(buffer
);
450 IMFSample_Release(sample
);
453 static void wait_on_sample(struct media_stream
*stream
, IUnknown
*token
)
455 PROPVARIANT empty_var
= {.vt
= VT_EMPTY
};
456 struct wg_parser_event event
;
458 TRACE("%p, %p\n", stream
, token
);
462 if (!unix_funcs
->wg_parser_stream_get_event(stream
->wg_stream
, &event
))
465 TRACE("Got event of type %#x.\n", event
.type
);
469 case WG_PARSER_EVENT_BUFFER
:
470 send_buffer(stream
, &event
, token
);
473 case WG_PARSER_EVENT_EOS
:
475 IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEEndOfStream
, &GUID_NULL
, S_OK
, &empty_var
);
476 dispatch_end_of_presentation(stream
->parent_source
);
479 case WG_PARSER_EVENT_SEGMENT
:
482 case WG_PARSER_EVENT_NONE
:
488 static HRESULT WINAPI
source_async_commands_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
490 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
491 struct source_async_command
*command
;
495 if (source
->state
== SOURCE_SHUTDOWN
)
498 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
501 command
= impl_from_async_command_IUnknown(state
);
504 case SOURCE_ASYNC_START
:
505 start_pipeline(source
, command
);
507 case SOURCE_ASYNC_STOP
:
508 stop_pipeline(source
);
510 case SOURCE_ASYNC_REQUEST_SAMPLE
:
511 wait_on_sample(command
->u
.request_sample
.stream
, command
->u
.request_sample
.token
);
515 IUnknown_Release(state
);
520 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl
=
522 callback_QueryInterface
,
523 source_async_commands_callback_AddRef
,
524 source_async_commands_callback_Release
,
525 callback_GetParameters
,
526 source_async_commands_Invoke
,
529 static DWORD CALLBACK
read_thread(void *arg
)
531 struct media_source
*source
= arg
;
532 IMFByteStream
*byte_stream
= source
->byte_stream
;
534 TRACE("Starting read thread for media source %p.\n", source
);
536 while (!source
->read_thread_shutdown
)
544 if (!unix_funcs
->wg_parser_get_read_request(source
->wg_parser
, &data
, &offset
, &size
))
547 if (SUCCEEDED(hr
= IMFByteStream_SetCurrentPosition(byte_stream
, offset
)))
548 hr
= IMFByteStream_Read(byte_stream
, data
, size
, &ret_size
);
549 if (SUCCEEDED(hr
) && ret_size
!= size
)
550 ERR("Unexpected short read: requested %u bytes, got %u.\n", size
, ret_size
);
551 unix_funcs
->wg_parser_complete_read_request(source
->wg_parser
, SUCCEEDED(hr
));
554 TRACE("Media source is shutting down; exiting.\n");
558 static HRESULT WINAPI
media_stream_QueryInterface(IMFMediaStream
*iface
, REFIID riid
, void **out
)
560 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
562 TRACE("(%p)->(%s %p)\n", stream
, debugstr_guid(riid
), out
);
564 if (IsEqualIID(riid
, &IID_IMFMediaStream
) ||
565 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
566 IsEqualIID(riid
, &IID_IUnknown
))
568 *out
= &stream
->IMFMediaStream_iface
;
572 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
574 return E_NOINTERFACE
;
577 IUnknown_AddRef((IUnknown
*)*out
);
581 static ULONG WINAPI
media_stream_AddRef(IMFMediaStream
*iface
)
583 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
584 ULONG ref
= InterlockedIncrement(&stream
->ref
);
586 TRACE("(%p) ref=%u\n", stream
, ref
);
591 static ULONG WINAPI
media_stream_Release(IMFMediaStream
*iface
)
593 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
595 ULONG ref
= InterlockedDecrement(&stream
->ref
);
597 TRACE("(%p) ref=%u\n", stream
, ref
);
601 if (stream
->event_queue
)
602 IMFMediaEventQueue_Release(stream
->event_queue
);
609 static HRESULT WINAPI
media_stream_GetEvent(IMFMediaStream
*iface
, DWORD flags
, IMFMediaEvent
**event
)
611 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
613 TRACE("(%p)->(%#x, %p)\n", stream
, flags
, event
);
615 return IMFMediaEventQueue_GetEvent(stream
->event_queue
, flags
, event
);
618 static HRESULT WINAPI
media_stream_BeginGetEvent(IMFMediaStream
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
620 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
622 TRACE("(%p)->(%p, %p)\n", stream
, callback
, state
);
624 return IMFMediaEventQueue_BeginGetEvent(stream
->event_queue
, callback
, state
);
627 static HRESULT WINAPI
media_stream_EndGetEvent(IMFMediaStream
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
629 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
631 TRACE("(%p)->(%p, %p)\n", stream
, result
, event
);
633 return IMFMediaEventQueue_EndGetEvent(stream
->event_queue
, result
, event
);
636 static HRESULT WINAPI
media_stream_QueueEvent(IMFMediaStream
*iface
, MediaEventType event_type
, REFGUID ext_type
,
637 HRESULT hr
, const PROPVARIANT
*value
)
639 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
641 TRACE("(%p)->(%d, %s, %#x, %p)\n", stream
, event_type
, debugstr_guid(ext_type
), hr
, value
);
643 return IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, event_type
, ext_type
, hr
, value
);
646 static HRESULT WINAPI
media_stream_GetMediaSource(IMFMediaStream
*iface
, IMFMediaSource
**source
)
648 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
650 TRACE("(%p)->(%p)\n", stream
, source
);
652 if (stream
->state
== STREAM_SHUTDOWN
)
653 return MF_E_SHUTDOWN
;
655 IMFMediaSource_AddRef(&stream
->parent_source
->IMFMediaSource_iface
);
656 *source
= &stream
->parent_source
->IMFMediaSource_iface
;
661 static HRESULT WINAPI
media_stream_GetStreamDescriptor(IMFMediaStream
* iface
, IMFStreamDescriptor
**descriptor
)
663 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
665 TRACE("(%p)->(%p)\n", stream
, descriptor
);
667 if (stream
->state
== STREAM_SHUTDOWN
)
668 return MF_E_SHUTDOWN
;
670 IMFStreamDescriptor_AddRef(stream
->descriptor
);
671 *descriptor
= stream
->descriptor
;
676 static HRESULT WINAPI
media_stream_RequestSample(IMFMediaStream
*iface
, IUnknown
*token
)
678 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
679 struct source_async_command
*command
;
682 TRACE("(%p)->(%p)\n", iface
, token
);
684 if (stream
->state
== STREAM_SHUTDOWN
)
685 return MF_E_SHUTDOWN
;
687 if (stream
->state
== STREAM_INACTIVE
)
689 WARN("Stream isn't active\n");
690 return MF_E_MEDIA_SOURCE_WRONGSTATE
;
695 return MF_E_END_OF_STREAM
;
698 if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE
, &command
)))
700 command
->u
.request_sample
.stream
= stream
;
702 IUnknown_AddRef(token
);
703 command
->u
.request_sample
.token
= token
;
705 /* Once pause support is added, this will need to put into a stream queue, and synchronization will need to be added*/
706 hr
= MFPutWorkItem(stream
->parent_source
->async_commands_queue
, &stream
->parent_source
->async_commands_callback
, &command
->IUnknown_iface
);
712 static const IMFMediaStreamVtbl media_stream_vtbl
=
714 media_stream_QueryInterface
,
716 media_stream_Release
,
717 media_stream_GetEvent
,
718 media_stream_BeginGetEvent
,
719 media_stream_EndGetEvent
,
720 media_stream_QueueEvent
,
721 media_stream_GetMediaSource
,
722 media_stream_GetStreamDescriptor
,
723 media_stream_RequestSample
726 static HRESULT
new_media_stream(struct media_source
*source
,
727 struct wg_parser_stream
*wg_stream
, DWORD stream_id
, struct media_stream
**out_stream
)
729 struct media_stream
*object
= calloc(1, sizeof(*object
));
732 TRACE("source %p, wg_stream %p, stream_id %u.\n", source
, wg_stream
, stream_id
);
734 object
->IMFMediaStream_iface
.lpVtbl
= &media_stream_vtbl
;
737 IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
738 object
->parent_source
= source
;
739 object
->stream_id
= stream_id
;
741 object
->state
= STREAM_INACTIVE
;
743 object
->wg_stream
= wg_stream
;
745 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
748 TRACE("->(%p)\n", object
);
749 *out_stream
= object
;
754 WARN("Failed to construct media stream, hr %#x.\n", hr
);
756 IMFMediaStream_Release(&object
->IMFMediaStream_iface
);
760 static HRESULT
media_stream_init_desc(struct media_stream
*stream
)
762 IMFMediaTypeHandler
*type_handler
= NULL
;
763 IMFMediaType
*stream_types
[6];
764 struct wg_format format
;
765 DWORD type_count
= 0;
769 unix_funcs
->wg_parser_stream_get_preferred_format(stream
->wg_stream
, &format
);
771 if (format
.major_type
== WG_MAJOR_TYPE_VIDEO
)
773 /* These are the most common native output types of decoders:
774 https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order */
775 static const GUID
*const video_types
[] =
784 IMFMediaType
*base_type
= mf_media_type_from_wg_format(&format
);
787 IMFMediaType_GetGUID(base_type
, &MF_MT_SUBTYPE
, &base_subtype
);
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
])))
809 else if (format
.major_type
== WG_MAJOR_TYPE_AUDIO
)
811 /* Expose at least one PCM and one floating point type for the
812 consumer to pick from. */
813 static const enum wg_audio_format audio_types
[] =
815 WG_AUDIO_FORMAT_S16LE
,
816 WG_AUDIO_FORMAT_F32LE
,
819 stream_types
[0] = mf_media_type_from_wg_format(&format
);
822 for (i
= 0; i
< ARRAY_SIZE(audio_types
); i
++)
824 struct wg_format new_format
;
825 if (format
.u
.audio
.format
== audio_types
[i
])
828 new_format
.u
.audio
.format
= audio_types
[i
];
829 stream_types
[type_count
++] = mf_media_type_from_wg_format(&new_format
);
834 if ((stream_types
[0] = mf_media_type_from_wg_format(&format
)))
838 assert(type_count
<= ARRAY_SIZE(stream_types
));
842 ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
846 if (FAILED(hr
= MFCreateStreamDescriptor(stream
->stream_id
, type_count
, stream_types
, &stream
->descriptor
)))
849 if (FAILED(hr
= IMFStreamDescriptor_GetMediaTypeHandler(stream
->descriptor
, &type_handler
)))
852 if (FAILED(hr
= IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, stream_types
[0])))
857 IMFMediaTypeHandler_Release(type_handler
);
858 for (i
= 0; i
< type_count
; i
++)
859 IMFMediaType_Release(stream_types
[i
]);
863 static HRESULT WINAPI
media_source_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
865 struct media_source
*source
= impl_from_IMFGetService(iface
);
866 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
869 static ULONG WINAPI
media_source_get_service_AddRef(IMFGetService
*iface
)
871 struct media_source
*source
= impl_from_IMFGetService(iface
);
872 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
875 static ULONG WINAPI
media_source_get_service_Release(IMFGetService
*iface
)
877 struct media_source
*source
= impl_from_IMFGetService(iface
);
878 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
881 static HRESULT WINAPI
media_source_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
883 struct media_source
*source
= impl_from_IMFGetService(iface
);
885 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
889 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
891 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
893 *obj
= &source
->IMFRateSupport_iface
;
895 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
897 *obj
= &source
->IMFRateControl_iface
;
901 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
904 IUnknown_AddRef((IUnknown
*)*obj
);
906 return *obj
? S_OK
: E_NOINTERFACE
;
909 static const IMFGetServiceVtbl media_source_get_service_vtbl
=
911 media_source_get_service_QueryInterface
,
912 media_source_get_service_AddRef
,
913 media_source_get_service_Release
,
914 media_source_get_service_GetService
,
917 static HRESULT WINAPI
media_source_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
919 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
920 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
923 static ULONG WINAPI
media_source_rate_support_AddRef(IMFRateSupport
*iface
)
925 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
926 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
929 static ULONG WINAPI
media_source_rate_support_Release(IMFRateSupport
*iface
)
931 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
932 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
935 static HRESULT WINAPI
media_source_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
, BOOL thin
, float *rate
)
937 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
944 static HRESULT WINAPI
media_source_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
, BOOL thin
, float *rate
)
946 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
948 *rate
= direction
== MFRATE_FORWARD
? 1e6f
: -1e6f
;
953 static HRESULT WINAPI
media_source_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
956 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_rate
);
959 *nearest_rate
= rate
;
961 return rate
>= -1e6f
&& rate
<= 1e6f
? S_OK
: MF_E_UNSUPPORTED_RATE
;
964 static const IMFRateSupportVtbl media_source_rate_support_vtbl
=
966 media_source_rate_support_QueryInterface
,
967 media_source_rate_support_AddRef
,
968 media_source_rate_support_Release
,
969 media_source_rate_support_GetSlowestRate
,
970 media_source_rate_support_GetFastestRate
,
971 media_source_rate_support_IsRateSupported
,
974 static HRESULT WINAPI
media_source_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
976 struct media_source
*source
= impl_from_IMFRateControl(iface
);
977 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
980 static ULONG WINAPI
media_source_rate_control_AddRef(IMFRateControl
*iface
)
982 struct media_source
*source
= impl_from_IMFRateControl(iface
);
983 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
986 static ULONG WINAPI
media_source_rate_control_Release(IMFRateControl
*iface
)
988 struct media_source
*source
= impl_from_IMFRateControl(iface
);
989 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
992 static HRESULT WINAPI
media_source_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
994 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
997 return MF_E_REVERSE_UNSUPPORTED
;
1000 return MF_E_THINNING_UNSUPPORTED
;
1003 return MF_E_UNSUPPORTED_RATE
;
1008 static HRESULT WINAPI
media_source_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
1010 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
1020 static const IMFRateControlVtbl media_source_rate_control_vtbl
=
1022 media_source_rate_control_QueryInterface
,
1023 media_source_rate_control_AddRef
,
1024 media_source_rate_control_Release
,
1025 media_source_rate_control_SetRate
,
1026 media_source_rate_control_GetRate
,
1029 static HRESULT WINAPI
media_source_QueryInterface(IMFMediaSource
*iface
, REFIID riid
, void **out
)
1031 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1033 TRACE("(%p)->(%s %p)\n", source
, debugstr_guid(riid
), out
);
1035 if (IsEqualIID(riid
, &IID_IMFMediaSource
) ||
1036 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1037 IsEqualIID(riid
, &IID_IUnknown
))
1039 *out
= &source
->IMFMediaSource_iface
;
1041 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1043 *out
= &source
->IMFGetService_iface
;
1047 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
1049 return E_NOINTERFACE
;
1052 IUnknown_AddRef((IUnknown
*)*out
);
1056 static ULONG WINAPI
media_source_AddRef(IMFMediaSource
*iface
)
1058 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1059 ULONG ref
= InterlockedIncrement(&source
->ref
);
1061 TRACE("(%p) ref=%u\n", source
, ref
);
1066 static ULONG WINAPI
media_source_Release(IMFMediaSource
*iface
)
1068 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1069 ULONG ref
= InterlockedDecrement(&source
->ref
);
1071 TRACE("(%p) ref=%u\n", source
, ref
);
1075 IMFMediaSource_Shutdown(&source
->IMFMediaSource_iface
);
1076 IMFMediaEventQueue_Release(source
->event_queue
);
1083 static HRESULT WINAPI
media_source_GetEvent(IMFMediaSource
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1085 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1087 TRACE("(%p)->(%#x, %p)\n", source
, flags
, event
);
1089 return IMFMediaEventQueue_GetEvent(source
->event_queue
, flags
, event
);
1092 static HRESULT WINAPI
media_source_BeginGetEvent(IMFMediaSource
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1094 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1096 TRACE("(%p)->(%p, %p)\n", source
, callback
, state
);
1098 return IMFMediaEventQueue_BeginGetEvent(source
->event_queue
, callback
, state
);
1101 static HRESULT WINAPI
media_source_EndGetEvent(IMFMediaSource
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1103 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1105 TRACE("(%p)->(%p, %p)\n", source
, result
, event
);
1107 return IMFMediaEventQueue_EndGetEvent(source
->event_queue
, result
, event
);
1110 static HRESULT WINAPI
media_source_QueueEvent(IMFMediaSource
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1111 HRESULT hr
, const PROPVARIANT
*value
)
1113 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1115 TRACE("(%p)->(%d, %s, %#x, %p)\n", source
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1117 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, event_type
, ext_type
, hr
, value
);
1120 static HRESULT WINAPI
media_source_GetCharacteristics(IMFMediaSource
*iface
, DWORD
*characteristics
)
1122 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1124 TRACE("(%p)->(%p)\n", source
, characteristics
);
1126 if (source
->state
== SOURCE_SHUTDOWN
)
1127 return MF_E_SHUTDOWN
;
1129 *characteristics
= MFMEDIASOURCE_CAN_SEEK
;
1134 static HRESULT WINAPI
media_source_CreatePresentationDescriptor(IMFMediaSource
*iface
, IMFPresentationDescriptor
**descriptor
)
1136 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1138 TRACE("(%p)->(%p)\n", source
, descriptor
);
1140 if (source
->state
== SOURCE_SHUTDOWN
)
1141 return MF_E_SHUTDOWN
;
1143 return IMFPresentationDescriptor_Clone(source
->pres_desc
, descriptor
);
1146 static HRESULT WINAPI
media_source_Start(IMFMediaSource
*iface
, IMFPresentationDescriptor
*descriptor
,
1147 const GUID
*time_format
, const PROPVARIANT
*position
)
1149 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1150 struct source_async_command
*command
;
1153 TRACE("(%p)->(%p, %p, %p)\n", source
, descriptor
, time_format
, position
);
1155 if (source
->state
== SOURCE_SHUTDOWN
)
1156 return MF_E_SHUTDOWN
;
1158 if (!(IsEqualIID(time_format
, &GUID_NULL
)))
1159 return MF_E_UNSUPPORTED_TIME_FORMAT
;
1161 if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_START
, &command
)))
1163 command
->u
.start
.descriptor
= descriptor
;
1164 command
->u
.start
.format
= *time_format
;
1165 PropVariantCopy(&command
->u
.start
.position
, position
);
1167 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, &command
->IUnknown_iface
);
1173 static HRESULT WINAPI
media_source_Stop(IMFMediaSource
*iface
)
1175 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1176 struct source_async_command
*command
;
1179 TRACE("(%p)\n", source
);
1181 if (source
->state
== SOURCE_SHUTDOWN
)
1182 return MF_E_SHUTDOWN
;
1184 if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_STOP
, &command
)))
1185 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, &command
->IUnknown_iface
);
1190 static HRESULT WINAPI
media_source_Pause(IMFMediaSource
*iface
)
1192 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1194 FIXME("(%p): stub\n", source
);
1196 if (source
->state
== SOURCE_SHUTDOWN
)
1197 return MF_E_SHUTDOWN
;
1202 static HRESULT WINAPI
media_source_Shutdown(IMFMediaSource
*iface
)
1204 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1207 TRACE("(%p)\n", source
);
1209 if (source
->state
== SOURCE_SHUTDOWN
)
1210 return MF_E_SHUTDOWN
;
1212 source
->state
= SOURCE_SHUTDOWN
;
1214 unix_funcs
->wg_parser_disconnect(source
->wg_parser
);
1216 if (source
->read_thread
)
1218 source
->read_thread_shutdown
= true;
1219 WaitForSingleObject(source
->read_thread
, INFINITE
);
1220 CloseHandle(source
->read_thread
);
1223 if (source
->pres_desc
)
1224 IMFPresentationDescriptor_Release(source
->pres_desc
);
1225 if (source
->event_queue
)
1226 IMFMediaEventQueue_Shutdown(source
->event_queue
);
1227 if (source
->byte_stream
)
1228 IMFByteStream_Release(source
->byte_stream
);
1230 for (i
= 0; i
< source
->stream_count
; i
++)
1232 struct media_stream
*stream
= source
->streams
[i
];
1234 stream
->state
= STREAM_SHUTDOWN
;
1236 if (stream
->event_queue
)
1237 IMFMediaEventQueue_Shutdown(stream
->event_queue
);
1238 if (stream
->descriptor
)
1239 IMFStreamDescriptor_Release(stream
->descriptor
);
1240 if (stream
->parent_source
)
1241 IMFMediaSource_Release(&stream
->parent_source
->IMFMediaSource_iface
);
1243 IMFMediaStream_Release(&stream
->IMFMediaStream_iface
);
1246 unix_funcs
->wg_parser_destroy(source
->wg_parser
);
1248 if (source
->stream_count
)
1249 free(source
->streams
);
1251 if (source
->async_commands_queue
)
1252 MFUnlockWorkQueue(source
->async_commands_queue
);
1257 static const IMFMediaSourceVtbl IMFMediaSource_vtbl
=
1259 media_source_QueryInterface
,
1260 media_source_AddRef
,
1261 media_source_Release
,
1262 media_source_GetEvent
,
1263 media_source_BeginGetEvent
,
1264 media_source_EndGetEvent
,
1265 media_source_QueueEvent
,
1266 media_source_GetCharacteristics
,
1267 media_source_CreatePresentationDescriptor
,
1271 media_source_Shutdown
,
1274 static HRESULT
media_source_constructor(IMFByteStream
*bytestream
, struct media_source
**out_media_source
)
1276 IMFStreamDescriptor
**descriptors
= NULL
;
1277 struct media_source
*object
;
1278 UINT64 total_pres_time
= 0;
1279 struct wg_parser
*parser
;
1280 DWORD bytestream_caps
;
1285 if (FAILED(hr
= IMFByteStream_GetCapabilities(bytestream
, &bytestream_caps
)))
1288 if (!(bytestream_caps
& MFBYTESTREAM_IS_SEEKABLE
))
1290 FIXME("Non-seekable bytestreams not supported.\n");
1291 return MF_E_BYTESTREAM_NOT_SEEKABLE
;
1294 if (FAILED(hr
= IMFByteStream_GetLength(bytestream
, &file_size
)))
1296 FIXME("Failed to get byte stream length, hr %#x.\n", hr
);
1300 if (!(object
= calloc(1, sizeof(*object
))))
1301 return E_OUTOFMEMORY
;
1303 object
->IMFMediaSource_iface
.lpVtbl
= &IMFMediaSource_vtbl
;
1304 object
->IMFGetService_iface
.lpVtbl
= &media_source_get_service_vtbl
;
1305 object
->IMFRateSupport_iface
.lpVtbl
= &media_source_rate_support_vtbl
;
1306 object
->IMFRateControl_iface
.lpVtbl
= &media_source_rate_control_vtbl
;
1307 object
->async_commands_callback
.lpVtbl
= &source_async_commands_callback_vtbl
;
1309 object
->byte_stream
= bytestream
;
1310 IMFByteStream_AddRef(bytestream
);
1312 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1315 if (FAILED(hr
= MFAllocateWorkQueue(&object
->async_commands_queue
)))
1318 object
->read_thread
= CreateThread(NULL
, 0, read_thread
, object
, 0, NULL
);
1320 if (!(parser
= unix_funcs
->wg_decodebin_parser_create()))
1325 object
->wg_parser
= parser
;
1327 object
->state
= SOURCE_OPENING
;
1329 if (FAILED(hr
= unix_funcs
->wg_parser_connect(parser
, file_size
)))
1332 /* In Media Foundation, sources may read from any media source stream
1333 * without fear of blocking due to buffering limits on another. Trailmakers,
1334 * a Unity3D Engine game, only reads one sample from the audio stream (and
1335 * never deselects it). Remove buffering limits from decodebin in order to
1336 * account for this. Note that this does leak memory, but the same memory
1337 * leak occurs with native. */
1338 unix_funcs
->wg_parser_set_unlimited_buffering(parser
);
1340 object
->stream_count
= unix_funcs
->wg_parser_get_stream_count(parser
);
1342 if (!(object
->streams
= calloc(object
->stream_count
, sizeof(*object
->streams
))))
1348 for (i
= 0; i
< object
->stream_count
; ++i
)
1350 if (FAILED(hr
= new_media_stream(object
, unix_funcs
->wg_parser_get_stream(parser
, i
), i
, &object
->streams
[i
])))
1353 if (FAILED(hr
= media_stream_init_desc(object
->streams
[i
])))
1355 ERR("Failed to finish initialization of media stream %p, hr %x.\n", object
->streams
[i
], hr
);
1356 IMFMediaStream_Release(&object
->streams
[i
]->IMFMediaStream_iface
);
1361 /* init presentation descriptor */
1363 descriptors
= malloc(object
->stream_count
* sizeof(IMFStreamDescriptor
*));
1364 for (i
= 0; i
< object
->stream_count
; i
++)
1366 IMFMediaStream_GetStreamDescriptor(&object
->streams
[i
]->IMFMediaStream_iface
, &descriptors
[i
]);
1369 if (FAILED(hr
= MFCreatePresentationDescriptor(object
->stream_count
, descriptors
, &object
->pres_desc
)))
1372 for (i
= 0; i
< object
->stream_count
; i
++)
1374 IMFPresentationDescriptor_SelectStream(object
->pres_desc
, i
);
1375 IMFStreamDescriptor_Release(descriptors
[i
]);
1380 for (i
= 0; i
< object
->stream_count
; i
++)
1381 total_pres_time
= max(total_pres_time
,
1382 unix_funcs
->wg_parser_stream_get_duration(object
->streams
[i
]->wg_stream
));
1384 if (object
->stream_count
)
1385 IMFPresentationDescriptor_SetUINT64(object
->pres_desc
, &MF_PD_DURATION
, total_pres_time
);
1387 object
->state
= SOURCE_STOPPED
;
1389 *out_media_source
= object
;
1393 WARN("Failed to construct MFMediaSource, hr %#x.\n", hr
);
1396 IMFMediaSource_Release(&object
->IMFMediaSource_iface
);
1400 struct winegstreamer_stream_handler_result
1403 IMFAsyncResult
*result
;
1404 MF_OBJECT_TYPE obj_type
;
1408 struct winegstreamer_stream_handler
1410 IMFByteStreamHandler IMFByteStreamHandler_iface
;
1411 IMFAsyncCallback IMFAsyncCallback_iface
;
1413 struct list results
;
1414 CRITICAL_SECTION cs
;
1417 static struct winegstreamer_stream_handler
*impl_from_IMFByteStreamHandler(IMFByteStreamHandler
*iface
)
1419 return CONTAINING_RECORD(iface
, struct winegstreamer_stream_handler
, IMFByteStreamHandler_iface
);
1422 static struct winegstreamer_stream_handler
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
1424 return CONTAINING_RECORD(iface
, struct winegstreamer_stream_handler
, IMFAsyncCallback_iface
);
1427 static HRESULT WINAPI
winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler
*iface
, REFIID riid
, void **obj
)
1429 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1431 if (IsEqualIID(riid
, &IID_IMFByteStreamHandler
) ||
1432 IsEqualIID(riid
, &IID_IUnknown
))
1435 IMFByteStreamHandler_AddRef(iface
);
1439 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1441 return E_NOINTERFACE
;
1444 static ULONG WINAPI
winegstreamer_stream_handler_AddRef(IMFByteStreamHandler
*iface
)
1446 struct winegstreamer_stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1447 ULONG refcount
= InterlockedIncrement(&handler
->refcount
);
1449 TRACE("%p, refcount %u.\n", handler
, refcount
);
1454 static ULONG WINAPI
winegstreamer_stream_handler_Release(IMFByteStreamHandler
*iface
)
1456 struct winegstreamer_stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1457 ULONG refcount
= InterlockedDecrement(&handler
->refcount
);
1458 struct winegstreamer_stream_handler_result
*result
, *next
;
1460 TRACE("%p, refcount %u.\n", iface
, refcount
);
1464 LIST_FOR_EACH_ENTRY_SAFE(result
, next
, &handler
->results
, struct winegstreamer_stream_handler_result
, entry
)
1466 list_remove(&result
->entry
);
1467 IMFAsyncResult_Release(result
->result
);
1469 IUnknown_Release(result
->object
);
1472 DeleteCriticalSection(&handler
->cs
);
1479 struct create_object_context
1481 IUnknown IUnknown_iface
;
1484 IPropertyStore
*props
;
1485 IMFByteStream
*stream
;
1490 static struct create_object_context
*impl_from_IUnknown(IUnknown
*iface
)
1492 return CONTAINING_RECORD(iface
, struct create_object_context
, IUnknown_iface
);
1495 static HRESULT WINAPI
create_object_context_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
1497 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1499 if (IsEqualIID(riid
, &IID_IUnknown
))
1502 IUnknown_AddRef(iface
);
1506 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1508 return E_NOINTERFACE
;
1511 static ULONG WINAPI
create_object_context_AddRef(IUnknown
*iface
)
1513 struct create_object_context
*context
= impl_from_IUnknown(iface
);
1514 ULONG refcount
= InterlockedIncrement(&context
->refcount
);
1516 TRACE("%p, refcount %u.\n", iface
, refcount
);
1521 static ULONG WINAPI
create_object_context_Release(IUnknown
*iface
)
1523 struct create_object_context
*context
= impl_from_IUnknown(iface
);
1524 ULONG refcount
= InterlockedDecrement(&context
->refcount
);
1526 TRACE("%p, refcount %u.\n", iface
, refcount
);
1531 IPropertyStore_Release(context
->props
);
1532 if (context
->stream
)
1533 IMFByteStream_Release(context
->stream
);
1541 static const IUnknownVtbl create_object_context_vtbl
=
1543 create_object_context_QueryInterface
,
1544 create_object_context_AddRef
,
1545 create_object_context_Release
,
1548 static HRESULT WINAPI
winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler
*iface
, IMFByteStream
*stream
, const WCHAR
*url
, DWORD flags
,
1549 IPropertyStore
*props
, IUnknown
**cancel_cookie
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1551 struct winegstreamer_stream_handler
*this = impl_from_IMFByteStreamHandler(iface
);
1552 struct create_object_context
*context
;
1553 IMFAsyncResult
*caller
, *item
;
1556 TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface
, debugstr_w(url
), flags
, props
, cancel_cookie
, callback
, state
);
1559 *cancel_cookie
= NULL
;
1561 if (FAILED(hr
= MFCreateAsyncResult(NULL
, callback
, state
, &caller
)))
1564 if (!(context
= calloc(1, sizeof(*context
))))
1566 IMFAsyncResult_Release(caller
);
1567 return E_OUTOFMEMORY
;
1570 context
->IUnknown_iface
.lpVtbl
= &create_object_context_vtbl
;
1571 context
->refcount
= 1;
1572 context
->props
= props
;
1574 IPropertyStore_AddRef(context
->props
);
1575 context
->flags
= flags
;
1576 context
->stream
= stream
;
1577 if (context
->stream
)
1578 IMFByteStream_AddRef(context
->stream
);
1580 context
->url
= wcsdup(url
);
1581 if (!context
->stream
)
1583 IMFAsyncResult_Release(caller
);
1584 IUnknown_Release(&context
->IUnknown_iface
);
1585 return E_OUTOFMEMORY
;
1588 hr
= MFCreateAsyncResult(&context
->IUnknown_iface
, &this->IMFAsyncCallback_iface
, (IUnknown
*)caller
, &item
);
1589 IUnknown_Release(&context
->IUnknown_iface
);
1592 if (SUCCEEDED(hr
= MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO
, item
)))
1596 *cancel_cookie
= (IUnknown
*)caller
;
1597 IUnknown_AddRef(*cancel_cookie
);
1601 IMFAsyncResult_Release(item
);
1603 IMFAsyncResult_Release(caller
);
1608 static HRESULT WINAPI
winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler
*iface
, IMFAsyncResult
*result
,
1609 MF_OBJECT_TYPE
*obj_type
, IUnknown
**object
)
1611 struct winegstreamer_stream_handler
*this = impl_from_IMFByteStreamHandler(iface
);
1612 struct winegstreamer_stream_handler_result
*found
= NULL
, *cur
;
1615 TRACE("%p, %p, %p, %p.\n", iface
, result
, obj_type
, object
);
1617 EnterCriticalSection(&this->cs
);
1619 LIST_FOR_EACH_ENTRY(cur
, &this->results
, struct winegstreamer_stream_handler_result
, entry
)
1621 if (result
== cur
->result
)
1623 list_remove(&cur
->entry
);
1629 LeaveCriticalSection(&this->cs
);
1633 *obj_type
= found
->obj_type
;
1634 *object
= found
->object
;
1635 hr
= IMFAsyncResult_GetStatus(found
->result
);
1636 IMFAsyncResult_Release(found
->result
);
1641 *obj_type
= MF_OBJECT_INVALID
;
1643 hr
= MF_E_UNEXPECTED
;
1649 static HRESULT WINAPI
winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler
*iface
, IUnknown
*cancel_cookie
)
1651 struct winegstreamer_stream_handler
*this = impl_from_IMFByteStreamHandler(iface
);
1652 struct winegstreamer_stream_handler_result
*found
= NULL
, *cur
;
1654 TRACE("%p, %p.\n", iface
, cancel_cookie
);
1656 EnterCriticalSection(&this->cs
);
1658 LIST_FOR_EACH_ENTRY(cur
, &this->results
, struct winegstreamer_stream_handler_result
, entry
)
1660 if (cancel_cookie
== (IUnknown
*)cur
->result
)
1662 list_remove(&cur
->entry
);
1668 LeaveCriticalSection(&this->cs
);
1672 IMFAsyncResult_Release(found
->result
);
1674 IUnknown_Release(found
->object
);
1678 return found
? S_OK
: MF_E_UNEXPECTED
;
1681 static HRESULT WINAPI
winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler
*iface
, QWORD
*bytes
)
1683 FIXME("stub (%p %p)\n", iface
, bytes
);
1687 static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl
=
1689 winegstreamer_stream_handler_QueryInterface
,
1690 winegstreamer_stream_handler_AddRef
,
1691 winegstreamer_stream_handler_Release
,
1692 winegstreamer_stream_handler_BeginCreateObject
,
1693 winegstreamer_stream_handler_EndCreateObject
,
1694 winegstreamer_stream_handler_CancelObjectCreation
,
1695 winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution
,
1698 static HRESULT WINAPI
winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1700 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1701 IsEqualIID(riid
, &IID_IUnknown
))
1704 IMFAsyncCallback_AddRef(iface
);
1708 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1710 return E_NOINTERFACE
;
1713 static ULONG WINAPI
winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback
*iface
)
1715 struct winegstreamer_stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1716 return IMFByteStreamHandler_AddRef(&handler
->IMFByteStreamHandler_iface
);
1719 static ULONG WINAPI
winegstreamer_stream_handler_callback_Release(IMFAsyncCallback
*iface
)
1721 struct winegstreamer_stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1722 return IMFByteStreamHandler_Release(&handler
->IMFByteStreamHandler_iface
);
1725 static HRESULT WINAPI
winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1730 static HRESULT
winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler
*This
, WCHAR
*url
, IMFByteStream
*stream
, DWORD flags
,
1731 IPropertyStore
*props
, IUnknown
**out_object
, MF_OBJECT_TYPE
*out_obj_type
)
1733 TRACE("(%p %s %p %u %p %p %p)\n", This
, debugstr_w(url
), stream
, flags
, props
, out_object
, out_obj_type
);
1735 if (flags
& MF_RESOLUTION_MEDIASOURCE
)
1738 struct media_source
*new_source
;
1740 if (FAILED(hr
= media_source_constructor(stream
, &new_source
)))
1743 TRACE("->(%p)\n", new_source
);
1745 *out_object
= (IUnknown
*)&new_source
->IMFMediaSource_iface
;
1746 *out_obj_type
= MF_OBJECT_MEDIASOURCE
;
1752 FIXME("flags = %08x\n", flags
);
1757 static HRESULT WINAPI
winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1759 struct winegstreamer_stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1760 struct winegstreamer_stream_handler_result
*handler_result
;
1761 MF_OBJECT_TYPE obj_type
= MF_OBJECT_INVALID
;
1762 IUnknown
*object
= NULL
, *context_object
;
1763 struct create_object_context
*context
;
1764 IMFAsyncResult
*caller
;
1767 caller
= (IMFAsyncResult
*)IMFAsyncResult_GetStateNoAddRef(result
);
1769 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &context_object
)))
1771 WARN("Expected context set for callee result.\n");
1775 context
= impl_from_IUnknown(context_object
);
1777 hr
= winegstreamer_stream_handler_create_object(handler
, context
->url
, context
->stream
, context
->flags
, context
->props
, &object
, &obj_type
);
1779 if ((handler_result
= malloc(sizeof(*handler_result
))))
1781 handler_result
->result
= caller
;
1782 IMFAsyncResult_AddRef(handler_result
->result
);
1783 handler_result
->obj_type
= obj_type
;
1784 handler_result
->object
= object
;
1786 EnterCriticalSection(&handler
->cs
);
1787 list_add_tail(&handler
->results
, &handler_result
->entry
);
1788 LeaveCriticalSection(&handler
->cs
);
1793 IUnknown_Release(object
);
1797 IUnknown_Release(&context
->IUnknown_iface
);
1799 IMFAsyncResult_SetStatus(caller
, hr
);
1800 MFInvokeCallback(caller
);
1805 static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl
=
1807 winegstreamer_stream_handler_callback_QueryInterface
,
1808 winegstreamer_stream_handler_callback_AddRef
,
1809 winegstreamer_stream_handler_callback_Release
,
1810 winegstreamer_stream_handler_callback_GetParameters
,
1811 winegstreamer_stream_handler_callback_Invoke
,
1814 HRESULT
winegstreamer_stream_handler_create(REFIID riid
, void **obj
)
1816 struct winegstreamer_stream_handler
*this;
1819 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
1821 if (!(this = calloc(1, sizeof(*this))))
1822 return E_OUTOFMEMORY
;
1824 list_init(&this->results
);
1825 InitializeCriticalSection(&this->cs
);
1827 this->IMFByteStreamHandler_iface
.lpVtbl
= &winegstreamer_stream_handler_vtbl
;
1828 this->IMFAsyncCallback_iface
.lpVtbl
= &winegstreamer_stream_handler_callback_vtbl
;
1831 hr
= IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface
, riid
, obj
);
1832 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface
);