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 IUnknown IUnknown_iface
;
35 IMFAsyncResult
*result
;
36 IMFByteStream
*stream
;
41 static struct object_context
*impl_from_IUnknown(IUnknown
*iface
)
43 return CONTAINING_RECORD(iface
, struct object_context
, IUnknown_iface
);
46 static HRESULT WINAPI
object_context_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
48 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
50 if (IsEqualIID(riid
, &IID_IUnknown
))
53 IUnknown_AddRef(iface
);
57 WARN("Unsupported %s.\n", debugstr_guid(riid
));
62 static ULONG WINAPI
object_context_AddRef(IUnknown
*iface
)
64 struct object_context
*context
= impl_from_IUnknown(iface
);
65 ULONG refcount
= InterlockedIncrement(&context
->refcount
);
67 TRACE("%p, refcount %lu.\n", iface
, refcount
);
72 static ULONG WINAPI
object_context_Release(IUnknown
*iface
)
74 struct object_context
*context
= impl_from_IUnknown(iface
);
75 ULONG refcount
= InterlockedDecrement(&context
->refcount
);
77 TRACE("%p, refcount %lu.\n", iface
, refcount
);
81 IMFAsyncResult_Release(context
->result
);
82 IMFByteStream_Release(context
->stream
);
90 static const IUnknownVtbl object_context_vtbl
=
92 object_context_QueryInterface
,
93 object_context_AddRef
,
94 object_context_Release
,
97 static HRESULT
object_context_create(DWORD flags
, IMFByteStream
*stream
, const WCHAR
*url
,
98 QWORD file_size
, IMFAsyncResult
*result
, IUnknown
**out
)
100 WCHAR
*tmp_url
= url
? wcsdup(url
) : NULL
;
101 struct object_context
*context
;
103 if (!(context
= calloc(1, sizeof(*context
))))
106 return E_OUTOFMEMORY
;
109 context
->IUnknown_iface
.lpVtbl
= &object_context_vtbl
;
110 context
->refcount
= 1;
111 context
->stream
= stream
;
112 IMFByteStream_AddRef(context
->stream
);
113 context
->file_size
= file_size
;
114 context
->url
= tmp_url
;
115 context
->result
= result
;
116 IMFAsyncResult_AddRef(context
->result
);
118 *out
= &context
->IUnknown_iface
;
124 IMFMediaStream IMFMediaStream_iface
;
127 IMFMediaSource
*media_source
;
128 IMFMediaEventQueue
*event_queue
;
129 IMFStreamDescriptor
*descriptor
;
131 wg_parser_stream_t wg_stream
;
133 IUnknown
**token_queue
;
134 LONG token_queue_count
;
135 LONG token_queue_cap
;
147 SOURCE_ASYNC_REQUEST_SAMPLE
,
150 struct source_async_command
152 IUnknown IUnknown_iface
;
154 enum source_async_op op
;
159 IMFPresentationDescriptor
*descriptor
;
161 PROPVARIANT position
;
165 struct media_stream
*stream
;
173 IMFMediaSource IMFMediaSource_iface
;
174 IMFGetService IMFGetService_iface
;
175 IMFRateSupport IMFRateSupport_iface
;
176 IMFRateControl IMFRateControl_iface
;
177 IMFAsyncCallback async_commands_callback
;
179 DWORD async_commands_queue
;
180 IMFMediaEventQueue
*event_queue
;
181 IMFByteStream
*byte_stream
;
186 wg_parser_t wg_parser
;
189 IMFStreamDescriptor
**descriptors
;
190 struct media_stream
**streams
;
204 bool read_thread_shutdown
;
207 static inline struct media_stream
*impl_from_IMFMediaStream(IMFMediaStream
*iface
)
209 return CONTAINING_RECORD(iface
, struct media_stream
, IMFMediaStream_iface
);
212 static inline struct media_source
*impl_from_IMFMediaSource(IMFMediaSource
*iface
)
214 return CONTAINING_RECORD(iface
, struct media_source
, IMFMediaSource_iface
);
217 static inline struct media_source
*impl_from_IMFGetService(IMFGetService
*iface
)
219 return CONTAINING_RECORD(iface
, struct media_source
, IMFGetService_iface
);
222 static inline struct media_source
*impl_from_IMFRateSupport(IMFRateSupport
*iface
)
224 return CONTAINING_RECORD(iface
, struct media_source
, IMFRateSupport_iface
);
227 static inline struct media_source
*impl_from_IMFRateControl(IMFRateControl
*iface
)
229 return CONTAINING_RECORD(iface
, struct media_source
, IMFRateControl_iface
);
232 static inline struct media_source
*impl_from_async_commands_callback_IMFAsyncCallback(IMFAsyncCallback
*iface
)
234 return CONTAINING_RECORD(iface
, struct media_source
, async_commands_callback
);
237 static inline struct source_async_command
*impl_from_async_command_IUnknown(IUnknown
*iface
)
239 return CONTAINING_RECORD(iface
, struct source_async_command
, IUnknown_iface
);
242 static HRESULT WINAPI
source_async_command_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
244 if (IsEqualIID(riid
, &IID_IUnknown
))
247 IUnknown_AddRef(iface
);
251 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
253 return E_NOINTERFACE
;
256 static ULONG WINAPI
source_async_command_AddRef(IUnknown
*iface
)
258 struct source_async_command
*command
= impl_from_async_command_IUnknown(iface
);
259 return InterlockedIncrement(&command
->refcount
);
262 static ULONG WINAPI
source_async_command_Release(IUnknown
*iface
)
264 struct source_async_command
*command
= impl_from_async_command_IUnknown(iface
);
265 ULONG refcount
= InterlockedDecrement(&command
->refcount
);
269 if (command
->op
== SOURCE_ASYNC_START
)
271 IMFPresentationDescriptor_Release(command
->u
.start
.descriptor
);
272 PropVariantClear(&command
->u
.start
.position
);
274 else if (command
->op
== SOURCE_ASYNC_REQUEST_SAMPLE
)
276 if (command
->u
.request_sample
.token
)
277 IUnknown_Release(command
->u
.request_sample
.token
);
285 static const IUnknownVtbl source_async_command_vtbl
=
287 source_async_command_QueryInterface
,
288 source_async_command_AddRef
,
289 source_async_command_Release
,
292 static HRESULT
source_create_async_op(enum source_async_op op
, IUnknown
**out
)
294 struct source_async_command
*command
;
296 if (!(command
= calloc(1, sizeof(*command
))))
297 return E_OUTOFMEMORY
;
299 command
->IUnknown_iface
.lpVtbl
= &source_async_command_vtbl
;
300 command
->refcount
= 1;
303 *out
= &command
->IUnknown_iface
;
307 static HRESULT WINAPI
callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
309 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
311 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
312 IsEqualIID(riid
, &IID_IUnknown
))
315 IMFAsyncCallback_AddRef(iface
);
319 WARN("Unsupported %s.\n", debugstr_guid(riid
));
321 return E_NOINTERFACE
;
324 static HRESULT WINAPI
callback_GetParameters(IMFAsyncCallback
*iface
,
325 DWORD
*flags
, DWORD
*queue
)
330 static ULONG WINAPI
source_async_commands_callback_AddRef(IMFAsyncCallback
*iface
)
332 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
333 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
336 static ULONG WINAPI
source_async_commands_callback_Release(IMFAsyncCallback
*iface
)
338 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
339 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
342 static HRESULT
stream_descriptor_get_media_type(IMFStreamDescriptor
*descriptor
, IMFMediaType
**media_type
)
344 IMFMediaTypeHandler
*handler
;
347 if (FAILED(hr
= IMFStreamDescriptor_GetMediaTypeHandler(descriptor
, &handler
)))
349 hr
= IMFMediaTypeHandler_GetCurrentMediaType(handler
, media_type
);
350 IMFMediaTypeHandler_Release(handler
);
355 static HRESULT
wg_format_from_stream_descriptor(IMFStreamDescriptor
*descriptor
, struct wg_format
*format
)
357 IMFMediaType
*media_type
;
360 if (FAILED(hr
= stream_descriptor_get_media_type(descriptor
, &media_type
)))
362 mf_media_type_to_wg_format(media_type
, format
);
363 IMFMediaType_Release(media_type
);
368 static HRESULT
stream_descriptor_set_tag(IMFStreamDescriptor
*descriptor
, wg_parser_stream_t stream
,
369 const GUID
*attr
, enum wg_parser_tag tag
)
376 if (!(str
= wg_parser_stream_get_tag(stream
, tag
))
377 || !(len
= MultiByteToWideChar(CP_UTF8
, 0, str
, -1, NULL
, 0)))
379 else if (!(strW
= malloc(len
* sizeof(*strW
))))
383 if (MultiByteToWideChar(CP_UTF8
, 0, str
, -1, strW
, len
))
384 hr
= IMFStreamDescriptor_SetString(descriptor
, attr
, strW
);
394 static HRESULT
init_video_media_types(struct wg_format
*format
, IMFMediaType
*types
[6], DWORD
*types_count
)
396 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
397 * YUV color space, and it's generally much less expensive for
398 * videoconvert to do YUV -> YUV transformations. */
399 static const enum wg_video_format video_formats
[] =
401 WG_VIDEO_FORMAT_NV12
,
402 WG_VIDEO_FORMAT_YV12
,
403 WG_VIDEO_FORMAT_YUY2
,
404 WG_VIDEO_FORMAT_I420
,
406 UINT count
= *types_count
, i
;
410 if (FAILED(hr
= IMFMediaType_GetGUID(types
[0], &MF_MT_SUBTYPE
, &base_subtype
)))
413 for (i
= 0; i
< ARRAY_SIZE(video_formats
); ++i
)
415 struct wg_format new_format
= *format
;
416 IMFMediaType
*new_type
;
418 new_format
.u
.video
.format
= video_formats
[i
];
420 if (!(new_type
= mf_media_type_from_wg_format(&new_format
)))
425 types
[count
++] = new_type
;
427 if (video_formats
[i
] == WG_VIDEO_FORMAT_I420
)
429 IMFMediaType
*iyuv_type
;
431 if (FAILED(hr
= MFCreateMediaType(&iyuv_type
)))
433 if (FAILED(hr
= IMFMediaType_CopyAllItems(new_type
, (IMFAttributes
*)iyuv_type
)))
435 if (FAILED(hr
= IMFMediaType_SetGUID(iyuv_type
, &MF_MT_SUBTYPE
, &MFVideoFormat_IYUV
)))
437 types
[count
++] = iyuv_type
;
442 *types_count
= count
;
446 static HRESULT
init_audio_media_types(struct wg_format
*format
, IMFMediaType
*types
[6], DWORD
*types_count
)
448 /* Expose at least one PCM and one floating point type for the
449 consumer to pick from. */
450 static const enum wg_audio_format audio_types
[] =
452 WG_AUDIO_FORMAT_S16LE
,
453 WG_AUDIO_FORMAT_F32LE
,
455 UINT count
= *types_count
, i
;
457 for (i
= 0; i
< ARRAY_SIZE(audio_types
); i
++)
459 struct wg_format new_format
= *format
;
460 if (new_format
.u
.audio
.format
== audio_types
[i
])
462 new_format
.u
.audio
.format
= audio_types
[i
];
463 if ((types
[count
] = mf_media_type_from_wg_format(&new_format
)))
467 *types_count
= count
;
471 static HRESULT
stream_descriptor_create(UINT32 id
, struct wg_format
*format
, IMFStreamDescriptor
**out
)
473 IMFStreamDescriptor
*descriptor
;
474 IMFMediaTypeHandler
*handler
;
475 IMFMediaType
*types
[6];
479 if (!(types
[0] = mf_media_type_from_wg_format(format
)))
480 return MF_E_INVALIDMEDIATYPE
;
483 if (format
->major_type
== WG_MAJOR_TYPE_VIDEO
)
485 if (FAILED(hr
= init_video_media_types(format
, types
, &count
)))
488 else if (format
->major_type
== WG_MAJOR_TYPE_AUDIO
)
490 if (FAILED(hr
= init_audio_media_types(format
, types
, &count
)))
494 assert(count
<= ARRAY_SIZE(types
));
496 if (FAILED(hr
= MFCreateStreamDescriptor(id
, count
, types
, &descriptor
)))
499 if (FAILED(hr
= IMFStreamDescriptor_GetMediaTypeHandler(descriptor
, &handler
)))
500 IMFStreamDescriptor_Release(descriptor
);
503 hr
= IMFMediaTypeHandler_SetCurrentMediaType(handler
, types
[0]);
504 IMFMediaTypeHandler_Release(handler
);
509 IMFMediaType_Release(types
[count
]);
510 *out
= SUCCEEDED(hr
) ? descriptor
: NULL
;
514 static BOOL
enqueue_token(struct media_stream
*stream
, IUnknown
*token
)
516 if (stream
->token_queue_count
== stream
->token_queue_cap
)
519 stream
->token_queue_cap
= stream
->token_queue_cap
* 2 + 1;
520 buf
= realloc(stream
->token_queue
, stream
->token_queue_cap
* sizeof(*buf
));
522 stream
->token_queue
= buf
;
525 stream
->token_queue_cap
= stream
->token_queue_count
;
529 stream
->token_queue
[stream
->token_queue_count
++] = token
;
533 static void flush_token_queue(struct media_stream
*stream
, BOOL send
)
535 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
538 for (i
= 0; i
< stream
->token_queue_count
; i
++)
545 if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE
, &op
)))
547 struct source_async_command
*command
= impl_from_async_command_IUnknown(op
);
548 command
->u
.request_sample
.stream
= stream
;
549 command
->u
.request_sample
.token
= stream
->token_queue
[i
];
551 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
552 IUnknown_Release(op
);
555 WARN("Could not enqueue sample request, hr %#lx\n", hr
);
557 else if (stream
->token_queue
[i
])
558 IUnknown_Release(stream
->token_queue
[i
]);
560 free(stream
->token_queue
);
561 stream
->token_queue
= NULL
;
562 stream
->token_queue_count
= 0;
563 stream
->token_queue_cap
= 0;
566 static HRESULT
media_stream_start(struct media_stream
*stream
, BOOL active
, BOOL seeking
, const PROPVARIANT
*position
)
568 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
569 struct wg_format format
;
572 TRACE("source %p, stream %p\n", source
, stream
);
574 if (FAILED(hr
= wg_format_from_stream_descriptor(stream
->descriptor
, &format
)))
575 WARN("Failed to get wg_format from stream descriptor, hr %#lx\n", hr
);
576 wg_parser_stream_enable(stream
->wg_stream
, &format
);
578 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamUnk(source
->event_queue
, active
? MEUpdatedStream
: MENewStream
,
579 &GUID_NULL
, S_OK
, (IUnknown
*)&stream
->IMFMediaStream_iface
)))
580 WARN("Failed to send source stream event, hr %#lx\n", hr
);
581 return IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, seeking
? MEStreamSeeked
: MEStreamStarted
,
582 &GUID_NULL
, S_OK
, position
);
585 static HRESULT
media_source_start(struct media_source
*source
, IMFPresentationDescriptor
*descriptor
,
586 GUID
*format
, PROPVARIANT
*position
)
588 BOOL starting
= source
->state
== SOURCE_STOPPED
, seek_message
= !starting
&& position
->vt
!= VT_EMPTY
;
589 IMFStreamDescriptor
**descriptors
;
593 TRACE("source %p, descriptor %p, format %s, position %s\n", source
, descriptor
,
594 debugstr_guid(format
), wine_dbgstr_variant((VARIANT
*)position
));
596 if (source
->state
== SOURCE_SHUTDOWN
)
597 return MF_E_SHUTDOWN
;
599 /* seek to beginning on stop->play */
600 if (source
->state
== SOURCE_STOPPED
&& position
->vt
== VT_EMPTY
)
602 position
->vt
= VT_I8
;
603 position
->hVal
.QuadPart
= 0;
606 if (!(descriptors
= calloc(source
->stream_count
, sizeof(*descriptors
))))
607 return E_OUTOFMEMORY
;
609 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorCount(descriptor
, &count
)))
610 WARN("Failed to get presentation descriptor stream count, hr %#lx\n", hr
);
612 for (i
= 0; i
< count
; i
++)
614 IMFStreamDescriptor
*stream_descriptor
;
618 if (FAILED(hr
= IMFPresentationDescriptor_GetStreamDescriptorByIndex(descriptor
, i
,
619 &selected
, &stream_descriptor
)))
620 WARN("Failed to get presentation stream descriptor, hr %#lx\n", hr
);
623 if (FAILED(hr
= IMFStreamDescriptor_GetStreamIdentifier(stream_descriptor
, &id
)))
624 WARN("Failed to get stream descriptor id, hr %#lx\n", hr
);
625 else if (id
>= source
->stream_count
)
626 WARN("Invalid stream descriptor id %lu, hr %#lx\n", id
, hr
);
628 IMFStreamDescriptor_AddRef((descriptors
[id
] = stream_descriptor
));
630 IMFStreamDescriptor_Release(stream_descriptor
);
634 for (i
= 0; i
< source
->stream_count
; i
++)
636 struct media_stream
*stream
= source
->streams
[i
];
637 BOOL was_active
= !starting
&& stream
->active
;
639 if (position
->vt
!= VT_EMPTY
)
642 if (!(stream
->active
= !!descriptors
[i
]))
643 wg_parser_stream_disable(stream
->wg_stream
);
646 if (FAILED(hr
= media_stream_start(stream
, was_active
, seek_message
, position
)))
647 WARN("Failed to start media stream, hr %#lx\n", hr
);
648 IMFStreamDescriptor_Release(descriptors
[i
]);
654 source
->state
= SOURCE_RUNNING
;
656 if (position
->vt
== VT_I8
)
657 wg_parser_stream_seek(source
->streams
[0]->wg_stream
, 1.0, position
->hVal
.QuadPart
, 0,
658 AM_SEEKING_AbsolutePositioning
, AM_SEEKING_NoPositioning
);
660 for (i
= 0; i
< source
->stream_count
; i
++)
661 flush_token_queue(source
->streams
[i
], position
->vt
== VT_EMPTY
);
663 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
,
664 seek_message
? MESourceSeeked
: MESourceStarted
, &GUID_NULL
, S_OK
, position
);
667 static HRESULT
media_source_pause(struct media_source
*source
)
672 TRACE("source %p\n", source
);
674 if (source
->state
== SOURCE_SHUTDOWN
)
675 return MF_E_SHUTDOWN
;
677 for (i
= 0; i
< source
->stream_count
; i
++)
679 struct media_stream
*stream
= source
->streams
[i
];
680 if (stream
->active
&& FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEStreamPaused
,
681 &GUID_NULL
, S_OK
, NULL
)))
682 WARN("Failed to queue MEStreamPaused event, hr %#lx\n", hr
);
685 source
->state
= SOURCE_PAUSED
;
686 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourcePaused
, &GUID_NULL
, S_OK
, NULL
);
689 static HRESULT
media_source_stop(struct media_source
*source
)
694 TRACE("source %p\n", source
);
696 if (source
->state
== SOURCE_SHUTDOWN
)
697 return MF_E_SHUTDOWN
;
699 for (i
= 0; i
< source
->stream_count
; i
++)
701 struct media_stream
*stream
= source
->streams
[i
];
702 if (stream
->active
&& FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEStreamStopped
,
703 &GUID_NULL
, S_OK
, NULL
)))
704 WARN("Failed to queue MEStreamStopped event, hr %#lx\n", hr
);
707 source
->state
= SOURCE_STOPPED
;
709 for (i
= 0; i
< source
->stream_count
; i
++)
710 flush_token_queue(source
->streams
[i
], FALSE
);
712 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourceStopped
, &GUID_NULL
, S_OK
, NULL
);
715 static HRESULT
media_stream_send_sample(struct media_stream
*stream
, const struct wg_parser_buffer
*wg_buffer
, IUnknown
*token
)
717 IMFSample
*sample
= NULL
;
718 IMFMediaBuffer
*buffer
;
722 if (FAILED(hr
= MFCreateMemoryBuffer(wg_buffer
->size
, &buffer
)))
724 if (FAILED(hr
= IMFMediaBuffer_SetCurrentLength(buffer
, wg_buffer
->size
)))
726 if (FAILED(hr
= IMFMediaBuffer_Lock(buffer
, &data
, NULL
, NULL
)))
729 if (!wg_parser_stream_copy_buffer(stream
->wg_stream
, data
, 0, wg_buffer
->size
))
731 wg_parser_stream_release_buffer(stream
->wg_stream
);
732 IMFMediaBuffer_Unlock(buffer
);
735 wg_parser_stream_release_buffer(stream
->wg_stream
);
737 if (FAILED(hr
= IMFMediaBuffer_Unlock(buffer
)))
740 if (FAILED(hr
= MFCreateSample(&sample
)))
742 if (FAILED(hr
= IMFSample_AddBuffer(sample
, buffer
)))
744 if (FAILED(hr
= IMFSample_SetSampleTime(sample
, wg_buffer
->pts
)))
746 if (FAILED(hr
= IMFSample_SetSampleDuration(sample
, wg_buffer
->duration
)))
748 if (token
&& FAILED(hr
= IMFSample_SetUnknown(sample
, &MFSampleExtension_Token
, token
)))
751 hr
= IMFMediaEventQueue_QueueEventParamUnk(stream
->event_queue
, MEMediaSample
,
752 &GUID_NULL
, S_OK
, (IUnknown
*)sample
);
756 IMFSample_Release(sample
);
757 IMFMediaBuffer_Release(buffer
);
761 static HRESULT
media_stream_send_eos(struct media_source
*source
, struct media_stream
*stream
)
763 PROPVARIANT empty
= {.vt
= VT_EMPTY
};
767 TRACE("source %p, stream %p\n", source
, stream
);
770 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, MEEndOfStream
, &GUID_NULL
, S_OK
, &empty
)))
771 WARN("Failed to queue MEEndOfStream event, hr %#lx\n", hr
);
773 for (i
= 0; i
< source
->stream_count
; i
++)
775 struct media_stream
*stream
= source
->streams
[i
];
776 if (stream
->active
&& !stream
->eos
)
780 if (FAILED(hr
= IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MEEndOfPresentation
, &GUID_NULL
, S_OK
, &empty
)))
781 WARN("Failed to queue MEEndOfPresentation event, hr %#lx\n", hr
);
785 static HRESULT
wait_on_sample(struct media_stream
*stream
, IUnknown
*token
)
787 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
788 struct wg_parser_buffer buffer
;
790 TRACE("%p, %p\n", stream
, token
);
792 if (wg_parser_stream_get_buffer(source
->wg_parser
, stream
->wg_stream
, &buffer
))
793 return media_stream_send_sample(stream
, &buffer
, token
);
795 return media_stream_send_eos(source
, stream
);
798 static HRESULT WINAPI
source_async_commands_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
800 struct media_source
*source
= impl_from_async_commands_callback_IMFAsyncCallback(iface
);
801 struct source_async_command
*command
;
805 if (FAILED(hr
= IMFAsyncResult_GetState(result
, &state
)))
808 EnterCriticalSection(&source
->cs
);
810 command
= impl_from_async_command_IUnknown(state
);
813 case SOURCE_ASYNC_START
:
815 IMFPresentationDescriptor
*descriptor
= command
->u
.start
.descriptor
;
816 GUID format
= command
->u
.start
.format
;
817 PROPVARIANT position
= command
->u
.start
.position
;
819 if (FAILED(hr
= media_source_start(source
, descriptor
, &format
, &position
)))
820 WARN("Failed to start source %p, hr %#lx\n", source
, hr
);
823 case SOURCE_ASYNC_PAUSE
:
824 if (FAILED(hr
= media_source_pause(source
)))
825 WARN("Failed to pause source %p, hr %#lx\n", source
, hr
);
827 case SOURCE_ASYNC_STOP
:
828 if (FAILED(hr
= media_source_stop(source
)))
829 WARN("Failed to stop source %p, hr %#lx\n", source
, hr
);
831 case SOURCE_ASYNC_REQUEST_SAMPLE
:
832 if (source
->state
== SOURCE_PAUSED
)
833 enqueue_token(command
->u
.request_sample
.stream
, command
->u
.request_sample
.token
);
834 else if (source
->state
== SOURCE_RUNNING
)
836 if (FAILED(hr
= wait_on_sample(command
->u
.request_sample
.stream
, command
->u
.request_sample
.token
)))
837 WARN("Failed to request sample, hr %#lx\n", hr
);
842 LeaveCriticalSection(&source
->cs
);
844 IUnknown_Release(state
);
849 static const IMFAsyncCallbackVtbl source_async_commands_callback_vtbl
=
851 callback_QueryInterface
,
852 source_async_commands_callback_AddRef
,
853 source_async_commands_callback_Release
,
854 callback_GetParameters
,
855 source_async_commands_Invoke
,
858 static DWORD CALLBACK
read_thread(void *arg
)
860 struct media_source
*source
= arg
;
861 IMFByteStream
*byte_stream
= source
->byte_stream
;
862 size_t buffer_size
= 4096;
866 if (!(data
= malloc(buffer_size
)))
869 IMFByteStream_GetLength(byte_stream
, &file_size
);
871 TRACE("Starting read thread for media source %p.\n", source
);
873 while (!source
->read_thread_shutdown
)
880 if (!wg_parser_get_next_read_offset(source
->wg_parser
, &offset
, &size
))
883 if (offset
>= file_size
)
885 else if (offset
+ size
>= file_size
)
886 size
= file_size
- offset
;
888 /* Some IMFByteStreams (including the standard file-based stream) return
889 * an error when reading past the file size. */
892 wg_parser_push_data(source
->wg_parser
, data
, 0);
896 if (!array_reserve(&data
, &buffer_size
, size
, 1))
904 if (SUCCEEDED(hr
= IMFByteStream_SetCurrentPosition(byte_stream
, offset
)))
905 hr
= IMFByteStream_Read(byte_stream
, data
, size
, &ret_size
);
907 ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size
, offset
, hr
);
908 else if (ret_size
!= size
)
909 ERR("Unexpected short read: requested %u bytes, got %lu.\n", size
, ret_size
);
910 wg_parser_push_data(source
->wg_parser
, SUCCEEDED(hr
) ? data
: NULL
, ret_size
);
914 TRACE("Media source is shutting down; exiting.\n");
918 static HRESULT WINAPI
media_stream_QueryInterface(IMFMediaStream
*iface
, REFIID riid
, void **out
)
920 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
922 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
924 if (IsEqualIID(riid
, &IID_IMFMediaStream
) ||
925 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
926 IsEqualIID(riid
, &IID_IUnknown
))
928 *out
= &stream
->IMFMediaStream_iface
;
932 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
934 return E_NOINTERFACE
;
937 IUnknown_AddRef((IUnknown
*)*out
);
941 static ULONG WINAPI
media_stream_AddRef(IMFMediaStream
*iface
)
943 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
944 ULONG ref
= InterlockedIncrement(&stream
->ref
);
946 TRACE("%p, refcount %lu.\n", iface
, ref
);
951 static ULONG WINAPI
media_stream_Release(IMFMediaStream
*iface
)
953 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
954 ULONG ref
= InterlockedDecrement(&stream
->ref
);
956 TRACE("%p, refcount %lu.\n", iface
, ref
);
960 IMFMediaSource_Release(stream
->media_source
);
961 IMFStreamDescriptor_Release(stream
->descriptor
);
962 IMFMediaEventQueue_Release(stream
->event_queue
);
963 flush_token_queue(stream
, FALSE
);
970 static HRESULT WINAPI
media_stream_GetEvent(IMFMediaStream
*iface
, DWORD flags
, IMFMediaEvent
**event
)
972 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
974 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
976 return IMFMediaEventQueue_GetEvent(stream
->event_queue
, flags
, event
);
979 static HRESULT WINAPI
media_stream_BeginGetEvent(IMFMediaStream
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
981 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
983 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
985 return IMFMediaEventQueue_BeginGetEvent(stream
->event_queue
, callback
, state
);
988 static HRESULT WINAPI
media_stream_EndGetEvent(IMFMediaStream
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
990 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
992 TRACE("%p, %p, %p.\n", stream
, result
, event
);
994 return IMFMediaEventQueue_EndGetEvent(stream
->event_queue
, result
, event
);
997 static HRESULT WINAPI
media_stream_QueueEvent(IMFMediaStream
*iface
, MediaEventType event_type
, REFGUID ext_type
,
998 HRESULT hr
, const PROPVARIANT
*value
)
1000 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
1002 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1004 return IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, event_type
, ext_type
, hr
, value
);
1007 static HRESULT WINAPI
media_stream_GetMediaSource(IMFMediaStream
*iface
, IMFMediaSource
**out
)
1009 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
1010 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
1013 TRACE("%p, %p.\n", iface
, out
);
1015 EnterCriticalSection(&source
->cs
);
1017 if (source
->state
== SOURCE_SHUTDOWN
)
1021 IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1022 *out
= &source
->IMFMediaSource_iface
;
1025 LeaveCriticalSection(&source
->cs
);
1030 static HRESULT WINAPI
media_stream_GetStreamDescriptor(IMFMediaStream
* iface
, IMFStreamDescriptor
**descriptor
)
1032 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
1033 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
1036 TRACE("%p, %p.\n", iface
, descriptor
);
1038 EnterCriticalSection(&source
->cs
);
1040 if (source
->state
== SOURCE_SHUTDOWN
)
1044 IMFStreamDescriptor_AddRef(stream
->descriptor
);
1045 *descriptor
= stream
->descriptor
;
1048 LeaveCriticalSection(&source
->cs
);
1053 static HRESULT WINAPI
media_stream_RequestSample(IMFMediaStream
*iface
, IUnknown
*token
)
1055 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
1056 struct media_source
*source
= impl_from_IMFMediaSource(stream
->media_source
);
1060 TRACE("%p, %p.\n", iface
, token
);
1062 EnterCriticalSection(&source
->cs
);
1064 if (source
->state
== SOURCE_SHUTDOWN
)
1066 else if (!stream
->active
)
1067 hr
= MF_E_MEDIA_SOURCE_WRONGSTATE
;
1068 else if (stream
->eos
)
1069 hr
= MF_E_END_OF_STREAM
;
1070 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_REQUEST_SAMPLE
, &op
)))
1072 struct source_async_command
*command
= impl_from_async_command_IUnknown(op
);
1073 command
->u
.request_sample
.stream
= stream
;
1075 IUnknown_AddRef(token
);
1076 command
->u
.request_sample
.token
= token
;
1078 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
1079 IUnknown_Release(op
);
1082 LeaveCriticalSection(&source
->cs
);
1087 static const IMFMediaStreamVtbl media_stream_vtbl
=
1089 media_stream_QueryInterface
,
1090 media_stream_AddRef
,
1091 media_stream_Release
,
1092 media_stream_GetEvent
,
1093 media_stream_BeginGetEvent
,
1094 media_stream_EndGetEvent
,
1095 media_stream_QueueEvent
,
1096 media_stream_GetMediaSource
,
1097 media_stream_GetStreamDescriptor
,
1098 media_stream_RequestSample
1101 static HRESULT
media_stream_create(IMFMediaSource
*source
, IMFStreamDescriptor
*descriptor
,
1102 wg_parser_stream_t wg_stream
, struct media_stream
**out
)
1104 struct media_stream
*object
;
1107 TRACE("source %p, descriptor %p, wg_stream %#I64x.\n", source
, descriptor
, wg_stream
);
1109 if (!(object
= calloc(1, sizeof(*object
))))
1110 return E_OUTOFMEMORY
;
1112 object
->IMFMediaStream_iface
.lpVtbl
= &media_stream_vtbl
;
1115 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1121 IMFMediaSource_AddRef(source
);
1122 object
->media_source
= source
;
1123 IMFStreamDescriptor_AddRef(descriptor
);
1124 object
->descriptor
= descriptor
;
1126 object
->active
= TRUE
;
1127 object
->eos
= FALSE
;
1128 object
->wg_stream
= wg_stream
;
1130 TRACE("Created stream object %p.\n", object
);
1136 static HRESULT WINAPI
media_source_get_service_QueryInterface(IMFGetService
*iface
, REFIID riid
, void **obj
)
1138 struct media_source
*source
= impl_from_IMFGetService(iface
);
1139 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
1142 static ULONG WINAPI
media_source_get_service_AddRef(IMFGetService
*iface
)
1144 struct media_source
*source
= impl_from_IMFGetService(iface
);
1145 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1148 static ULONG WINAPI
media_source_get_service_Release(IMFGetService
*iface
)
1150 struct media_source
*source
= impl_from_IMFGetService(iface
);
1151 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
1154 static HRESULT WINAPI
media_source_get_service_GetService(IMFGetService
*iface
, REFGUID service
, REFIID riid
, void **obj
)
1156 struct media_source
*source
= impl_from_IMFGetService(iface
);
1158 TRACE("%p, %s, %s, %p.\n", iface
, debugstr_guid(service
), debugstr_guid(riid
), obj
);
1162 if (IsEqualGUID(service
, &MF_RATE_CONTROL_SERVICE
))
1164 if (IsEqualIID(riid
, &IID_IMFRateSupport
))
1166 *obj
= &source
->IMFRateSupport_iface
;
1168 else if (IsEqualIID(riid
, &IID_IMFRateControl
))
1170 *obj
= &source
->IMFRateControl_iface
;
1174 FIXME("Unsupported service %s.\n", debugstr_guid(service
));
1177 IUnknown_AddRef((IUnknown
*)*obj
);
1179 return *obj
? S_OK
: E_NOINTERFACE
;
1182 static const IMFGetServiceVtbl media_source_get_service_vtbl
=
1184 media_source_get_service_QueryInterface
,
1185 media_source_get_service_AddRef
,
1186 media_source_get_service_Release
,
1187 media_source_get_service_GetService
,
1190 static HRESULT WINAPI
media_source_rate_support_QueryInterface(IMFRateSupport
*iface
, REFIID riid
, void **obj
)
1192 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
1193 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
1196 static ULONG WINAPI
media_source_rate_support_AddRef(IMFRateSupport
*iface
)
1198 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
1199 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1202 static ULONG WINAPI
media_source_rate_support_Release(IMFRateSupport
*iface
)
1204 struct media_source
*source
= impl_from_IMFRateSupport(iface
);
1205 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
1208 static HRESULT WINAPI
media_source_rate_support_GetSlowestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
, BOOL thin
, float *rate
)
1210 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1217 static HRESULT WINAPI
media_source_rate_support_GetFastestRate(IMFRateSupport
*iface
, MFRATE_DIRECTION direction
, BOOL thin
, float *rate
)
1219 TRACE("%p, %d, %d, %p.\n", iface
, direction
, thin
, rate
);
1221 *rate
= direction
== MFRATE_FORWARD
? 1e6f
: -1e6f
;
1226 static HRESULT WINAPI
media_source_rate_support_IsRateSupported(IMFRateSupport
*iface
, BOOL thin
, float rate
,
1227 float *nearest_rate
)
1229 TRACE("%p, %d, %f, %p.\n", iface
, thin
, rate
, nearest_rate
);
1232 *nearest_rate
= rate
;
1234 return rate
>= -1e6f
&& rate
<= 1e6f
? S_OK
: MF_E_UNSUPPORTED_RATE
;
1237 static const IMFRateSupportVtbl media_source_rate_support_vtbl
=
1239 media_source_rate_support_QueryInterface
,
1240 media_source_rate_support_AddRef
,
1241 media_source_rate_support_Release
,
1242 media_source_rate_support_GetSlowestRate
,
1243 media_source_rate_support_GetFastestRate
,
1244 media_source_rate_support_IsRateSupported
,
1247 static HRESULT WINAPI
media_source_rate_control_QueryInterface(IMFRateControl
*iface
, REFIID riid
, void **obj
)
1249 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1250 return IMFMediaSource_QueryInterface(&source
->IMFMediaSource_iface
, riid
, obj
);
1253 static ULONG WINAPI
media_source_rate_control_AddRef(IMFRateControl
*iface
)
1255 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1256 return IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
1259 static ULONG WINAPI
media_source_rate_control_Release(IMFRateControl
*iface
)
1261 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1262 return IMFMediaSource_Release(&source
->IMFMediaSource_iface
);
1265 static HRESULT WINAPI
media_source_rate_control_SetRate(IMFRateControl
*iface
, BOOL thin
, float rate
)
1267 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1270 FIXME("%p, %d, %f.\n", iface
, thin
, rate
);
1273 return MF_E_REVERSE_UNSUPPORTED
;
1276 return MF_E_THINNING_UNSUPPORTED
;
1278 if (FAILED(hr
= IMFRateSupport_IsRateSupported(&source
->IMFRateSupport_iface
, thin
, rate
, NULL
)))
1281 EnterCriticalSection(&source
->cs
);
1282 source
->rate
= rate
;
1283 LeaveCriticalSection(&source
->cs
);
1285 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, MESourceRateChanged
, &GUID_NULL
, S_OK
, NULL
);
1288 static HRESULT WINAPI
media_source_rate_control_GetRate(IMFRateControl
*iface
, BOOL
*thin
, float *rate
)
1290 struct media_source
*source
= impl_from_IMFRateControl(iface
);
1292 TRACE("%p, %p, %p.\n", iface
, thin
, rate
);
1297 EnterCriticalSection(&source
->cs
);
1298 *rate
= source
->rate
;
1299 LeaveCriticalSection(&source
->cs
);
1304 static const IMFRateControlVtbl media_source_rate_control_vtbl
=
1306 media_source_rate_control_QueryInterface
,
1307 media_source_rate_control_AddRef
,
1308 media_source_rate_control_Release
,
1309 media_source_rate_control_SetRate
,
1310 media_source_rate_control_GetRate
,
1313 static HRESULT WINAPI
media_source_QueryInterface(IMFMediaSource
*iface
, REFIID riid
, void **out
)
1315 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1317 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), out
);
1319 if (IsEqualIID(riid
, &IID_IMFMediaSource
) ||
1320 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
1321 IsEqualIID(riid
, &IID_IUnknown
))
1323 *out
= &source
->IMFMediaSource_iface
;
1325 else if (IsEqualIID(riid
, &IID_IMFGetService
))
1327 *out
= &source
->IMFGetService_iface
;
1331 FIXME("%s, %p.\n", debugstr_guid(riid
), out
);
1333 return E_NOINTERFACE
;
1336 IUnknown_AddRef((IUnknown
*)*out
);
1340 static ULONG WINAPI
media_source_AddRef(IMFMediaSource
*iface
)
1342 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1343 ULONG ref
= InterlockedIncrement(&source
->ref
);
1345 TRACE("%p, refcount %lu.\n", iface
, ref
);
1350 static ULONG WINAPI
media_source_Release(IMFMediaSource
*iface
)
1352 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1353 ULONG ref
= InterlockedDecrement(&source
->ref
);
1355 TRACE("%p, refcount %lu.\n", iface
, ref
);
1359 IMFMediaSource_Shutdown(iface
);
1360 IMFMediaEventQueue_Release(source
->event_queue
);
1361 IMFByteStream_Release(source
->byte_stream
);
1362 wg_parser_destroy(source
->wg_parser
);
1363 source
->cs
.DebugInfo
->Spare
[0] = 0;
1364 DeleteCriticalSection(&source
->cs
);
1371 static HRESULT WINAPI
media_source_GetEvent(IMFMediaSource
*iface
, DWORD flags
, IMFMediaEvent
**event
)
1373 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1375 TRACE("%p, %#lx, %p.\n", iface
, flags
, event
);
1377 return IMFMediaEventQueue_GetEvent(source
->event_queue
, flags
, event
);
1380 static HRESULT WINAPI
media_source_BeginGetEvent(IMFMediaSource
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1382 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1384 TRACE("%p, %p, %p.\n", iface
, callback
, state
);
1386 return IMFMediaEventQueue_BeginGetEvent(source
->event_queue
, callback
, state
);
1389 static HRESULT WINAPI
media_source_EndGetEvent(IMFMediaSource
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
1391 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1393 TRACE("%p, %p, %p.\n", iface
, result
, event
);
1395 return IMFMediaEventQueue_EndGetEvent(source
->event_queue
, result
, event
);
1398 static HRESULT WINAPI
media_source_QueueEvent(IMFMediaSource
*iface
, MediaEventType event_type
, REFGUID ext_type
,
1399 HRESULT hr
, const PROPVARIANT
*value
)
1401 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1403 TRACE("%p, %lu, %s, %#lx, %p.\n", iface
, event_type
, debugstr_guid(ext_type
), hr
, value
);
1405 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, event_type
, ext_type
, hr
, value
);
1408 static HRESULT WINAPI
media_source_GetCharacteristics(IMFMediaSource
*iface
, DWORD
*characteristics
)
1410 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1413 TRACE("%p, %p.\n", iface
, characteristics
);
1415 EnterCriticalSection(&source
->cs
);
1417 if (source
->state
== SOURCE_SHUTDOWN
)
1420 *characteristics
= MFMEDIASOURCE_CAN_SEEK
| MFMEDIASOURCE_CAN_PAUSE
;
1422 LeaveCriticalSection(&source
->cs
);
1427 static HRESULT WINAPI
media_source_CreatePresentationDescriptor(IMFMediaSource
*iface
, IMFPresentationDescriptor
**descriptor
)
1429 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1433 TRACE("%p, %p.\n", iface
, descriptor
);
1435 EnterCriticalSection(&source
->cs
);
1437 if (source
->state
== SOURCE_SHUTDOWN
)
1439 else if (SUCCEEDED(hr
= MFCreatePresentationDescriptor(source
->stream_count
, source
->descriptors
, descriptor
)))
1441 if (FAILED(hr
= IMFPresentationDescriptor_SetUINT64(*descriptor
, &MF_PD_DURATION
, source
->duration
)))
1442 WARN("Failed to set presentation descriptor MF_PD_DURATION, hr %#lx\n", hr
);
1444 for (i
= 0; i
< source
->stream_count
; ++i
)
1446 if (FAILED(hr
= IMFPresentationDescriptor_SelectStream(*descriptor
, i
)))
1447 WARN("Failed to select stream %u, hr %#lx\n", i
, hr
);
1453 LeaveCriticalSection(&source
->cs
);
1458 static HRESULT WINAPI
media_source_Start(IMFMediaSource
*iface
, IMFPresentationDescriptor
*descriptor
,
1459 const GUID
*time_format
, const PROPVARIANT
*position
)
1461 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1465 TRACE("%p, %p, %p, %p.\n", iface
, descriptor
, time_format
, position
);
1467 EnterCriticalSection(&source
->cs
);
1469 if (source
->state
== SOURCE_SHUTDOWN
)
1471 else if (!(IsEqualIID(time_format
, &GUID_NULL
)))
1472 hr
= MF_E_UNSUPPORTED_TIME_FORMAT
;
1473 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_START
, &op
)))
1475 struct source_async_command
*command
= impl_from_async_command_IUnknown(op
);
1476 command
->u
.start
.descriptor
= descriptor
;
1477 IMFPresentationDescriptor_AddRef(descriptor
);
1478 command
->u
.start
.format
= *time_format
;
1479 PropVariantCopy(&command
->u
.start
.position
, position
);
1481 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
1482 IUnknown_Release(op
);
1485 LeaveCriticalSection(&source
->cs
);
1490 static HRESULT WINAPI
media_source_Stop(IMFMediaSource
*iface
)
1492 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1496 TRACE("%p.\n", iface
);
1498 EnterCriticalSection(&source
->cs
);
1500 if (source
->state
== SOURCE_SHUTDOWN
)
1502 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_STOP
, &op
)))
1504 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
1505 IUnknown_Release(op
);
1508 LeaveCriticalSection(&source
->cs
);
1513 static HRESULT WINAPI
media_source_Pause(IMFMediaSource
*iface
)
1515 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1519 TRACE("%p.\n", iface
);
1521 EnterCriticalSection(&source
->cs
);
1523 if (source
->state
== SOURCE_SHUTDOWN
)
1525 else if (source
->state
!= SOURCE_RUNNING
)
1526 hr
= MF_E_INVALID_STATE_TRANSITION
;
1527 else if (SUCCEEDED(hr
= source_create_async_op(SOURCE_ASYNC_PAUSE
, &op
)))
1529 hr
= MFPutWorkItem(source
->async_commands_queue
, &source
->async_commands_callback
, op
);
1530 IUnknown_Release(op
);
1533 LeaveCriticalSection(&source
->cs
);
1538 static HRESULT WINAPI
media_source_Shutdown(IMFMediaSource
*iface
)
1540 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
1542 TRACE("%p.\n", iface
);
1544 EnterCriticalSection(&source
->cs
);
1546 if (source
->state
== SOURCE_SHUTDOWN
)
1548 LeaveCriticalSection(&source
->cs
);
1549 return MF_E_SHUTDOWN
;
1552 source
->state
= SOURCE_SHUTDOWN
;
1554 wg_parser_disconnect(source
->wg_parser
);
1556 source
->read_thread_shutdown
= true;
1557 WaitForSingleObject(source
->read_thread
, INFINITE
);
1558 CloseHandle(source
->read_thread
);
1560 IMFMediaEventQueue_Shutdown(source
->event_queue
);
1561 IMFByteStream_Close(source
->byte_stream
);
1563 while (source
->stream_count
--)
1565 struct media_stream
*stream
= source
->streams
[source
->stream_count
];
1566 IMFStreamDescriptor_Release(source
->descriptors
[source
->stream_count
]);
1567 IMFMediaEventQueue_Shutdown(stream
->event_queue
);
1568 IMFMediaStream_Release(&stream
->IMFMediaStream_iface
);
1570 free(source
->descriptors
);
1571 free(source
->streams
);
1573 LeaveCriticalSection(&source
->cs
);
1575 MFUnlockWorkQueue(source
->async_commands_queue
);
1580 static const IMFMediaSourceVtbl IMFMediaSource_vtbl
=
1582 media_source_QueryInterface
,
1583 media_source_AddRef
,
1584 media_source_Release
,
1585 media_source_GetEvent
,
1586 media_source_BeginGetEvent
,
1587 media_source_EndGetEvent
,
1588 media_source_QueueEvent
,
1589 media_source_GetCharacteristics
,
1590 media_source_CreatePresentationDescriptor
,
1594 media_source_Shutdown
,
1597 static void media_source_init_descriptors(struct media_source
*source
)
1602 for (i
= 0; i
< source
->stream_count
; i
++)
1604 struct media_stream
*stream
= source
->streams
[i
];
1605 IMFStreamDescriptor
*descriptor
= stream
->descriptor
;
1607 if (FAILED(hr
= stream_descriptor_set_tag(descriptor
, stream
->wg_stream
,
1608 &MF_SD_LANGUAGE
, WG_PARSER_TAG_LANGUAGE
)))
1609 WARN("Failed to set stream descriptor language, hr %#lx\n", hr
);
1610 if (FAILED(hr
= stream_descriptor_set_tag(descriptor
, stream
->wg_stream
,
1611 &MF_SD_STREAM_NAME
, WG_PARSER_TAG_NAME
)))
1612 WARN("Failed to set stream descriptor name, hr %#lx\n", hr
);
1616 static HRESULT
media_source_create(struct object_context
*context
, IMFMediaSource
**out
)
1618 unsigned int stream_count
= UINT_MAX
;
1619 struct media_source
*object
;
1624 if (!(object
= calloc(1, sizeof(*object
))))
1625 return E_OUTOFMEMORY
;
1627 object
->IMFMediaSource_iface
.lpVtbl
= &IMFMediaSource_vtbl
;
1628 object
->IMFGetService_iface
.lpVtbl
= &media_source_get_service_vtbl
;
1629 object
->IMFRateSupport_iface
.lpVtbl
= &media_source_rate_support_vtbl
;
1630 object
->IMFRateControl_iface
.lpVtbl
= &media_source_rate_control_vtbl
;
1631 object
->async_commands_callback
.lpVtbl
= &source_async_commands_callback_vtbl
;
1633 object
->byte_stream
= context
->stream
;
1634 IMFByteStream_AddRef(context
->stream
);
1635 object
->file_size
= context
->file_size
;
1636 object
->rate
= 1.0f
;
1637 InitializeCriticalSection(&object
->cs
);
1638 object
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": cs");
1640 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
1643 if (FAILED(hr
= MFAllocateWorkQueue(&object
->async_commands_queue
)))
1646 if (!(parser
= wg_parser_create(WG_PARSER_DECODEBIN
, FALSE
)))
1651 object
->wg_parser
= parser
;
1653 object
->read_thread
= CreateThread(NULL
, 0, read_thread
, object
, 0, NULL
);
1655 object
->state
= SOURCE_OPENING
;
1657 if (FAILED(hr
= wg_parser_connect(parser
, object
->file_size
)))
1660 stream_count
= wg_parser_get_stream_count(parser
);
1662 if (!(object
->descriptors
= calloc(stream_count
, sizeof(*object
->descriptors
)))
1663 || !(object
->streams
= calloc(stream_count
, sizeof(*object
->streams
))))
1669 for (i
= 0; i
< stream_count
; ++i
)
1671 wg_parser_stream_t wg_stream
= wg_parser_get_stream(object
->wg_parser
, i
);
1672 IMFStreamDescriptor
*descriptor
;
1673 struct media_stream
*stream
;
1674 struct wg_format format
;
1676 wg_parser_stream_get_preferred_format(wg_stream
, &format
);
1677 if (FAILED(hr
= stream_descriptor_create(i
, &format
, &descriptor
)))
1679 if (FAILED(hr
= media_stream_create(&object
->IMFMediaSource_iface
, descriptor
, wg_stream
, &stream
)))
1681 IMFStreamDescriptor_Release(descriptor
);
1685 object
->duration
= max(object
->duration
, wg_parser_stream_get_duration(wg_stream
));
1686 IMFStreamDescriptor_AddRef(descriptor
);
1687 object
->descriptors
[i
] = descriptor
;
1688 object
->streams
[i
] = stream
;
1689 object
->stream_count
++;
1692 media_source_init_descriptors(object
);
1693 object
->state
= SOURCE_STOPPED
;
1695 *out
= &object
->IMFMediaSource_iface
;
1696 TRACE("Created IMFMediaSource %p\n", *out
);
1700 WARN("Failed to construct MFMediaSource, hr %#lx.\n", hr
);
1702 while (object
->streams
&& object
->stream_count
--)
1704 struct media_stream
*stream
= object
->streams
[object
->stream_count
];
1705 IMFStreamDescriptor_Release(object
->descriptors
[object
->stream_count
]);
1706 IMFMediaStream_Release(&stream
->IMFMediaStream_iface
);
1708 free(object
->descriptors
);
1709 free(object
->streams
);
1711 if (stream_count
!= UINT_MAX
)
1712 wg_parser_disconnect(object
->wg_parser
);
1713 if (object
->read_thread
)
1715 object
->read_thread_shutdown
= true;
1716 WaitForSingleObject(object
->read_thread
, INFINITE
);
1717 CloseHandle(object
->read_thread
);
1719 if (object
->wg_parser
)
1720 wg_parser_destroy(object
->wg_parser
);
1721 if (object
->async_commands_queue
)
1722 MFUnlockWorkQueue(object
->async_commands_queue
);
1723 if (object
->event_queue
)
1724 IMFMediaEventQueue_Release(object
->event_queue
);
1725 IMFByteStream_Release(object
->byte_stream
);
1733 IMFAsyncResult
*result
;
1734 MF_OBJECT_TYPE type
;
1738 static HRESULT
result_entry_create(IMFAsyncResult
*result
, MF_OBJECT_TYPE type
,
1739 IUnknown
*object
, struct result_entry
**out
)
1741 struct result_entry
*entry
;
1743 if (!(entry
= malloc(sizeof(*entry
))))
1744 return E_OUTOFMEMORY
;
1746 entry
->result
= result
;
1747 IMFAsyncResult_AddRef(entry
->result
);
1748 entry
->object
= object
;
1749 IUnknown_AddRef(entry
->object
);
1756 static void result_entry_destroy(struct result_entry
*entry
)
1758 IMFAsyncResult_Release(entry
->result
);
1759 IUnknown_Release(entry
->object
);
1763 struct stream_handler
1765 IMFByteStreamHandler IMFByteStreamHandler_iface
;
1766 IMFAsyncCallback IMFAsyncCallback_iface
;
1768 struct list results
;
1769 CRITICAL_SECTION cs
;
1772 static struct result_entry
*handler_find_result_entry(struct stream_handler
*handler
, IMFAsyncResult
*result
)
1774 struct result_entry
*entry
;
1776 EnterCriticalSection(&handler
->cs
);
1777 LIST_FOR_EACH_ENTRY(entry
, &handler
->results
, struct result_entry
, entry
)
1779 if (result
== entry
->result
)
1781 list_remove(&entry
->entry
);
1782 LeaveCriticalSection(&handler
->cs
);
1786 LeaveCriticalSection(&handler
->cs
);
1791 static struct stream_handler
*impl_from_IMFByteStreamHandler(IMFByteStreamHandler
*iface
)
1793 return CONTAINING_RECORD(iface
, struct stream_handler
, IMFByteStreamHandler_iface
);
1796 static struct stream_handler
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
1798 return CONTAINING_RECORD(iface
, struct stream_handler
, IMFAsyncCallback_iface
);
1801 static HRESULT WINAPI
stream_handler_QueryInterface(IMFByteStreamHandler
*iface
, REFIID riid
, void **obj
)
1803 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
1805 if (IsEqualIID(riid
, &IID_IMFByteStreamHandler
) ||
1806 IsEqualIID(riid
, &IID_IUnknown
))
1809 IMFByteStreamHandler_AddRef(iface
);
1813 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1815 return E_NOINTERFACE
;
1818 static ULONG WINAPI
stream_handler_AddRef(IMFByteStreamHandler
*iface
)
1820 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1821 ULONG refcount
= InterlockedIncrement(&handler
->refcount
);
1823 TRACE("%p, refcount %lu.\n", handler
, refcount
);
1828 static ULONG WINAPI
stream_handler_Release(IMFByteStreamHandler
*iface
)
1830 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1831 ULONG refcount
= InterlockedDecrement(&handler
->refcount
);
1832 struct result_entry
*result
, *next
;
1834 TRACE("%p, refcount %lu.\n", iface
, refcount
);
1838 LIST_FOR_EACH_ENTRY_SAFE(result
, next
, &handler
->results
, struct result_entry
, entry
)
1839 result_entry_destroy(result
);
1840 DeleteCriticalSection(&handler
->cs
);
1847 static HRESULT WINAPI
stream_handler_BeginCreateObject(IMFByteStreamHandler
*iface
, IMFByteStream
*stream
, const WCHAR
*url
, DWORD flags
,
1848 IPropertyStore
*props
, IUnknown
**cancel_cookie
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1850 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1851 IMFAsyncResult
*result
;
1857 TRACE("%p, %s, %#lx, %p, %p, %p, %p.\n", iface
, debugstr_w(url
), flags
, props
, cancel_cookie
, callback
, state
);
1860 *cancel_cookie
= NULL
;
1863 return E_INVALIDARG
;
1864 if (flags
!= MF_RESOLUTION_MEDIASOURCE
)
1865 FIXME("Unimplemented flags %#lx\n", flags
);
1867 if (FAILED(hr
= IMFByteStream_GetCapabilities(stream
, &caps
)))
1869 if (!(caps
& MFBYTESTREAM_IS_SEEKABLE
))
1871 FIXME("Non-seekable bytestreams not supported.\n");
1872 return MF_E_BYTESTREAM_NOT_SEEKABLE
;
1874 if (FAILED(hr
= IMFByteStream_GetLength(stream
, &file_size
)))
1876 FIXME("Failed to get byte stream length, hr %#lx.\n", hr
);
1880 if (FAILED(hr
= MFCreateAsyncResult(NULL
, callback
, state
, &result
)))
1882 if (FAILED(hr
= object_context_create(flags
, stream
, url
, file_size
, result
, &context
)))
1884 IMFAsyncResult_Release(result
);
1888 hr
= MFPutWorkItem(MFASYNC_CALLBACK_QUEUE_IO
, &handler
->IMFAsyncCallback_iface
, context
);
1889 IUnknown_Release(context
);
1891 if (SUCCEEDED(hr
) && cancel_cookie
)
1893 *cancel_cookie
= (IUnknown
*)result
;
1894 IUnknown_AddRef(*cancel_cookie
);
1897 IMFAsyncResult_Release(result
);
1902 static HRESULT WINAPI
stream_handler_EndCreateObject(IMFByteStreamHandler
*iface
, IMFAsyncResult
*result
,
1903 MF_OBJECT_TYPE
*type
, IUnknown
**object
)
1905 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1906 struct result_entry
*entry
;
1909 TRACE("%p, %p, %p, %p.\n", iface
, result
, type
, object
);
1911 if (!(entry
= handler_find_result_entry(handler
, result
)))
1913 *type
= MF_OBJECT_INVALID
;
1915 return MF_E_UNEXPECTED
;
1918 hr
= IMFAsyncResult_GetStatus(entry
->result
);
1919 *type
= entry
->type
;
1920 *object
= entry
->object
;
1921 IUnknown_AddRef(*object
);
1922 result_entry_destroy(entry
);
1926 static HRESULT WINAPI
stream_handler_CancelObjectCreation(IMFByteStreamHandler
*iface
, IUnknown
*cookie
)
1928 struct stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
1929 IMFAsyncResult
*result
= (IMFAsyncResult
*)cookie
;
1930 struct result_entry
*entry
;
1932 TRACE("%p, %p.\n", iface
, cookie
);
1934 if (!(entry
= handler_find_result_entry(handler
, result
)))
1935 return MF_E_UNEXPECTED
;
1937 result_entry_destroy(entry
);
1941 static HRESULT WINAPI
stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler
*iface
, QWORD
*bytes
)
1943 FIXME("stub (%p %p)\n", iface
, bytes
);
1947 static const IMFByteStreamHandlerVtbl stream_handler_vtbl
=
1949 stream_handler_QueryInterface
,
1950 stream_handler_AddRef
,
1951 stream_handler_Release
,
1952 stream_handler_BeginCreateObject
,
1953 stream_handler_EndCreateObject
,
1954 stream_handler_CancelObjectCreation
,
1955 stream_handler_GetMaxNumberOfBytesRequiredForResolution
,
1958 static HRESULT WINAPI
stream_handler_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1960 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1961 IsEqualIID(riid
, &IID_IUnknown
))
1964 IMFAsyncCallback_AddRef(iface
);
1968 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1970 return E_NOINTERFACE
;
1973 static ULONG WINAPI
stream_handler_callback_AddRef(IMFAsyncCallback
*iface
)
1975 struct stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1976 return IMFByteStreamHandler_AddRef(&handler
->IMFByteStreamHandler_iface
);
1979 static ULONG WINAPI
stream_handler_callback_Release(IMFAsyncCallback
*iface
)
1981 struct stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1982 return IMFByteStreamHandler_Release(&handler
->IMFByteStreamHandler_iface
);
1985 static HRESULT WINAPI
stream_handler_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1990 static HRESULT WINAPI
stream_handler_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1992 struct stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1993 IUnknown
*object
, *state
= IMFAsyncResult_GetStateNoAddRef(result
);
1994 struct object_context
*context
;
1995 struct result_entry
*entry
;
1998 if (!state
|| !(context
= impl_from_IUnknown(state
)))
1999 return E_INVALIDARG
;
2001 if (FAILED(hr
= media_source_create(context
, (IMFMediaSource
**)&object
)))
2002 WARN("Failed to create media source, hr %#lx\n", hr
);
2005 if (FAILED(hr
= result_entry_create(context
->result
, MF_OBJECT_MEDIASOURCE
, object
, &entry
)))
2006 WARN("Failed to create handler result, hr %#lx\n", hr
);
2009 EnterCriticalSection(&handler
->cs
);
2010 list_add_tail(&handler
->results
, &entry
->entry
);
2011 LeaveCriticalSection(&handler
->cs
);
2014 IUnknown_Release(object
);
2017 IMFAsyncResult_SetStatus(context
->result
, hr
);
2018 MFInvokeCallback(context
->result
);
2023 static const IMFAsyncCallbackVtbl stream_handler_callback_vtbl
=
2025 stream_handler_callback_QueryInterface
,
2026 stream_handler_callback_AddRef
,
2027 stream_handler_callback_Release
,
2028 stream_handler_callback_GetParameters
,
2029 stream_handler_callback_Invoke
,
2032 HRESULT
gstreamer_byte_stream_handler_create(REFIID riid
, void **obj
)
2034 struct stream_handler
*handler
;
2037 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
2039 if (!(handler
= calloc(1, sizeof(*handler
))))
2040 return E_OUTOFMEMORY
;
2042 list_init(&handler
->results
);
2043 InitializeCriticalSection(&handler
->cs
);
2045 handler
->IMFByteStreamHandler_iface
.lpVtbl
= &stream_handler_vtbl
;
2046 handler
->IMFAsyncCallback_iface
.lpVtbl
= &stream_handler_callback_vtbl
;
2047 handler
->refcount
= 1;
2049 hr
= IMFByteStreamHandler_QueryInterface(&handler
->IMFByteStreamHandler_iface
, riid
, obj
);
2050 IMFByteStreamHandler_Release(&handler
->IMFByteStreamHandler_iface
);