mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 06:16:36 +00:00
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
This commit is contained in:
parent
59fb749ef6
commit
c9904fb639
2 changed files with 111 additions and 36 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue