From cf9da5c280603edde373f71ff1319aea4222130a Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Thu, 13 Oct 2011 11:34:49 -0400 Subject: [PATCH] decodebin2: Link elements before testing if they can reach the READY state This is made possible by filtering errors. This is required to let harware accelerated element query the video context. The video context is used to determine if the HW is capable, and thus if the element is supported or not. Fixes bug #662330. --- gst/playback/gstdecodebin2.c | 96 +++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 24 deletions(-) diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index 826ca85992..d1eb15413f 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -175,6 +175,8 @@ struct _GstDecodeBin gboolean expose_allstreams; /* Whether to expose unknow type streams or not */ gboolean upstream_seekable; /* if upstream is seekable */ + + GList *filtered; /* elements for which error messages are filtered */ }; struct _GstDecodeBinClass @@ -296,6 +298,7 @@ static void caps_notify_cb (GstPad * pad, GParamSpec * unused, static GstPad *find_sink_pad (GstElement * element); static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element, GstStateChange transition); +static void gst_decode_bin_handle_message (GstBin * bin, GstMessage * message); #define EXPOSE_LOCK(dbin) G_STMT_START { \ GST_LOG_OBJECT (dbin, \ @@ -588,9 +591,11 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass) { GObjectClass *gobject_klass; GstElementClass *gstelement_klass; + GstBinClass *gstbin_klass; gobject_klass = (GObjectClass *) klass; gstelement_klass = (GstElementClass *) klass; + gstbin_klass = (GstBinClass *) klass; parent_class = g_type_class_peek_parent (klass); @@ -937,6 +942,9 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass) gstelement_klass->change_state = GST_DEBUG_FUNCPTR (gst_decode_bin_change_state); + + gstbin_klass->handle_message = + GST_DEBUG_FUNCPTR (gst_decode_bin_handle_message); } /* Must be called with factories lock! */ @@ -1731,6 +1739,21 @@ setup_caps_delay: } } +static void +add_error_filter (GstDecodeBin * dbin, GstElement * element) +{ + GST_OBJECT_LOCK (dbin); + dbin->filtered = g_list_prepend (dbin->filtered, element); + GST_OBJECT_UNLOCK (dbin); +} + +static void +remove_error_filter (GstDecodeBin * dbin, GstElement * element) +{ + GST_OBJECT_LOCK (dbin); + dbin->filtered = g_list_remove (dbin->filtered, element); + GST_OBJECT_UNLOCK (dbin); +} /* connect_pad: * @@ -1855,45 +1878,52 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad, continue; } - /* ... activate it ... We do this before adding it to the bin so that we - * don't accidentally make it post error messages that will stop - * everything. */ - if ((gst_element_set_state (element, - GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) { - GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY", - GST_ELEMENT_NAME (element)); - gst_object_unref (element); - continue; - } + /* Filter errors, this will prevent the element from causing the pipeline + * to error while we test it using READY state. */ + add_error_filter (dbin, element); - /* 2.3. Find its sink pad, this should work after activating it. */ - if (!(sinkpad = find_sink_pad (element))) { - GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad", - GST_ELEMENT_NAME (element)); - gst_element_set_state (element, GST_STATE_NULL); - gst_object_unref (element); - continue; - } - - /* 2.4 add it ... */ + /* ... add it ... */ if (!(gst_bin_add (GST_BIN_CAST (dbin), element))) { GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin", GST_ELEMENT_NAME (element)); - gst_object_unref (sinkpad); - gst_element_set_state (element, GST_STATE_NULL); + remove_error_filter (dbin, element); gst_object_unref (element); continue; } - /* 2.5 ...and try to link */ + /* Find its sink pad. */ + if (!(sinkpad = find_sink_pad (element))) { + GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad", + GST_ELEMENT_NAME (element)); + remove_error_filter (dbin, element); + gst_bin_remove (GST_BIN (dbin), element); + continue; + } + + /* ... and try to link */ if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) { GST_WARNING_OBJECT (dbin, "Link failed on pad %s:%s", GST_DEBUG_PAD_NAME (sinkpad)); - gst_element_set_state (element, GST_STATE_NULL); + remove_error_filter (dbin, element); gst_object_unref (sinkpad); gst_bin_remove (GST_BIN (dbin), element); continue; } + + /* ... activate it ... */ + if ((gst_element_set_state (element, + GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) { + GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY", + GST_ELEMENT_NAME (element)); + remove_error_filter (dbin, element); + gst_object_unref (sinkpad); + gst_bin_remove (GST_BIN (dbin), element); + continue; + } + + /* Stop filtering errors. */ + remove_error_filter (dbin, element); + gst_object_unref (sinkpad); GST_LOG_OBJECT (dbin, "linked on pad %s:%s", GST_DEBUG_PAD_NAME (pad)); @@ -3993,6 +4023,24 @@ activate_failed: } } +static void +gst_decode_bin_handle_message (GstBin * bin, GstMessage * msg) +{ + GstDecodeBin *dbin = GST_DECODE_BIN (bin); + gboolean drop = FALSE; + + if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) { + GST_OBJECT_LOCK (dbin); + drop = (g_list_find (dbin->filtered, GST_MESSAGE_SRC (msg)) != NULL); + GST_OBJECT_UNLOCK (dbin); + } + + if (drop) + gst_message_unref (msg); + else + GST_BIN_CLASS (parent_class)->handle_message (bin, msg); +} + gboolean gst_decode_bin_plugin_init (GstPlugin * plugin) {