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);