From 2768ed75e099dac907528e13f4f7ef5a035b651a Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 3 Aug 2011 13:31:59 -0300 Subject: [PATCH] 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 --- gst/encoding/gstencodebin.c | 85 ++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 7 deletions(-) diff --git a/gst/encoding/gstencodebin.c b/gst/encoding/gstencodebin.c index e4a5833a50..062bae745f 100644 --- a/gst/encoding/gstencodebin.c +++ b/gst/encoding/gstencodebin.c @@ -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; }