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