summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2014-08-25 20:59:40 +0300
committerSebastian Dröge <sebastian@centricular.com>2014-08-25 21:01:16 +0300
commita5cf0a4572177128cd2ef41ed23dff4bc717b947 (patch)
tree3fda9797a700bc100d15a00e5a62a92b63d7d4c0
parent22a138b71687cfc9d995ae38cacf6d756fa7789f (diff)
decodebin: Include information from the error messages of tried but failed elements in the missing plugin errors
-rw-r--r--gst/playback/gstdecodebin2.c170
-rw-r--r--gst/playback/gsturidecodebin.c36
2 files changed, 184 insertions, 22 deletions
diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c
index 4fa6bd7f6..4076769ec 100644
--- a/gst/playback/gstdecodebin2.c
+++ b/gst/playback/gstdecodebin2.c
@@ -183,6 +183,7 @@ struct _GstDecodeBin
gboolean expose_allstreams; /* Whether to expose unknow type streams or not */
GList *filtered; /* elements for which error messages are filtered */
+ GList *filtered_errors; /* filtered error messages */
GList *buffering_status; /* element currently buffering messages */
};
@@ -445,6 +446,7 @@ struct _GstDecodeChain
e.g. no suitable decoder could be found
e.g. stream got EOS without buffers
*/
+ gchar *deadend_details;
GstCaps *endcaps; /* Caps that were used when linking to the endpad
or that resulted in the deadend
*/
@@ -462,7 +464,8 @@ static GstDecodeGroup *gst_decode_group_new (GstDecodeBin * dbin,
GstDecodeChain * chain);
static gboolean gst_decode_chain_is_complete (GstDecodeChain * chain);
static gboolean gst_decode_chain_expose (GstDecodeChain * chain,
- GList ** endpads, gboolean * missing_plugin, gboolean * last_group);
+ GList ** endpads, gboolean * missing_plugin,
+ GString * missing_plugin_details, gboolean * last_group);
static gboolean gst_decode_chain_is_drained (GstDecodeChain * chain);
static gboolean gst_decode_chain_reset_buffering (GstDecodeChain * chain);
static gboolean gst_decode_group_is_complete (GstDecodeGroup * group);
@@ -1419,7 +1422,7 @@ static gboolean is_adaptive_demuxer_element (GstElement * srcelement);
static gboolean connect_pad (GstDecodeBin * dbin, GstElement * src,
GstDecodePad * dpad, GstPad * pad, GstCaps * caps, GValueArray * factories,
- GstDecodeChain * chain);
+ GstDecodeChain * chain, gchar ** deadend_details);
static GList *connect_element (GstDecodeBin * dbin, GstDecodeElement * delem,
GstDecodeChain * chain);
static void expose_pad (GstDecodeBin * dbin, GstElement * src,
@@ -1488,6 +1491,7 @@ analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
const gchar *classification;
gboolean is_parser_converter = FALSE;
gboolean res;
+ gchar *deadend_details = NULL;
GST_DEBUG_OBJECT (dbin, "Pad %s:%s caps:%" GST_PTR_FORMAT,
GST_DEBUG_PAD_NAME (pad), caps);
@@ -1756,7 +1760,9 @@ analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
/* 1.h else continue autoplugging something from the list. */
GST_LOG_OBJECT (pad, "Let's continue discovery on this pad");
- res = connect_pad (dbin, src, dpad, pad, caps, factories, chain);
+ res =
+ connect_pad (dbin, src, dpad, pad, caps, factories, chain,
+ &deadend_details);
/* Need to unref the capsfilter srcpad here if
* we inserted a capsfilter */
@@ -1804,6 +1810,7 @@ unknown_type:
{
GST_LOG_OBJECT (pad, "Unknown type, posting message and firing signal");
+ chain->deadend_details = deadend_details;
chain->deadend = TRUE;
chain->endcaps = caps;
gst_object_replace ((GstObject **) & chain->current_pad, NULL);
@@ -1880,10 +1887,31 @@ add_error_filter (GstDecodeBin * dbin, GstElement * element)
}
static void
-remove_error_filter (GstDecodeBin * dbin, GstElement * element)
+remove_error_filter (GstDecodeBin * dbin, GstElement * element,
+ GstMessage ** error)
{
+ GList *l;
+
GST_OBJECT_LOCK (dbin);
dbin->filtered = g_list_remove (dbin->filtered, element);
+
+ if (error)
+ *error = NULL;
+
+ l = dbin->filtered_errors;
+ while (l) {
+ GstMessage *msg = l->data;
+
+ if (GST_MESSAGE_SRC (msg) == GST_OBJECT_CAST (element)) {
+ /* Get the last error of this element, i.e. the earliest */
+ if (error)
+ gst_message_replace (error, msg);
+ gst_message_unref (msg);
+ l = g_list_delete_link (dbin->filtered_errors, l);
+ } else {
+ l = l->next;
+ }
+ }
GST_OBJECT_UNLOCK (dbin);
}
@@ -1921,6 +1949,28 @@ send_sticky_events (GstDecodeBin * dbin, GstPad * pad)
return data.ret;
}
+static gchar *
+error_message_to_string (GstMessage * msg)
+{
+ GError *err;
+ gchar *debug, *message, *full_message;
+
+ gst_message_parse_error (msg, &err, &debug);
+
+ message = gst_error_get_message (err->domain, err->code);
+
+ if (debug)
+ full_message = g_strdup_printf ("%s\n%s\n%s", message, err->message, debug);
+ else
+ full_message = g_strdup_printf ("%s\n%s", message, err->message);
+
+ g_free (message);
+ g_free (debug);
+ g_clear_error (&err);
+
+ return full_message;
+}
+
/* connect_pad:
*
* Try to connect the given pad to an element created from one of the factories,
@@ -1934,11 +1984,12 @@ send_sticky_events (GstDecodeBin * dbin, GstPad * pad)
static gboolean
connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
GstPad * pad, GstCaps * caps, GValueArray * factories,
- GstDecodeChain * chain)
+ GstDecodeChain * chain, gchar ** deadend_details)
{
gboolean res = FALSE;
GstPad *mqpad = NULL;
gboolean is_demuxer = chain->parent && !chain->elements; /* First pad after the demuxer */
+ GString *error_details = NULL;
g_return_val_if_fail (factories != NULL, FALSE);
g_return_val_if_fail (factories->n_values > 0, FALSE);
@@ -1961,6 +2012,8 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
decode_pad_set_target (dpad, pad);
}
+ error_details = g_string_new ("");
+
/* 2. Try to create an element and link to it */
while (factories->n_values > 0) {
GstAutoplugSelectResult ret;
@@ -2103,6 +2156,9 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
GST_WARNING_OBJECT (dbin, "Could not create an element from %s",
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
+ g_string_append_printf (error_details,
+ "Could not create an element from %s\n",
+ gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
continue;
}
@@ -2117,7 +2173,9 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
if (!(gst_bin_add (GST_BIN_CAST (dbin), element))) {
GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
GST_ELEMENT_NAME (element));
- remove_error_filter (dbin, element);
+ remove_error_filter (dbin, element, NULL);
+ g_string_append_printf (error_details, "Couldn't add %s to the bin\n",
+ GST_ELEMENT_NAME (element));
gst_object_unref (element);
continue;
}
@@ -2126,7 +2184,9 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
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);
+ remove_error_filter (dbin, element, NULL);
+ g_string_append_printf (error_details,
+ "Element %s doesn't have a sink pad", GST_ELEMENT_NAME (element));
gst_bin_remove (GST_BIN (dbin), element);
continue;
}
@@ -2135,7 +2195,9 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
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));
- remove_error_filter (dbin, element);
+ remove_error_filter (dbin, element, NULL);
+ g_string_append_printf (error_details, "Link failed on pad %s:%s",
+ GST_DEBUG_PAD_NAME (sinkpad));
gst_object_unref (sinkpad);
gst_bin_remove (GST_BIN (dbin), element);
continue;
@@ -2144,9 +2206,22 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
/* ... activate it ... */
if ((gst_element_set_state (element,
GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
+ GstMessage *error_msg;
+
GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY",
GST_ELEMENT_NAME (element));
- remove_error_filter (dbin, element);
+ remove_error_filter (dbin, element, &error_msg);
+
+ if (error_msg) {
+ gchar *error_string = error_message_to_string (error_msg);
+ g_string_append_printf (error_details, "Couldn't set %s to READY:\n%s",
+ GST_ELEMENT_NAME (element), error_string);
+ gst_message_unref (error_msg);
+ g_free (error_string);
+ } else {
+ g_string_append_printf (error_details, "Couldn't set %s to READY",
+ GST_ELEMENT_NAME (element));
+ }
gst_object_unref (sinkpad);
gst_bin_remove (GST_BIN (dbin), element);
continue;
@@ -2155,10 +2230,24 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
/* check if we still accept the caps on the pad after setting
* the element to READY */
if (!gst_pad_query_accept_caps (sinkpad, caps)) {
+ GstMessage *error_msg;
+
GST_WARNING_OBJECT (dbin, "Element %s does not accept caps",
GST_ELEMENT_NAME (element));
- remove_error_filter (dbin, element);
+ remove_error_filter (dbin, element, &error_msg);
+
+ if (error_msg) {
+ gchar *error_string = error_message_to_string (error_msg);
+ g_string_append_printf (error_details,
+ "Element %s does not accept caps:\n%s", GST_ELEMENT_NAME (element),
+ error_string);
+ gst_message_unref (error_msg);
+ g_free (error_string);
+ } else {
+ g_string_append_printf (error_details,
+ "Element %s does not accept caps", GST_ELEMENT_NAME (element));
+ }
gst_element_set_state (element, GST_STATE_NULL);
gst_object_unref (sinkpad);
@@ -2281,6 +2370,7 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
!send_sticky_events (dbin, pad)) {
GstDecodeElement *dtmp = NULL;
GstElement *tmp = NULL;
+ GstMessage *error_msg;
GST_WARNING_OBJECT (dbin, "Couldn't set %s to PAUSED",
GST_ELEMENT_NAME (element));
@@ -2289,7 +2379,18 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
g_list_free (to_connect);
to_connect = NULL;
- remove_error_filter (dbin, element);
+ remove_error_filter (dbin, element, &error_msg);
+
+ if (error_msg) {
+ gchar *error_string = error_message_to_string (error_msg);
+ g_string_append_printf (error_details, "Couldn't set %s to PAUSED:\n%s",
+ GST_ELEMENT_NAME (element), error_string);
+ gst_message_unref (error_msg);
+ g_free (error_string);
+ } else {
+ g_string_append_printf (error_details, "Couldn't set %s to PAUSED",
+ GST_ELEMENT_NAME (element));
+ }
/* Remove all elements in this chain that were just added. No
* other thread could've added elements in the meantime */
@@ -2348,7 +2449,7 @@ connect_pad (GstDecodeBin * dbin, GstElement * src, GstDecodePad * dpad,
/* Remove error filter now, from now on we can't gracefully
* handle errors of the element anymore */
- remove_error_filter (dbin, element);
+ remove_error_filter (dbin, element, NULL);
/* Now let the bin handle the state */
gst_element_set_locked_state (element, FALSE);
@@ -2386,6 +2487,11 @@ beach:
if (mqpad)
gst_object_unref (mqpad);
+ if (error_details)
+ *deadend_details = g_string_free (error_details, (error_details->len == 0));
+ else
+ *deadend_details = NULL;
+
return res;
}
@@ -3091,6 +3197,8 @@ gst_decode_chain_free_internal (GstDecodeChain * chain, gboolean hide)
gst_caps_unref (chain->endcaps);
chain->endcaps = NULL;
}
+ g_free (chain->deadend_details);
+ chain->deadend_details = NULL;
GST_DEBUG_OBJECT (chain->dbin, "%s chain %p", (hide ? "Hidden" : "Freed"),
chain);
@@ -4022,6 +4130,7 @@ gst_decode_bin_expose (GstDecodeBin * dbin)
{
GList *tmp, *endpads;
gboolean missing_plugin;
+ GString *missing_plugin_details;
gboolean already_exposed;
gboolean last_group;
@@ -4031,6 +4140,8 @@ retry:
already_exposed = TRUE;
last_group = TRUE;
+ missing_plugin_details = g_string_new ("");
+
GST_DEBUG_OBJECT (dbin, "Exposing currently active chains/groups");
/* Don't expose if we're currently shutting down */
@@ -4044,21 +4155,31 @@ retry:
/* Get the pads that we're going to expose and mark things as exposed */
if (!gst_decode_chain_expose (dbin->decode_chain, &endpads, &missing_plugin,
- &last_group)) {
+ missing_plugin_details, &last_group)) {
g_list_foreach (endpads, (GFunc) gst_object_unref, NULL);
g_list_free (endpads);
+ g_string_free (missing_plugin_details, TRUE);
GST_ERROR_OBJECT (dbin, "Broken chain/group tree");
g_return_val_if_reached (FALSE);
return FALSE;
}
if (endpads == NULL) {
if (missing_plugin) {
- GST_WARNING_OBJECT (dbin, "No suitable plugins found");
- GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL),
- ("no suitable plugins found"));
+ if (missing_plugin_details->len > 0) {
+ gchar *details = g_string_free (missing_plugin_details, FALSE);
+ GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL),
+ ("no suitable plugins found:\n%s", details));
+ g_free (details);
+ } else {
+ g_string_free (missing_plugin_details, TRUE);
+ GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL),
+ ("no suitable plugins found"));
+ }
} else {
/* in this case, the stream ended without buffers,
* just post a warning */
+ g_string_free (missing_plugin_details, TRUE);
+
GST_WARNING_OBJECT (dbin, "All streams finished without buffers. "
"Last group: %d", last_group);
if (last_group) {
@@ -4081,6 +4202,8 @@ retry:
return FALSE;
}
+ g_string_free (missing_plugin_details, TRUE);
+
/* Check if this was called when everything was exposed already */
for (tmp = endpads; tmp && already_exposed; tmp = tmp->next) {
GstDecodePad *dpad = tmp->data;
@@ -4181,15 +4304,21 @@ retry:
*/
static gboolean
gst_decode_chain_expose (GstDecodeChain * chain, GList ** endpads,
- gboolean * missing_plugin, gboolean * last_group)
+ gboolean * missing_plugin, GString * missing_plugin_details,
+ gboolean * last_group)
{
GstDecodeGroup *group;
GList *l;
GstDecodeBin *dbin;
if (chain->deadend) {
- if (chain->endcaps)
+ if (chain->endcaps) {
+ if (chain->deadend_details) {
+ g_string_append (missing_plugin_details, chain->deadend_details);
+ g_string_append_c (missing_plugin_details, '\n');
+ }
*missing_plugin = TRUE;
+ }
return TRUE;
}
@@ -4223,7 +4352,7 @@ gst_decode_chain_expose (GstDecodeChain * chain, GList ** endpads,
GstDecodeChain *childchain = l->data;
if (!gst_decode_chain_expose (childchain, endpads, missing_plugin,
- last_group))
+ missing_plugin_details, last_group))
return FALSE;
}
@@ -4701,6 +4830,9 @@ gst_decode_bin_handle_message (GstBin * bin, GstMessage * msg)
if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_ERROR) {
GST_OBJECT_LOCK (dbin);
drop = (g_list_find (dbin->filtered, GST_MESSAGE_SRC (msg)) != NULL);
+ if (drop)
+ dbin->filtered_errors =
+ g_list_prepend (dbin->filtered_errors, gst_message_ref (msg));
GST_OBJECT_UNLOCK (dbin);
} else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_BUFFERING) {
gint perc, msg_perc;
diff --git a/gst/playback/gsturidecodebin.c b/gst/playback/gsturidecodebin.c
index 8090a2b48..f21658f34 100644
--- a/gst/playback/gsturidecodebin.c
+++ b/gst/playback/gsturidecodebin.c
@@ -110,6 +110,7 @@ struct _GstURIDecodeBin
guint src_np_sig_id; /* new-pad signal id */
guint src_nmp_sig_id; /* no-more-pads signal id */
gint pending;
+ GList *missing_plugin_errors;
gboolean async_pending; /* async-start has been emitted */
@@ -986,8 +987,29 @@ done:
* decodebins had missing plugins for all of their streams!
*/
if (!decoder->streams || g_hash_table_size (decoder->streams) == 0) {
- GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN, (NULL),
- ("no suitable plugins found"));
+ if (decoder->missing_plugin_errors) {
+ GString *str = g_string_new ("");
+ GList *l;
+
+ for (l = decoder->missing_plugin_errors; l; l = l->next) {
+ GstMessage *msg = l->data;
+ gchar *debug;
+
+ gst_message_parse_error (msg, NULL, &debug);
+ g_string_append (str, debug);
+ g_free (debug);
+ gst_message_unref (msg);
+ }
+ g_list_free (decoder->missing_plugin_errors);
+ decoder->missing_plugin_errors = NULL;
+
+ GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN, (NULL),
+ ("no suitable plugins found:\n%s", str->str));
+ g_string_free (str, TRUE);
+ } else {
+ GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN, (NULL),
+ ("no suitable plugins found"));
+ }
} else {
gst_element_no_more_pads (GST_ELEMENT_CAST (decoder));
}
@@ -2400,6 +2422,8 @@ handle_redirect_message (GstURIDecodeBin * dec, GstMessage * msg)
static void
handle_message (GstBin * bin, GstMessage * msg)
{
+ GstURIDecodeBin *dec = GST_URI_DECODE_BIN (bin);
+
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ELEMENT:{
if (gst_message_has_name (msg, "redirect")) {
@@ -2407,7 +2431,7 @@ handle_message (GstBin * bin, GstMessage * msg)
* the user of this element as it can in most cases just pick the first item
* of the sorted list as a good redirection candidate. It can of course
* choose something else from the list if it has a better way. */
- msg = handle_redirect_message (GST_URI_DECODE_BIN (bin), msg);
+ msg = handle_redirect_message (dec, msg);
}
break;
}
@@ -2422,6 +2446,9 @@ handle_message (GstBin * bin, GstMessage * msg)
if (g_error_matches (err, GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN)
|| g_error_matches (err, GST_STREAM_ERROR,
GST_STREAM_ERROR_CODEC_NOT_FOUND)) {
+ dec->missing_plugin_errors =
+ g_list_prepend (dec->missing_plugin_errors, gst_message_ref (msg));
+
no_more_pads_full (GST_ELEMENT (GST_MESSAGE_SRC (msg)), FALSE,
GST_URI_DECODE_BIN (bin));
gst_message_unref (msg);
@@ -2767,6 +2794,9 @@ gst_uri_decode_bin_change_state (GstElement * element,
remove_decoders (decoder, FALSE);
remove_source (decoder);
do_async_done (decoder);
+ g_list_free_full (decoder->missing_plugin_errors,
+ (GDestroyNotify) gst_message_unref);
+ decoder->missing_plugin_errors = NULL;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
GST_DEBUG ("ready to null");