From c9904fb639023d73d338a09ea2fb029e9f4be6ac Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 30 Jul 2014 16:59:15 -0300 Subject: [PATCH] encodebin: delay missing encoder error as passthrough is still possible Set up a fakesink with a pad probe to replace the missing encoder to detect if encoding was really required and only error out in this case. Otherwise just let passthrough branch work. This delays the error posting from the set_state function to when buffers are really flowing. Unit test updated accordingly https://bugzilla.gnome.org/show_bug.cgi?id=650652 --- gst/encoding/gstencodebin.c | 121 ++++++++++++++++++++++--------- tests/check/elements/encodebin.c | 26 ++++++- 2 files changed, 111 insertions(+), 36 deletions(-) diff --git a/gst/encoding/gstencodebin.c b/gst/encoding/gstencodebin.c index 6728e58625..8e8ebf5ea5 100644 --- a/gst/encoding/gstencodebin.c +++ b/gst/encoding/gstencodebin.c @@ -215,6 +215,7 @@ struct _StreamGroup GList *converters; /* List of conversion GstElement */ GstElement *capsfilter; /* profile->restriction (if non-NULL/ANY) */ GstElement *encoder; /* Encoder (can be NULL) */ + GstElement *fakesink; /* Fakesink (can be NULL) */ GstElement *combiner; GstElement *parser; GstElement *smartencoder; @@ -1076,7 +1077,45 @@ _profile_restriction_caps_cb (GstEncodingProfile * profile, g_object_set (group->capsfilter, "caps", restriction, NULL); } -/* FIXME : Add handling of streams that don't need encoding */ +static void +_post_missing_plugin_message (GstEncodeBin * ebin, GstEncodingProfile * prof) +{ + GstCaps *format; + format = gst_encoding_profile_get_format (prof); + + GST_ERROR_OBJECT (ebin, "Couldn't create encoder for format %" GST_PTR_FORMAT, + format); + /* missing plugin support */ + gst_element_post_message (GST_ELEMENT_CAST (ebin), + gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format)); + GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL), + ("Couldn't create encoder for format %" GST_PTR_FORMAT, format)); + + gst_caps_unref (format); +} + +static GstPadProbeReturn +_missing_plugin_probe (GstPad * pad, GstPadProbeInfo * info, gpointer udata) +{ + StreamGroup *sgroup = udata; + GstEncodeBin *ebin = sgroup->ebin; + + _post_missing_plugin_message (ebin, sgroup->profile); + + return GST_PAD_PROBE_OK; +} + +static void +_set_up_fake_encoder_pad_probe (GstEncodeBin * ebin, StreamGroup * sgroup) +{ + GstPad *pad = gst_element_get_static_pad (sgroup->fakesink, "sink"); + + gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, _missing_plugin_probe, + sgroup, NULL); + + gst_object_unref (pad); +} + /* FIXME : Add handling of streams that don't require conversion elements */ /* * Create the elements, StreamGroup, add the sink pad, link it to the muxer @@ -1091,6 +1130,7 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof, GstPad *sinkpad, *srcpad, *muxerpad = NULL; /* Element we will link to the encoder */ GstElement *last = NULL; + GstElement *encoder = NULL; GList *tmp, *tosync = NULL; GstCaps *format, *restriction; const gchar *missing_element_name; @@ -1116,14 +1156,6 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof, * * One for already encoded data */ - /* Exception to the rule above: - * We check if we have an available encoder so we can abort early */ - /* FIXME : What if we only want to do passthrough ??? */ - GST_LOG ("Checking for encoder availability"); - sgroup->encoder = _get_encoder (ebin, sprof); - if (G_UNLIKELY (sgroup->encoder == NULL)) - goto no_encoder; - /* Muxer. * If we are handling a container profile, figure out if the muxer has a * sinkpad compatible with the selected profile */ @@ -1287,19 +1319,30 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof, /* 1. Create the encoder */ GST_LOG ("Adding encoder"); - last = sgroup->encoder; - gst_bin_add ((GstBin *) ebin, sgroup->encoder); - tosync = g_list_append (tosync, sgroup->encoder); + sgroup->encoder = _get_encoder (ebin, sprof); + if (sgroup->encoder != NULL) { + last = sgroup->encoder; + gst_bin_add ((GstBin *) ebin, sgroup->encoder); + tosync = g_list_append (tosync, sgroup->encoder); - sinkpad = - local_element_request_pad (sgroup->combiner, NULL, "encodingsink", NULL); - if (G_UNLIKELY (sinkpad == NULL)) - goto no_combiner_sinkpad; - srcpad = gst_element_get_static_pad (sgroup->encoder, "src"); - if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK)) - goto encoder_link_failure; - g_object_unref (sinkpad); - g_object_unref (srcpad); + sinkpad = + local_element_request_pad (sgroup->combiner, NULL, "encodingsink", + NULL); + if (G_UNLIKELY (sinkpad == NULL)) + goto no_combiner_sinkpad; + srcpad = gst_element_get_static_pad (sgroup->encoder, "src"); + if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK)) + goto encoder_link_failure; + g_object_unref (sinkpad); + g_object_unref (srcpad); + } else if (gst_encoding_profile_get_preset (sgroup->profile) + || gst_encoding_profile_get_preset_name (sgroup->profile)) { + _post_missing_plugin_message (ebin, sprof); + goto cleanup; + } else { + /* passthrough can still work, if we discover that * + * encoding is required we post a missing plugin message */ + } /* 3. Create the conversion/restriction elements */ @@ -1312,7 +1355,21 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof, g_object_set (sgroup->capsfilter, "caps", restriction, NULL); gst_bin_add ((GstBin *) ebin, sgroup->capsfilter); tosync = g_list_append (tosync, sgroup->capsfilter); - fast_element_link (sgroup->capsfilter, sgroup->encoder); + if (sgroup->encoder == NULL) { + /* no encoder available but it might be possible to just do passthrough, so + * let's just set up a fake pad to detect that encoding was attempted and + * if so it posts the missing plugin message */ + sgroup->fakesink = gst_element_factory_make ("fakesink", NULL); + g_object_set (sgroup->fakesink, "async", FALSE, NULL); + gst_bin_add (GST_BIN_CAST (ebin), sgroup->fakesink); + tosync = g_list_append (tosync, sgroup->fakesink); + encoder = sgroup->fakesink; + + _set_up_fake_encoder_pad_probe (ebin, sgroup); + } else { + encoder = sgroup->encoder; + } + fast_element_link (sgroup->capsfilter, encoder); sgroup->restriction_sid = g_signal_connect (sprof, "notify::restriction-caps", G_CALLBACK (_profile_restriction_caps_cb), sgroup); @@ -1464,16 +1521,6 @@ splitter_encoding_failure: GST_ERROR_OBJECT (ebin, "Error linking splitter to encoding stream"); goto cleanup; -no_encoder: - GST_ERROR_OBJECT (ebin, "Couldn't create encoder for format %" GST_PTR_FORMAT, - format); - /* missing plugin support */ - gst_element_post_message (GST_ELEMENT_CAST (ebin), - gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format)); - GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL), - ("Couldn't create encoder for format %" GST_PTR_FORMAT, format)); - goto cleanup; - no_muxer_pad: GST_ERROR_OBJECT (ebin, "Couldn't find a compatible muxer pad to link encoder to"); @@ -1934,6 +1981,8 @@ stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup) if (sgroup->encoder) gst_element_set_state (sgroup->encoder, GST_STATE_NULL); + if (sgroup->fakesink) + gst_element_set_state (sgroup->fakesink, GST_STATE_NULL); if (sgroup->outfilter) gst_element_set_state (sgroup->outfilter, GST_STATE_NULL); if (sgroup->smartencoder) @@ -1941,7 +1990,10 @@ stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup) if (sgroup->capsfilter) { gst_element_set_state (sgroup->capsfilter, GST_STATE_NULL); - gst_element_unlink (sgroup->capsfilter, sgroup->encoder); + if (sgroup->encoder) + gst_element_unlink (sgroup->capsfilter, sgroup->encoder); + else + gst_element_unlink (sgroup->capsfilter, sgroup->fakesink); gst_bin_remove ((GstBin *) ebin, sgroup->capsfilter); } @@ -1990,6 +2042,9 @@ stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup) if (sgroup->encoder) gst_bin_remove ((GstBin *) ebin, sgroup->encoder); + if (sgroup->fakesink) + gst_bin_remove ((GstBin *) ebin, sgroup->fakesink); + if (sgroup->smartencoder) gst_bin_remove ((GstBin *) ebin, sgroup->smartencoder); diff --git a/tests/check/elements/encodebin.c b/tests/check/elements/encodebin.c index 3fdb5861e2..0d9fe6807a 100644 --- a/tests/check/elements/encodebin.c +++ b/tests/check/elements/encodebin.c @@ -104,13 +104,19 @@ create_vorbis_only_profile (void) return prof; } +static GstCaps * +create_unsupported_caps (void) +{ + return gst_caps_new_empty_simple ("audio/x-bogus"); +} + static GstEncodingProfile * create_unsupported_profile (void) { GstEncodingProfile *prof; GstCaps *caps; - caps = gst_caps_new_empty_simple ("audio/x-bogus"); + caps = create_unsupported_caps (); prof = (GstEncodingProfile *) gst_encoding_audio_profile_new (caps, NULL, NULL, 0); @@ -1042,14 +1048,28 @@ GST_START_TEST (test_encodebin_missing_plugin_messages) GstBus *bus = gst_pipeline_get_bus ((GstPipeline *) pipeline); GstElement *ebin = gst_element_factory_make ("encodebin", NULL); GstMessage *message; + GstElement *audiotestsrc; + GstPad *sinkpad, *srcpad; + + audiotestsrc = gst_element_factory_make ("audiotestsrc", NULL); + g_object_set (audiotestsrc, "num-buffers", 1, NULL); + gst_bin_add ((GstBin *) pipeline, audiotestsrc); /* first add to bin, then set profile */ gst_bin_add ((GstBin *) pipeline, ebin); set_profile (ebin, create_unsupported_profile ()); - gst_element_set_state (pipeline, GST_STATE_READY); + srcpad = gst_element_get_static_pad (audiotestsrc, "src"); + sinkpad = gst_element_get_static_pad (ebin, "audio_0"); + fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK); + gst_object_unref (srcpad); + gst_object_unref (sinkpad); - message = gst_bus_pop_filtered (bus, GST_MESSAGE_ELEMENT); + gst_element_set_state (pipeline, GST_STATE_PLAYING); + + message = + gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, + GST_MESSAGE_ELEMENT); fail_if (message == NULL); fail_if (!gst_is_missing_plugin_message (message)); gst_message_unref (message);