gdi32: Move the text metrics cache into the generic font structure.
[wine/zf.git] / dlls / winegstreamer / media_source.c
blob5f3c43a020490a707f9a51a80f41ca9a6d9c7212
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
20 #include "config.h"
22 #include <gst/gst.h>
24 #include "gst_private.h"
25 #include "gst_cbs.h"
27 #include <assert.h>
28 #include <stdarg.h>
29 #include <assert.h>
31 #define COBJMACROS
32 #define NONAMELESSUNION
34 #include "mfapi.h"
35 #include "mferror.h"
36 #include "mfidl.h"
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);
45 struct media_stream
47 IMFMediaStream IMFMediaStream_iface;
48 LONG ref;
49 struct media_source *parent_source;
50 IMFMediaEventQueue *event_queue;
51 IMFStreamDescriptor *descriptor;
52 GstElement *appsink;
53 GstPad *their_src, *my_sink;
54 enum
56 STREAM_INACTIVE,
57 STREAM_SHUTDOWN,
58 } state;
59 DWORD stream_id;
62 struct media_source
64 IMFMediaSource IMFMediaSource_iface;
65 LONG ref;
66 IMFMediaEventQueue *event_queue;
67 IMFByteStream *byte_stream;
68 struct media_stream **streams;
69 ULONG stream_count;
70 GstBus *bus;
71 GstElement *container;
72 GstElement *decodebin;
73 GstPad *my_src, *their_sink;
74 enum
76 SOURCE_OPENING,
77 SOURCE_STOPPED,
78 SOURCE_SHUTDOWN,
79 } state;
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,
94 GstBuffer **buf)
96 struct media_source *source = gst_pad_get_element_private(pad);
97 IMFByteStream *byte_stream = source->byte_stream;
98 ULONG bytes_read;
99 GstMapInfo info;
100 BOOL is_eof;
101 HRESULT hr;
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;
113 if (is_eof)
114 return GST_FLOW_EOS;
116 if (!(*buf))
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);
124 if (FAILED(hr))
125 return GST_FLOW_ERROR;
126 return GST_FLOW_OK;
129 static gboolean bytestream_query(GstPad *pad, GstObject *parent, GstQuery *query)
131 struct media_source *source = gst_pad_get_element_private(pad);
132 GstFormat format;
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)))
138 return FALSE;
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);
148 return TRUE;
150 else if (format == GST_FORMAT_BYTES)
152 QWORD length;
153 IMFByteStream_GetLength(source->byte_stream, &length);
154 gst_query_set_duration(query, GST_FORMAT_BYTES, length);
155 return TRUE;
157 return FALSE;
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));
165 return FALSE;
167 gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, bytestream_len);
168 return TRUE;
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);
174 return TRUE;
176 default:
178 WARN("Unhandled query type %s\n", GST_QUERY_TYPE_NAME(query));
179 return FALSE;
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 */
202 case GST_EVENT_SEEK:
203 return FALSE;
204 default:
205 WARN("Ignoring \"%s\" event.\n", GST_EVENT_TYPE_NAME(event));
206 case GST_EVENT_TAG:
207 case GST_EVENT_QOS:
208 case GST_EVENT_RECONFIGURE:
209 return gst_pad_event_default(pad, parent, event);
211 return TRUE;
214 GstBusSyncReply bus_watch(GstBus *bus, GstMessage *message, gpointer user)
216 struct media_source *source = user;
217 gchar *dbg_info = NULL;
218 GError *err = 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);
228 g_error_free(err);
229 g_free(dbg_info);
230 break;
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);
235 g_error_free(err);
236 g_free(dbg_info);
237 break;
238 default:
239 break;
242 gst_message_unref(message);
243 return GST_BUS_DROP;
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;
258 else
260 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
261 *out = NULL;
262 return E_NOINTERFACE;
265 IUnknown_AddRef((IUnknown*)*out);
266 return S_OK;
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);
276 return 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);
287 if (!ref)
289 if (stream->event_queue)
290 IMFMediaEventQueue_Release(stream->event_queue);
291 heap_free(stream);
294 return ref;
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;
343 return E_NOTIMPL;
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;
358 return S_OK;
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;
370 return E_NOTIMPL;
373 static const IMFMediaStreamVtbl media_stream_vtbl =
375 media_stream_QueryInterface,
376 media_stream_AddRef,
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));
390 HRESULT hr;
392 TRACE("(%p %p)->(%p)\n", source, pad, out_stream);
394 object->IMFMediaStream_iface.lpVtbl = &media_stream_vtbl;
395 object->ref = 1;
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)))
405 goto fail;
407 if (!(object->appsink = gst_element_factory_make("appsink", NULL)))
409 hr = E_OUTOFMEMORY;
410 goto fail;
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;
425 return S_OK;
427 fail:
428 WARN("Failed to construct media stream, hr %#x.\n", hr);
430 IMFMediaStream_Release(&object->IMFMediaStream_iface);
431 return hr;
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;
439 HRESULT hr;
441 stream_type = mf_media_type_from_caps(current_caps);
442 gst_caps_unref(current_caps);
443 if (!stream_type)
444 return E_FAIL;
446 hr = MFCreateStreamDescriptor(stream->stream_id, 1, &stream_type, &stream->descriptor);
448 IMFMediaType_Release(stream_type);
450 if (FAILED(hr))
451 return hr;
453 if (FAILED(hr = IMFStreamDescriptor_GetMediaTypeHandler(stream->descriptor, &type_handler)))
454 return hr;
456 hr = IMFMediaTypeHandler_SetCurrentMediaType(type_handler, stream_type);
458 IMFMediaTypeHandler_Release(type_handler);
460 return hr;
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;
475 else
477 FIXME("(%s, %p)\n", debugstr_guid(riid), out);
478 *out = NULL;
479 return E_NOINTERFACE;
482 IUnknown_AddRef((IUnknown*)*out);
483 return S_OK;
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);
493 return 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);
503 if (!ref)
505 IMFMediaSource_Shutdown(&source->IMFMediaSource_iface);
506 IMFMediaEventQueue_Release(source->event_queue);
507 heap_free(source);
510 return ref;
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;
559 return E_NOTIMPL;
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;
571 return E_NOTIMPL;
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;
584 return E_NOTIMPL;
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;
596 return E_NOTIMPL;
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;
608 return E_NOTIMPL;
611 static HRESULT WINAPI media_source_Shutdown(IMFMediaSource *iface)
613 struct media_source *source = impl_from_IMFMediaSource(iface);
614 unsigned int i;
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));
629 if (source->my_src)
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;
645 if (stream->my_sink)
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);
663 return S_OK;
666 static const IMFMediaSourceVtbl IMFMediaSource_vtbl =
668 media_source_QueryInterface,
669 media_source_AddRef,
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,
677 media_source_Start,
678 media_source_Stop,
679 media_source_Pause,
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)
690 return;
692 if (FAILED(new_media_stream(source, pad, source->stream_count, &stream)))
693 return;
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);
699 return;
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;
709 unsigned int i;
711 for (i = 0; i < source->stream_count; i++)
713 struct media_stream *stream = source->streams[i];
714 if (stream->their_src != pad)
715 continue;
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));
734 unsigned int i;
735 HRESULT hr;
736 int ret;
738 if (!object)
739 return E_OUTOFMEMORY;
741 object->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl;
742 object->ref = 1;
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)))
748 goto fail;
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");
765 hr = E_OUTOFMEMORY;
766 goto fail;
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);
792 hr = E_FAIL;
793 goto fail;
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);
803 hr = E_FAIL;
804 goto fail;
807 WaitForSingleObject(object->no_more_pads_event, INFINITE);
808 for (i = 0; i < object->stream_count; i++)
810 GstSample *preroll;
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);
816 goto fail;
818 gst_sample_unref(preroll);
821 object->state = SOURCE_STOPPED;
823 *out_media_source = object;
824 return S_OK;
826 fail:
827 WARN("Failed to construct MFMediaSource, hr %#x.\n", hr);
829 IMFMediaSource_Release(&object->IMFMediaSource_iface);
830 return hr;
833 struct winegstreamer_stream_handler_result
835 struct list entry;
836 IMFAsyncResult *result;
837 MF_OBJECT_TYPE obj_type;
838 IUnknown *object;
841 struct winegstreamer_stream_handler
843 IMFByteStreamHandler IMFByteStreamHandler_iface;
844 IMFAsyncCallback IMFAsyncCallback_iface;
845 LONG refcount;
846 struct list results;
847 CRITICAL_SECTION cs;
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))
867 *obj = iface;
868 IMFByteStreamHandler_AddRef(iface);
869 return S_OK;
872 WARN("Unsupported %s.\n", debugstr_guid(riid));
873 *obj = NULL;
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);
884 return 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);
895 if (!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);
901 if (result->object)
902 IUnknown_Release(result->object);
903 heap_free(result);
905 DeleteCriticalSection(&handler->cs);
906 heap_free(handler);
909 return refcount;
912 struct create_object_context
914 IUnknown IUnknown_iface;
915 LONG refcount;
917 IPropertyStore *props;
918 IMFByteStream *stream;
919 WCHAR *url;
920 DWORD flags;
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))
934 *obj = iface;
935 IUnknown_AddRef(iface);
936 return S_OK;
939 WARN("Unsupported %s.\n", debugstr_guid(riid));
940 *obj = NULL;
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);
951 return 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);
961 if (!refcount)
963 if (context->props)
964 IPropertyStore_Release(context->props);
965 if (context->stream)
966 IMFByteStream_Release(context->stream);
967 heap_free(context->url);
968 heap_free(context);
971 return refcount;
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)
983 WCHAR *ret = NULL;
985 if (str)
987 unsigned int size;
989 size = (lstrlenW(str) + 1) * sizeof(WCHAR);
990 ret = heap_alloc(size);
991 if (ret)
992 memcpy(ret, str, size);
995 return ret;
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;
1004 HRESULT hr;
1006 TRACE("%p, %s, %#x, %p, %p, %p, %p.\n", iface, debugstr_w(url), flags, props, cancel_cookie, callback, state);
1008 if (cancel_cookie)
1009 *cancel_cookie = NULL;
1011 if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
1012 return hr;
1014 context = heap_alloc(sizeof(*context));
1015 if (!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;
1024 if (context->props)
1025 IPropertyStore_AddRef(context->props);
1026 context->flags = flags;
1027 context->stream = stream;
1028 if (context->stream)
1029 IMFByteStream_AddRef(context->stream);
1030 if (url)
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);
1041 if (SUCCEEDED(hr))
1043 if (SUCCEEDED(hr = MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_IO, item)))
1045 if (cancel_cookie)
1047 *cancel_cookie = (IUnknown *)caller;
1048 IUnknown_AddRef(*cancel_cookie);
1052 IMFAsyncResult_Release(item);
1054 IMFAsyncResult_Release(caller);
1056 return hr;
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;
1064 HRESULT hr;
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);
1075 found = cur;
1076 break;
1080 LeaveCriticalSection(&this->cs);
1082 if (found)
1084 *obj_type = found->obj_type;
1085 *object = found->object;
1086 hr = IMFAsyncResult_GetStatus(found->result);
1087 IMFAsyncResult_Release(found->result);
1088 heap_free(found);
1090 else
1092 *obj_type = MF_OBJECT_INVALID;
1093 *object = NULL;
1094 hr = MF_E_UNEXPECTED;
1097 return hr;
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);
1114 found = cur;
1115 break;
1119 LeaveCriticalSection(&this->cs);
1121 if (found)
1123 IMFAsyncResult_Release(found->result);
1124 if (found->object)
1125 IUnknown_Release(found->object);
1126 heap_free(found);
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);
1135 return E_NOTIMPL;
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))
1154 *obj = iface;
1155 IMFAsyncCallback_AddRef(iface);
1156 return S_OK;
1159 WARN("Unsupported %s.\n", debugstr_guid(riid));
1160 *obj = NULL;
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)
1178 return E_NOTIMPL;
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)
1188 HRESULT hr;
1189 struct media_source *new_source;
1191 if (FAILED(hr = media_source_constructor(stream, &new_source)))
1192 return hr;
1194 TRACE("->(%p)\n", new_source);
1196 *out_object = (IUnknown*)&new_source->IMFMediaSource_iface;
1197 *out_obj_type = MF_OBJECT_MEDIASOURCE;
1199 return S_OK;
1201 else
1203 FIXME("flags = %08x\n", flags);
1204 return E_NOTIMPL;
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;
1216 HRESULT hr;
1218 caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
1220 if (FAILED(hr = IMFAsyncResult_GetObject(result, &context_object)))
1222 WARN("Expected context set for callee result.\n");
1223 return hr;
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));
1231 if (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);
1242 else
1244 if (object)
1245 IUnknown_Release(object);
1246 hr = E_OUTOFMEMORY;
1249 IUnknown_Release(&context->IUnknown_iface);
1251 IMFAsyncResult_SetStatus(caller, hr);
1252 MFInvokeCallback(caller);
1254 return S_OK;
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;
1269 HRESULT hr;
1271 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1273 this = heap_alloc_zero(sizeof(*this));
1274 if (!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;
1282 this->refcount = 1;
1284 hr = IMFByteStreamHandler_QueryInterface(&this->IMFByteStreamHandler_iface, riid, obj);
1285 IMFByteStreamHandler_Release(&this->IMFByteStreamHandler_iface);
1287 return hr;
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);
1300 break;
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);
1306 break;
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);
1312 break;
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);
1318 break;
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);
1324 break;
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);
1330 break;
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);
1336 break;
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);
1342 break;
1344 default:
1346 assert(0);