encodebin: Select muxer further

Sort muxers based on their caps and ranking before iterating to
find one that fits the profile.

Sorting is done by putting the elements that have a pad template
that can produce the exact caps that is on the profile. For example:
when asking for "video/quicktime, variant=iso", muxers that
have this exact caps on their pad templates will be put first on
the list than ones that have only "video/quicktime".

https://bugzilla.gnome.org/show_bug.cgi?id=651496
This commit is contained in:
Thiago Santos 2011-08-03 13:31:59 -03:00
parent de4fc848fa
commit 2768ed75e0

View file

@ -1479,17 +1479,59 @@ cleanup:
}
static gboolean
_factory_can_sink_caps (GstElementFactory * factory, const GstCaps * caps)
_gst_caps_match_foreach (GQuark field_id, const GValue * value, gpointer data)
{
GstStructure *structure = data;
const GValue *other_value = gst_structure_id_get_value (structure, field_id);
if (G_UNLIKELY (other_value == NULL))
return FALSE;
if (gst_value_compare (value, other_value) == GST_VALUE_EQUAL) {
return TRUE;
}
return FALSE;
}
/*
* checks that there is at least one structure on caps_a that has
* all its fields exactly the same as one structure on caps_b
*/
static gboolean
_gst_caps_match (const GstCaps * caps_a, const GstCaps * caps_b)
{
gint i, j;
gboolean res = FALSE;
for (i = 0; i < gst_caps_get_size (caps_a); i++) {
GstStructure *structure_a = gst_caps_get_structure (caps_a, i);
for (j = 0; j < gst_caps_get_size (caps_b); j++) {
GstStructure *structure_b = gst_caps_get_structure (caps_b, j);
res = gst_structure_foreach (structure_a, _gst_caps_match_foreach,
structure_b);
if (res)
goto end;
}
}
end:
return res;
}
static gboolean
_factory_can_handle_caps (GstElementFactory * factory, const GstCaps * caps,
GstPadDirection dir, gboolean exact)
{
GList *templates = factory->staticpadtemplates;
while (templates) {
GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
if (template->direction == GST_PAD_SINK) {
if (template->direction == dir) {
GstCaps *tmp = gst_static_caps_get (&template->static_caps);
if (gst_caps_can_intersect (tmp, caps)) {
if ((exact && _gst_caps_match (caps, tmp)) ||
(!exact && gst_caps_can_intersect (tmp, caps))) {
gst_caps_unref (tmp);
return TRUE;
}
@ -1540,6 +1582,31 @@ beach:
return formatter;
}
static gint
compare_elements (gconstpointer a, gconstpointer b, gpointer udata)
{
GstCaps *caps = udata;
GstElementFactory *fac_a = (GstElementFactory *) a;
GstElementFactory *fac_b = (GstElementFactory *) b;
/* FIXME not quite sure this is the best algorithm to order the elements
* Some caps similarity comparison algorithm would fit better than going
* boolean (equals/not equals).
*/
gboolean equals_a = _factory_can_handle_caps (fac_a, caps, GST_PAD_SRC, TRUE);
gboolean equals_b = _factory_can_handle_caps (fac_b, caps, GST_PAD_SRC, TRUE);
if (equals_a == equals_b) {
return gst_plugin_feature_get_rank ((GstPluginFeature *) fac_b) -
gst_plugin_feature_get_rank ((GstPluginFeature *) fac_a);
} else if (equals_a) {
return -1;
} else if (equals_b) {
return 1;
}
return 0;
}
static inline GstElement *
_get_muxer (GstEncodeBin * ebin)
{
@ -1562,6 +1629,10 @@ _get_muxer (GstEncodeBin * ebin)
gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
TRUE);
muxers = g_list_sort_with_data (muxers, compare_elements, (gpointer) format);
formatters =
g_list_sort_with_data (formatters, compare_elements, (gpointer) format);
muxers = g_list_concat (muxers, formatters);
if (muxers == NULL)
@ -1582,10 +1653,10 @@ _get_muxer (GstEncodeBin * ebin)
for (tmp = profiles; tmp; tmp = tmp->next) {
GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
if (!_factory_can_sink_caps (muxerfact,
gst_encoding_profile_get_format (sprof))) {
GST_DEBUG ("Skipping muxer because it can't sink caps %" GST_PTR_FORMAT,
gst_encoding_profile_get_format (sprof));
if (!_factory_can_handle_caps (muxerfact,
gst_encoding_profile_get_format (sprof), GST_PAD_SINK, FALSE)) {
GST_DEBUG ("Skipping muxer because it can't sink caps %"
GST_PTR_FORMAT, gst_encoding_profile_get_format (sprof));
cansinkstreams = FALSE;
break;
}