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.
This commit is contained in:
Nicolas Dufresne 2011-10-13 11:34:49 -04:00 committed by Sebastian Dröge
parent 54be243757
commit cf9da5c280

View file

@ -175,6 +175,8 @@ struct _GstDecodeBin
gboolean expose_allstreams; /* Whether to expose unknow type streams or not */ gboolean expose_allstreams; /* Whether to expose unknow type streams or not */
gboolean upstream_seekable; /* if upstream is seekable */ gboolean upstream_seekable; /* if upstream is seekable */
GList *filtered; /* elements for which error messages are filtered */
}; };
struct _GstDecodeBinClass struct _GstDecodeBinClass
@ -296,6 +298,7 @@ static void caps_notify_cb (GstPad * pad, GParamSpec * unused,
static GstPad *find_sink_pad (GstElement * element); static GstPad *find_sink_pad (GstElement * element);
static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element, static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element,
GstStateChange transition); GstStateChange transition);
static void gst_decode_bin_handle_message (GstBin * bin, GstMessage * message);
#define EXPOSE_LOCK(dbin) G_STMT_START { \ #define EXPOSE_LOCK(dbin) G_STMT_START { \
GST_LOG_OBJECT (dbin, \ GST_LOG_OBJECT (dbin, \
@ -588,9 +591,11 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
{ {
GObjectClass *gobject_klass; GObjectClass *gobject_klass;
GstElementClass *gstelement_klass; GstElementClass *gstelement_klass;
GstBinClass *gstbin_klass;
gobject_klass = (GObjectClass *) klass; gobject_klass = (GObjectClass *) klass;
gstelement_klass = (GstElementClass *) klass; gstelement_klass = (GstElementClass *) klass;
gstbin_klass = (GstBinClass *) klass;
parent_class = g_type_class_peek_parent (klass); parent_class = g_type_class_peek_parent (klass);
@ -937,6 +942,9 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
gstelement_klass->change_state = gstelement_klass->change_state =
GST_DEBUG_FUNCPTR (gst_decode_bin_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! */ /* 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: /* connect_pad:
* *
@ -1855,45 +1878,52 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
continue; continue;
} }
/* ... activate it ... We do this before adding it to the bin so that we /* Filter errors, this will prevent the element from causing the pipeline
* don't accidentally make it post error messages that will stop * to error while we test it using READY state. */
* everything. */ add_error_filter (dbin, element);
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;
}
/* 2.3. Find its sink pad, this should work after activating it. */ /* ... add 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 ... */
if (!(gst_bin_add (GST_BIN_CAST (dbin), element))) { if (!(gst_bin_add (GST_BIN_CAST (dbin), element))) {
GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin", GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
GST_ELEMENT_NAME (element)); GST_ELEMENT_NAME (element));
gst_object_unref (sinkpad); remove_error_filter (dbin, element);
gst_element_set_state (element, GST_STATE_NULL);
gst_object_unref (element); gst_object_unref (element);
continue; 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) { if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) {
GST_WARNING_OBJECT (dbin, "Link failed on pad %s:%s", GST_WARNING_OBJECT (dbin, "Link failed on pad %s:%s",
GST_DEBUG_PAD_NAME (sinkpad)); GST_DEBUG_PAD_NAME (sinkpad));
gst_element_set_state (element, GST_STATE_NULL); remove_error_filter (dbin, element);
gst_object_unref (sinkpad); gst_object_unref (sinkpad);
gst_bin_remove (GST_BIN (dbin), element); gst_bin_remove (GST_BIN (dbin), element);
continue; 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_object_unref (sinkpad);
GST_LOG_OBJECT (dbin, "linked on pad %s:%s", GST_DEBUG_PAD_NAME (pad)); 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 gboolean
gst_decode_bin_plugin_init (GstPlugin * plugin) gst_decode_bin_plugin_init (GstPlugin * plugin)
{ {