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
)
177 PropVariantClear(&command
->u
.start
.position
);
178 else if (command
->op
== SOURCE_ASYNC_REQUEST_SAMPLE
)
180 if (command
->u
.request_sample
.token
)
181 IUnknown_Release(command
->u
.request_sample
.token
);
189 static const IUnknownVtbl source_async_command_vtbl
=
191 source_async_command_QueryInterface
,
192 source_async_command_AddRef
,
193 source_async_command_Release
,
196 static HRESULT
source_create_async_op(enum source_async_op op
, IUnknown
**out
)
198 struct source_async_command
*command
;
200 if (!(command
= calloc(1, sizeof(*command
))))
201 return E_OUTOFMEMORY
;
203 command
->IUnknown_iface
.lpVtbl
= &source_async_command_vtbl
;
204 command
->refcount
= 1;
207 *out
= &command
->IUnknown_iface
;
211 static HRESULT WINAPI
callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
213 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
215 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
216 IsEqualIID(riid
, &IID_IUnknown
))
219 IMFAsyncCallback_AddRef(iface
);
223 WARN("Unsupported %s.\n", debugstr_guid(riid
));
225 return E_NOINTERFACE
;
228 static HRESULT WINAPI
callback_GetParameters(IMFAsyncCallback
*iface
,
229 DWORD
*flags
, DWORD
*queue
)
234 static ULONG WINAPI
source_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
236 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
237 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
240 static ULONG WINAPI
source_async_commands_callback_Release(IMFAsyncCallback
*iface
)
242 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
243 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
246 static HRESULT
stream_descriptor_get_media_type(IMFStreamDescriptor
*descriptor
, IMFMediaType
**media_type
)
248 IMFMediaTypeHandler
*handler
;
251 if (FAILED(hr
= IMFStreamDescriptor_GetMediaTypeHandler(descriptor
, &handler
)))
253 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
254 IMFMediaTypeHandler_Release(handler
);
259 static HRESULT
wg_format_from_stream_descriptor(IMFStreamDescriptor
*descriptor
, struct wg_format
*format
)
261 IMFMediaType
*media_type
;
264 if (FAILED(hr
= stream_descriptor_get_media_type(descriptor
, &media_type
)))
266 mf_media_type_to_wg_format(media_type
, format
);
267 IMFMediaType_Release(media_type
);
272 static IMFStreamDescriptor
*stream_descriptor_from_id(IMFPresentationDescriptor
*pres_desc
, DWORD id
, BOOL
*selected
)
275 IMFStreamDescriptor
*ret
;
278 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorCount(pres_desc
, &sd_count
)))
281 for (i
= 0; i
< sd_count
; i
++)
285 if (FAILED(IMFPresentationDescriptor_GetStreamDescriptorByIndex(pres_desc
, i
, selected
, &ret
)))
288 if (SUCCEEDED(IMFStreamDescriptor_GetStreamIdentifier(ret
, &stream_id
)) && stream_id
== id
)
291 IMFStreamDescriptor_Release(ret
);
296 static BOOL
enqueue_token(struct media_stream
*stream
, IUnknown
*token
)
298 if (stream
->token_queue_count
== stream
->token_queue_cap
)
301 stream
->token_queue_cap
= stream
->token_queue_cap
* 2 + 1;
302 buf
= realloc(stream
->token_queue
, stream
->token_queue_cap
* sizeof(*buf
));
304 stream
->token_queue
= buf
;
307 stream
->token_queue_cap
= stream
->token_queue_count
;
311 stream
->token_queue
[stream
->token_queue_count
++] = token
;
315 static void flush_token_queue(struct media_stream
*stream
, BOOL send
)
317 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
320 for (i
= 0; i
< stream
->token_queue_count
; i
++)
327 if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE
, &op
)))
329 struct source_async_command
*command
= impl_from_async_command_IUnknown(op
);
330 command
->u
.request_sample
.stream
= stream
;
331 command
->u
.request_sample
.token
= stream
->token_queue
[i
];
333 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
334 IUnknown_Release(op
);
337 WARN("Could not enqueue sample request, hr %#lx\n", hr
);
339 else if (stream
->token_queue
[i
])
340 IUnknown_Release(stream
->token_queue
[i
]);
342 free(stream
->token_queue
);
343 stream
->token_queue
= NULL
;
344 stream
->token_queue_count
= 0;
345 stream
->token_queue_cap
= 0;
348 static HRESULT
media_stream_start(struct media_stream
*stream
, BOOL active
, BOOL seeking
, const PROPVARIANT
*position
)
350 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
351 struct wg_format format
;
354 TRACE("source %p, stream %p\n", source
, stream
);
356 if (FAILED(hr
= wg_format_from_stream_descriptor(stream
->descriptor
, &format
)))
357 WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr
);
358 wg_parser_stream_enable(stream
->wg_stream
, &format
);
360 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamUnk(source
->event_queue
, active
? MEUpdatedStream
: MENewStream
,
361 &GUID_NULL
, S_OK
, (IUnknown
*)&stream
->IMFMediaStream_iface
)))
362 WARN("Failed to send source stream event, hr %#lx\n", hr
);
363 return IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, seeking
? MEStreamSeeked
: MEStreamStarted
,
364 &GUID_NULL
, S_OK
, position
);
367 static HRESULT
media_source_start(struct media_source
*source
, IMFPresentationDescriptor
*descriptor
,
368 GUID
*format
, PROPVARIANT
*position
)
370 BOOL starting
= source
->state
== SOURCE_STOPPED
, seek_message
= !starting
&& position
->vt
!= VT_EMPTY
;
374 TRACE("source %p, descriptor %p, format %s, position %s\n", source
, descriptor
,
375 debugstr_guid(format
), wine_dbgstr_variant((VARIANT
*)position
));
377 if (source
->state
== SOURCE_SHUTDOWN
)
378 return MF_E_SHUTDOWN
;
380 /* seek to beginning on stop->play */
381 if (source
->state
== SOURCE_STOPPED
&& position
->vt
== VT_EMPTY
)
383 position
->vt
= VT_I8
;
384 position
->hVal
.QuadPart
= 0;
387 for (i
= 0; i
< source
->stream_count
; i
++)
389 struct media_stream
*stream
;
390 BOOL was_active
, selected
;
391 IMFStreamDescriptor
*sd
;
394 stream
= source
->streams
[i
];
395 was_active
= !starting
&& stream
->active
;
397 IMFStreamDescriptor_GetStreamIdentifier(stream
->descriptor
, &stream_id
);
398 sd
= stream_descriptor_from_id(descriptor
, stream_id
, &selected
);
399 IMFStreamDescriptor_Release(sd
);
401 if (position
->vt
!= VT_EMPTY
)
404 if (!(stream
->active
= selected
))
405 wg_parser_stream_disable(stream
->wg_stream
);
406 else if (FAILED(hr
= media_stream_start(stream
, was_active
, seek_message
, position
)))
407 WARN("Failed to start media stream, hr %#lx\n", hr
);
410 source
->state
= SOURCE_RUNNING
;
412 if (position
->vt
== VT_I8
)
413 wg_parser_stream_seek(source
->streams
[0]->wg_stream
, 1.0, position
->hVal
.QuadPart
, 0,
414 AM_SEEKING_AbsolutePositioning
, AM_SEEKING_NoPositioning
);
416 for (i
= 0; i
< source
->stream_count
; i
++)
417 flush_token_queue(source
->streams
[i
], position
->vt
== VT_EMPTY
);
419 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
,
420 seek_message
? MESourceSeeked
: MESourceStarted
, &GUID_NULL
, S_OK
, position
);
423 static HRESULT
media_source_pause(struct media_source
*source
)
428 TRACE("source %p\n", source
);
430 if (source
->state
== SOURCE_SHUTDOWN
)
431 return MF_E_SHUTDOWN
;
433 for (i
= 0; i
< source
->stream_count
; i
++)
435 struct media_stream
*stream
= source
->streams
[i
];
436 if (stream
->active
&& FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEStreamPaused
,
437 &GUID_NULL
, S_OK
, NULL
)))
438 WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr
);
441 source
->state
= SOURCE_PAUSED
;
442 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourcePaused
, &GUID_NULL
, S_OK
, NULL
);
445 static HRESULT
media_source_stop(struct media_source
*source
)
450 TRACE("source %p\n", source
);
452 if (source
->state
== SOURCE_SHUTDOWN
)
453 return MF_E_SHUTDOWN
;
455 for (i
= 0; i
< source
->stream_count
; i
++)
457 struct media_stream
*stream
= source
->streams
[i
];
458 if (stream
->active
&& FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEStreamStopped
,
459 &GUID_NULL
, S_OK
, NULL
)))
460 WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr
);
463 source
->state
= SOURCE_STOPPED
;
465 for (i
= 0; i
< source
->stream_count
; i
++)
466 flush_token_queue(source
->streams
[i
], FALSE
);
468 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourceStopped
, &GUID_NULL
, S_OK
, NULL
);
471 static HRESULT
media_stream_send_sample(struct media_stream
*stream
, const struct wg_parser_buffer
*wg_buffer
, IUnknown
*token
)
473 IMFSample
*sample
= NULL
;
474 IMFMediaBuffer
*buffer
;
478 if (FAILED(hr
= MFCreateMemoryBuffer(wg_buffer
->size
, &buffer
)))
480 if (FAILED(hr
= IMFMediaBuffer_SetCurrentLength(buffer
, wg_buffer
->size
)))
482 if (FAILED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, NULL
, NULL
)))
485 if (!wg_parser_stream_copy_buffer(stream
->wg_stream
, data
, 0, wg_buffer
->size
))
487 wg_parser_stream_release_buffer(stream
->wg_stream
);
488 IMFMediaBuffer_Unlock(buffer
);
491 wg_parser_stream_release_buffer(stream
->wg_stream
);
493 if (FAILED(hr
= IMFMediaBuffer_Unlock(buffer
)))
496 if (FAILED(hr
= MFCreateSample(&sample
)))
498 if (FAILED(hr
= IMFSample_AddBuffer(sample
, buffer
)))
500 if (FAILED(hr
= IMFSample_SetSampleTime(sample
, wg_buffer
->pts
)))
502 if (FAILED(hr
= IMFSample_SetSampleDuration(sample
, wg_buffer
->duration
)))
504 if (token
&& FAILED(hr
= IMFSample_SetUnknown(sample
, &MFSampleExtension_Token
, token
)))
507 hr
= IMFMediaEventQueue_QueueEventParamUnk(stream
->event_queue
, MEMediaSample
,
508 &GUID_NULL
, S_OK
, (IUnknown
*)sample
);
512 IMFSample_Release(sample
);
513 IMFMediaBuffer_Release(buffer
);
517 static HRESULT
media_stream_send_eos(struct media_source
*source
, struct media_stream
*stream
)
519 PROPVARIANT empty
= {.vt
= VT_EMPTY
};
523 TRACE("source %p, stream %p\n", source
, stream
);
526 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEEndOfStream
, &GUID_NULL
, S_OK
, &empty
)))
527 WARN("Failed to queue MEEndOfStream event, hr %#lx\n", hr
);
529 for (i
= 0; i
< source
->stream_count
; i
++)
531 struct media_stream
*stream
= source
->streams
[i
];
532 if (stream
->active
&& !stream
->eos
)
536 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, &empty
)))
537 WARN("Failed to queue MEEndOfPresentation event, hr %#lx\n", hr
);
541 static HRESULT
wait_on_sample(struct media_stream
*stream
, IUnknown
*token
)
543 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
544 struct wg_parser_buffer buffer
;
546 TRACE("%p, %p\n", stream
, token
);
548 if (wg_parser_stream_get_buffer(source
->wg_parser
, stream
->wg_stream
, &buffer
))
549 return media_stream_send_sample(stream
, &buffer
, token
);
551 return media_stream_send_eos(source
, stream
);
554 static HRESULT WINAPI
source_async_commands_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
556 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
557 struct source_async_command
*command
;
561 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
564 EnterCriticalSection(&source
->cs
);
566 command
= impl_from_async_command_IUnknown(state
);
569 case SOURCE_ASYNC_START
:
571 IMFPresentationDescriptor
*descriptor
= command
->u
.start
.descriptor
;
572 GUID format
= command
->u
.start
.format
;
573 PROPVARIANT position
= command
->u
.start
.position
;
575 if (FAILED(hr
= media_source_start(source
, descriptor
, &format
, &position
)))
576 WARN("Failed to start source %p, hr %#lx\n", source
, hr
);
579 case SOURCE_ASYNC_PAUSE
:
580 if (FAILED(hr
= media_source_pause(source
)))
581 WARN("Failed to pause source %p, hr %#lx\n", source
, hr
);
583 case SOURCE_ASYNC_STOP
:
584 if (FAILED(hr
= media_source_stop(source
)))
585 WARN("Failed to stop source %p, hr %#lx\n", source
, hr
);
587 case SOURCE_ASYNC_REQUEST_SAMPLE
:
588 if (source
->state
== SOURCE_PAUSED
)
589 enqueue_token(command
->u
.request_sample
.stream
, command
->u
.request_sample
.token
);
590 else if (source
->state
== SOURCE_RUNNING
)
592 if (FAILED(hr
= wait_on_sample(command
->u
.request_sample
.stream
, command
->u
.request_sample
.token
)))
593 WARN("Failed to request sample, hr %#lx\n", hr
);
598 LeaveCriticalSection(&source
->cs
);
600 IUnknown_Release(state
);
605 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl
=
607 callback_QueryInterface
,
608 source_async_commands_callback_AddRef
,
609 source_async_commands_callback_Release
,
610 callback_GetParameters
,
611 source_async_commands_Invoke
,
614 static DWORD CALLBACK
read_thread(void *arg
)
616 struct media_source
*source
= arg
;
617 IMFByteStream
*byte_stream
= source
->byte_stream
;
618 size_t buffer_size
= 4096;
622 if (!(data
= malloc(buffer_size
)))
625 IMFByteStream_GetLength(byte_stream
, &file_size
);
627 TRACE("Starting read thread for media source %p.\n", source
);
629 while (!source
->read_thread_shutdown
)
636 if (!wg_parser_get_next_read_offset(source
->wg_parser
, &offset
, &size
))
639 if (offset
>= file_size
)
641 else if (offset
+ size
>= file_size
)
642 size
= file_size
- offset
;
644 /* Some IMFByteStreams (including the standard file-based stream) return
645 * an error when reading past the file size. */
648 wg_parser_push_data(source
->wg_parser
, data
, 0);
652 if (!array_reserve(&data
, &buffer_size
, size
, 1))
660 if (SUCCEEDED(hr
= IMFByteStream_SetCurrentPosition(byte_stream
, offset
)))
661 hr
= IMFByteStream_Read(byte_stream
, data
, size
, &ret_size
);
663 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size
, offset
, hr
);
664 else if (ret_size
!= size
)
665 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size
, ret_size
);
666 wg_parser_push_data(source
->wg_parser
, SUCCEEDED(hr
) ? data
: NULL
, ret_size
);
670 TRACE("Media source is shutting down; exiting.\n");
674 static HRESULT WINAPI
media_stream_QueryInterface(IMFMediaStream
*iface
, REFIID riid
, void **out
)
676 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
678 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
680 if (IsEqualIID(riid
, &IID_IMFMediaStream
) ||
681 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
682 IsEqualIID(riid
, &IID_IUnknown
))
684 *out
= &stream
->IMFMediaStream_iface
;
688 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
690 return E_NOINTERFACE
;
693 IUnknown_AddRef((IUnknown
*)*out
);
697 static ULONG WINAPI
media_stream_AddRef(IMFMediaStream
*iface
)
699 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
700 ULONG ref
= InterlockedIncrement(&stream
->ref
);
702 TRACE("%p, refcount %lu.\n", iface
, ref
);
707 static ULONG WINAPI
media_stream_Release(IMFMediaStream
*iface
)
709 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
710 ULONG ref
= InterlockedDecrement(&stream
->ref
);
712 TRACE("%p, refcount %lu.\n", iface
, ref
);
716 IMFMediaSource_Release(stream
->media_source
);
717 IMFStreamDescriptor_Release(stream
->descriptor
);
718 IMFMediaEventQueue_Release(stream
->event_queue
);
719 flush_token_queue(stream
, FALSE
);
726 static HRESULT WINAPI
media_stream_GetEvent(IMFMediaStream
*iface
, DWORD flags
, IMFMediaEvent
**event
)
728 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
730 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
732 return IMFMediaEventQueue_GetEvent(stream
->event_queue
, flags
, event
);
735 static HRESULT WINAPI
media_stream_BeginGetEvent(IMFMediaStream
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
737 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
739 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
741 return IMFMediaEventQueue_BeginGetEvent(stream
->event_queue
, callback
, state
);
744 static HRESULT WINAPI
media_stream_EndGetEvent(IMFMediaStream
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
746 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
748 TRACE("%p, %p, %p.\n", stream
, result
, event
);
750 return IMFMediaEventQueue_EndGetEvent(stream
->event_queue
, result
, event
);
753 static HRESULT WINAPI
media_stream_QueueEvent(IMFMediaStream
*iface
, MediaEventType event_type
, REFGUID ext_type
,
754 HRESULT hr
, const PROPVARIANT
*value
)
756 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
758 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
760 return IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, event_type
, ext_type
, hr
, value
);
763 static HRESULT WINAPI
media_stream_GetMediaSource(IMFMediaStream
*iface
, IMFMediaSource
**out
)
765 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
766 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
769 TRACE("%p, %p.\n", iface
, out
);
771 EnterCriticalSection(&source
->cs
);
773 if (source
->state
== SOURCE_SHUTDOWN
)
777 IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
778 *out
= &source
->IMFMediaSource_iface
;
781 LeaveCriticalSection(&source
->cs
);
786 static HRESULT WINAPI
media_stream_GetStreamDescriptor(IMFMediaStream
* iface
, IMFStreamDescriptor
**descriptor
)
788 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
789 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
792 TRACE("%p, %p.\n", iface
, descriptor
);
794 EnterCriticalSection(&source
->cs
);
796 if (source
->state
== SOURCE_SHUTDOWN
)
800 IMFStreamDescriptor_AddRef(stream
->descriptor
);
801 *descriptor
= stream
->descriptor
;
804 LeaveCriticalSection(&source
->cs
);
809 static HRESULT WINAPI
media_stream_RequestSample(IMFMediaStream
*iface
, IUnknown
*token
)
811 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
812 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
816 TRACE("%p, %p.\n", iface
, token
);
818 EnterCriticalSection(&source
->cs
);
820 if (source
->state
== SOURCE_SHUTDOWN
)
822 else if (!stream
->active
)
823 hr
= MF_E_MEDIA_SOURCE_WRONGSTATE
;
824 else if (stream
->eos
)
825 hr
= MF_E_END_OF_STREAM
;
826 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE
, &op
)))
828 struct source_async_command
*command
= impl_from_async_command_IUnknown(op
);
829 command
->u
.request_sample
.stream
= stream
;
831 IUnknown_AddRef(token
);
832 command
->u
.request_sample
.token
= token
;
834 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
835 IUnknown_Release(op
);
838 LeaveCriticalSection(&source
->cs
);
843 static const IMFMediaStreamVtbl media_stream_vtbl
=
845 media_stream_QueryInterface
,
847 media_stream_Release
,
848 media_stream_GetEvent
,
849 media_stream_BeginGetEvent
,
850 media_stream_EndGetEvent
,
851 media_stream_QueueEvent
,
852 media_stream_GetMediaSource
,
853 media_stream_GetStreamDescriptor
,
854 media_stream_RequestSample
857 static HRESULT
media_stream_create(IMFMediaSource
*source
, DWORD id
,
858 struct media_stream
**out
)
860 struct wg_parser
*wg_parser
= impl_from_IMFMediaSource(source
)->wg_parser
;
861 struct media_stream
*object
;
864 TRACE("source %p, id %lu.\n", source
, id
);
866 if (!(object
= calloc(1, sizeof(*object
))))
867 return E_OUTOFMEMORY
;
869 object
->IMFMediaStream_iface
.lpVtbl
= &media_stream_vtbl
;
872 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
878 IMFMediaSource_AddRef(source
);
879 object
->media_source
= source
;
880 object
->stream_id
= id
;
882 object
->active
= TRUE
;
884 object
->wg_stream
= wg_parser_get_stream(wg_parser
, id
);
886 TRACE("Created stream object %p.\n", object
);
892 static HRESULT
media_stream_init_desc(struct media_stream
*stream
)
894 IMFMediaTypeHandler
*type_handler
= NULL
;
895 IMFMediaType
*stream_types
[6];
896 struct wg_format format
;
897 DWORD type_count
= 0;
901 wg_parser_stream_get_preferred_format(stream
->wg_stream
, &format
);
903 if (format
.major_type
== WG_MAJOR_TYPE_VIDEO
)
905 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
906 * YUV color space, and it's generally much less expensive for
907 * videoconvert to do YUV -> YUV transformations. */
908 static const enum wg_video_format video_formats
[] =
910 WG_VIDEO_FORMAT_NV12
,
911 WG_VIDEO_FORMAT_YV12
,
912 WG_VIDEO_FORMAT_YUY2
,
913 WG_VIDEO_FORMAT_I420
,
916 IMFMediaType
*base_type
= mf_media_type_from_wg_format(&format
);
921 hr
= MF_E_INVALIDMEDIATYPE
;
925 IMFMediaType_GetGUID(base_type
, &MF_MT_SUBTYPE
, &base_subtype
);
927 stream_types
[0] = base_type
;
930 for (i
= 0; i
< ARRAY_SIZE(video_formats
); ++i
)
932 struct wg_format new_format
= format
;
933 IMFMediaType
*new_type
;
935 new_format
.u
.video
.format
= video_formats
[i
];
937 if (!(new_type
= mf_media_type_from_wg_format(&new_format
)))
942 stream_types
[type_count
++] = new_type
;
944 if (video_formats
[i
] == WG_VIDEO_FORMAT_I420
)
946 IMFMediaType
*iyuv_type
;
948 if (FAILED(hr
= MFCreateMediaType(&iyuv_type
)))
950 if (FAILED(hr
= IMFMediaType_CopyAllItems(new_type
, (IMFAttributes
*)iyuv_type
)))
952 if (FAILED(hr
= IMFMediaType_SetGUID(iyuv_type
, &MF_MT_SUBTYPE
, &MFVideoFormat_IYUV
)))
954 stream_types
[type_count
++] = iyuv_type
;
958 else if (format
.major_type
== WG_MAJOR_TYPE_AUDIO
)
960 /* Expose at least one PCM and one floating point type for the
961 consumer to pick from. */
962 static const enum wg_audio_format audio_types
[] =
964 WG_AUDIO_FORMAT_S16LE
,
965 WG_AUDIO_FORMAT_F32LE
,
968 if ((stream_types
[0] = mf_media_type_from_wg_format(&format
)))
971 for (i
= 0; i
< ARRAY_SIZE(audio_types
); i
++)
973 struct wg_format new_format
;
974 if (format
.u
.audio
.format
== audio_types
[i
])
977 new_format
.u
.audio
.format
= audio_types
[i
];
978 if ((stream_types
[type_count
] = mf_media_type_from_wg_format(&new_format
)))
984 if ((stream_types
[0] = mf_media_type_from_wg_format(&format
)))
988 assert(type_count
<= ARRAY_SIZE(stream_types
));
992 ERR("Failed to establish an IMFMediaType from any of the possible stream caps!\n");
996 if (FAILED(hr
= MFCreateStreamDescriptor(stream
->stream_id
, type_count
, stream_types
, &stream
->descriptor
)))
999 if (FAILED(hr
= IMFStreamDescriptor_GetMediaTypeHandler(stream
->descriptor
, &type_handler
)))
1001 IMFStreamDescriptor_Release(stream
->descriptor
);
1005 if (FAILED(hr
= IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, stream_types
[0])))
1007 IMFStreamDescriptor_Release(stream
->descriptor
);
1013 IMFMediaTypeHandler_Release(type_handler
);
1014 for (i
= 0; i
< type_count
; i
++)
1015 IMFMediaType_Release(stream_types
[i
]);
1019 static HRESULT WINAPI
media_source_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1021 struct media_source
*source
= impl_from_IMFGetService(iface
);
1022 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
1025 static ULONG WINAPI
media_source_get_service_AddRef(IMFGetService
*iface
)
1027 struct media_source
*source
= impl_from_IMFGetService(iface
);
1028 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1031 static ULONG WINAPI
media_source_get_service_Release(IMFGetService
*iface
)
1033 struct media_source
*source
= impl_from_IMFGetService(iface
);
1034 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
1037 static HRESULT WINAPI
media_source_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
1039 struct media_source
*source
= impl_from_IMFGetService(iface
);
1041 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1045 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1047 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1049 *obj
= &source
->IMFRateSupport_iface
;
1051 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
1053 *obj
= &source
->IMFRateControl_iface
;
1057 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
1060 IUnknown_AddRef((IUnknown
*)*obj
);
1062 return *obj
? S_OK
: E_NOINTERFACE
;
1065 static const IMFGetServiceVtbl media_source_get_service_vtbl
=
1067 media_source_get_service_QueryInterface
,
1068 media_source_get_service_AddRef
,
1069 media_source_get_service_Release
,
1070 media_source_get_service_GetService
,
1073 static HRESULT WINAPI
media_source_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
1075 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
1076 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
1079 static ULONG WINAPI
media_source_rate_support_AddRef(IMFRateSupport
*iface
)
1081 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
1082 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1085 static ULONG WINAPI
media_source_rate_support_Release(IMFRateSupport
*iface
)
1087 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
1088 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
1091 static HRESULT WINAPI
media_source_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
, BOOL thin
, float *rate
)
1093 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1100 static HRESULT WINAPI
media_source_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
, BOOL thin
, float *rate
)
1102 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1104 *rate
= direction
== MFRATE_FORWARD
? 1e6f
: -1e6f
;
1109 static HRESULT WINAPI
media_source_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
1110 float *nearest_rate
)
1112 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_rate
);
1115 *nearest_rate
= rate
;
1117 return rate
>= -1e6f
&& rate
<= 1e6f
? S_OK
: MF_E_UNSUPPORTED_RATE
;
1120 static const IMFRateSupportVtbl media_source_rate_support_vtbl
=
1122 media_source_rate_support_QueryInterface
,
1123 media_source_rate_support_AddRef
,
1124 media_source_rate_support_Release
,
1125 media_source_rate_support_GetSlowestRate
,
1126 media_source_rate_support_GetFastestRate
,
1127 media_source_rate_support_IsRateSupported
,
1130 static HRESULT WINAPI
media_source_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
1132 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1133 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
1136 static ULONG WINAPI
media_source_rate_control_AddRef(IMFRateControl
*iface
)
1138 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1139 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1142 static ULONG WINAPI
media_source_rate_control_Release(IMFRateControl
*iface
)
1144 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1145 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
1148 static HRESULT WINAPI
media_source_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
1150 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1153 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
1156 return MF_E_REVERSE_UNSUPPORTED
;
1159 return MF_E_THINNING_UNSUPPORTED
;
1161 if (FAILED(hr
= IMFRateSupport_IsRateSupported(&source
->IMFRateSupport_iface
, thin
, rate
, NULL
)))
1164 EnterCriticalSection(&source
->cs
);
1165 source
->rate
= rate
;
1166 LeaveCriticalSection(&source
->cs
);
1168 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourceRateChanged
, &GUID_NULL
, S_OK
, NULL
);
1171 static HRESULT WINAPI
media_source_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
1173 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1175 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
1180 EnterCriticalSection(&source
->cs
);
1181 *rate
= source
->rate
;
1182 LeaveCriticalSection(&source
->cs
);
1187 static const IMFRateControlVtbl media_source_rate_control_vtbl
=
1189 media_source_rate_control_QueryInterface
,
1190 media_source_rate_control_AddRef
,
1191 media_source_rate_control_Release
,
1192 media_source_rate_control_SetRate
,
1193 media_source_rate_control_GetRate
,
1196 static HRESULT WINAPI
media_source_QueryInterface(IMFMediaSource
*iface
, REFIID riid
, void **out
)
1198 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1200 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1202 if (IsEqualIID(riid
, &IID_IMFMediaSource
) ||
1203 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1204 IsEqualIID(riid
, &IID_IUnknown
))
1206 *out
= &source
->IMFMediaSource_iface
;
1208 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1210 *out
= &source
->IMFGetService_iface
;
1214 FIXME("%s, %p.\n", debugstr_guid(riid
), out
);
1216 return E_NOINTERFACE
;
1219 IUnknown_AddRef((IUnknown
*)*out
);
1223 static ULONG WINAPI
media_source_AddRef(IMFMediaSource
*iface
)
1225 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1226 ULONG ref
= InterlockedIncrement(&source
->ref
);
1228 TRACE("%p, refcount %lu.\n", iface
, ref
);
1233 static ULONG WINAPI
media_source_Release(IMFMediaSource
*iface
)
1235 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1236 ULONG ref
= InterlockedDecrement(&source
->ref
);
1238 TRACE("%p, refcount %lu.\n", iface
, ref
);
1242 IMFMediaSource_Shutdown(iface
);
1243 IMFMediaEventQueue_Release(source
->event_queue
);
1244 IMFByteStream_Release(source
->byte_stream
);
1245 wg_parser_destroy(source
->wg_parser
);
1246 source
->cs
.DebugInfo
->Spare
[0] = 0;
1247 DeleteCriticalSection(&source
->cs
);
1254 static HRESULT WINAPI
media_source_GetEvent(IMFMediaSource
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1256 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1258 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
1260 return IMFMediaEventQueue_GetEvent(source
->event_queue
, flags
, event
);
1263 static HRESULT WINAPI
media_source_BeginGetEvent(IMFMediaSource
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1265 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1267 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1269 return IMFMediaEventQueue_BeginGetEvent(source
->event_queue
, callback
, state
);
1272 static HRESULT WINAPI
media_source_EndGetEvent(IMFMediaSource
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1274 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1276 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1278 return IMFMediaEventQueue_EndGetEvent(source
->event_queue
, result
, event
);
1281 static HRESULT WINAPI
media_source_QueueEvent(IMFMediaSource
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1282 HRESULT hr
, const PROPVARIANT
*value
)
1284 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1286 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1288 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, event_type
, ext_type
, hr
, value
);
1291 static HRESULT WINAPI
media_source_GetCharacteristics(IMFMediaSource
*iface
, DWORD
*characteristics
)
1293 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1296 TRACE("%p, %p.\n", iface
, characteristics
);
1298 EnterCriticalSection(&source
->cs
);
1300 if (source
->state
== SOURCE_SHUTDOWN
)
1303 *characteristics
= MFMEDIASOURCE_CAN_SEEK
| MFMEDIASOURCE_CAN_PAUSE
;
1305 LeaveCriticalSection(&source
->cs
);
1310 static HRESULT WINAPI
media_source_CreatePresentationDescriptor(IMFMediaSource
*iface
, IMFPresentationDescriptor
**descriptor
)
1312 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1316 TRACE("%p, %p.\n", iface
, descriptor
);
1318 EnterCriticalSection(&source
->cs
);
1320 if (source
->state
== SOURCE_SHUTDOWN
)
1322 else if (SUCCEEDED(hr
= MFCreatePresentationDescriptor(source
->stream_count
, source
->descriptors
, descriptor
)))
1324 if (FAILED(hr
= IMFPresentationDescriptor_SetUINT64(*descriptor
, &MF_PD_DURATION
, source
->duration
)))
1325 WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr
);
1327 for (i
= 0; i
< source
->stream_count
; ++i
)
1329 if (FAILED(hr
= IMFPresentationDescriptor_SelectStream(*descriptor
, i
)))
1330 WARN("Failed to select stream %u, hr %#lx\n", i
, hr
);
1336 LeaveCriticalSection(&source
->cs
);
1341 static HRESULT WINAPI
media_source_Start(IMFMediaSource
*iface
, IMFPresentationDescriptor
*descriptor
,
1342 const GUID
*time_format
, const PROPVARIANT
*position
)
1344 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1348 TRACE("%p, %p, %p, %p.\n", iface
, descriptor
, time_format
, position
);
1350 EnterCriticalSection(&source
->cs
);
1352 if (source
->state
== SOURCE_SHUTDOWN
)
1354 else if (!(IsEqualIID(time_format
, &GUID_NULL
)))
1355 hr
= MF_E_UNSUPPORTED_TIME_FORMAT
;
1356 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_START
, &op
)))
1358 struct source_async_command
*command
= impl_from_async_command_IUnknown(op
);
1359 command
->u
.start
.descriptor
= descriptor
;
1360 command
->u
.start
.format
= *time_format
;
1361 PropVariantCopy(&command
->u
.start
.position
, position
);
1363 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
1364 IUnknown_Release(op
);
1367 LeaveCriticalSection(&source
->cs
);
1372 static HRESULT WINAPI
media_source_Stop(IMFMediaSource
*iface
)
1374 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1378 TRACE("%p.\n", iface
);
1380 EnterCriticalSection(&source
->cs
);
1382 if (source
->state
== SOURCE_SHUTDOWN
)
1384 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_STOP
, &op
)))
1386 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
1387 IUnknown_Release(op
);
1390 LeaveCriticalSection(&source
->cs
);
1395 static HRESULT WINAPI
media_source_Pause(IMFMediaSource
*iface
)
1397 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1401 TRACE("%p.\n", iface
);
1403 EnterCriticalSection(&source
->cs
);
1405 if (source
->state
== SOURCE_SHUTDOWN
)
1407 else if (source
->state
!= SOURCE_RUNNING
)
1408 hr
= MF_E_INVALID_STATE_TRANSITION
;
1409 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_PAUSE
, &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_Shutdown(IMFMediaSource
*iface
)
1422 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1424 TRACE("%p.\n", iface
);
1426 EnterCriticalSection(&source
->cs
);
1428 if (source
->state
== SOURCE_SHUTDOWN
)
1430 LeaveCriticalSection(&source
->cs
);
1431 return MF_E_SHUTDOWN
;
1434 source
->state
= SOURCE_SHUTDOWN
;
1436 wg_parser_disconnect(source
->wg_parser
);
1438 source
->read_thread_shutdown
= true;
1439 WaitForSingleObject(source
->read_thread
, INFINITE
);
1440 CloseHandle(source
->read_thread
);
1442 IMFMediaEventQueue_Shutdown(source
->event_queue
);
1443 IMFByteStream_Close(source
->byte_stream
);
1445 while (source
->stream_count
--)
1447 struct media_stream
*stream
= source
->streams
[source
->stream_count
];
1448 IMFStreamDescriptor_Release(source
->descriptors
[source
->stream_count
]);
1449 IMFMediaEventQueue_Shutdown(stream
->event_queue
);
1450 IMFMediaStream_Release(&stream
->IMFMediaStream_iface
);
1452 free(source
->descriptors
);
1453 free(source
->streams
);
1455 MFUnlockWorkQueue(source
->async_commands_queue
);
1457 LeaveCriticalSection(&source
->cs
);
1462 static const IMFMediaSourceVtbl IMFMediaSource_vtbl
=
1464 media_source_QueryInterface
,
1465 media_source_AddRef
,
1466 media_source_Release
,
1467 media_source_GetEvent
,
1468 media_source_BeginGetEvent
,
1469 media_source_EndGetEvent
,
1470 media_source_QueueEvent
,
1471 media_source_GetCharacteristics
,
1472 media_source_CreatePresentationDescriptor
,
1476 media_source_Shutdown
,
1479 static HRESULT
media_source_constructor(IMFByteStream
*bytestream
, struct media_source
**out_media_source
)
1481 unsigned int stream_count
= UINT_MAX
;
1482 struct media_source
*object
;
1483 struct wg_parser
*parser
;
1484 DWORD bytestream_caps
;
1489 if (FAILED(hr
= IMFByteStream_GetCapabilities(bytestream
, &bytestream_caps
)))
1492 if (!(bytestream_caps
& MFBYTESTREAM_IS_SEEKABLE
))
1494 FIXME("Non-seekable bytestreams not supported.\n");
1495 return MF_E_BYTESTREAM_NOT_SEEKABLE
;
1498 if (FAILED(hr
= IMFByteStream_GetLength(bytestream
, &file_size
)))
1500 FIXME("Failed to get byte stream length, hr %#lx.\n", hr
);
1504 if (!(object
= calloc(1, sizeof(*object
))))
1505 return E_OUTOFMEMORY
;
1507 object
->IMFMediaSource_iface
.lpVtbl
= &IMFMediaSource_vtbl
;
1508 object
->IMFGetService_iface
.lpVtbl
= &media_source_get_service_vtbl
;
1509 object
->IMFRateSupport_iface
.lpVtbl
= &media_source_rate_support_vtbl
;
1510 object
->IMFRateControl_iface
.lpVtbl
= &media_source_rate_control_vtbl
;
1511 object
->async_commands_callback
.lpVtbl
= &source_async_commands_callback_vtbl
;
1513 object
->byte_stream
= bytestream
;
1514 IMFByteStream_AddRef(bytestream
);
1515 object
->rate
= 1.0f
;
1516 InitializeCriticalSection(&object
->cs
);
1517 object
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": cs");
1519 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1522 if (FAILED(hr
= MFAllocateWorkQueue(&object
->async_commands_queue
)))
1525 /* In Media Foundation, sources may read from any media source stream
1526 * without fear of blocking due to buffering limits on another. Trailmakers,
1527 * a Unity3D Engine game, only reads one sample from the audio stream (and
1528 * never deselects it). Remove buffering limits from decodebin in order to
1529 * account for this. Note that this does leak memory, but the same memory
1530 * leak occurs with native. */
1531 if (!(parser
= wg_parser_create(WG_PARSER_DECODEBIN
, true)))
1536 object
->wg_parser
= parser
;
1538 object
->read_thread
= CreateThread(NULL
, 0, read_thread
, object
, 0, NULL
);
1540 object
->state
= SOURCE_OPENING
;
1542 if (FAILED(hr
= wg_parser_connect(parser
, file_size
)))
1545 stream_count
= wg_parser_get_stream_count(parser
);
1547 if (!(object
->descriptors
= calloc(stream_count
, sizeof(*object
->descriptors
)))
1548 || !(object
->streams
= calloc(stream_count
, sizeof(*object
->streams
))))
1550 free(object
->descriptors
);
1555 for (i
= 0; i
< stream_count
; ++i
)
1557 struct media_stream
*stream
;
1559 if (FAILED(hr
= media_stream_create(&object
->IMFMediaSource_iface
, i
, &stream
)))
1561 if (FAILED(hr
= media_stream_init_desc(stream
)))
1563 ERR("Failed to finish initialization of media stream %p, hr %#lx.\n", stream
, hr
);
1564 IMFMediaSource_Release(stream
->media_source
);
1565 IMFMediaEventQueue_Release(stream
->event_queue
);
1570 object
->duration
= max(object
->duration
, wg_parser_stream_get_duration(stream
->wg_stream
));
1571 IMFStreamDescriptor_AddRef(stream
->descriptor
);
1572 object
->descriptors
[i
] = stream
->descriptor
;
1573 object
->streams
[i
] = stream
;
1574 object
->stream_count
++;
1577 /* init presentation descriptor */
1579 for (i
= 0; i
< object
->stream_count
; i
++)
1583 enum wg_parser_tag tag
;
1584 const GUID
*mf_attr
;
1588 {WG_PARSER_TAG_LANGUAGE
, &MF_SD_LANGUAGE
},
1589 {WG_PARSER_TAG_NAME
, &MF_SD_STREAM_NAME
},
1596 for (j
= 0; j
< ARRAY_SIZE(tags
); ++j
)
1598 if (!(str
= wg_parser_stream_get_tag(object
->streams
[i
]->wg_stream
, tags
[j
].tag
)))
1600 if (!(len
= MultiByteToWideChar(CP_UTF8
, 0, str
, -1, NULL
, 0)))
1605 strW
= malloc(len
* sizeof(*strW
));
1606 if (MultiByteToWideChar(CP_UTF8
, 0, str
, -1, strW
, len
))
1607 IMFStreamDescriptor_SetString(object
->descriptors
[i
], tags
[j
].mf_attr
, strW
);
1613 object
->state
= SOURCE_STOPPED
;
1615 *out_media_source
= object
;
1619 WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr
);
1621 while (object
->streams
&& object
->stream_count
--)
1623 struct media_stream
*stream
= object
->streams
[object
->stream_count
];
1624 IMFStreamDescriptor_Release(object
->descriptors
[object
->stream_count
]);
1625 IMFMediaStream_Release(&stream
->IMFMediaStream_iface
);
1627 free(object
->descriptors
);
1628 free(object
->streams
);
1630 if (stream_count
!= UINT_MAX
)
1631 wg_parser_disconnect(object
->wg_parser
);
1632 if (object
->read_thread
)
1634 object
->read_thread_shutdown
= true;
1635 WaitForSingleObject(object
->read_thread
, INFINITE
);
1636 CloseHandle(object
->read_thread
);
1638 if (object
->wg_parser
)
1639 wg_parser_destroy(object
->wg_parser
);
1640 if (object
->async_commands_queue
)
1641 MFUnlockWorkQueue(object
->async_commands_queue
);
1642 if (object
->event_queue
)
1643 IMFMediaEventQueue_Release(object
->event_queue
);
1644 IMFByteStream_Release(object
->byte_stream
);
1649 struct winegstreamer_stream_handler_result
1652 IMFAsyncResult
*result
;
1653 MF_OBJECT_TYPE obj_type
;
1657 struct winegstreamer_stream_handler
1659 IMFByteStreamHandler IMFByteStreamHandler_iface
;
1660 IMFAsyncCallback IMFAsyncCallback_iface
;
1662 struct list results
;
1663 CRITICAL_SECTION cs
;
1666 static struct winegstreamer_stream_handler
*impl_from_IMFByteStreamHandler(IMFByteStreamHandler
*iface
)
1668 return CONTAINING_RECORD(iface
, struct winegstreamer_stream_handler
, IMFByteStreamHandler_iface
);
1671 static struct winegstreamer_stream_handler
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
1673 return CONTAINING_RECORD(iface
, struct winegstreamer_stream_handler
, IMFAsyncCallback_iface
);
1676 static HRESULT WINAPI
winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler
*iface
, REFIID riid
, void **obj
)
1678 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1680 if (IsEqualIID(riid
, &IID_IMFByteStreamHandler
) ||
1681 IsEqualIID(riid
, &IID_IUnknown
))
1684 IMFByteStreamHandler_AddRef(iface
);
1688 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1690 return E_NOINTERFACE
;
1693 static ULONG WINAPI
winegstreamer_stream_handler_AddRef(IMFByteStreamHandler
*iface
)
1695 struct winegstreamer_stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1696 ULONG refcount
= InterlockedIncrement(&handler
->refcount
);
1698 TRACE("%p, refcount %lu.\n", handler
, refcount
);
1703 static ULONG WINAPI
winegstreamer_stream_handler_Release(IMFByteStreamHandler
*iface
)
1705 struct winegstreamer_stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1706 ULONG refcount
= InterlockedDecrement(&handler
->refcount
);
1707 struct winegstreamer_stream_handler_result
*result
, *next
;
1709 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1713 LIST_FOR_EACH_ENTRY_SAFE(result
, next
, &handler
->results
, struct winegstreamer_stream_handler_result
, entry
)
1715 list_remove(&result
->entry
);
1716 IMFAsyncResult_Release(result
->result
);
1718 IUnknown_Release(result
->object
);
1721 DeleteCriticalSection(&handler
->cs
);
1728 struct create_object_context
1730 IUnknown IUnknown_iface
;
1733 IPropertyStore
*props
;
1734 IMFByteStream
*stream
;
1739 static struct create_object_context
*impl_from_IUnknown(IUnknown
*iface
)
1741 return CONTAINING_RECORD(iface
, struct create_object_context
, IUnknown_iface
);
1744 static HRESULT WINAPI
create_object_context_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
1746 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1748 if (IsEqualIID(riid
, &IID_IUnknown
))
1751 IUnknown_AddRef(iface
);
1755 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1757 return E_NOINTERFACE
;
1760 static ULONG WINAPI
create_object_context_AddRef(IUnknown
*iface
)
1762 struct create_object_context
*context
= impl_from_IUnknown(iface
);
1763 ULONG refcount
= InterlockedIncrement(&context
->refcount
);
1765 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1770 static ULONG WINAPI
create_object_context_Release(IUnknown
*iface
)
1772 struct create_object_context
*context
= impl_from_IUnknown(iface
);
1773 ULONG refcount
= InterlockedDecrement(&context
->refcount
);
1775 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1780 IPropertyStore_Release(context
->props
);
1781 if (context
->stream
)
1782 IMFByteStream_Release(context
->stream
);
1790 static const IUnknownVtbl create_object_context_vtbl
=
1792 create_object_context_QueryInterface
,
1793 create_object_context_AddRef
,
1794 create_object_context_Release
,
1797 static HRESULT WINAPI
winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler
*iface
, IMFByteStream
*stream
, const WCHAR
*url
, DWORD flags
,
1798 IPropertyStore
*props
, IUnknown
**cancel_cookie
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1800 struct winegstreamer_stream_handler
*this = impl_from_IMFByteStreamHandler(iface
);
1801 struct create_object_context
*context
;
1802 IMFAsyncResult
*caller
, *item
;
1805 TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface
, debugstr_w(url
), flags
, props
, cancel_cookie
, callback
, state
);
1808 *cancel_cookie
= NULL
;
1810 if (FAILED(hr
= MFCreateAsyncResult(NULL
, callback
, state
, &caller
)))
1813 if (!(context
= calloc(1, sizeof(*context
))))
1815 IMFAsyncResult_Release(caller
);
1816 return E_OUTOFMEMORY
;
1819 context
->IUnknown_iface
.lpVtbl
= &create_object_context_vtbl
;
1820 context
->refcount
= 1;
1821 context
->props
= props
;
1823 IPropertyStore_AddRef(context
->props
);
1824 context
->flags
= flags
;
1825 context
->stream
= stream
;
1826 if (context
->stream
)
1827 IMFByteStream_AddRef(context
->stream
);
1829 context
->url
= wcsdup(url
);
1830 if (!context
->stream
)
1832 IMFAsyncResult_Release(caller
);
1833 IUnknown_Release(&context
->IUnknown_iface
);
1834 return E_OUTOFMEMORY
;
1837 hr
= MFCreateAsyncResult(&context
->IUnknown_iface
, &this->IMFAsyncCallback_iface
, (IUnknown
*)caller
, &item
);
1838 IUnknown_Release(&context
->IUnknown_iface
);
1841 if (SUCCEEDED(hr
= MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO
, item
)))
1845 *cancel_cookie
= (IUnknown
*)caller
;
1846 IUnknown_AddRef(*cancel_cookie
);
1850 IMFAsyncResult_Release(item
);
1852 IMFAsyncResult_Release(caller
);
1857 static HRESULT WINAPI
winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler
*iface
, IMFAsyncResult
*result
,
1858 MF_OBJECT_TYPE
*obj_type
, IUnknown
**object
)
1860 struct winegstreamer_stream_handler
*this = impl_from_IMFByteStreamHandler(iface
);
1861 struct winegstreamer_stream_handler_result
*found
= NULL
, *cur
;
1864 TRACE("%p, %p, %p, %p.\n", iface
, result
, obj_type
, object
);
1866 EnterCriticalSection(&this->cs
);
1868 LIST_FOR_EACH_ENTRY(cur
, &this->results
, struct winegstreamer_stream_handler_result
, entry
)
1870 if (result
== cur
->result
)
1872 list_remove(&cur
->entry
);
1878 LeaveCriticalSection(&this->cs
);
1882 *obj_type
= found
->obj_type
;
1883 *object
= found
->object
;
1884 hr
= IMFAsyncResult_GetStatus(found
->result
);
1885 IMFAsyncResult_Release(found
->result
);
1890 *obj_type
= MF_OBJECT_INVALID
;
1892 hr
= MF_E_UNEXPECTED
;
1898 static HRESULT WINAPI
winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler
*iface
, IUnknown
*cancel_cookie
)
1900 struct winegstreamer_stream_handler
*this = impl_from_IMFByteStreamHandler(iface
);
1901 struct winegstreamer_stream_handler_result
*found
= NULL
, *cur
;
1903 TRACE("%p, %p.\n", iface
, cancel_cookie
);
1905 EnterCriticalSection(&this->cs
);
1907 LIST_FOR_EACH_ENTRY(cur
, &this->results
, struct winegstreamer_stream_handler_result
, entry
)
1909 if (cancel_cookie
== (IUnknown
*)cur
->result
)
1911 list_remove(&cur
->entry
);
1917 LeaveCriticalSection(&this->cs
);
1921 IMFAsyncResult_Release(found
->result
);
1923 IUnknown_Release(found
->object
);
1927 return found
? S_OK
: MF_E_UNEXPECTED
;
1930 static HRESULT WINAPI
winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler
*iface
, QWORD
*bytes
)
1932 FIXME("stub (%p %p)\n", iface
, bytes
);
1936 static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl
=
1938 winegstreamer_stream_handler_QueryInterface
,
1939 winegstreamer_stream_handler_AddRef
,
1940 winegstreamer_stream_handler_Release
,
1941 winegstreamer_stream_handler_BeginCreateObject
,
1942 winegstreamer_stream_handler_EndCreateObject
,
1943 winegstreamer_stream_handler_CancelObjectCreation
,
1944 winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution
,
1947 static HRESULT WINAPI
winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1949 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1950 IsEqualIID(riid
, &IID_IUnknown
))
1953 IMFAsyncCallback_AddRef(iface
);
1957 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1959 return E_NOINTERFACE
;
1962 static ULONG WINAPI
winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback
*iface
)
1964 struct winegstreamer_stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1965 return IMFByteStreamHandler_AddRef(&handler
->IMFByteStreamHandler_iface
);
1968 static ULONG WINAPI
winegstreamer_stream_handler_callback_Release(IMFAsyncCallback
*iface
)
1970 struct winegstreamer_stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1971 return IMFByteStreamHandler_Release(&handler
->IMFByteStreamHandler_iface
);
1974 static HRESULT WINAPI
winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1979 static HRESULT
winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler
*This
, WCHAR
*url
, IMFByteStream
*stream
, DWORD flags
,
1980 IPropertyStore
*props
, IUnknown
**out_object
, MF_OBJECT_TYPE
*out_obj_type
)
1982 TRACE("%p, %s, %p, %#lx, %p, %p, %p.\n", This
, debugstr_w(url
), stream
, flags
, props
, out_object
, out_obj_type
);
1984 if (flags
& MF_RESOLUTION_MEDIASOURCE
)
1987 struct media_source
*new_source
;
1989 if (FAILED(hr
= media_source_constructor(stream
, &new_source
)))
1992 TRACE("->(%p)\n", new_source
);
1994 *out_object
= (IUnknown
*)&new_source
->IMFMediaSource_iface
;
1995 *out_obj_type
= MF_OBJECT_MEDIASOURCE
;
2001 FIXME("Unhandled flags %#lx.\n", flags
);
2006 static HRESULT WINAPI
winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
2008 struct winegstreamer_stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
2009 struct winegstreamer_stream_handler_result
*handler_result
;
2010 MF_OBJECT_TYPE obj_type
= MF_OBJECT_INVALID
;
2011 IUnknown
*object
= NULL
, *context_object
;
2012 struct create_object_context
*context
;
2013 IMFAsyncResult
*caller
;
2016 caller
= (IMFAsyncResult
*)IMFAsyncResult_GetStateNoAddRef(result
);
2018 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &context_object
)))
2020 WARN("Expected context set for callee result.\n");
2024 context
= impl_from_IUnknown(context_object
);
2026 hr
= winegstreamer_stream_handler_create_object(handler
, context
->url
, context
->stream
, context
->flags
, context
->props
, &object
, &obj_type
);
2028 if ((handler_result
= malloc(sizeof(*handler_result
))))
2030 handler_result
->result
= caller
;
2031 IMFAsyncResult_AddRef(handler_result
->result
);
2032 handler_result
->obj_type
= obj_type
;
2033 handler_result
->object
= object
;
2035 EnterCriticalSection(&handler
->cs
);
2036 list_add_tail(&handler
->results
, &handler_result
->entry
);
2037 LeaveCriticalSection(&handler
->cs
);
2042 IUnknown_Release(object
);
2046 IUnknown_Release(&context
->IUnknown_iface
);
2048 IMFAsyncResult_SetStatus(caller
, hr
);
2049 MFInvokeCallback(caller
);
2054 static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl
=
2056 winegstreamer_stream_handler_callback_QueryInterface
,
2057 winegstreamer_stream_handler_callback_AddRef
,
2058 winegstreamer_stream_handler_callback_Release
,
2059 winegstreamer_stream_handler_callback_GetParameters
,
2060 winegstreamer_stream_handler_callback_Invoke
,
2063 HRESULT
winegstreamer_stream_handler_create(REFIID riid
, void **obj
)
2065 struct winegstreamer_stream_handler
*this;
2068 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
2070 if (!(this = calloc(1, sizeof(*this))))
2071 return E_OUTOFMEMORY
;
2073 list_init(&this->results
);
2074 InitializeCriticalSection(&this->cs
);
2076 this->IMFByteStreamHandler_iface
.lpVtbl
= &winegstreamer_stream_handler_vtbl
;
2077 this->IMFAsyncCallback_iface
.lpVtbl
= &winegstreamer_stream_handler_callback_vtbl
;
2080 hr
= IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface
, riid
, obj
);
2081 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface
);