From: Derek Lesho Subject: [PATCH resend 4/5] winegstreamer: Find an appropriate demuxer for the source. Message-Id: <20200406175757.285865-4-dlesho@codeweavers.com> Date: Mon, 6 Apr 2020 12:57:56 -0500 In-Reply-To: <20200406175757.285865-1-dlesho@codeweavers.com> References: <20200406175757.285865-1-dlesho@codeweavers.com> We can add a path later which uses decodebin as the demuxer, for use with formats not supported on windows. (like Theora) Signed-off-by: Derek Lesho --- dlls/winegstreamer/gst_cbs.c | 15 ++++- dlls/winegstreamer/gst_cbs.h | 2 + dlls/winegstreamer/media_source.c | 101 +++++++++++++++++++++++++++++- 3 files changed, 115 insertions(+), 3 deletions(-) diff --git a/dlls/winegstreamer/gst_cbs.c b/dlls/winegstreamer/gst_cbs.c index 141ab3c611..51b017ded6 100644 --- a/dlls/winegstreamer/gst_cbs.c +++ b/dlls/winegstreamer/gst_cbs.c @@ -358,4 +358,17 @@ gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, Gs call_cb(&cbdata); return cbdata.u.event_src_data.ret; -} \ No newline at end of file +} + +GstBusSyncReply watch_source_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user) +{ + struct cb_data cbdata = { WATCH_SOURCE_BUS }; + + cbdata.u.watch_bus_data.bus = bus; + cbdata.u.watch_bus_data.msg = message; + cbdata.u.watch_bus_data.user = user; + + call_cb(&cbdata); + + return cbdata.u.watch_bus_data.ret; +} diff --git a/dlls/winegstreamer/gst_cbs.h b/dlls/winegstreamer/gst_cbs.h index 10e999feea..0d7acaf0b8 100644 --- a/dlls/winegstreamer/gst_cbs.h +++ b/dlls/winegstreamer/gst_cbs.h @@ -48,6 +48,7 @@ enum CB_TYPE { QUERY_BYTESTREAM, ACTIVATE_BYTESTREAM_PAD_MODE, PROCESS_BYTESTREAM_PAD_EVENT, + WATCH_SOURCE_BUS, MEDIA_SOURCE_MAX, }; @@ -164,5 +165,6 @@ GstFlowReturn pull_from_bytestream_wrapper(GstPad *pad, GstObject *parent, guint gboolean query_bytestream_wrapper(GstPad *pad, GstObject *parent, GstQuery *query) DECLSPEC_HIDDEN; gboolean activate_bytestream_pad_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate) DECLSPEC_HIDDEN; gboolean process_bytestream_pad_event_wrapper(GstPad *pad, GstObject *parent, GstEvent *event) DECLSPEC_HIDDEN; +GstBusSyncReply watch_source_bus_wrapper(GstBus *bus, GstMessage *message, gpointer user) DECLSPEC_HIDDEN; #endif diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c index c0d35df6fa..d3ed74876e 100644 --- a/dlls/winegstreamer/media_source.c +++ b/dlls/winegstreamer/media_source.c @@ -38,7 +38,12 @@ struct media_source enum source_type type; IMFMediaEventQueue *event_queue; IMFByteStream *byte_stream; - GstPad *my_src; + struct media_stream **streams; + ULONG stream_count; + GstBus *bus; + GstElement *container; + GstElement *demuxer; + GstPad *my_src, *their_sink; enum { SOURCE_OPENING, @@ -218,6 +223,13 @@ static HRESULT media_source_teardown(struct media_source *This) { if (This->my_src) gst_object_unref(GST_OBJECT(This->my_src)); + if (This->their_sink) + gst_object_unref(GST_OBJECT(This->their_sink)); + if (This->container) + { + gst_element_set_state(This->container, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(This->container)); + } if (This->event_queue) IMFMediaEventQueue_Release(This->event_queue); if (This->byte_stream) @@ -390,6 +402,37 @@ static gboolean process_bytestream_pad_event(GstPad *pad, GstObject *parent, Gst return TRUE; } +GstBusSyncReply watch_source_bus(GstBus *bus, GstMessage *message, gpointer user) +{ + struct media_stream *This = (struct media_stream *) user; + GError *err = NULL; + gchar *dbg_info = NULL; + + TRACE("source %p message type %s\n", This, GST_MESSAGE_TYPE_NAME(message)); + + switch (message->type) + { + case GST_MESSAGE_ERROR: + gst_message_parse_error(message, &err, &dbg_info); + ERR("%s: %s\n", GST_OBJECT_NAME(message->src), err->message); + ERR("%s\n", dbg_info); + g_error_free(err); + g_free(dbg_info); + break; + case GST_MESSAGE_WARNING: + gst_message_parse_warning(message, &err, &dbg_info); + WARN("%s: %s\n", GST_OBJECT_NAME(message->src), err->message); + WARN("%s\n", dbg_info); + g_error_free(err); + g_free(dbg_info); + break; + default: + break; + } + + return GST_BUS_DROP; +} + static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_type type, struct media_source **out_media_source) { GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE( @@ -399,6 +442,9 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t source_descs[type].bytestream_caps); struct media_source *This = heap_alloc_zero(sizeof(*This)); + GList *demuxer_list_one, *demuxer_list_two; + GstElementFactory *demuxer_factory = NULL; + int ret; HRESULT hr; if (!This) @@ -409,7 +455,25 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t if (FAILED(hr = MFCreateEventQueue(&This->event_queue))) goto fail; - This->state = SOURCE_STOPPED; + /* Find demuxer */ + demuxer_list_one = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_DEMUXER, 1); + + demuxer_list_two = gst_element_factory_list_filter(demuxer_list_one, gst_static_caps_get(&source_descs[type].bytestream_caps), GST_PAD_SINK, 0); + gst_plugin_feature_list_free(demuxer_list_one); + + if (!(g_list_length(demuxer_list_two))) + { + ERR("Failed to find demuxer for source.\n"); + gst_plugin_feature_list_free(demuxer_list_two); + hr = E_FAIL; + goto fail; + } + + demuxer_factory = g_list_first(demuxer_list_two)->data; + gst_object_ref(demuxer_factory); + gst_plugin_feature_list_free(demuxer_list_two); + + TRACE("Found demuxer %s.\n", GST_ELEMENT_NAME(demuxer_factory)); if (FAILED(hr = IMFByteStream_QueryInterface(bytestream, &IID_IMFByteStream, (void **)&This->byte_stream))) { @@ -423,6 +487,31 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t gst_pad_set_activatemode_function(This->my_src, activate_bytestream_pad_mode_wrapper); gst_pad_set_event_function(This->my_src, process_bytestream_pad_event_wrapper); + This->container = gst_bin_new(NULL); + This->bus = gst_bus_new(); + gst_bus_set_sync_handler(This->bus, watch_source_bus_wrapper, This, NULL); + gst_element_set_bus(This->container, This->bus); + + This->demuxer = gst_element_factory_create(demuxer_factory, NULL); + if (!(This->demuxer)) + { + WARN("Failed to create demuxer for source\n"); + hr = E_OUTOFMEMORY; + goto fail; + } + gst_bin_add(GST_BIN(This->container), This->demuxer); + + This->their_sink = gst_element_get_static_pad(This->demuxer, "sink"); + + if ((ret = gst_pad_link(This->my_src, This->their_sink)) < 0) + { + WARN("Failed to link our bytestream pad to the demuxer input\n"); + hr = E_OUTOFMEMORY; + goto fail; + } + + This->state = SOURCE_STOPPED; + This->IMFMediaSource_iface.lpVtbl = &IMFMediaSource_vtbl; This->ref = 1; @@ -432,6 +521,8 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, enum source_t fail: WARN("Failed to construct MFMediaSource, hr %#x.\n", hr); + if (demuxer_factory) + gst_object_unref(demuxer_factory); media_source_teardown(This); heap_free(This); *out_media_source = NULL; @@ -930,6 +1021,12 @@ void perform_cb_media_source(struct cb_data *cbdata) cbdata->u.event_src_data.ret = process_bytestream_pad_event(data->pad, data->parent, data->event); break; } + case WATCH_SOURCE_BUS: + { + struct watch_bus_data *data = &cbdata->u.watch_bus_data; + cbdata->u.watch_bus_data.ret = watch_source_bus(data->bus, data->msg, data->user); + break; + } default: { ERR("Wrong callback forwarder called\n"); -- 2.26.0