diff options
author | Sreerenj Balachandran <sreerenj.balachandran@intel.com> | 2013-04-23 19:13:23 +0300 |
---|---|---|
committer | Sreerenj Balachandran <sreerenj.balachandran@intel.com> | 2013-04-23 19:13:23 +0300 |
commit | b78d8b4e94350f08531e5fe010a123fb030ae716 (patch) | |
tree | c239688675ac2771af8151f7e0f40a7a5057f789 | |
parent | c5840ebbd9911348675f0c197566db27409c2124 (diff) |
-rw-r--r-- | gst/playback/gstplaybin2.c | 370 |
1 files changed, 320 insertions, 50 deletions
diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index 0d473879e..4eb150c2c 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -285,6 +285,18 @@ enum PLAYBIN_STREAM_LAST }; +static void velements_free (GList * list); + +/* structure to hold the video_decoder and video_sink factories + * together with the number of common caps features */ +typedef struct +{ + GstElementFactory *vdec; /* video decoder */ + GstElementFactory *vsink; /* video sink */ + guint n_comm_cf; /* number of common caps features */ + gboolean is_dirty; +} GstVideoElement; + /* a structure to hold the objects for decoding a uri and the subtitle uri */ struct _GstSourceGroup @@ -309,6 +321,8 @@ struct _GstSourceGroup GstElement *audio_sink; /* autoplugged audio and video sinks */ GstElement *video_sink; + GList *velements; /* a list of GstVideoElements */ + /* uridecodebins for uri and subtitle uri */ GstElement *uridecodebin; GstElement *suburidecodebin; @@ -1255,6 +1269,10 @@ free_group (GstPlayBin * playbin, GstSourceGroup * group) } group->video_sink = NULL; + if (group->velements) + velements_free (group->velements); + group->velements = NULL; + g_list_free (group->stream_changed_pending); group->stream_changed_pending = NULL; @@ -3235,6 +3253,163 @@ _factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps) return FALSE; } +static void +velements_free (GList * list) +{ + GList *l; + GstVideoElement *elm; + + for (l = list; l; l = l->next) { + elm = (GstVideoElement *) l->data; + gst_object_unref (elm->vdec); + gst_object_unref (elm->vsink); + g_slice_free (GstVideoElement, elm); + } + g_list_free (list); +} + +static gint +velement_compare (gconstpointer p1, gconstpointer p2) +{ + GstVideoElement *v1, *v2; + GstPluginFeature *fd1, *fd2, *fs1, *fs2; + gint diff, v1_rank, v2_rank; + + v1 = (GstVideoElement *) p1; + v2 = (GstVideoElement *) p2; + + fs1 = (GstPluginFeature *) v1->vsink; + fs2 = (GstPluginFeature *) v2->vsink; + fd1 = (GstPluginFeature *) v1->vdec; + fd2 = (GstPluginFeature *) v2->vdec; + + v1_rank = + gst_plugin_feature_get_rank (fd1) + gst_plugin_feature_get_rank (fs1); + v2_rank = + gst_plugin_feature_get_rank (fd2) + gst_plugin_feature_get_rank (fs2); + + /* comparison based on the rank */ + diff = v2_rank - v1_rank; + if (diff != 0) + return diff; + + /* comparison based on number of common caps features */ + diff = v2->n_comm_cf - v1->n_comm_cf; + if (diff != 0) + return diff; + + /* comparison based on the name of sink elements */ + return strcmp (GST_OBJECT_NAME (fs1), GST_OBJECT_NAME (fs2)); +} + +static GList * +create_velements_list (GList * dec_list, GList * sink_list) +{ + GstElementFactory *d_factory, *s_factory; + GstVideoElement *ve; + GList *dl, *sl; + GList *ve_list = NULL, *tmp = NULL; + + dl = dec_list; + sl = sink_list; + + /* create a list of video elements. Each element in the list + * is holding a video_decoder and a video_sink */ + for (; dl; dl = dl->next) { + d_factory = (GstElementFactory *) dl->data; + if (gst_element_factory_list_is_type (d_factory, + GST_ELEMENT_FACTORY_TYPE_DECODER)) { + + for (; sl; sl = sl->next) { + s_factory = (GstElementFactory *) sl->data; + + ve = g_slice_new (GstVideoElement); + ve->vdec = gst_object_ref (d_factory); + ve->vsink = gst_object_ref (s_factory); + ve_list = g_list_prepend (ve_list, ve); + } + sl = sink_list; + } + } + + tmp = ve_list; + + /* compute the number of common caps features */ + for (; tmp; tmp = tmp->next) { + GstVideoElement *velm; + GstElementFactory *dec, *sink; + const GList *d_templates, *s_templates; + GstStaticPadTemplate *d_templ = NULL, *s_templ = NULL, *tmp_templ; + GstCaps *d_tmpl_caps, *s_tmpl_caps; + GstCapsFeatures *d_features, *s_features; + guint d_caps_size, s_caps_size; + guint i, j, n_common = 0; + GList *walk; + + velm = (GstVideoElement *) tmp->data; + dec = (GstElementFactory *) velm->vdec; + sink = (GstElementFactory *) velm->vsink; + + d_templates = gst_element_factory_get_static_pad_templates (dec); + for (walk = (GList *) d_templates; walk; walk = g_list_next (walk)) { + tmp_templ = walk->data; + if (tmp_templ->direction == GST_PAD_SRC) + d_templ = tmp_templ; + else + continue; + } + s_templates = gst_element_factory_get_static_pad_templates (sink); + s_templ = s_templates->data; + + d_tmpl_caps = gst_static_caps_get (&d_templ->static_caps); + s_tmpl_caps = gst_static_caps_get (&s_templ->static_caps); + d_caps_size = gst_caps_get_size (d_tmpl_caps); + s_caps_size = gst_caps_get_size (s_tmpl_caps); + + for (i = 0; i < d_caps_size; i++) { + d_features = gst_caps_get_features ((const GstCaps *) d_tmpl_caps, i); + for (j = 0; j < s_caps_size; j++) { + s_features = gst_caps_get_features ((const GstCaps *) s_tmpl_caps, j); + if (gst_caps_features_is_equal (d_features, s_features)) + n_common++; + } + } + velm->n_comm_cf = n_common; + + gst_caps_unref (d_tmpl_caps); + gst_caps_unref (s_tmpl_caps); + } + + ve_list = g_list_sort (ve_list, (GCompareFunc) velement_compare); + return ve_list; +} + +static GList * +create_decoders_list (GList * mylist, GList * velements) +{ + GList *list = NULL; + GstElementFactory *factory; + GstVideoElement *ve; + + for (; mylist; mylist = mylist->next) { + factory = (GstElementFactory *) mylist->data; + /* if there are parsers, add them first */ + if (!gst_element_factory_list_is_type (factory, + GST_ELEMENT_FACTORY_TYPE_DECODER)) + list = g_list_prepend (list, factory); + } + + for (; velements; velements = velements->next) { + ve = (GstVideoElement *) velements->data; + if (!g_list_find (list, ve->vdec)) + list = g_list_prepend (list, ve->vdec); + } + + list = g_list_reverse (list); + + return list; +} + /* Called when we must provide a list of factories to plug to @pad with @caps. * We first check if we have a sink that can handle the format and if we do, we * return NULL, to expose the pad. If we have no sink (or the sink does not @@ -3247,6 +3422,7 @@ autoplug_factories_cb (GstElement * decodebin, GstPad * pad, GList *mylist, *tmp; GValueArray *result; gboolean unref_caps = FALSE; + gboolean need_video_dec_list = FALSE; if (!caps) { caps = gst_caps_new_any (); @@ -3254,7 +3430,6 @@ autoplug_factories_cb (GstElement * decodebin, GstPad * pad, } playbin = group->playbin; - GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT, group, GST_DEBUG_PAD_NAME (pad), caps); @@ -3269,6 +3444,48 @@ autoplug_factories_cb (GstElement * decodebin, GstPad * pad, GST_DEBUG_OBJECT (playbin, "found factories %p", mylist); GST_PLUGIN_FEATURE_LIST_DEBUG (mylist); + /* check whether the caps are asking for a list of video_decoders */ + tmp = mylist; + if (!gst_caps_is_any (caps)) { + for (; tmp; tmp = tmp->next) { + GstElementFactory *factory = (GstElementFactory *) tmp->data; + + if (gst_element_factory_list_is_type (factory, + GST_ELEMENT_FACTORY_TYPE_DECODER | + GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO | + GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) { + need_video_dec_list = TRUE; + break; + } + } + } + + if (need_video_dec_list && !group->velements) { + GList *video_sinks; + /* get a list of available video sink elements. The video_sink ref + * will get released once the grop->velements get freed */ + video_sinks = gst_element_factory_list_get_elements + (GST_ELEMENT_FACTORY_TYPE_SINK | + GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO | + GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE, GST_RANK_MARGINAL); + video_sinks = + g_list_sort (video_sinks, gst_plugin_feature_rank_compare_func); + + GST_SOURCE_GROUP_LOCK (group); + /* create the video element list */ + group->velements = create_velements_list (mylist, video_sinks); + GST_SOURCE_GROUP_UNLOCK (group); + + gst_plugin_feature_list_free (video_sinks); + } + + if (group->velements && need_video_dec_list) { + GST_SOURCE_GROUP_LOCK (group); + /* sort mylist based on the video element list priority */ + mylist = create_decoders_list (mylist, group->velements); + GST_SOURCE_GROUP_UNLOCK (group); + } + /* 2 additional elements for the already set audio/video sinks */ result = g_value_array_new (g_list_length (mylist) + 2); @@ -3454,6 +3671,7 @@ sink_accepts_caps (GstElement * sink, GstCaps * caps) return TRUE; } + static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw"); static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw"); @@ -3470,6 +3688,8 @@ autoplug_select_cb (GstElement * decodebin, GstPad * pad, const gchar *klass; GstPlaySinkType type; GstElement **sinkp; + GstVideoElement *ve = NULL; + GList *ve_list = NULL, *tmp = NULL; playbin = group->playbin; @@ -3490,62 +3710,112 @@ autoplug_select_cb (GstElement * decodebin, GstPad * pad, GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO); - /* If it is a decoder and we have a fixed sink for the media - * type it outputs, check that the decoder is compatible with this sink */ - if ((isvideodec && group->video_sink) || (isaudiodec && group->audio_sink)) { - gboolean compatible = TRUE; - GstPad *sinkpad; - GstCaps *caps; - GstElement *sink; + ve_list = group->velements; - if (isaudiodec) - sink = group->audio_sink; - else - sink = group->video_sink; - - if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) { - GstPlayFlags flags = gst_play_bin_get_flags (playbin); - GstCaps *raw_caps = - (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) : - gst_static_caps_get (&raw_video_caps); - - caps = gst_pad_query_caps (sinkpad, NULL); - - /* If the sink supports raw audio/video, we first check - * if the decoder could output any raw audio/video format - * and assume it is compatible with the sink then. We don't - * do a complete compatibility check here if converters - * are plugged between the decoder and the sink because - * the converters will convert between raw formats and - * even if the decoder format is not supported by the decoder - * a converter will convert it. - * - * We assume here that the converters can convert between - * any raw format. - */ - if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO) - && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec - && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO) - && gst_caps_can_intersect (caps, raw_caps))) { - compatible = gst_element_factory_can_src_any_caps (factory, raw_caps) - || gst_element_factory_can_src_any_caps (factory, caps); - } else { - compatible = gst_element_factory_can_src_any_caps (factory, caps); + do { + + if (!isvideodec && !isaudiodec) + return GST_AUTOPLUG_SELECT_TRY; + + /* if it is a decoder and we don't have a fixed sink, then find out + * the matching video_sink from GstVideoElements list */ + if (isvideodec && !group->video_sink && ve_list) { + tmp = group->velements; + for (; tmp; tmp = tmp->next) { + ve = (GstVideoElement *) tmp->data; + if (!ve->is_dirty && factory == ve->vdec) { + ve->is_dirty = 1; + break; + } } + GST_SOURCE_GROUP_LOCK (group); + if (ve && ve->vsink) + group->video_sink = + gst_element_factory_create (ve->vsink, "video-sink"); + GST_SOURCE_GROUP_UNLOCK (group); + } - gst_object_unref (sinkpad); - gst_caps_unref (caps); + /* If it is a decoder and we have a fixed sink for the media + * type it outputs, check that the decoder is compatible with this sink */ + if ((isvideodec && group->video_sink) || (isaudiodec + && group->audio_sink)) { + gboolean compatible = TRUE; + GstPad *sinkpad; + GstCaps *caps; + GstElement *sink; + + if (isaudiodec) + sink = group->audio_sink; + else + sink = group->video_sink; + + if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) { + GstPlayFlags flags = gst_play_bin_get_flags (playbin); + GstCaps *raw_caps = + (isaudiodec) ? gst_static_caps_get (&raw_audio_caps) : + gst_static_caps_get (&raw_video_caps); + + caps = gst_pad_query_caps (sinkpad, NULL); + + /* If the sink supports raw audio/video, we first check + * if the decoder could output any raw audio/video format + * and assume it is compatible with the sink then. We don't + * do a complete compatibility check here if converters + * are plugged between the decoder and the sink because + * the converters will convert between raw formats and + * even if the decoder format is not supported by the decoder + * a converter will convert it. + * + * We assume here that the converters can convert between + * any raw format. + */ + if ((isaudiodec && !(flags & GST_PLAY_FLAG_NATIVE_AUDIO) + && gst_caps_can_intersect (caps, raw_caps)) || (!isaudiodec + && !(flags & GST_PLAY_FLAG_NATIVE_VIDEO) + && gst_caps_can_intersect (caps, raw_caps))) { + compatible = + gst_element_factory_can_src_any_caps (factory, raw_caps) + || gst_element_factory_can_src_any_caps (factory, caps); + } else { + compatible = gst_element_factory_can_src_any_caps (factory, caps); + } + + gst_object_unref (sinkpad); + gst_caps_unref (caps); + } + + if (compatible) + break; + + GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink", + GST_OBJECT_NAME (factory)); + + if (!isvideodec) + return GST_AUTOPLUG_SELECT_SKIP; + + if (group->video_sink != playbin->video_sink) { + GST_SOURCE_GROUP_LOCK (group); + gst_element_set_state (group->video_sink, GST_STATE_NULL); + gst_object_unref (group->video_sink); + group->video_sink = NULL; + GST_SOURCE_GROUP_UNLOCK (group); + } else + return GST_AUTOPLUG_SELECT_SKIP; } - if (compatible) - return GST_AUTOPLUG_SELECT_TRY; + ve_list = ve_list->next; + } while (ve_list); - GST_DEBUG_OBJECT (playbin, "%s not compatible with the fixed sink", - GST_OBJECT_NAME (factory)); + /* unset all dirty flags */ + if (isvideodec) { + tmp = group->velements; + for (; tmp; tmp = tmp->next) { + ve = (GstVideoElement *) tmp->data; + ve->is_dirty = 1; + } + } - return GST_AUTOPLUG_SELECT_SKIP; - } else - return GST_AUTOPLUG_SELECT_TRY; + return GST_AUTOPLUG_SELECT_TRY; } /* it's a sink, see if an instance of it actually works */ |