1 /* GStreamer Media Source
3 * Copyright 2020 Derek Lesho
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "gst_private.h"
32 #define NONAMELESSUNION
37 #include "mfobjects.h"
39 #include "wine/debug.h"
40 #include "wine/heap.h"
41 #include "wine/list.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(mfplat
);
47 IMFMediaStream IMFMediaStream_iface
;
49 struct media_source
*parent_source
;
50 IMFMediaEventQueue
*event_queue
;
51 IMFStreamDescriptor
*descriptor
;
53 GstPad
*their_src
, *my_sink
;
64 IMFMediaSource IMFMediaSource_iface
;
66 IMFMediaEventQueue
*event_queue
;
67 IMFByteStream
*byte_stream
;
68 struct media_stream
**streams
;
71 GstElement
*container
;
72 GstElement
*decodebin
;
73 GstPad
*my_src
, *their_sink
;
80 HANDLE no_more_pads_event
;
83 static inline struct media_stream
*impl_from_IMFMediaStream(IMFMediaStream
*iface
)
85 return CONTAINING_RECORD(iface
, struct media_stream
, IMFMediaStream_iface
);
88 static inline struct media_source
*impl_from_IMFMediaSource(IMFMediaSource
*iface
)
90 return CONTAINING_RECORD(iface
, struct media_source
, IMFMediaSource_iface
);
93 static GstFlowReturn
bytestream_wrapper_pull(GstPad
*pad
, GstObject
*parent
, guint64 ofs
, guint len
,
96 struct media_source
*source
= gst_pad_get_element_private(pad
);
97 IMFByteStream
*byte_stream
= source
->byte_stream
;
103 TRACE("requesting %u bytes at %s from source %p into buffer %p\n", len
, wine_dbgstr_longlong(ofs
), source
, *buf
);
105 if (ofs
!= GST_BUFFER_OFFSET_NONE
)
107 if (FAILED(IMFByteStream_SetCurrentPosition(byte_stream
, ofs
)))
108 return GST_FLOW_ERROR
;
111 if (FAILED(IMFByteStream_IsEndOfStream(byte_stream
, &is_eof
)))
112 return GST_FLOW_ERROR
;
117 *buf
= gst_buffer_new_and_alloc(len
);
118 gst_buffer_map(*buf
, &info
, GST_MAP_WRITE
);
119 hr
= IMFByteStream_Read(byte_stream
, info
.data
, len
, &bytes_read
);
120 gst_buffer_unmap(*buf
, &info
);
122 gst_buffer_set_size(*buf
, bytes_read
);
125 return GST_FLOW_ERROR
;
129 static gboolean
bytestream_query(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
131 struct media_source
*source
= gst_pad_get_element_private(pad
);
133 QWORD bytestream_len
;
135 TRACE("GStreamer queries source %p for %s\n", source
, GST_QUERY_TYPE_NAME(query
));
137 if (FAILED(IMFByteStream_GetLength(source
->byte_stream
, &bytestream_len
)))
140 switch (GST_QUERY_TYPE(query
))
142 case GST_QUERY_DURATION
:
144 gst_query_parse_duration(query
, &format
, NULL
);
145 if (format
== GST_FORMAT_PERCENT
)
147 gst_query_set_duration(query
, GST_FORMAT_PERCENT
, GST_FORMAT_PERCENT_MAX
);
150 else if (format
== GST_FORMAT_BYTES
)
153 IMFByteStream_GetLength(source
->byte_stream
, &length
);
154 gst_query_set_duration(query
, GST_FORMAT_BYTES
, length
);
159 case GST_QUERY_SEEKING
:
161 gst_query_parse_seeking (query
, &format
, NULL
, NULL
, NULL
);
162 if (format
!= GST_FORMAT_BYTES
)
164 WARN("Cannot seek using format \"%s\".\n", gst_format_get_name(format
));
167 gst_query_set_seeking(query
, GST_FORMAT_BYTES
, 1, 0, bytestream_len
);
170 case GST_QUERY_SCHEDULING
:
172 gst_query_set_scheduling(query
, GST_SCHEDULING_FLAG_SEEKABLE
, 1, -1, 0);
173 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PULL
);
178 WARN("Unhandled query type %s\n", GST_QUERY_TYPE_NAME(query
));
184 static gboolean
bytestream_pad_mode_activate(GstPad
*pad
, GstObject
*parent
, GstPadMode mode
, gboolean activate
)
186 struct media_source
*source
= gst_pad_get_element_private(pad
);
188 TRACE("%s source pad for mediasource %p in %s mode.\n",
189 activate
? "Activating" : "Deactivating", source
, gst_pad_mode_get_name(mode
));
191 return mode
== GST_PAD_MODE_PULL
;
194 static gboolean
bytestream_pad_event_process(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
196 struct media_source
*source
= gst_pad_get_element_private(pad
);
198 TRACE("source %p, type \"%s\".\n", source
, GST_EVENT_TYPE_NAME(event
));
200 switch (event
->type
) {
201 /* the seek event should fail in pull mode */
205 WARN("Ignoring \"%s\" event.\n", GST_EVENT_TYPE_NAME(event
));
208 case GST_EVENT_RECONFIGURE
:
209 return gst_pad_event_default(pad
, parent
, event
);
214 GstBusSyncReply
bus_watch(GstBus
*bus
, GstMessage
*message
, gpointer user
)
216 struct media_source
*source
= user
;
217 gchar
*dbg_info
= NULL
;
220 TRACE("source %p message type %s\n", source
, GST_MESSAGE_TYPE_NAME(message
));
222 switch (message
->type
)
224 case GST_MESSAGE_ERROR
:
225 gst_message_parse_error(message
, &err
, &dbg_info
);
226 ERR("%s: %s\n", GST_OBJECT_NAME(message
->src
), err
->message
);
227 ERR("%s\n", dbg_info
);
231 case GST_MESSAGE_WARNING
:
232 gst_message_parse_warning(message
, &err
, &dbg_info
);
233 WARN("%s: %s\n", GST_OBJECT_NAME(message
->src
), err
->message
);
234 WARN("%s\n", dbg_info
);
242 gst_message_unref(message
);
246 static HRESULT WINAPI
media_stream_QueryInterface(IMFMediaStream
*iface
, REFIID riid
, void **out
)
248 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
250 TRACE("(%p)->(%s %p)\n", stream
, debugstr_guid(riid
), out
);
252 if (IsEqualIID(riid
, &IID_IMFMediaStream
) ||
253 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
254 IsEqualIID(riid
, &IID_IUnknown
))
256 *out
= &stream
->IMFMediaStream_iface
;
260 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
262 return E_NOINTERFACE
;
265 IUnknown_AddRef((IUnknown
*)*out
);
269 static ULONG WINAPI
media_stream_AddRef(IMFMediaStream
*iface
)
271 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
272 ULONG ref
= InterlockedIncrement(&stream
->ref
);
274 TRACE("(%p) ref=%u\n", stream
, ref
);
279 static ULONG WINAPI
media_stream_Release(IMFMediaStream
*iface
)
281 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
283 ULONG ref
= InterlockedDecrement(&stream
->ref
);
285 TRACE("(%p) ref=%u\n", stream
, ref
);
289 if (stream
->event_queue
)
290 IMFMediaEventQueue_Release(stream
->event_queue
);
297 static HRESULT WINAPI
media_stream_GetEvent(IMFMediaStream
*iface
, DWORD flags
, IMFMediaEvent
**event
)
299 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
301 TRACE("(%p)->(%#x, %p)\n", stream
, flags
, event
);
303 return IMFMediaEventQueue_GetEvent(stream
->event_queue
, flags
, event
);
306 static HRESULT WINAPI
media_stream_BeginGetEvent(IMFMediaStream
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
308 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
310 TRACE("(%p)->(%p, %p)\n", stream
, callback
, state
);
312 return IMFMediaEventQueue_BeginGetEvent(stream
->event_queue
, callback
, state
);
315 static HRESULT WINAPI
media_stream_EndGetEvent(IMFMediaStream
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
317 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
319 TRACE("(%p)->(%p, %p)\n", stream
, result
, event
);
321 return IMFMediaEventQueue_EndGetEvent(stream
->event_queue
, result
, event
);
324 static HRESULT WINAPI
media_stream_QueueEvent(IMFMediaStream
*iface
, MediaEventType event_type
, REFGUID ext_type
,
325 HRESULT hr
, const PROPVARIANT
*value
)
327 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
329 TRACE("(%p)->(%d, %s, %#x, %p)\n", stream
, event_type
, debugstr_guid(ext_type
), hr
, value
);
331 return IMFMediaEventQueue_QueueEventParamVar(stream
->event_queue
, event_type
, ext_type
, hr
, value
);
334 static HRESULT WINAPI
media_stream_GetMediaSource(IMFMediaStream
*iface
, IMFMediaSource
**source
)
336 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
338 FIXME("stub (%p)->(%p)\n", stream
, source
);
340 if (stream
->state
== STREAM_SHUTDOWN
)
341 return MF_E_SHUTDOWN
;
346 static HRESULT WINAPI
media_stream_GetStreamDescriptor(IMFMediaStream
* iface
, IMFStreamDescriptor
**descriptor
)
348 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
350 TRACE("(%p)->(%p)\n", stream
, descriptor
);
352 if (stream
->state
== STREAM_SHUTDOWN
)
353 return MF_E_SHUTDOWN
;
355 IMFStreamDescriptor_AddRef(stream
->descriptor
);
356 *descriptor
= stream
->descriptor
;
361 static HRESULT WINAPI
media_stream_RequestSample(IMFMediaStream
*iface
, IUnknown
*token
)
363 struct media_stream
*stream
= impl_from_IMFMediaStream(iface
);
365 TRACE("(%p)->(%p)\n", iface
, token
);
367 if (stream
->state
== STREAM_SHUTDOWN
)
368 return MF_E_SHUTDOWN
;
373 static const IMFMediaStreamVtbl media_stream_vtbl
=
375 media_stream_QueryInterface
,
377 media_stream_Release
,
378 media_stream_GetEvent
,
379 media_stream_BeginGetEvent
,
380 media_stream_EndGetEvent
,
381 media_stream_QueueEvent
,
382 media_stream_GetMediaSource
,
383 media_stream_GetStreamDescriptor
,
384 media_stream_RequestSample
387 static HRESULT
new_media_stream(struct media_source
*source
, GstPad
*pad
, DWORD stream_id
, struct media_stream
**out_stream
)
389 struct media_stream
*object
= heap_alloc_zero(sizeof(*object
));
392 TRACE("(%p %p)->(%p)\n", source
, pad
, out_stream
);
394 object
->IMFMediaStream_iface
.lpVtbl
= &media_stream_vtbl
;
397 IMFMediaSource_AddRef(&source
->IMFMediaSource_iface
);
398 object
->parent_source
= source
;
399 object
->their_src
= pad
;
400 object
->stream_id
= stream_id
;
402 object
->state
= STREAM_INACTIVE
;
404 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
407 if (!(object
->appsink
= gst_element_factory_make("appsink", NULL
)))
412 gst_bin_add(GST_BIN(object
->parent_source
->container
), object
->appsink
);
414 g_object_set(object
->appsink
, "sync", FALSE
, NULL
);
415 g_object_set(object
->appsink
, "max-buffers", 5, NULL
);
417 object
->my_sink
= gst_element_get_static_pad(object
->appsink
, "sink");
418 gst_pad_link(object
->their_src
, object
->my_sink
);
420 gst_element_sync_state_with_parent(object
->appsink
);
422 TRACE("->(%p)\n", object
);
423 *out_stream
= object
;
428 WARN("Failed to construct media stream, hr %#x.\n", hr
);
430 IMFMediaStream_Release(&object
->IMFMediaStream_iface
);
434 static HRESULT
media_stream_init_desc(struct media_stream
*stream
)
436 GstCaps
*current_caps
= gst_pad_get_current_caps(stream
->their_src
);
437 IMFMediaTypeHandler
*type_handler
;
438 IMFMediaType
*stream_type
= NULL
;
441 stream_type
= mf_media_type_from_caps(current_caps
);
442 gst_caps_unref(current_caps
);
446 hr
= MFCreateStreamDescriptor(stream
->stream_id
, 1, &stream_type
, &stream
->descriptor
);
448 IMFMediaType_Release(stream_type
);
453 if (FAILED(hr
= IMFStreamDescriptor_GetMediaTypeHandler(stream
->descriptor
, &type_handler
)))
456 hr
= IMFMediaTypeHandler_SetCurrentMediaType(type_handler
, stream_type
);
458 IMFMediaTypeHandler_Release(type_handler
);
463 static HRESULT WINAPI
media_source_QueryInterface(IMFMediaSource
*iface
, REFIID riid
, void **out
)
465 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
467 TRACE("(%p)->(%s %p)\n", source
, debugstr_guid(riid
), out
);
469 if (IsEqualIID(riid
, &IID_IMFMediaSource
) ||
470 IsEqualIID(riid
, &IID_IMFMediaEventGenerator
) ||
471 IsEqualIID(riid
, &IID_IUnknown
))
473 *out
= &source
->IMFMediaSource_iface
;
477 FIXME("(%s, %p)\n", debugstr_guid(riid
), out
);
479 return E_NOINTERFACE
;
482 IUnknown_AddRef((IUnknown
*)*out
);
486 static ULONG WINAPI
media_source_AddRef(IMFMediaSource
*iface
)
488 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
489 ULONG ref
= InterlockedIncrement(&source
->ref
);
491 TRACE("(%p) ref=%u\n", source
, ref
);
496 static ULONG WINAPI
media_source_Release(IMFMediaSource
*iface
)
498 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
499 ULONG ref
= InterlockedDecrement(&source
->ref
);
501 TRACE("(%p) ref=%u\n", source
, ref
);
505 IMFMediaSource_Shutdown(&source
->IMFMediaSource_iface
);
506 IMFMediaEventQueue_Release(source
->event_queue
);
513 static HRESULT WINAPI
media_source_GetEvent(IMFMediaSource
*iface
, DWORD flags
, IMFMediaEvent
**event
)
515 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
517 TRACE("(%p)->(%#x, %p)\n", source
, flags
, event
);
519 return IMFMediaEventQueue_GetEvent(source
->event_queue
, flags
, event
);
522 static HRESULT WINAPI
media_source_BeginGetEvent(IMFMediaSource
*iface
, IMFAsyncCallback
*callback
, IUnknown
*state
)
524 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
526 TRACE("(%p)->(%p, %p)\n", source
, callback
, state
);
528 return IMFMediaEventQueue_BeginGetEvent(source
->event_queue
, callback
, state
);
531 static HRESULT WINAPI
media_source_EndGetEvent(IMFMediaSource
*iface
, IMFAsyncResult
*result
, IMFMediaEvent
**event
)
533 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
535 TRACE("(%p)->(%p, %p)\n", source
, result
, event
);
537 return IMFMediaEventQueue_EndGetEvent(source
->event_queue
, result
, event
);
540 static HRESULT WINAPI
media_source_QueueEvent(IMFMediaSource
*iface
, MediaEventType event_type
, REFGUID ext_type
,
541 HRESULT hr
, const PROPVARIANT
*value
)
543 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
545 TRACE("(%p)->(%d, %s, %#x, %p)\n", source
, event_type
, debugstr_guid(ext_type
), hr
, value
);
547 return IMFMediaEventQueue_QueueEventParamVar(source
->event_queue
, event_type
, ext_type
, hr
, value
);
550 static HRESULT WINAPI
media_source_GetCharacteristics(IMFMediaSource
*iface
, DWORD
*characteristics
)
552 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
554 FIXME("(%p)->(%p): stub\n", source
, characteristics
);
556 if (source
->state
== SOURCE_SHUTDOWN
)
557 return MF_E_SHUTDOWN
;
562 static HRESULT WINAPI
media_source_CreatePresentationDescriptor(IMFMediaSource
*iface
, IMFPresentationDescriptor
**descriptor
)
564 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
566 FIXME("(%p)->(%p): stub\n", source
, descriptor
);
568 if (source
->state
== SOURCE_SHUTDOWN
)
569 return MF_E_SHUTDOWN
;
574 static HRESULT WINAPI
media_source_Start(IMFMediaSource
*iface
, IMFPresentationDescriptor
*descriptor
,
575 const GUID
*time_format
, const PROPVARIANT
*start_position
)
577 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
579 FIXME("(%p)->(%p, %p, %p): stub\n", source
, descriptor
, time_format
, start_position
);
581 if (source
->state
== SOURCE_SHUTDOWN
)
582 return MF_E_SHUTDOWN
;
587 static HRESULT WINAPI
media_source_Stop(IMFMediaSource
*iface
)
589 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
591 FIXME("(%p): stub\n", source
);
593 if (source
->state
== SOURCE_SHUTDOWN
)
594 return MF_E_SHUTDOWN
;
599 static HRESULT WINAPI
media_source_Pause(IMFMediaSource
*iface
)
601 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
603 FIXME("(%p): stub\n", source
);
605 if (source
->state
== SOURCE_SHUTDOWN
)
606 return MF_E_SHUTDOWN
;
611 static HRESULT WINAPI
media_source_Shutdown(IMFMediaSource
*iface
)
613 struct media_source
*source
= impl_from_IMFMediaSource(iface
);
616 TRACE("(%p)\n", source
);
618 if (source
->state
== SOURCE_SHUTDOWN
)
619 return MF_E_SHUTDOWN
;
621 source
->state
= SOURCE_SHUTDOWN
;
623 if (source
->container
)
625 gst_element_set_state(source
->container
, GST_STATE_NULL
);
626 gst_object_unref(GST_OBJECT(source
->container
));
630 gst_object_unref(GST_OBJECT(source
->my_src
));
631 if (source
->their_sink
)
632 gst_object_unref(GST_OBJECT(source
->their_sink
));
634 if (source
->event_queue
)
635 IMFMediaEventQueue_Shutdown(source
->event_queue
);
636 if (source
->byte_stream
)
637 IMFByteStream_Release(source
->byte_stream
);
639 for (i
= 0; i
< source
->stream_count
; i
++)
641 struct media_stream
*stream
= source
->streams
[i
];
643 stream
->state
= STREAM_SHUTDOWN
;
646 gst_object_unref(GST_OBJECT(stream
->my_sink
));
647 if (stream
->event_queue
)
648 IMFMediaEventQueue_Shutdown(stream
->event_queue
);
649 if (stream
->descriptor
)
650 IMFStreamDescriptor_Release(stream
->descriptor
);
651 if (stream
->parent_source
)
652 IMFMediaSource_Release(&stream
->parent_source
->IMFMediaSource_iface
);
654 IMFMediaStream_Release(&stream
->IMFMediaStream_iface
);
657 if (source
->stream_count
)
658 heap_free(source
->streams
);
660 if (source
->no_more_pads_event
)
661 CloseHandle(source
->no_more_pads_event
);
666 static const IMFMediaSourceVtbl IMFMediaSource_vtbl
=
668 media_source_QueryInterface
,
670 media_source_Release
,
671 media_source_GetEvent
,
672 media_source_BeginGetEvent
,
673 media_source_EndGetEvent
,
674 media_source_QueueEvent
,
675 media_source_GetCharacteristics
,
676 media_source_CreatePresentationDescriptor
,
680 media_source_Shutdown
,
683 static void stream_added(GstElement
*element
, GstPad
*pad
, gpointer user
)
685 struct media_source
*source
= user
;
686 struct media_stream
**new_stream_array
;
687 struct media_stream
*stream
;
689 if (gst_pad_get_direction(pad
) != GST_PAD_SRC
)
692 if (FAILED(new_media_stream(source
, pad
, source
->stream_count
, &stream
)))
695 if (!(new_stream_array
= heap_realloc(source
->streams
, (source
->stream_count
+ 1) * (sizeof(*new_stream_array
)))))
697 ERR("Failed to add stream to source\n");
698 IMFMediaStream_Release(&stream
->IMFMediaStream_iface
);
702 source
->streams
= new_stream_array
;
703 source
->streams
[source
->stream_count
++] = stream
;
706 static void stream_removed(GstElement
*element
, GstPad
*pad
, gpointer user
)
708 struct media_source
*source
= user
;
711 for (i
= 0; i
< source
->stream_count
; i
++)
713 struct media_stream
*stream
= source
->streams
[i
];
714 if (stream
->their_src
!= pad
)
716 stream
->their_src
= NULL
;
717 stream
->state
= STREAM_INACTIVE
;
721 static void no_more_pads(GstElement
*element
, gpointer user
)
723 struct media_source
*source
= user
;
725 SetEvent(source
->no_more_pads_event
);
728 static HRESULT
media_source_constructor(IMFByteStream
*bytestream
, struct media_source
**out_media_source
)
730 GstStaticPadTemplate src_template
=
731 GST_STATIC_PAD_TEMPLATE("mf_src", GST_PAD_SRC
, GST_PAD_ALWAYS
, GST_STATIC_CAPS_ANY
);
733 struct media_source
*object
= heap_alloc_zero(sizeof(*object
));
739 return E_OUTOFMEMORY
;
741 object
->IMFMediaSource_iface
.lpVtbl
= &IMFMediaSource_vtbl
;
743 object
->byte_stream
= bytestream
;
744 IMFByteStream_AddRef(bytestream
);
745 object
->no_more_pads_event
= CreateEventA(NULL
, FALSE
, FALSE
, NULL
);
747 if (FAILED(hr
= MFCreateEventQueue(&object
->event_queue
)))
750 object
->container
= gst_bin_new(NULL
);
751 object
->bus
= gst_bus_new();
752 gst_bus_set_sync_handler(object
->bus
, mf_src_bus_watch_wrapper
, object
, NULL
);
753 gst_element_set_bus(object
->container
, object
->bus
);
755 object
->my_src
= gst_pad_new_from_static_template(&src_template
, "mf-src");
756 gst_pad_set_element_private(object
->my_src
, object
);
757 gst_pad_set_getrange_function(object
->my_src
, bytestream_wrapper_pull_wrapper
);
758 gst_pad_set_query_function(object
->my_src
, bytestream_query_wrapper
);
759 gst_pad_set_activatemode_function(object
->my_src
, bytestream_pad_mode_activate_wrapper
);
760 gst_pad_set_event_function(object
->my_src
, bytestream_pad_event_process_wrapper
);
762 if (!(object
->decodebin
= gst_element_factory_make("decodebin", NULL
)))
764 WARN("Failed to create decodebin for source\n");
769 /* In Media Foundation, sources may read from any media source stream
770 without fear of blocking due to buffering limits on another. Trailmakers,
771 a Unity3D engine game does this by only reading from the audio stream once,
772 and never deselecting this. These properties replicate that behavior.
774 Note that with most elements, this causes excessive memory use, however
775 this is also what occurs on Windows.
777 g_object_set(object
->decodebin
, "max-size-buffers", 0, NULL
);
778 g_object_set(object
->decodebin
, "max-size-time", G_GUINT64_CONSTANT(0), NULL
);
779 g_object_set(object
->decodebin
, "max-size-bytes", 0, NULL
);
781 gst_bin_add(GST_BIN(object
->container
), object
->decodebin
);
783 g_signal_connect(object
->decodebin
, "pad-added", G_CALLBACK(mf_src_stream_added_wrapper
), object
);
784 g_signal_connect(object
->decodebin
, "pad-removed", G_CALLBACK(mf_src_stream_removed_wrapper
), object
);
785 g_signal_connect(object
->decodebin
, "no-more-pads", G_CALLBACK(mf_src_no_more_pads_wrapper
), object
);
787 object
->their_sink
= gst_element_get_static_pad(object
->decodebin
, "sink");
789 if ((ret
= gst_pad_link(object
->my_src
, object
->their_sink
)) < 0)
791 WARN("Failed to link our bytestream pad to the demuxer input, error %d.\n", ret
);
796 object
->state
= SOURCE_OPENING
;
798 gst_element_set_state(object
->container
, GST_STATE_PAUSED
);
799 ret
= gst_element_get_state(object
->container
, NULL
, NULL
, -1);
800 if (ret
== GST_STATE_CHANGE_FAILURE
)
802 ERR("Failed to play source, error %d.\n", ret
);
807 WaitForSingleObject(object
->no_more_pads_event
, INFINITE
);
808 for (i
= 0; i
< object
->stream_count
; i
++)
811 g_signal_emit_by_name(object
->streams
[i
]->appsink
, "pull-preroll", &preroll
);
812 if (FAILED(hr
= media_stream_init_desc(object
->streams
[i
])))
814 ERR("Failed to finish initialization of media stream %p, hr %x.\n", object
->streams
[i
], hr
);
815 IMFMediaStream_Release(&object
->streams
[i
]->IMFMediaStream_iface
);
818 gst_sample_unref(preroll
);
821 object
->state
= SOURCE_STOPPED
;
823 *out_media_source
= object
;
827 WARN("Failed to construct MFMediaSource, hr %#x.\n", hr
);
829 IMFMediaSource_Release(&object
->IMFMediaSource_iface
);
833 struct winegstreamer_stream_handler_result
836 IMFAsyncResult
*result
;
837 MF_OBJECT_TYPE obj_type
;
841 struct winegstreamer_stream_handler
843 IMFByteStreamHandler IMFByteStreamHandler_iface
;
844 IMFAsyncCallback IMFAsyncCallback_iface
;
850 static struct winegstreamer_stream_handler
*impl_from_IMFByteStreamHandler(IMFByteStreamHandler
*iface
)
852 return CONTAINING_RECORD(iface
, struct winegstreamer_stream_handler
, IMFByteStreamHandler_iface
);
855 static struct winegstreamer_stream_handler
*impl_from_IMFAsyncCallback(IMFAsyncCallback
*iface
)
857 return CONTAINING_RECORD(iface
, struct winegstreamer_stream_handler
, IMFAsyncCallback_iface
);
860 static HRESULT WINAPI
winegstreamer_stream_handler_QueryInterface(IMFByteStreamHandler
*iface
, REFIID riid
, void **obj
)
862 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
864 if (IsEqualIID(riid
, &IID_IMFByteStreamHandler
) ||
865 IsEqualIID(riid
, &IID_IUnknown
))
868 IMFByteStreamHandler_AddRef(iface
);
872 WARN("Unsupported %s.\n", debugstr_guid(riid
));
874 return E_NOINTERFACE
;
877 static ULONG WINAPI
winegstreamer_stream_handler_AddRef(IMFByteStreamHandler
*iface
)
879 struct winegstreamer_stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
880 ULONG refcount
= InterlockedIncrement(&handler
->refcount
);
882 TRACE("%p, refcount %u.\n", handler
, refcount
);
887 static ULONG WINAPI
winegstreamer_stream_handler_Release(IMFByteStreamHandler
*iface
)
889 struct winegstreamer_stream_handler
*handler
= impl_from_IMFByteStreamHandler(iface
);
890 ULONG refcount
= InterlockedDecrement(&handler
->refcount
);
891 struct winegstreamer_stream_handler_result
*result
, *next
;
893 TRACE("%p, refcount %u.\n", iface
, refcount
);
897 LIST_FOR_EACH_ENTRY_SAFE(result
, next
, &handler
->results
, struct winegstreamer_stream_handler_result
, entry
)
899 list_remove(&result
->entry
);
900 IMFAsyncResult_Release(result
->result
);
902 IUnknown_Release(result
->object
);
905 DeleteCriticalSection(&handler
->cs
);
912 struct create_object_context
914 IUnknown IUnknown_iface
;
917 IPropertyStore
*props
;
918 IMFByteStream
*stream
;
923 static struct create_object_context
*impl_from_IUnknown(IUnknown
*iface
)
925 return CONTAINING_RECORD(iface
, struct create_object_context
, IUnknown_iface
);
928 static HRESULT WINAPI
create_object_context_QueryInterface(IUnknown
*iface
, REFIID riid
, void **obj
)
930 TRACE("%p, %s, %p.\n", iface
, debugstr_guid(riid
), obj
);
932 if (IsEqualIID(riid
, &IID_IUnknown
))
935 IUnknown_AddRef(iface
);
939 WARN("Unsupported %s.\n", debugstr_guid(riid
));
941 return E_NOINTERFACE
;
944 static ULONG WINAPI
create_object_context_AddRef(IUnknown
*iface
)
946 struct create_object_context
*context
= impl_from_IUnknown(iface
);
947 ULONG refcount
= InterlockedIncrement(&context
->refcount
);
949 TRACE("%p, refcount %u.\n", iface
, refcount
);
954 static ULONG WINAPI
create_object_context_Release(IUnknown
*iface
)
956 struct create_object_context
*context
= impl_from_IUnknown(iface
);
957 ULONG refcount
= InterlockedDecrement(&context
->refcount
);
959 TRACE("%p, refcount %u.\n", iface
, refcount
);
964 IPropertyStore_Release(context
->props
);
966 IMFByteStream_Release(context
->stream
);
967 heap_free(context
->url
);
974 static const IUnknownVtbl create_object_context_vtbl
=
976 create_object_context_QueryInterface
,
977 create_object_context_AddRef
,
978 create_object_context_Release
,
981 static WCHAR
*heap_strdupW(const WCHAR
*str
)
989 size
= (lstrlenW(str
) + 1) * sizeof(WCHAR
);
990 ret
= heap_alloc(size
);
992 memcpy(ret
, str
, size
);
998 static HRESULT WINAPI
winegstreamer_stream_handler_BeginCreateObject(IMFByteStreamHandler
*iface
, IMFByteStream
*stream
, const WCHAR
*url
, DWORD flags
,
999 IPropertyStore
*props
, IUnknown
**cancel_cookie
, IMFAsyncCallback
*callback
, IUnknown
*state
)
1001 struct winegstreamer_stream_handler
*this = impl_from_IMFByteStreamHandler(iface
);
1002 struct create_object_context
*context
;
1003 IMFAsyncResult
*caller
, *item
;
1006 TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface
, debugstr_w(url
), flags
, props
, cancel_cookie
, callback
, state
);
1009 *cancel_cookie
= NULL
;
1011 if (FAILED(hr
= MFCreateAsyncResult(NULL
, callback
, state
, &caller
)))
1014 context
= heap_alloc(sizeof(*context
));
1017 IMFAsyncResult_Release(caller
);
1018 return E_OUTOFMEMORY
;
1021 context
->IUnknown_iface
.lpVtbl
= &create_object_context_vtbl
;
1022 context
->refcount
= 1;
1023 context
->props
= props
;
1025 IPropertyStore_AddRef(context
->props
);
1026 context
->flags
= flags
;
1027 context
->stream
= stream
;
1028 if (context
->stream
)
1029 IMFByteStream_AddRef(context
->stream
);
1031 context
->url
= heap_strdupW(url
);
1032 if (!context
->stream
)
1034 IMFAsyncResult_Release(caller
);
1035 IUnknown_Release(&context
->IUnknown_iface
);
1036 return E_OUTOFMEMORY
;
1039 hr
= MFCreateAsyncResult(&context
->IUnknown_iface
, &this->IMFAsyncCallback_iface
, (IUnknown
*)caller
, &item
);
1040 IUnknown_Release(&context
->IUnknown_iface
);
1043 if (SUCCEEDED(hr
= MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO
, item
)))
1047 *cancel_cookie
= (IUnknown
*)caller
;
1048 IUnknown_AddRef(*cancel_cookie
);
1052 IMFAsyncResult_Release(item
);
1054 IMFAsyncResult_Release(caller
);
1059 static HRESULT WINAPI
winegstreamer_stream_handler_EndCreateObject(IMFByteStreamHandler
*iface
, IMFAsyncResult
*result
,
1060 MF_OBJECT_TYPE
*obj_type
, IUnknown
**object
)
1062 struct winegstreamer_stream_handler
*this = impl_from_IMFByteStreamHandler(iface
);
1063 struct winegstreamer_stream_handler_result
*found
= NULL
, *cur
;
1066 TRACE("%p, %p, %p, %p.\n", iface
, result
, obj_type
, object
);
1068 EnterCriticalSection(&this->cs
);
1070 LIST_FOR_EACH_ENTRY(cur
, &this->results
, struct winegstreamer_stream_handler_result
, entry
)
1072 if (result
== cur
->result
)
1074 list_remove(&cur
->entry
);
1080 LeaveCriticalSection(&this->cs
);
1084 *obj_type
= found
->obj_type
;
1085 *object
= found
->object
;
1086 hr
= IMFAsyncResult_GetStatus(found
->result
);
1087 IMFAsyncResult_Release(found
->result
);
1092 *obj_type
= MF_OBJECT_INVALID
;
1094 hr
= MF_E_UNEXPECTED
;
1100 static HRESULT WINAPI
winegstreamer_stream_handler_CancelObjectCreation(IMFByteStreamHandler
*iface
, IUnknown
*cancel_cookie
)
1102 struct winegstreamer_stream_handler
*this = impl_from_IMFByteStreamHandler(iface
);
1103 struct winegstreamer_stream_handler_result
*found
= NULL
, *cur
;
1105 TRACE("%p, %p.\n", iface
, cancel_cookie
);
1107 EnterCriticalSection(&this->cs
);
1109 LIST_FOR_EACH_ENTRY(cur
, &this->results
, struct winegstreamer_stream_handler_result
, entry
)
1111 if (cancel_cookie
== (IUnknown
*)cur
->result
)
1113 list_remove(&cur
->entry
);
1119 LeaveCriticalSection(&this->cs
);
1123 IMFAsyncResult_Release(found
->result
);
1125 IUnknown_Release(found
->object
);
1129 return found
? S_OK
: MF_E_UNEXPECTED
;
1132 static HRESULT WINAPI
winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution(IMFByteStreamHandler
*iface
, QWORD
*bytes
)
1134 FIXME("stub (%p %p)\n", iface
, bytes
);
1138 static const IMFByteStreamHandlerVtbl winegstreamer_stream_handler_vtbl
=
1140 winegstreamer_stream_handler_QueryInterface
,
1141 winegstreamer_stream_handler_AddRef
,
1142 winegstreamer_stream_handler_Release
,
1143 winegstreamer_stream_handler_BeginCreateObject
,
1144 winegstreamer_stream_handler_EndCreateObject
,
1145 winegstreamer_stream_handler_CancelObjectCreation
,
1146 winegstreamer_stream_handler_GetMaxNumberOfBytesRequiredForResolution
,
1149 static HRESULT WINAPI
winegstreamer_stream_handler_callback_QueryInterface(IMFAsyncCallback
*iface
, REFIID riid
, void **obj
)
1151 if (IsEqualIID(riid
, &IID_IMFAsyncCallback
) ||
1152 IsEqualIID(riid
, &IID_IUnknown
))
1155 IMFAsyncCallback_AddRef(iface
);
1159 WARN("Unsupported %s.\n", debugstr_guid(riid
));
1161 return E_NOINTERFACE
;
1164 static ULONG WINAPI
winegstreamer_stream_handler_callback_AddRef(IMFAsyncCallback
*iface
)
1166 struct winegstreamer_stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1167 return IMFByteStreamHandler_AddRef(&handler
->IMFByteStreamHandler_iface
);
1170 static ULONG WINAPI
winegstreamer_stream_handler_callback_Release(IMFAsyncCallback
*iface
)
1172 struct winegstreamer_stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1173 return IMFByteStreamHandler_Release(&handler
->IMFByteStreamHandler_iface
);
1176 static HRESULT WINAPI
winegstreamer_stream_handler_callback_GetParameters(IMFAsyncCallback
*iface
, DWORD
*flags
, DWORD
*queue
)
1181 static HRESULT
winegstreamer_stream_handler_create_object(struct winegstreamer_stream_handler
*This
, WCHAR
*url
, IMFByteStream
*stream
, DWORD flags
,
1182 IPropertyStore
*props
, IUnknown
**out_object
, MF_OBJECT_TYPE
*out_obj_type
)
1184 TRACE("(%p %s %p %u %p %p %p)\n", This
, debugstr_w(url
), stream
, flags
, props
, out_object
, out_obj_type
);
1186 if (flags
& MF_RESOLUTION_MEDIASOURCE
)
1189 struct media_source
*new_source
;
1191 if (FAILED(hr
= media_source_constructor(stream
, &new_source
)))
1194 TRACE("->(%p)\n", new_source
);
1196 *out_object
= (IUnknown
*)&new_source
->IMFMediaSource_iface
;
1197 *out_obj_type
= MF_OBJECT_MEDIASOURCE
;
1203 FIXME("flags = %08x\n", flags
);
1208 static HRESULT WINAPI
winegstreamer_stream_handler_callback_Invoke(IMFAsyncCallback
*iface
, IMFAsyncResult
*result
)
1210 struct winegstreamer_stream_handler
*handler
= impl_from_IMFAsyncCallback(iface
);
1211 struct winegstreamer_stream_handler_result
*handler_result
;
1212 MF_OBJECT_TYPE obj_type
= MF_OBJECT_INVALID
;
1213 IUnknown
*object
= NULL
, *context_object
;
1214 struct create_object_context
*context
;
1215 IMFAsyncResult
*caller
;
1218 caller
= (IMFAsyncResult
*)IMFAsyncResult_GetStateNoAddRef(result
);
1220 if (FAILED(hr
= IMFAsyncResult_GetObject(result
, &context_object
)))
1222 WARN("Expected context set for callee result.\n");
1226 context
= impl_from_IUnknown(context_object
);
1228 hr
= winegstreamer_stream_handler_create_object(handler
, context
->url
, context
->stream
, context
->flags
, context
->props
, &object
, &obj_type
);
1230 handler_result
= heap_alloc(sizeof(*handler_result
));
1233 handler_result
->result
= caller
;
1234 IMFAsyncResult_AddRef(handler_result
->result
);
1235 handler_result
->obj_type
= obj_type
;
1236 handler_result
->object
= object
;
1238 EnterCriticalSection(&handler
->cs
);
1239 list_add_tail(&handler
->results
, &handler_result
->entry
);
1240 LeaveCriticalSection(&handler
->cs
);
1245 IUnknown_Release(object
);
1249 IUnknown_Release(&context
->IUnknown_iface
);
1251 IMFAsyncResult_SetStatus(caller
, hr
);
1252 MFInvokeCallback(caller
);
1257 static const IMFAsyncCallbackVtbl winegstreamer_stream_handler_callback_vtbl
=
1259 winegstreamer_stream_handler_callback_QueryInterface
,
1260 winegstreamer_stream_handler_callback_AddRef
,
1261 winegstreamer_stream_handler_callback_Release
,
1262 winegstreamer_stream_handler_callback_GetParameters
,
1263 winegstreamer_stream_handler_callback_Invoke
,
1266 HRESULT
winegstreamer_stream_handler_create(REFIID riid
, void **obj
)
1268 struct winegstreamer_stream_handler
*this;
1271 TRACE("%s, %p.\n", debugstr_guid(riid
), obj
);
1273 this = heap_alloc_zero(sizeof(*this));
1275 return E_OUTOFMEMORY
;
1277 list_init(&this->results
);
1278 InitializeCriticalSection(&this->cs
);
1280 this->IMFByteStreamHandler_iface
.lpVtbl
= &winegstreamer_stream_handler_vtbl
;
1281 this->IMFAsyncCallback_iface
.lpVtbl
= &winegstreamer_stream_handler_callback_vtbl
;
1284 hr
= IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface
, riid
, obj
);
1285 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface
);
1290 /* helper for callback forwarding */
1291 void perform_cb_media_source(struct cb_data
*cbdata
)
1293 switch(cbdata
->type
)
1295 case BYTESTREAM_WRAPPER_PULL
:
1297 struct getrange_data
*data
= &cbdata
->u
.getrange_data
;
1298 cbdata
->u
.getrange_data
.ret
= bytestream_wrapper_pull(data
->pad
, data
->parent
,
1299 data
->ofs
, data
->len
, data
->buf
);
1302 case BYTESTREAM_QUERY
:
1304 struct query_function_data
*data
= &cbdata
->u
.query_function_data
;
1305 cbdata
->u
.query_function_data
.ret
= bytestream_query(data
->pad
, data
->parent
, data
->query
);
1308 case BYTESTREAM_PAD_MODE_ACTIVATE
:
1310 struct activate_mode_data
*data
= &cbdata
->u
.activate_mode_data
;
1311 cbdata
->u
.activate_mode_data
.ret
= bytestream_pad_mode_activate(data
->pad
, data
->parent
, data
->mode
, data
->activate
);
1314 case BYTESTREAM_PAD_EVENT_PROCESS
:
1316 struct event_src_data
*data
= &cbdata
->u
.event_src_data
;
1317 cbdata
->u
.event_src_data
.ret
= bytestream_pad_event_process(data
->pad
, data
->parent
, data
->event
);
1320 case MF_SRC_BUS_WATCH
:
1322 struct watch_bus_data
*data
= &cbdata
->u
.watch_bus_data
;
1323 cbdata
->u
.watch_bus_data
.ret
= bus_watch(data
->bus
, data
->msg
, data
->user
);
1326 case MF_SRC_STREAM_ADDED
:
1328 struct pad_added_data
*data
= &cbdata
->u
.pad_added_data
;
1329 stream_added(data
->element
, data
->pad
, data
->user
);
1332 case MF_SRC_STREAM_REMOVED
:
1334 struct pad_removed_data
*data
= &cbdata
->u
.pad_removed_data
;
1335 stream_removed(data
->element
, data
->pad
, data
->user
);
1338 case MF_SRC_NO_MORE_PADS
:
1340 struct no_more_pads_data
*data
= &cbdata
->u
.no_more_pads_data
;
1341 no_more_pads(data
->element
, data
->user
);