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
;
35 IMFMediaSource
*media_source
;
36 IMFMediaEventQueue
*event_queue
;
37 IMFStreamDescriptor
*descriptor
;
39 struct wg_parser_stream
*wg_stream
;
41 IUnknown
**token_queue
;
42 LONG token_queue_count
;
55 SOURCE_ASYNC_REQUEST_SAMPLE
,
58 struct source_async_command
60 IUnknown IUnknown_iface
;
62 enum source_async_op op
;
67 IMFPresentationDescriptor
*descriptor
;
73 struct media_stream
*stream
;
81 IMFMediaSource IMFMediaSource_iface
;
82 IMFGetService IMFGetService_iface
;
83 IMFRateSupport IMFRateSupport_iface
;
84 IMFRateControl IMFRateControl_iface
;
85 IMFAsyncCallback async_commands_callback
;
87 DWORD async_commands_queue
;
88 IMFMediaEventQueue
*event_queue
;
89 IMFByteStream
*byte_stream
;
93 struct wg_parser
*wg_parser
;
96 IMFStreamDescriptor
**descriptors
;
97 struct media_stream
**streams
;
111 bool read_thread_shutdown
;
114 static inline struct media_stream
*impl_from_IMFMediaStream(IMFMediaStream
*iface
)
116 return CONTAINING_RECORD(iface
, struct media_stream
, IMFMediaStream_iface
);
119 static inline struct media_source
*impl_from_IMFMediaSource(IMFMediaSource
*iface
)
121 return CONTAINING_RECORD(iface
, struct media_source
, IMFMediaSource_iface
);
124 static inline struct media_source
*impl_from_IMFGetService(IMFGetService
*iface
)
126 return CONTAINING_RECORD(iface
, struct media_source
, IMFGetService_iface
);
129 static inline struct media_source
*impl_from_IMFRateSupport(IMFRateSupport
*iface
)
131 return CONTAINING_RECORD(iface
, struct media_source
, IMFRateSupport_iface
);
134 static inline struct media_source
*impl_from_IMFRateControl(IMFRateControl
*iface
)
136 return CONTAINING_RECORD(iface
, struct media_source
, IMFRateControl_iface
);
139 static inline struct media_source
*impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
141 return CONTAINING_RECORD(iface
, struct media_source
, async_commands_callback
);
144 static inline struct source_async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
146 return CONTAINING_RECORD(iface
, struct source_async_command
, IUnknown_iface
);
149 static HRESULT WINAPI
source_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
151 if (IsEqualIID(riid
, &IID_IUnknown
))
154 IUnknown_AddRef(iface
);
158 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
160 return E_NOINTERFACE
;
163 static ULONG WINAPI
source_async_command_AddRef(IUnknown
*iface
)
165 struct source_async_command
*command
= impl_from_async_command_IUnknown(iface
);
166 return InterlockedIncrement(&command
->refcount
);
169 static ULONG WINAPI
source_async_command_Release(IUnknown
*iface
)
171 struct source_async_command
*command
= impl_from_async_command_IUnknown(iface
);
172 ULONG refcount
= InterlockedDecrement(&command
->refcount
);
176 if (command
->op
== SOURCE_ASYNC_START
)
178 IMFPresentationDescriptor_Release(command
->u
.start
.descriptor
);
179 PropVariantClear(&command
->u
.start
.position
);
181 else if (command
->op
== SOURCE_ASYNC_REQUEST_SAMPLE
)
183 if (command
->u
.request_sample
.token
)
184 IUnknown_Release(command
->u
.request_sample
.token
);
192 static const IUnknownVtbl source_async_command_vtbl
=
194 source_async_command_QueryInterface
,
195 source_async_command_AddRef
,
196 source_async_command_Release
,
199 static HRESULT
source_create_async_op(enum source_async_op op
, IUnknown
**out
)
201 struct source_async_command
*command
;
203 if (!(command
= calloc(1, sizeof(*command
))))
204 return E_OUTOFMEMORY
;
206 command
->IUnknown_iface
.lpVtbl
= &source_async_command_vtbl
;
207 command
->refcount
= 1;
210 *out
= &command
->IUnknown_iface
;
214 static HRESULT WINAPI
callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
216 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
218 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
219 IsEqualIID(riid
, &IID_IUnknown
))
222 IMFAsyncCallback_AddRef(iface
);
226 WARN("Unsupported %s.\n", debugstr_guid(riid
));
228 return E_NOINTERFACE
;
231 static HRESULT WINAPI
callback_GetParameters(IMFAsyncCallback
*iface
,
232 DWORD
*flags
, DWORD
*queue
)
237 static ULONG WINAPI
source_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
239 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
240 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
243 static ULONG WINAPI
source_async_commands_callback_Release(IMFAsyncCallback
*iface
)
245 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
246 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
249 static HRESULT
stream_descriptor_get_media_type(IMFStreamDescriptor
*descriptor
, IMFMediaType
**media_type
)
251 IMFMediaTypeHandler
*handler
;
254 if (FAILED(hr
= IMFStreamDescriptor_GetMediaTypeHandler(descriptor
, &handler
)))
256 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
257 IMFMediaTypeHandler_Release(handler
);
262 static HRESULT
wg_format_from_stream_descriptor(IMFStreamDescriptor
*descriptor
, struct wg_format
*format
)
264 IMFMediaType
*media_type
;
267 if (FAILED(hr
= stream_descriptor_get_media_type(descriptor
, &media_type
)))
269 mf_media_type_to_wg_format(media_type
, format
);
270 IMFMediaType_Release(media_type
);
275 static HRESULT
stream_descriptor_set_tag(IMFStreamDescriptor
*descriptor
, struct wg_parser_stream
*stream
,
276 const GUID
*attr
, enum wg_parser_tag tag
)
283 if (!(str
= wg_parser_stream_get_tag(stream
, tag
))
284 || !(len
= MultiByteToWideChar(CP_UTF8
, 0, str
, -1, NULL
, 0)))
286 else if (!(strW
= malloc(len
* sizeof(*strW
))))
290 if (MultiByteToWideChar(CP_UTF8
, 0, str
, -1, strW
, len
))
291 hr
= IMFStreamDescriptor_SetString(descriptor
, attr
, strW
);
301 static HRESULT
init_video_media_types(struct wg_format
*format
, IMFMediaType
*types
[6], DWORD
*types_count
)
303 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
304 * YUV color space, and it's generally much less expensive for
305 * videoconvert to do YUV -> YUV transformations. */
306 static const enum wg_video_format video_formats
[] =
308 WG_VIDEO_FORMAT_NV12
,
309 WG_VIDEO_FORMAT_YV12
,
310 WG_VIDEO_FORMAT_YUY2
,
311 WG_VIDEO_FORMAT_I420
,
313 UINT count
= *types_count
, i
;
317 if (FAILED(hr
= IMFMediaType_GetGUID(types
[0], &MF_MT_SUBTYPE
, &base_subtype
)))
320 for (i
= 0; i
< ARRAY_SIZE(video_formats
); ++i
)
322 struct wg_format new_format
= *format
;
323 IMFMediaType
*new_type
;
325 new_format
.u
.video
.format
= video_formats
[i
];
327 if (!(new_type
= mf_media_type_from_wg_format(&new_format
)))
332 types
[count
++] = new_type
;
334 if (video_formats
[i
] == WG_VIDEO_FORMAT_I420
)
336 IMFMediaType
*iyuv_type
;
338 if (FAILED(hr
= MFCreateMediaType(&iyuv_type
)))
340 if (FAILED(hr
= IMFMediaType_CopyAllItems(new_type
, (IMFAttributes
*)iyuv_type
)))
342 if (FAILED(hr
= IMFMediaType_SetGUID(iyuv_type
, &MF_MT_SUBTYPE
, &MFVideoFormat_IYUV
)))
344 types
[count
++] = iyuv_type
;
349 *types_count
= count
;
353 static HRESULT
init_audio_media_types(struct wg_format
*format
, IMFMediaType
*types
[6], DWORD
*types_count
)
355 /* Expose at least one PCM and one floating point type for the
356 consumer to pick from. */
357 static const enum wg_audio_format audio_types
[] =
359 WG_AUDIO_FORMAT_S16LE
,
360 WG_AUDIO_FORMAT_F32LE
,
362 UINT count
= *types_count
, i
;
364 for (i
= 0; i
< ARRAY_SIZE(audio_types
); i
++)
366 struct wg_format new_format
= *format
;
367 if (new_format
.u
.audio
.format
== audio_types
[i
])
369 new_format
.u
.audio
.format
= audio_types
[i
];
370 if ((types
[count
] = mf_media_type_from_wg_format(&new_format
)))
374 *types_count
= count
;
378 static HRESULT
stream_descriptor_create(UINT32 id
, struct wg_format
*format
, IMFStreamDescriptor
**out
)
380 IMFStreamDescriptor
*descriptor
;
381 IMFMediaTypeHandler
*handler
;
382 IMFMediaType
*types
[6];
386 if (!(types
[0] = mf_media_type_from_wg_format(format
)))
387 return MF_E_INVALIDMEDIATYPE
;
390 if (format
->major_type
== WG_MAJOR_TYPE_VIDEO
)
392 if (FAILED(hr
= init_video_media_types(format
, types
, &count
)))
395 else if (format
->major_type
== WG_MAJOR_TYPE_AUDIO
)
397 if (FAILED(hr
= init_audio_media_types(format
, types
, &count
)))
401 assert(count
<= ARRAY_SIZE(types
));
403 if (FAILED(hr
= MFCreateStreamDescriptor(id
, count
, types
, &descriptor
)))
406 if (FAILED(hr
= IMFStreamDescriptor_GetMediaTypeHandler(descriptor
, &handler
)))
407 IMFStreamDescriptor_Release(descriptor
);
410 hr
= IMFMediaTypeHandler_SetCurrentMediaType(handler
, types
[0]);
411 IMFMediaTypeHandler_Release(handler
);
416 IMFMediaType_Release(types
[count
]);
417 *out
= SUCCEEDED(hr
) ? descriptor
: NULL
;
421 static BOOL
enqueue_token(struct media_stream
*stream
, IUnknown
*token
)
423 if (stream
->token_queue_count
== stream
->token_queue_cap
)
426 stream
->token_queue_cap
= stream
->token_queue_cap
* 2 + 1;
427 buf
= realloc(stream
->token_queue
, stream
->token_queue_cap
* sizeof(*buf
));
429 stream
->token_queue
= buf
;
432 stream
->token_queue_cap
= stream
->token_queue_count
;
436 stream
->token_queue
[stream
->token_queue_count
++] = token
;
440 static void flush_token_queue(struct media_stream
*stream
, BOOL send
)
442 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
445 for (i
= 0; i
< stream
->token_queue_count
; i
++)
452 if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE
, &op
)))
454 struct source_async_command
*command
= impl_from_async_command_IUnknown(op
);
455 command
->u
.request_sample
.stream
= stream
;
456 command
->u
.request_sample
.token
= stream
->token_queue
[i
];
458 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
459 IUnknown_Release(op
);
462 WARN("Could not enqueue sample request, hr %#lx\n", hr
);
464 else if (stream
->token_queue
[i
])
465 IUnknown_Release(stream
->token_queue
[i
]);
467 free(stream
->token_queue
);
468 stream
->token_queue
= NULL
;
469 stream
->token_queue_count
= 0;
470 stream
->token_queue_cap
= 0;
473 static HRESULT
media_stream_start(struct media_stream
*stream
, BOOL active
, BOOL seeking
, const PROPVARIANT
*position
)
475 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
476 struct wg_format format
;
479 TRACE("source %p, stream %p\n", source
, stream
);
481 if (FAILED(hr
= wg_format_from_stream_descriptor(stream
->descriptor
, &format
)))
482 WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr
);
483 wg_parser_stream_enable(stream
->wg_stream
, &format
);
485 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamUnk(source
->event_queue
, active
? MEUpdatedStream
: MENewStream
,
486 &GUID_NULL
, S_OK
, (IUnknown
*)&stream
->IMFMediaStream_iface
)))
487 WARN("Failed to send source stream event, hr %#lx\n", hr
);
488 return IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, seeking
? MEStreamSeeked
: MEStreamStarted
,
489 &GUID_NULL
, S_OK
, position
);
492 static HRESULT
media_source_start(struct media_source
*source
, IMFPresentationDescriptor
*descriptor
,
493 GUID
*format
, PROPVARIANT
*position
)
495 BOOL starting
= source
->state
== SOURCE_STOPPED
, seek_message
= !starting
&& position
->vt
!= VT_EMPTY
;
496 IMFStreamDescriptor
**descriptors
;
500 TRACE("source %p, descriptor %p, format %s, position %s\n", source
, descriptor
,
501 debugstr_guid(format
), wine_dbgstr_variant((VARIANT
*)position
));
503 if (source
->state
== SOURCE_SHUTDOWN
)
504 return MF_E_SHUTDOWN
;
506 /* seek to beginning on stop->play */
507 if (source
->state
== SOURCE_STOPPED
&& position
->vt
== VT_EMPTY
)
509 position
->vt
= VT_I8
;
510 position
->hVal
.QuadPart
= 0;
513 if (!(descriptors
= calloc(source
->stream_count
, sizeof(*descriptors
))))
514 return E_OUTOFMEMORY
;
516 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
517 WARN("Failed to get presentation descriptor stream count, hr %#lx\n", hr
);
519 for (i
= 0; i
< count
; i
++)
521 IMFStreamDescriptor
*stream_descriptor
;
525 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
,
526 &selected
, &stream_descriptor
)))
527 WARN("Failed to get presentation stream descriptor, hr %#lx\n", hr
);
530 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(stream_descriptor
, &id
)))
531 WARN("Failed to get stream descriptor id, hr %#lx\n", hr
);
532 else if (id
>= source
->stream_count
)
533 WARN("Invalid stream descriptor id %lu, hr %#lx\n", id
, hr
);
535 IMFStreamDescriptor_AddRef((descriptors
[id
] = stream_descriptor
));
537 IMFStreamDescriptor_Release(stream_descriptor
);
541 for (i
= 0; i
< source
->stream_count
; i
++)
543 struct media_stream
*stream
= source
->streams
[i
];
544 BOOL was_active
= !starting
&& stream
->active
;
546 if (position
->vt
!= VT_EMPTY
)
549 if (!(stream
->active
= !!descriptors
[i
]))
550 wg_parser_stream_disable(stream
->wg_stream
);
553 if (FAILED(hr
= media_stream_start(stream
, was_active
, seek_message
, position
)))
554 WARN("Failed to start media stream, hr %#lx\n", hr
);
555 IMFStreamDescriptor_Release(descriptors
[i
]);
561 source
->state
= SOURCE_RUNNING
;
563 if (position
->vt
== VT_I8
)
564 wg_parser_stream_seek(source
->streams
[0]->wg_stream
, 1.0, position
->hVal
.QuadPart
, 0,
565 AM_SEEKING_AbsolutePositioning
, AM_SEEKING_NoPositioning
);
567 for (i
= 0; i
< source
->stream_count
; i
++)
568 flush_token_queue(source
->streams
[i
], position
->vt
== VT_EMPTY
);
570 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
,
571 seek_message
? MESourceSeeked
: MESourceStarted
, &GUID_NULL
, S_OK
, position
);
574 static HRESULT
media_source_pause(struct media_source
*source
)
579 TRACE("source %p\n", source
);
581 if (source
->state
== SOURCE_SHUTDOWN
)
582 return MF_E_SHUTDOWN
;
584 for (i
= 0; i
< source
->stream_count
; i
++)
586 struct media_stream
*stream
= source
->streams
[i
];
587 if (stream
->active
&& FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEStreamPaused
,
588 &GUID_NULL
, S_OK
, NULL
)))
589 WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr
);
592 source
->state
= SOURCE_PAUSED
;
593 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourcePaused
, &GUID_NULL
, S_OK
, NULL
);
596 static HRESULT
media_source_stop(struct media_source
*source
)
601 TRACE("source %p\n", source
);
603 if (source
->state
== SOURCE_SHUTDOWN
)
604 return MF_E_SHUTDOWN
;
606 for (i
= 0; i
< source
->stream_count
; i
++)
608 struct media_stream
*stream
= source
->streams
[i
];
609 if (stream
->active
&& FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEStreamStopped
,
610 &GUID_NULL
, S_OK
, NULL
)))
611 WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr
);
614 source
->state
= SOURCE_STOPPED
;
616 for (i
= 0; i
< source
->stream_count
; i
++)
617 flush_token_queue(source
->streams
[i
], FALSE
);
619 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourceStopped
, &GUID_NULL
, S_OK
, NULL
);
622 static HRESULT
media_stream_send_sample(struct media_stream
*stream
, const struct wg_parser_buffer
*wg_buffer
, IUnknown
*token
)
624 IMFSample
*sample
= NULL
;
625 IMFMediaBuffer
*buffer
;
629 if (FAILED(hr
= MFCreateMemoryBuffer(wg_buffer
->size
, &buffer
)))
631 if (FAILED(hr
= IMFMediaBuffer_SetCurrentLength(buffer
, wg_buffer
->size
)))
633 if (FAILED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, NULL
, NULL
)))
636 if (!wg_parser_stream_copy_buffer(stream
->wg_stream
, data
, 0, wg_buffer
->size
))
638 wg_parser_stream_release_buffer(stream
->wg_stream
);
639 IMFMediaBuffer_Unlock(buffer
);
642 wg_parser_stream_release_buffer(stream
->wg_stream
);
644 if (FAILED(hr
= IMFMediaBuffer_Unlock(buffer
)))
647 if (FAILED(hr
= MFCreateSample(&sample
)))
649 if (FAILED(hr
= IMFSample_AddBuffer(sample
, buffer
)))
651 if (FAILED(hr
= IMFSample_SetSampleTime(sample
, wg_buffer
->pts
)))
653 if (FAILED(hr
= IMFSample_SetSampleDuration(sample
, wg_buffer
->duration
)))
655 if (token
&& FAILED(hr
= IMFSample_SetUnknown(sample
, &MFSampleExtension_Token
, token
)))
658 hr
= IMFMediaEventQueue_QueueEventParamUnk(stream
->event_queue
, MEMediaSample
,
659 &GUID_NULL
, S_OK
, (IUnknown
*)sample
);
663 IMFSample_Release(sample
);
664 IMFMediaBuffer_Release(buffer
);
668 static HRESULT
media_stream_send_eos(struct media_source
*source
, struct media_stream
*stream
)
670 PROPVARIANT empty
= {.vt
= VT_EMPTY
};
674 TRACE("source %p, stream %p\n", source
, stream
);
677 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEEndOfStream
, &GUID_NULL
, S_OK
, &empty
)))
678 WARN("Failed to queue MEEndOfStream event, hr %#lx\n", hr
);
680 for (i
= 0; i
< source
->stream_count
; i
++)
682 struct media_stream
*stream
= source
->streams
[i
];
683 if (stream
->active
&& !stream
->eos
)
687 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, &empty
)))
688 WARN("Failed to queue MEEndOfPresentation event, hr %#lx\n", hr
);
692 static HRESULT
wait_on_sample(struct media_stream
*stream
, IUnknown
*token
)
694 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
695 struct wg_parser_buffer buffer
;
697 TRACE("%p, %p\n", stream
, token
);
699 if (wg_parser_stream_get_buffer(source
->wg_parser
, stream
->wg_stream
, &buffer
))
700 return media_stream_send_sample(stream
, &buffer
, token
);
702 return media_stream_send_eos(source
, stream
);
705 static HRESULT WINAPI
source_async_commands_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
707 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
708 struct source_async_command
*command
;
712 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
715 EnterCriticalSection(&source
->cs
);
717 command
= impl_from_async_command_IUnknown(state
);
720 case SOURCE_ASYNC_START
:
722 IMFPresentationDescriptor
*descriptor
= command
->u
.start
.descriptor
;
723 GUID format
= command
->u
.start
.format
;
724 PROPVARIANT position
= command
->u
.start
.position
;
726 if (FAILED(hr
= media_source_start(source
, descriptor
, &format
, &position
)))
727 WARN("Failed to start source %p, hr %#lx\n", source
, hr
);
730 case SOURCE_ASYNC_PAUSE
:
731 if (FAILED(hr
= media_source_pause(source
)))
732 WARN("Failed to pause source %p, hr %#lx\n", source
, hr
);
734 case SOURCE_ASYNC_STOP
:
735 if (FAILED(hr
= media_source_stop(source
)))
736 WARN("Failed to stop source %p, hr %#lx\n", source
, hr
);
738 case SOURCE_ASYNC_REQUEST_SAMPLE
:
739 if (source
->state
== SOURCE_PAUSED
)
740 enqueue_token(command
->u
.request_sample
.stream
, command
->u
.request_sample
.token
);
741 else if (source
->state
== SOURCE_RUNNING
)
743 if (FAILED(hr
= wait_on_sample(command
->u
.request_sample
.stream
, command
->u
.request_sample
.token
)))
744 WARN("Failed to request sample, hr %#lx\n", hr
);
749 LeaveCriticalSection(&source
->cs
);
751 IUnknown_Release(state
);
756 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl
=
758 callback_QueryInterface
,
759 source_async_commands_callback_AddRef
,
760 source_async_commands_callback_Release
,
761 callback_GetParameters
,
762 source_async_commands_Invoke
,
765 static DWORD CALLBACK
read_thread(void *arg
)
767 struct media_source
*source
= arg
;
768 IMFByteStream
*byte_stream
= source
->byte_stream
;
769 size_t buffer_size
= 4096;
773 if (!(data
= malloc(buffer_size
)))
776 IMFByteStream_GetLength(byte_stream
, &file_size
);
778 TRACE("Starting read thread for media source %p.\n", source
);
780 while (!source
->read_thread_shutdown
)
787 if (!wg_parser_get_next_read_offset(source
->wg_parser
, &offset
, &size
))
790 if (offset
>= file_size
)
792 else if (offset
+ size
>= file_size
)
793 size
= file_size
- offset
;
795 /* Some IMFByteStreams (including the standard file-based stream) return
796 * an error when reading past the file size. */
799 wg_parser_push_data(source
->wg_parser
, data
, 0);
803 if (!array_reserve(&data
, &buffer_size
, size
, 1))
811 if (SUCCEEDED(hr
= IMFByteStream_SetCurrentPosition(byte_stream
, offset
)))
812 hr
= IMFByteStream_Read(byte_stream
, data
, size
, &ret_size
);
814 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size
, offset
, hr
);
815 else if (ret_size
!= size
)
816 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size
, ret_size
);
817 wg_parser_push_data(source
->wg_parser
, SUCCEEDED(hr
) ? data
: NULL
, ret_size
);
821 TRACE("Media source is shutting down; exiting.\n");
825 static HRESULT WINAPI
media_stream_QueryInterface(IMFMediaStream
*iface
, REFIID riid
, void **out
)
827 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
829 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
831 if (IsEqualIID(riid
, &IID_IMFMediaStream
) ||
832 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
833 IsEqualIID(riid
, &IID_IUnknown
))
835 *out
= &stream
->IMFMediaStream_iface
;
839 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
841 return E_NOINTERFACE
;
844 IUnknown_AddRef((IUnknown
*)*out
);
848 static ULONG WINAPI
media_stream_AddRef(IMFMediaStream
*iface
)
850 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
851 ULONG ref
= InterlockedIncrement(&stream
->ref
);
853 TRACE("%p, refcount %lu.\n", iface
, ref
);
858 static ULONG WINAPI
media_stream_Release(IMFMediaStream
*iface
)
860 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
861 ULONG ref
= InterlockedDecrement(&stream
->ref
);
863 TRACE("%p, refcount %lu.\n", iface
, ref
);
867 IMFMediaSource_Release(stream
->media_source
);
868 IMFStreamDescriptor_Release(stream
->descriptor
);
869 IMFMediaEventQueue_Release(stream
->event_queue
);
870 flush_token_queue(stream
, FALSE
);
877 static HRESULT WINAPI
media_stream_GetEvent(IMFMediaStream
*iface
, DWORD flags
, IMFMediaEvent
**event
)
879 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
881 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
883 return IMFMediaEventQueue_GetEvent(stream
->event_queue
, flags
, event
);
886 static HRESULT WINAPI
media_stream_BeginGetEvent(IMFMediaStream
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
888 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
890 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
892 return IMFMediaEventQueue_BeginGetEvent(stream
->event_queue
, callback
, state
);
895 static HRESULT WINAPI
media_stream_EndGetEvent(IMFMediaStream
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
897 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
899 TRACE("%p, %p, %p.\n", stream
, result
, event
);
901 return IMFMediaEventQueue_EndGetEvent(stream
->event_queue
, result
, event
);
904 static HRESULT WINAPI
media_stream_QueueEvent(IMFMediaStream
*iface
, MediaEventType event_type
, REFGUID ext_type
,
905 HRESULT hr
, const PROPVARIANT
*value
)
907 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
909 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
911 return IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, event_type
, ext_type
, hr
, value
);
914 static HRESULT WINAPI
media_stream_GetMediaSource(IMFMediaStream
*iface
, IMFMediaSource
**out
)
916 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
917 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
920 TRACE("%p, %p.\n", iface
, out
);
922 EnterCriticalSection(&source
->cs
);
924 if (source
->state
== SOURCE_SHUTDOWN
)
928 IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
929 *out
= &source
->IMFMediaSource_iface
;
932 LeaveCriticalSection(&source
->cs
);
937 static HRESULT WINAPI
media_stream_GetStreamDescriptor(IMFMediaStream
* iface
, IMFStreamDescriptor
**descriptor
)
939 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
940 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
943 TRACE("%p, %p.\n", iface
, descriptor
);
945 EnterCriticalSection(&source
->cs
);
947 if (source
->state
== SOURCE_SHUTDOWN
)
951 IMFStreamDescriptor_AddRef(stream
->descriptor
);
952 *descriptor
= stream
->descriptor
;
955 LeaveCriticalSection(&source
->cs
);
960 static HRESULT WINAPI
media_stream_RequestSample(IMFMediaStream
*iface
, IUnknown
*token
)
962 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
963 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
967 TRACE("%p, %p.\n", iface
, token
);
969 EnterCriticalSection(&source
->cs
);
971 if (source
->state
== SOURCE_SHUTDOWN
)
973 else if (!stream
->active
)
974 hr
= MF_E_MEDIA_SOURCE_WRONGSTATE
;
975 else if (stream
->eos
)
976 hr
= MF_E_END_OF_STREAM
;
977 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE
, &op
)))
979 struct source_async_command
*command
= impl_from_async_command_IUnknown(op
);
980 command
->u
.request_sample
.stream
= stream
;
982 IUnknown_AddRef(token
);
983 command
->u
.request_sample
.token
= token
;
985 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
986 IUnknown_Release(op
);
989 LeaveCriticalSection(&source
->cs
);
994 static const IMFMediaStreamVtbl media_stream_vtbl
=
996 media_stream_QueryInterface
,
998 media_stream_Release
,
999 media_stream_GetEvent
,
1000 media_stream_BeginGetEvent
,
1001 media_stream_EndGetEvent
,
1002 media_stream_QueueEvent
,
1003 media_stream_GetMediaSource
,
1004 media_stream_GetStreamDescriptor
,
1005 media_stream_RequestSample
1008 static HRESULT
media_stream_create(IMFMediaSource
*source
, IMFStreamDescriptor
*descriptor
,
1009 struct wg_parser_stream
*wg_stream
, struct media_stream
**out
)
1011 struct media_stream
*object
;
1014 TRACE("source %p, descriptor %p, wg_stream %p.\n", source
, descriptor
, wg_stream
);
1016 if (!(object
= calloc(1, sizeof(*object
))))
1017 return E_OUTOFMEMORY
;
1019 object
->IMFMediaStream_iface
.lpVtbl
= &media_stream_vtbl
;
1022 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1028 IMFMediaSource_AddRef(source
);
1029 object
->media_source
= source
;
1030 IMFStreamDescriptor_AddRef(descriptor
);
1031 object
->descriptor
= descriptor
;
1033 object
->active
= TRUE
;
1034 object
->eos
= FALSE
;
1035 object
->wg_stream
= wg_stream
;
1037 TRACE("Created stream object %p.\n", object
);
1043 static HRESULT WINAPI
media_source_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1045 struct media_source
*source
= impl_from_IMFGetService(iface
);
1046 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
1049 static ULONG WINAPI
media_source_get_service_AddRef(IMFGetService
*iface
)
1051 struct media_source
*source
= impl_from_IMFGetService(iface
);
1052 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1055 static ULONG WINAPI
media_source_get_service_Release(IMFGetService
*iface
)
1057 struct media_source
*source
= impl_from_IMFGetService(iface
);
1058 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
1061 static HRESULT WINAPI
media_source_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
1063 struct media_source
*source
= impl_from_IMFGetService(iface
);
1065 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1069 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1071 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1073 *obj
= &source
->IMFRateSupport_iface
;
1075 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
1077 *obj
= &source
->IMFRateControl_iface
;
1081 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
1084 IUnknown_AddRef((IUnknown
*)*obj
);
1086 return *obj
? S_OK
: E_NOINTERFACE
;
1089 static const IMFGetServiceVtbl media_source_get_service_vtbl
=
1091 media_source_get_service_QueryInterface
,
1092 media_source_get_service_AddRef
,
1093 media_source_get_service_Release
,
1094 media_source_get_service_GetService
,
1097 static HRESULT WINAPI
media_source_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
1099 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
1100 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
1103 static ULONG WINAPI
media_source_rate_support_AddRef(IMFRateSupport
*iface
)
1105 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
1106 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1109 static ULONG WINAPI
media_source_rate_support_Release(IMFRateSupport
*iface
)
1111 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
1112 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
1115 static HRESULT WINAPI
media_source_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
, BOOL thin
, float *rate
)
1117 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1124 static HRESULT WINAPI
media_source_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
, BOOL thin
, float *rate
)
1126 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1128 *rate
= direction
== MFRATE_FORWARD
? 1e6f
: -1e6f
;
1133 static HRESULT WINAPI
media_source_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
1134 float *nearest_rate
)
1136 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_rate
);
1139 *nearest_rate
= rate
;
1141 return rate
>= -1e6f
&& rate
<= 1e6f
? S_OK
: MF_E_UNSUPPORTED_RATE
;
1144 static const IMFRateSupportVtbl media_source_rate_support_vtbl
=
1146 media_source_rate_support_QueryInterface
,
1147 media_source_rate_support_AddRef
,
1148 media_source_rate_support_Release
,
1149 media_source_rate_support_GetSlowestRate
,
1150 media_source_rate_support_GetFastestRate
,
1151 media_source_rate_support_IsRateSupported
,
1154 static HRESULT WINAPI
media_source_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
1156 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1157 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
1160 static ULONG WINAPI
media_source_rate_control_AddRef(IMFRateControl
*iface
)
1162 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1163 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1166 static ULONG WINAPI
media_source_rate_control_Release(IMFRateControl
*iface
)
1168 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1169 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
1172 static HRESULT WINAPI
media_source_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
1174 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1177 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
1180 return MF_E_REVERSE_UNSUPPORTED
;
1183 return MF_E_THINNING_UNSUPPORTED
;
1185 if (FAILED(hr
= IMFRateSupport_IsRateSupported(&source
->IMFRateSupport_iface
, thin
, rate
, NULL
)))
1188 EnterCriticalSection(&source
->cs
);
1189 source
->rate
= rate
;
1190 LeaveCriticalSection(&source
->cs
);
1192 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourceRateChanged
, &GUID_NULL
, S_OK
, NULL
);
1195 static HRESULT WINAPI
media_source_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
1197 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1199 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
1204 EnterCriticalSection(&source
->cs
);
1205 *rate
= source
->rate
;
1206 LeaveCriticalSection(&source
->cs
);
1211 static const IMFRateControlVtbl media_source_rate_control_vtbl
=
1213 media_source_rate_control_QueryInterface
,
1214 media_source_rate_control_AddRef
,
1215 media_source_rate_control_Release
,
1216 media_source_rate_control_SetRate
,
1217 media_source_rate_control_GetRate
,
1220 static HRESULT WINAPI
media_source_QueryInterface(IMFMediaSource
*iface
, REFIID riid
, void **out
)
1222 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1224 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1226 if (IsEqualIID(riid
, &IID_IMFMediaSource
) ||
1227 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1228 IsEqualIID(riid
, &IID_IUnknown
))
1230 *out
= &source
->IMFMediaSource_iface
;
1232 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1234 *out
= &source
->IMFGetService_iface
;
1238 FIXME("%s, %p.\n", debugstr_guid(riid
), out
);
1240 return E_NOINTERFACE
;
1243 IUnknown_AddRef((IUnknown
*)*out
);
1247 static ULONG WINAPI
media_source_AddRef(IMFMediaSource
*iface
)
1249 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1250 ULONG ref
= InterlockedIncrement(&source
->ref
);
1252 TRACE("%p, refcount %lu.\n", iface
, ref
);
1257 static ULONG WINAPI
media_source_Release(IMFMediaSource
*iface
)
1259 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1260 ULONG ref
= InterlockedDecrement(&source
->ref
);
1262 TRACE("%p, refcount %lu.\n", iface
, ref
);
1266 IMFMediaSource_Shutdown(iface
);
1267 IMFMediaEventQueue_Release(source
->event_queue
);
1268 IMFByteStream_Release(source
->byte_stream
);
1269 wg_parser_destroy(source
->wg_parser
);
1270 source
->cs
.DebugInfo
->Spare
[0] = 0;
1271 DeleteCriticalSection(&source
->cs
);
1278 static HRESULT WINAPI
media_source_GetEvent(IMFMediaSource
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1280 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1282 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
1284 return IMFMediaEventQueue_GetEvent(source
->event_queue
, flags
, event
);
1287 static HRESULT WINAPI
media_source_BeginGetEvent(IMFMediaSource
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1289 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1291 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1293 return IMFMediaEventQueue_BeginGetEvent(source
->event_queue
, callback
, state
);
1296 static HRESULT WINAPI
media_source_EndGetEvent(IMFMediaSource
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1298 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1300 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1302 return IMFMediaEventQueue_EndGetEvent(source
->event_queue
, result
, event
);
1305 static HRESULT WINAPI
media_source_QueueEvent(IMFMediaSource
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1306 HRESULT hr
, const PROPVARIANT
*value
)
1308 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1310 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1312 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, event_type
, ext_type
, hr
, value
);
1315 static HRESULT WINAPI
media_source_GetCharacteristics(IMFMediaSource
*iface
, DWORD
*characteristics
)
1317 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1320 TRACE("%p, %p.\n", iface
, characteristics
);
1322 EnterCriticalSection(&source
->cs
);
1324 if (source
->state
== SOURCE_SHUTDOWN
)
1327 *characteristics
= MFMEDIASOURCE_CAN_SEEK
| MFMEDIASOURCE_CAN_PAUSE
;
1329 LeaveCriticalSection(&source
->cs
);
1334 static HRESULT WINAPI
media_source_CreatePresentationDescriptor(IMFMediaSource
*iface
, IMFPresentationDescriptor
**descriptor
)
1336 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1340 TRACE("%p, %p.\n", iface
, descriptor
);
1342 EnterCriticalSection(&source
->cs
);
1344 if (source
->state
== SOURCE_SHUTDOWN
)
1346 else if (SUCCEEDED(hr
= MFCreatePresentationDescriptor(source
->stream_count
, source
->descriptors
, descriptor
)))
1348 if (FAILED(hr
= IMFPresentationDescriptor_SetUINT64(*descriptor
, &MF_PD_DURATION
, source
->duration
)))
1349 WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr
);
1351 for (i
= 0; i
< source
->stream_count
; ++i
)
1353 if (FAILED(hr
= IMFPresentationDescriptor_SelectStream(*descriptor
, i
)))
1354 WARN("Failed to select stream %u, hr %#lx\n", i
, hr
);
1360 LeaveCriticalSection(&source
->cs
);
1365 static HRESULT WINAPI
media_source_Start(IMFMediaSource
*iface
, IMFPresentationDescriptor
*descriptor
,
1366 const GUID
*time_format
, const PROPVARIANT
*position
)
1368 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1372 TRACE("%p, %p, %p, %p.\n", iface
, descriptor
, time_format
, position
);
1374 EnterCriticalSection(&source
->cs
);
1376 if (source
->state
== SOURCE_SHUTDOWN
)
1378 else if (!(IsEqualIID(time_format
, &GUID_NULL
)))
1379 hr
= MF_E_UNSUPPORTED_TIME_FORMAT
;
1380 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_START
, &op
)))
1382 struct source_async_command
*command
= impl_from_async_command_IUnknown(op
);
1383 command
->u
.start
.descriptor
= descriptor
;
1384 IMFPresentationDescriptor_AddRef(descriptor
);
1385 command
->u
.start
.format
= *time_format
;
1386 PropVariantCopy(&command
->u
.start
.position
, position
);
1388 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
1389 IUnknown_Release(op
);
1392 LeaveCriticalSection(&source
->cs
);
1397 static HRESULT WINAPI
media_source_Stop(IMFMediaSource
*iface
)
1399 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1403 TRACE("%p.\n", iface
);
1405 EnterCriticalSection(&source
->cs
);
1407 if (source
->state
== SOURCE_SHUTDOWN
)
1409 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_STOP
, &op
)))
1411 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
1412 IUnknown_Release(op
);
1415 LeaveCriticalSection(&source
->cs
);
1420 static HRESULT WINAPI
media_source_Pause(IMFMediaSource
*iface
)
1422 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1426 TRACE("%p.\n", iface
);
1428 EnterCriticalSection(&source
->cs
);
1430 if (source
->state
== SOURCE_SHUTDOWN
)
1432 else if (source
->state
!= SOURCE_RUNNING
)
1433 hr
= MF_E_INVALID_STATE_TRANSITION
;
1434 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_PAUSE
, &op
)))
1436 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
1437 IUnknown_Release(op
);
1440 LeaveCriticalSection(&source
->cs
);
1445 static HRESULT WINAPI
media_source_Shutdown(IMFMediaSource
*iface
)
1447 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1449 TRACE("%p.\n", iface
);
1451 EnterCriticalSection(&source
->cs
);
1453 if (source
->state
== SOURCE_SHUTDOWN
)
1455 LeaveCriticalSection(&source
->cs
);
1456 return MF_E_SHUTDOWN
;
1459 source
->state
= SOURCE_SHUTDOWN
;
1461 wg_parser_disconnect(source
->wg_parser
);
1463 source
->read_thread_shutdown
= true;
1464 WaitForSingleObject(source
->read_thread
, INFINITE
);
1465 CloseHandle(source
->read_thread
);
1467 IMFMediaEventQueue_Shutdown(source
->event_queue
);
1468 IMFByteStream_Close(source
->byte_stream
);
1470 while (source
->stream_count
--)
1472 struct media_stream
*stream
= source
->streams
[source
->stream_count
];
1473 IMFStreamDescriptor_Release(source
->descriptors
[source
->stream_count
]);
1474 IMFMediaEventQueue_Shutdown(stream
->event_queue
);
1475 IMFMediaStream_Release(&stream
->IMFMediaStream_iface
);
1477 free(source
->descriptors
);
1478 free(source
->streams
);
1480 MFUnlockWorkQueue(source
->async_commands_queue
);
1482 LeaveCriticalSection(&source
->cs
);
1487 static const IMFMediaSourceVtbl IMFMediaSource_vtbl
=
1489 media_source_QueryInterface
,
1490 media_source_AddRef
,
1491 media_source_Release
,
1492 media_source_GetEvent
,
1493 media_source_BeginGetEvent
,
1494 media_source_EndGetEvent
,
1495 media_source_QueueEvent
,
1496 media_source_GetCharacteristics
,
1497 media_source_CreatePresentationDescriptor
,
1501 media_source_Shutdown
,
1504 static void media_source_init_descriptors(struct media_source
*source
)
1509 for (i
= 0; i
< source
->stream_count
; i
++)
1511 struct media_stream
*stream
= source
->streams
[i
];
1512 IMFStreamDescriptor
*descriptor
= stream
->descriptor
;
1514 if (FAILED(hr
= stream_descriptor_set_tag(descriptor
, stream
->wg_stream
,
1515 &MF_SD_LANGUAGE
, WG_PARSER_TAG_LANGUAGE
)))
1516 WARN("Failed to set stream descriptor language, hr %#lx\n", hr
);
1517 if (FAILED(hr
= stream_descriptor_set_tag(descriptor
, stream
->wg_stream
,
1518 &MF_SD_STREAM_NAME
, WG_PARSER_TAG_NAME
)))
1519 WARN("Failed to set stream descriptor name, hr %#lx\n", hr
);
1523 static HRESULT
media_source_constructor(IMFByteStream
*bytestream
, struct media_source
**out_media_source
)
1525 unsigned int stream_count
= UINT_MAX
;
1526 struct media_source
*object
;
1527 struct wg_parser
*parser
;
1528 DWORD bytestream_caps
;
1533 if (FAILED(hr
= IMFByteStream_GetCapabilities(bytestream
, &bytestream_caps
)))
1536 if (!(bytestream_caps
& MFBYTESTREAM_IS_SEEKABLE
))
1538 FIXME("Non-seekable bytestreams not supported.\n");
1539 return MF_E_BYTESTREAM_NOT_SEEKABLE
;
1542 if (FAILED(hr
= IMFByteStream_GetLength(bytestream
, &file_size
)))
1544 FIXME("Failed to get byte stream length, hr %#lx.\n", hr
);
1548 if (!(object
= calloc(1, sizeof(*object
))))
1549 return E_OUTOFMEMORY
;
1551 object
->IMFMediaSource_iface
.lpVtbl
= &IMFMediaSource_vtbl
;
1552 object
->IMFGetService_iface
.lpVtbl
= &media_source_get_service_vtbl
;
1553 object
->IMFRateSupport_iface
.lpVtbl
= &media_source_rate_support_vtbl
;
1554 object
->IMFRateControl_iface
.lpVtbl
= &media_source_rate_control_vtbl
;
1555 object
->async_commands_callback
.lpVtbl
= &source_async_commands_callback_vtbl
;
1557 object
->byte_stream
= bytestream
;
1558 IMFByteStream_AddRef(bytestream
);
1559 object
->rate
= 1.0f
;
1560 InitializeCriticalSection(&object
->cs
);
1561 object
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": cs");
1563 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1566 if (FAILED(hr
= MFAllocateWorkQueue(&object
->async_commands_queue
)))
1569 /* In Media Foundation, sources may read from any media source stream
1570 * without fear of blocking due to buffering limits on another. Trailmakers,
1571 * a Unity3D Engine game, only reads one sample from the audio stream (and
1572 * never deselects it). Remove buffering limits from decodebin in order to
1573 * account for this. Note that this does leak memory, but the same memory
1574 * leak occurs with native. */
1575 if (!(parser
= wg_parser_create(WG_PARSER_DECODEBIN
, true)))
1580 object
->wg_parser
= parser
;
1582 object
->read_thread
= CreateThread(NULL
, 0, read_thread
, object
, 0, NULL
);
1584 object
->state
= SOURCE_OPENING
;
1586 if (FAILED(hr
= wg_parser_connect(parser
, file_size
)))
1589 stream_count
= wg_parser_get_stream_count(parser
);
1591 if (!(object
->descriptors
= calloc(stream_count
, sizeof(*object
->descriptors
)))
1592 || !(object
->streams
= calloc(stream_count
, sizeof(*object
->streams
))))
1594 free(object
->descriptors
);
1599 for (i
= 0; i
< stream_count
; ++i
)
1601 struct wg_parser_stream
*wg_stream
= wg_parser_get_stream(object
->wg_parser
, i
);
1602 IMFStreamDescriptor
*descriptor
;
1603 struct media_stream
*stream
;
1604 struct wg_format format
;
1606 wg_parser_stream_get_preferred_format(wg_stream
, &format
);
1607 if (FAILED(hr
= stream_descriptor_create(i
, &format
, &descriptor
)))
1609 if (FAILED(hr
= media_stream_create(&object
->IMFMediaSource_iface
, descriptor
, wg_stream
, &stream
)))
1611 IMFStreamDescriptor_Release(descriptor
);
1615 object
->duration
= max(object
->duration
, wg_parser_stream_get_duration(wg_stream
));
1616 IMFStreamDescriptor_AddRef(descriptor
);
1617 object
->descriptors
[i
] = descriptor
;
1618 object
->streams
[i
] = stream
;
1619 object
->stream_count
++;
1622 media_source_init_descriptors(object
);
1623 object
->state
= SOURCE_STOPPED
;
1625 *out_media_source
= object
;
1629 WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr
);
1631 while (object
->streams
&& object
->stream_count
--)
1633 struct media_stream
*stream
= object
->streams
[object
->stream_count
];
1634 IMFStreamDescriptor_Release(object
->descriptors
[object
->stream_count
]);
1635 IMFMediaStream_Release(&stream
->IMFMediaStream_iface
);
1637 free(object
->descriptors
);
1638 free(object
->streams
);
1640 if (stream_count
!= UINT_MAX
)
1641 wg_parser_disconnect(object
->wg_parser
);
1642 if (object
->read_thread
)
1644 object
->read_thread_shutdown
= true;
1645 WaitForSingleObject(object
->read_thread
, INFINITE
);
1646 CloseHandle(object
->read_thread
);
1648 if (object
->wg_parser
)
1649 wg_parser_destroy(object
->wg_parser
);
1650 if (object
->async_commands_queue
)
1651 MFUnlockWorkQueue(object
->async_commands_queue
);
1652 if (object
->event_queue
)
1653 IMFMediaEventQueue_Release(object
->event_queue
);
1654 IMFByteStream_Release(object
->byte_stream
);
1662 IMFAsyncResult
*result
;
1663 MF_OBJECT_TYPE type
;
1667 static HRESULT
result_entry_create(IMFAsyncResult
*result
, MF_OBJECT_TYPE type
,
1668 IUnknown
*object
, struct result_entry
**out
)
1670 struct result_entry
*entry
;
1672 if (!(entry
= malloc(sizeof(*entry
))))
1673 return E_OUTOFMEMORY
;
1675 entry
->result
= result
;
1676 IMFAsyncResult_AddRef(entry
->result
);
1677 entry
->object
= object
;
1678 IUnknown_AddRef(entry
->object
);
1685 static void result_entry_destroy(struct result_entry
*entry
)
1687 IMFAsyncResult_Release(entry
->result
);
1688 IUnknown_Release(entry
->object
);
1692 struct stream_handler
1694 IMFByteStreamHandler IMFByteStreamHandler_iface
;
1695 IMFAsyncCallback IMFAsyncCallback_iface
;
1697 struct list results
;
1698 CRITICAL_SECTION cs
;
1701 static struct result_entry
*handler_find_result_entry(struct stream_handler
*handler
, IMFAsyncResult
*result
)
1703 struct result_entry
*entry
;
1705 EnterCriticalSection(&handler
->cs
);
1706 LIST_FOR_EACH_ENTRY(entry
, &handler
->results
, struct result_entry
, entry
)
1708 if (result
== entry
->result
)
1710 list_remove(&entry
->entry
);
1711 LeaveCriticalSection(&handler
->cs
);
1715 LeaveCriticalSection(&handler
->cs
);
1720 static struct stream_handler
*impl_from_IMFByteStreamHandler(IMFByteStreamHandler
*iface
)
1722 return CONTAINING_RECORD(iface
, struct stream_handler
, IMFByteStreamHandler_iface
);
1725 static struct stream_handler
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
1727 return CONTAINING_RECORD(iface
, struct stream_handler
, IMFAsyncCallback_iface
);
1730 static HRESULT WINAPI
stream_handler_QueryInterface(IMFByteStreamHandler
*iface
, REFIID riid
, void **obj
)
1732 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1734 if (IsEqualIID(riid
, &IID_IMFByteStreamHandler
) ||
1735 IsEqualIID(riid
, &IID_IUnknown
))
1738 IMFByteStreamHandler_AddRef(iface
);
1742 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1744 return E_NOINTERFACE
;
1747 static ULONG WINAPI
stream_handler_AddRef(IMFByteStreamHandler
*iface
)
1749 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1750 ULONG refcount
= InterlockedIncrement(&handler
->refcount
);
1752 TRACE("%p, refcount %lu.\n", handler
, refcount
);
1757 static ULONG WINAPI
stream_handler_Release(IMFByteStreamHandler
*iface
)
1759 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1760 ULONG refcount
= InterlockedDecrement(&handler
->refcount
);
1761 struct result_entry
*result
, *next
;
1763 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1767 LIST_FOR_EACH_ENTRY_SAFE(result
, next
, &handler
->results
, struct result_entry
, entry
)
1768 result_entry_destroy(result
);
1769 DeleteCriticalSection(&handler
->cs
);
1776 struct create_object_context
1778 IUnknown IUnknown_iface
;
1781 IMFByteStream
*stream
;
1785 static struct create_object_context
*impl_from_IUnknown(IUnknown
*iface
)
1787 return CONTAINING_RECORD(iface
, struct create_object_context
, IUnknown_iface
);
1790 static HRESULT WINAPI
create_object_context_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
1792 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1794 if (IsEqualIID(riid
, &IID_IUnknown
))
1797 IUnknown_AddRef(iface
);
1801 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1803 return E_NOINTERFACE
;
1806 static ULONG WINAPI
create_object_context_AddRef(IUnknown
*iface
)
1808 struct create_object_context
*context
= impl_from_IUnknown(iface
);
1809 ULONG refcount
= InterlockedIncrement(&context
->refcount
);
1811 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1816 static ULONG WINAPI
create_object_context_Release(IUnknown
*iface
)
1818 struct create_object_context
*context
= impl_from_IUnknown(iface
);
1819 ULONG refcount
= InterlockedDecrement(&context
->refcount
);
1821 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1825 IMFByteStream_Release(context
->stream
);
1833 static const IUnknownVtbl create_object_context_vtbl
=
1835 create_object_context_QueryInterface
,
1836 create_object_context_AddRef
,
1837 create_object_context_Release
,
1840 static HRESULT WINAPI
stream_handler_BeginCreateObject(IMFByteStreamHandler
*iface
, IMFByteStream
*stream
, const WCHAR
*url
, DWORD flags
,
1841 IPropertyStore
*props
, IUnknown
**cancel_cookie
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1843 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1844 struct create_object_context
*context
;
1845 IMFAsyncResult
*caller
, *item
;
1848 TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface
, debugstr_w(url
), flags
, props
, cancel_cookie
, callback
, state
);
1851 *cancel_cookie
= NULL
;
1854 return E_INVALIDARG
;
1855 if (flags
!= MF_RESOLUTION_MEDIASOURCE
)
1856 FIXME("Unimplemented flags %#lx\n", flags
);
1858 if (FAILED(hr
= MFCreateAsyncResult(NULL
, callback
, state
, &caller
)))
1861 if (!(context
= calloc(1, sizeof(*context
))))
1863 IMFAsyncResult_Release(caller
);
1864 return E_OUTOFMEMORY
;
1867 context
->IUnknown_iface
.lpVtbl
= &create_object_context_vtbl
;
1868 context
->refcount
= 1;
1869 context
->stream
= stream
;
1870 IMFByteStream_AddRef(context
->stream
);
1872 context
->url
= wcsdup(url
);
1874 hr
= MFCreateAsyncResult(&context
->IUnknown_iface
, &handler
->IMFAsyncCallback_iface
, (IUnknown
*)caller
, &item
);
1875 IUnknown_Release(&context
->IUnknown_iface
);
1878 if (SUCCEEDED(hr
= MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO
, item
)))
1882 *cancel_cookie
= (IUnknown
*)caller
;
1883 IUnknown_AddRef(*cancel_cookie
);
1887 IMFAsyncResult_Release(item
);
1889 IMFAsyncResult_Release(caller
);
1894 static HRESULT WINAPI
stream_handler_EndCreateObject(IMFByteStreamHandler
*iface
, IMFAsyncResult
*result
,
1895 MF_OBJECT_TYPE
*type
, IUnknown
**object
)
1897 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1898 struct result_entry
*entry
;
1901 TRACE("%p, %p, %p, %p.\n", iface
, result
, type
, object
);
1903 if (!(entry
= handler_find_result_entry(handler
, result
)))
1905 *type
= MF_OBJECT_INVALID
;
1907 return MF_E_UNEXPECTED
;
1910 hr
= IMFAsyncResult_GetStatus(entry
->result
);
1911 *type
= entry
->type
;
1912 *object
= entry
->object
;
1913 IUnknown_AddRef(*object
);
1914 result_entry_destroy(entry
);
1918 static HRESULT WINAPI
stream_handler_CancelObjectCreation(IMFByteStreamHandler
*iface
, IUnknown
*cookie
)
1920 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1921 IMFAsyncResult
*result
= (IMFAsyncResult
*)cookie
;
1922 struct result_entry
*entry
;
1924 TRACE("%p, %p.\n", iface
, cookie
);
1926 if (!(entry
= handler_find_result_entry(handler
, result
)))
1927 return MF_E_UNEXPECTED
;
1929 result_entry_destroy(entry
);
1933 static HRESULT WINAPI
stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler
*iface
, QWORD
*bytes
)
1935 FIXME("stub (%p %p)\n", iface
, bytes
);
1939 static const IMFByteStreamHandlerVtbl stream_handler_vtbl
=
1941 stream_handler_QueryInterface
,
1942 stream_handler_AddRef
,
1943 stream_handler_Release
,
1944 stream_handler_BeginCreateObject
,
1945 stream_handler_EndCreateObject
,
1946 stream_handler_CancelObjectCreation
,
1947 stream_handler_GetMaxNumberOfBytesRequiredForResolution
,
1950 static HRESULT WINAPI
stream_handler_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1952 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1953 IsEqualIID(riid
, &IID_IUnknown
))
1956 IMFAsyncCallback_AddRef(iface
);
1960 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1962 return E_NOINTERFACE
;
1965 static ULONG WINAPI
stream_handler_callback_AddRef(IMFAsyncCallback
*iface
)
1967 struct stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1968 return IMFByteStreamHandler_AddRef(&handler
->IMFByteStreamHandler_iface
);
1971 static ULONG WINAPI
stream_handler_callback_Release(IMFAsyncCallback
*iface
)
1973 struct stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1974 return IMFByteStreamHandler_Release(&handler
->IMFByteStreamHandler_iface
);
1977 static HRESULT WINAPI
stream_handler_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1982 static HRESULT
stream_handler_create_object(struct stream_handler
*handler
, WCHAR
*url
, IMFByteStream
*stream
,
1983 IUnknown
**out_object
)
1986 struct media_source
*new_source
;
1988 TRACE("%p, %s, %p, %p.\n", handler
, debugstr_w(url
), stream
, out_object
);
1990 if (FAILED(hr
= media_source_constructor(stream
, &new_source
)))
1993 TRACE("->(%p)\n", new_source
);
1995 *out_object
= (IUnknown
*)&new_source
->IMFMediaSource_iface
;
2000 static HRESULT WINAPI
stream_handler_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2002 struct stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
2003 IUnknown
*object
= NULL
, *context_object
;
2004 struct create_object_context
*context
;
2005 struct result_entry
*entry
;
2006 IMFAsyncResult
*caller
;
2009 caller
= (IMFAsyncResult
*)IMFAsyncResult_GetStateNoAddRef(result
);
2011 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &context_object
)))
2013 WARN("Expected context set for callee result.\n");
2017 context
= impl_from_IUnknown(context_object
);
2019 if (FAILED(hr
= stream_handler_create_object(handler
, context
->url
, context
->stream
, &object
)))
2020 WARN("Failed to create object, hr %#lx\n", hr
);
2023 if (FAILED(hr
= result_entry_create(caller
, MF_OBJECT_MEDIASOURCE
, object
, &entry
)))
2024 WARN("Failed to create handler result, hr %#lx\n", hr
);
2027 EnterCriticalSection(&handler
->cs
);
2028 list_add_tail(&handler
->results
, &entry
->entry
);
2029 LeaveCriticalSection(&handler
->cs
);
2032 IUnknown_Release(object
);
2035 IUnknown_Release(&context
->IUnknown_iface
);
2037 IMFAsyncResult_SetStatus(caller
, hr
);
2038 MFInvokeCallback(caller
);
2043 static const IMFAsyncCallbackVtbl stream_handler_callback_vtbl
=
2045 stream_handler_callback_QueryInterface
,
2046 stream_handler_callback_AddRef
,
2047 stream_handler_callback_Release
,
2048 stream_handler_callback_GetParameters
,
2049 stream_handler_callback_Invoke
,
2052 HRESULT
gstreamer_byte_stream_handler_create(REFIID riid
, void **obj
)
2054 struct stream_handler
*handler
;
2057 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
2059 if (!(handler
= calloc(1, sizeof(*handler
))))
2060 return E_OUTOFMEMORY
;
2062 list_init(&handler
->results
);
2063 InitializeCriticalSection(&handler
->cs
);
2065 handler
->IMFByteStreamHandler_iface
.lpVtbl
= &stream_handler_vtbl
;
2066 handler
->IMFAsyncCallback_iface
.lpVtbl
= &stream_handler_callback_vtbl
;
2067 handler
->refcount
= 1;
2069 hr
= IMFByteStreamHandler_QueryInterface(&handler
->IMFByteStreamHandler_iface
, riid
, obj
);
2070 IMFByteStreamHandler_Release(&handler
->IMFByteStreamHandler_iface
);