encodebin: Autoplug formatters

Autoplug formatters for streams if a formatter with secondary or
higher rank is found. Formatters are autoplugged when there is no
muxer or when the muxer doesn't implement the tagsetter interface.

Currently only the first formatter found is plugged, this might
help in lots of cases, but it doesn't solve the
'lamemp3 ! xingmux ! id3mux'
case.

https://bugzilla.gnome.org/show_bug.cgi?id=649841
This commit is contained in:
Thiago Santos 2011-05-19 08:30:14 -03:00
parent 0060900d68
commit b5fb542386

View file

@ -162,6 +162,7 @@ struct _GstEncodeBin
/* available muxers, encoders and parsers */ /* available muxers, encoders and parsers */
GList *muxers; GList *muxers;
GList *formatters;
GList *encoders; GList *encoders;
GList *parsers; GList *parsers;
@ -205,6 +206,7 @@ struct _StreamGroup
GstElement *parser; GstElement *parser;
GstElement *smartencoder; GstElement *smartencoder;
GstElement *outfilter; /* Output capsfilter (streamprofile.format) */ GstElement *outfilter; /* Output capsfilter (streamprofile.format) */
GstElement *formatter;
GstElement *outqueue; /* Queue just before the muxer */ GstElement *outqueue; /* Queue just before the muxer */
}; };
@ -279,6 +281,9 @@ static void stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup);
static GstPad *gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin, static GstPad *gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin,
GstCaps * caps); GstCaps * caps);
static inline GstElement *_get_formatter (GstEncodeBin * ebin,
GstEncodingProfile * sprof);
static void static void
gst_encode_bin_class_init (GstEncodeBinClass * klass) gst_encode_bin_class_init (GstEncodeBinClass * klass)
{ {
@ -388,6 +393,9 @@ gst_encode_bin_dispose (GObject * object)
if (ebin->muxers) if (ebin->muxers)
gst_plugin_feature_list_free (ebin->muxers); gst_plugin_feature_list_free (ebin->muxers);
if (ebin->formatters)
gst_plugin_feature_list_free (ebin->formatters);
if (ebin->encoders) if (ebin->encoders)
gst_plugin_feature_list_free (ebin->encoders); gst_plugin_feature_list_free (ebin->encoders);
@ -410,15 +418,14 @@ static void
gst_encode_bin_init (GstEncodeBin * encode_bin) gst_encode_bin_init (GstEncodeBin * encode_bin)
{ {
GstPadTemplate *tmpl; GstPadTemplate *tmpl;
GList *formatters;
encode_bin->muxers = encode_bin->muxers =
gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER, gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER,
GST_RANK_MARGINAL); GST_RANK_MARGINAL);
formatters =
encode_bin->formatters =
gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_FORMATTER, gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_FORMATTER,
GST_RANK_SECONDARY); GST_RANK_SECONDARY);
encode_bin->muxers = g_list_concat (encode_bin->muxers, formatters);
encode_bin->encoders = encode_bin->encoders =
gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER, gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER,
@ -910,6 +917,16 @@ no_template:
} }
} }
static gboolean
_has_class (GstElement * element, const gchar * classname)
{
GstElementClass *klass;
klass = GST_ELEMENT_GET_CLASS (element);
return strstr (klass->details.klass, classname) != NULL;
}
/* FIXME : Add handling of streams that don't need encoding */ /* FIXME : Add handling of streams that don't need encoding */
/* FIXME : Add handling of streams that don't require conversion elements */ /* FIXME : Add handling of streams that don't require conversion elements */
/* /*
@ -966,6 +983,7 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
muxerpad = get_compatible_muxer_sink_pad (ebin, NULL, format); muxerpad = get_compatible_muxer_sink_pad (ebin, NULL, format);
if (G_UNLIKELY (muxerpad == NULL)) if (G_UNLIKELY (muxerpad == NULL))
goto no_muxer_pad; goto no_muxer_pad;
} }
/* Output Queue. /* Output Queue.
@ -988,6 +1006,26 @@ _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
} }
gst_object_unref (srcpad); gst_object_unref (srcpad);
/* Check if we need a formatter
* If we have no muxer or
* if the muxer isn't a formatter and doesn't implement the tagsetter interface
*/
if (!ebin->muxer
|| (!gst_element_implements_interface (ebin->muxer, GST_TYPE_TAG_SETTER)
|| !_has_class (ebin->muxer, "Formatter"))) {
sgroup->formatter = _get_formatter (ebin, sprof);
if (sgroup->formatter) {
GST_DEBUG ("Adding formatter for %" GST_PTR_FORMAT, format);
gst_bin_add (GST_BIN (ebin), sgroup->formatter);
tosync = g_list_append (tosync, sgroup->formatter);
if (G_UNLIKELY (!fast_element_link (sgroup->formatter, last)))
goto formatter_link_failure;
last = sgroup->formatter;
}
}
/* Output capsfilter /* Output capsfilter
* This will receive the format caps from the streamprofile */ * This will receive the format caps from the streamprofile */
GST_DEBUG ("Adding output capsfilter for %" GST_PTR_FORMAT, format); GST_DEBUG ("Adding output capsfilter for %" GST_PTR_FORMAT, format);
@ -1327,10 +1365,15 @@ muxer_link_failure:
GST_ERROR_OBJECT (ebin, "Couldn't link encoder to muxer"); GST_ERROR_OBJECT (ebin, "Couldn't link encoder to muxer");
goto cleanup; goto cleanup;
outfilter_link_failure: formatter_link_failure:
GST_ERROR_OBJECT (ebin, "Couldn't link output filter to output queue"); GST_ERROR_OBJECT (ebin, "Couldn't link output filter to output queue");
goto cleanup; goto cleanup;
outfilter_link_failure:
GST_ERROR_OBJECT (ebin,
"Couldn't link output filter to output queue/formatter");
goto cleanup;
passthrough_link_failure: passthrough_link_failure:
GST_ERROR_OBJECT (ebin, "Failed linking splitter in passthrough mode"); GST_ERROR_OBJECT (ebin, "Failed linking splitter in passthrough mode");
goto cleanup; goto cleanup;
@ -1390,10 +1433,49 @@ _factory_can_sink_caps (GstElementFactory * factory, const GstCaps * caps)
return FALSE; return FALSE;
} }
static inline GstElement *
_get_formatter (GstEncodeBin * ebin, GstEncodingProfile * sprof)
{
GList *formatters, *tmpfmtr;
GstElement *formatter = NULL;
GstElementFactory *formatterfact = NULL;
const GstCaps *format;
const gchar *preset;
format = gst_encoding_profile_get_format (sprof);
preset = gst_encoding_profile_get_preset (sprof);
GST_DEBUG ("Getting list of formatters for format %" GST_PTR_FORMAT, format);
formatters =
gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
FALSE);
if (formatters == NULL)
goto beach;
/* FIXME : signal the user if he wants this */
for (tmpfmtr = formatters; tmpfmtr; tmpfmtr = tmpfmtr->next) {
formatterfact = (GstElementFactory *) tmpfmtr->data;
GST_DEBUG_OBJECT (ebin, "Trying formatter %s",
GST_PLUGIN_FEATURE_NAME (formatterfact));
if ((formatter =
_create_element_and_set_preset (formatterfact, preset, NULL)))
break;
}
gst_plugin_feature_list_free (formatters);
beach:
return formatter;
}
static inline GstElement * static inline GstElement *
_get_muxer (GstEncodeBin * ebin) _get_muxer (GstEncodeBin * ebin)
{ {
GList *muxers, *tmpmux; GList *muxers, *formatters, *tmpmux;
GstElement *muxer = NULL; GstElement *muxer = NULL;
GstElementFactory *muxerfact = NULL; GstElementFactory *muxerfact = NULL;
const GList *tmp; const GList *tmp;
@ -1408,6 +1490,12 @@ _get_muxer (GstEncodeBin * ebin)
muxers = muxers =
gst_element_factory_list_filter (ebin->muxers, format, GST_PAD_SRC, TRUE); gst_element_factory_list_filter (ebin->muxers, format, GST_PAD_SRC, TRUE);
formatters =
gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
TRUE);
muxers = g_list_concat (muxers, formatters);
if (muxers == NULL) if (muxers == NULL)
goto beach; goto beach;
@ -1592,9 +1680,17 @@ stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup)
if (sgroup->outqueue) if (sgroup->outqueue)
gst_element_set_state (sgroup->outqueue, GST_STATE_NULL); gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
if (sgroup->formatter) {
/* capsfilter - formatter - outqueue */
gst_element_set_state (sgroup->formatter, GST_STATE_NULL);
gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
gst_element_unlink (sgroup->formatter, sgroup->outqueue);
gst_element_unlink (sgroup->outfilter, sgroup->formatter);
} else {
/* Capsfilter - outqueue */ /* Capsfilter - outqueue */
gst_element_set_state (sgroup->outfilter, GST_STATE_NULL); gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
gst_element_unlink (sgroup->outfilter, sgroup->outqueue); gst_element_unlink (sgroup->outfilter, sgroup->outqueue);
}
gst_element_set_state (sgroup->outqueue, GST_STATE_NULL); gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
gst_bin_remove (GST_BIN (ebin), sgroup->outqueue); gst_bin_remove (GST_BIN (ebin), sgroup->outqueue);