(s) & GST_STREAM_TYPE_TEXT ? "text " : ""
-#if 0 /* AUTOPLUG DISABLED */
-static void avelements_free (gpointer data);
-static GSequence *avelements_create (GstPlayBin3 * playbin,
- gboolean isaudioelement);
-#endif
-
-/* The GstAudioVideoElement structure holding the audio/video decoder
- * and the audio/video sink factories together with field indicating
- * the number of common caps features */
-typedef struct
-{
- GstElementFactory *dec; /* audio:video decoder */
- GstElementFactory *sink; /* audio:video sink */
- guint n_comm_cf; /* number of common caps features */
-} GstAVElement;
-
/* a structure to hold information about a uridecodebin pad */
struct _SourcePad
{
gulong source_setup_id;
gulong about_to_finish_id;
-#if 0 /* AUTOPLUG DISABLED */
- gulong autoplug_factories_id;
- gulong autoplug_select_id;
- gulong autoplug_continue_id;
- gulong autoplug_query_id;
-#endif
-
gboolean stream_changed_pending;
/* Active stream collection */
gint shutdown;
gboolean async_pending; /* async-start has been emitted */
- GMutex elements_lock;
- guint32 elements_cookie;
- GList *elements; /* factories we can use for selecting elements */
-
gboolean have_selector; /* set to FALSE when we fail to create an
* input-selector, so that we only post a
* warning once */
GstElement *video_stream_combiner; /* configured video stream combiner, or NULL */
GstElement *text_stream_combiner; /* configured text stream combiner, or NULL */
- GSequence *aelements; /* a list of GstAVElements for audio stream */
- GSequence *velements; /* a list of GstAVElements for video stream */
-
guint64 ring_buffer_max_size; /* 0 means disabled */
gboolean is_live; /* Whether our current group is live */
LAST_SIGNAL
};
-#if 0 /* AUTOPLUG DISABLED */
-static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw(ANY)");
-static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw(ANY)");
-#endif
-
static void gst_play_bin3_finalize (GObject * object);
static void gst_play_bin3_set_property (GObject * object, guint prop_id,
gst_color_balance_value_changed (GST_COLOR_BALANCE (playbin), channel, value);
}
-#if 0 /* AUTOPLUG DISABLED */
-static gint
-compare_factories_func (gconstpointer p1, gconstpointer p2)
-{
- GstPluginFeature *f1, *f2;
- gboolean is_sink1, is_sink2;
- gboolean is_parser1, is_parser2;
-
- f1 = (GstPluginFeature *) p1;
- f2 = (GstPluginFeature *) p2;
-
- is_sink1 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f1),
- GST_ELEMENT_FACTORY_TYPE_SINK);
- is_sink2 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f2),
- GST_ELEMENT_FACTORY_TYPE_SINK);
- is_parser1 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f1),
- GST_ELEMENT_FACTORY_TYPE_PARSER);
- is_parser2 = gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (f2),
- GST_ELEMENT_FACTORY_TYPE_PARSER);
-
- /* First we want all sinks as we prefer a sink if it directly
- * supports the current caps */
- if (is_sink1 && !is_sink2)
- return -1;
- else if (!is_sink1 && is_sink2)
- return 1;
-
- /* Then we want all parsers as we always want to plug parsers
- * before decoders */
- if (is_parser1 && !is_parser2)
- return -1;
- else if (!is_parser1 && is_parser2)
- return 1;
-
- /* And if it's a both a parser or sink we first sort by rank
- * and then by factory name */
- return gst_plugin_feature_rank_compare_func (p1, p2);
-}
-
-/* Must be called with elements lock! */
-static void
-gst_play_bin3_update_elements_list (GstPlayBin3 * playbin)
-{
- GList *res, *tmp;
- guint cookie;
-
- cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
-
- if (!playbin->elements || playbin->elements_cookie != cookie) {
- if (playbin->elements)
- gst_plugin_feature_list_free (playbin->elements);
- res =
- gst_element_factory_list_get_elements
- (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
- tmp =
- gst_element_factory_list_get_elements
- (GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
- playbin->elements = g_list_concat (res, tmp);
- playbin->elements = g_list_sort (playbin->elements, compare_factories_func);
- }
-
- if (!playbin->aelements || playbin->elements_cookie != cookie) {
- if (playbin->aelements)
- g_sequence_free (playbin->aelements);
- playbin->aelements = avelements_create (playbin, TRUE);
- }
-
- if (!playbin->velements || playbin->elements_cookie != cookie) {
- if (playbin->velements)
- g_sequence_free (playbin->velements);
- playbin->velements = avelements_create (playbin, FALSE);
- }
-
- playbin->elements_cookie = cookie;
-}
-#endif
-
static void
gst_play_bin3_init (GstPlayBin3 * playbin)
{
init_group (playbin, &playbin->groups[0]);
init_group (playbin, &playbin->groups[1]);
- /* first filter out the interesting element factories */
- g_mutex_init (&playbin->elements_lock);
-
g_rec_mutex_init (&playbin->activation_lock);
/* add sink */
g_ptr_array_free (playbin->combiner[PLAYBIN_STREAM_TEXT].streams, TRUE);
g_ptr_array_free (playbin->combiner[PLAYBIN_STREAM_TEXT].inputpads, TRUE);
- if (playbin->elements)
- gst_plugin_feature_list_free (playbin->elements);
-
- if (playbin->aelements)
- g_sequence_free (playbin->aelements);
-
- if (playbin->velements)
- g_sequence_free (playbin->velements);
-
g_rec_mutex_clear (&playbin->activation_lock);
g_rec_mutex_clear (&playbin->lock);
g_mutex_clear (&playbin->buffering_post_lock);
g_mutex_clear (&playbin->dyn_lock);
- g_mutex_clear (&playbin->elements_lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
emit_about_to_finish (playbin);
}
-#if 0 /* AUTOPLUG DISABLED */
-/* Like gst_element_factory_can_sink_any_caps() but doesn't
- * allow ANY caps on the sinkpad template */
-static gboolean
-_factory_can_sink_caps (GstElementFactory * factory, GstCaps * caps)
-{
- const GList *templs;
-
- templs = gst_element_factory_get_static_pad_templates (factory);
-
- while (templs) {
- GstStaticPadTemplate *templ = (GstStaticPadTemplate *) templs->data;
-
- if (templ->direction == GST_PAD_SINK) {
- GstCaps *templcaps = gst_static_caps_get (&templ->static_caps);
-
- if (!gst_caps_is_any (templcaps)
- && gst_caps_is_subset (caps, templcaps)) {
- gst_caps_unref (templcaps);
- return TRUE;
- }
- gst_caps_unref (templcaps);
- }
- templs = g_list_next (templs);
- }
-
- return FALSE;
-}
-
-static void
-avelements_free (gpointer avelement)
-{
- GstAVElement *elm = (GstAVElement *) avelement;
-
- if (elm->dec)
- gst_object_unref (elm->dec);
- if (elm->sink)
- gst_object_unref (elm->sink);
- g_slice_free (GstAVElement, elm);
-}
-
-static gint
-avelement_compare_decoder (gconstpointer p1, gconstpointer p2,
- gpointer user_data)
-{
- GstAVElement *v1, *v2;
-
- v1 = (GstAVElement *) p1;
- v2 = (GstAVElement *) p2;
-
- return strcmp (GST_OBJECT_NAME (v1->dec), GST_OBJECT_NAME (v2->dec));
-}
-
-static gint
-avelement_lookup_decoder (gconstpointer p1, gconstpointer p2,
- gpointer user_data)
-{
- GstAVElement *v1;
- GstElementFactory *f2;
-
- v1 = (GstAVElement *) p1;
- f2 = (GstElementFactory *) p2;
-
- return strcmp (GST_OBJECT_NAME (v1->dec), GST_OBJECT_NAME (f2));
-}
-
-static gint
-avelement_compare (gconstpointer p1, gconstpointer p2)
-{
- GstAVElement *v1, *v2;
- GstPluginFeature *fd1, *fd2, *fs1, *fs2;
- gint64 diff, v1_rank, v2_rank;
-
- v1 = (GstAVElement *) p1;
- v2 = (GstAVElement *) p2;
-
- fd1 = (GstPluginFeature *) v1->dec;
- fd2 = (GstPluginFeature *) v2->dec;
-
- /* If both have a sink, we also compare their ranks */
- if (v1->sink && v2->sink) {
- fs1 = (GstPluginFeature *) v1->sink;
- fs2 = (GstPluginFeature *) v2->sink;
- v1_rank = (gint64) gst_plugin_feature_get_rank (fd1) *
- gst_plugin_feature_get_rank (fs1);
- v2_rank = (gint64) gst_plugin_feature_get_rank (fd2) *
- gst_plugin_feature_get_rank (fs2);
- } else {
- v1_rank = gst_plugin_feature_get_rank (fd1);
- v2_rank = gst_plugin_feature_get_rank (fd2);
- fs1 = fs2 = NULL;
- }
-
- /* comparison based on the rank */
- diff = v2_rank - v1_rank;
- if (diff < 0)
- return -1;
- else if (diff > 0)
- return 1;
-
- /* comparison based on number of common caps features */
- diff = v2->n_comm_cf - v1->n_comm_cf;
- if (diff != 0)
- return diff;
-
- if (fs1 && fs2) {
- /* comparison based on the name of sink elements */
- diff = strcmp (GST_OBJECT_NAME (fs1), GST_OBJECT_NAME (fs2));
- if (diff != 0)
- return diff;
- }
-
- /* comparison based on the name of decoder elements */
- return strcmp (GST_OBJECT_NAME (fd1), GST_OBJECT_NAME (fd2));
-}
-
-static GSequence *
-avelements_create (GstPlayBin3 * playbin, gboolean isaudioelement)
-{
- GstElementFactory *d_factory, *s_factory;
- GList *dec_list, *sink_list, *dl, *sl;
- GSequence *ave_seq = NULL;
- GstAVElement *ave;
- guint n_common_cf = 0;
-
- if (isaudioelement) {
- sink_list = gst_element_factory_list_get_elements
- (GST_ELEMENT_FACTORY_TYPE_SINK |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_MARGINAL);
- dec_list =
- gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_DECODER
- | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_MARGINAL);
- } else {
- sink_list = 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);
-
- dec_list =
- gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_DECODER
- | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE, GST_RANK_MARGINAL);
- }
-
- /* create a list of audio/video elements. Each element in the list
- * is holding an audio/video decoder and an audio/video sink in which
- * the decoders srcpad template caps and sink element's sinkpad template
- * caps are compatible */
- dl = dec_list;
- sl = sink_list;
-
- ave_seq = g_sequence_new ((GDestroyNotify) avelements_free);
-
- for (; dl; dl = dl->next) {
- d_factory = (GstElementFactory *) dl->data;
- for (; sl; sl = sl->next) {
- s_factory = (GstElementFactory *) sl->data;
-
- n_common_cf =
- gst_playback_utils_get_n_common_capsfeatures (d_factory, s_factory,
- gst_play_bin3_get_flags (playbin), isaudioelement);
- if (n_common_cf < 1)
- continue;
-
- ave = g_slice_new (GstAVElement);
- ave->dec = gst_object_ref (d_factory);
- ave->sink = gst_object_ref (s_factory);
- ave->n_comm_cf = n_common_cf;
- g_sequence_append (ave_seq, ave);
- }
- sl = sink_list;
- }
- g_sequence_sort (ave_seq, (GCompareDataFunc) avelement_compare_decoder, NULL);
-
- gst_plugin_feature_list_free (dec_list);
- gst_plugin_feature_list_free (sink_list);
-
- return ave_seq;
-}
-
-static gboolean
-avelement_iter_is_equal (GSequenceIter * iter, GstElementFactory * factory)
-{
- GstAVElement *ave;
-
- if (!iter)
- return FALSE;
-
- ave = g_sequence_get (iter);
- if (!ave)
- return FALSE;
-
- return strcmp (GST_OBJECT_NAME (ave->dec), GST_OBJECT_NAME (factory)) == 0;
-}
-
-static GList *
-create_decoders_list (GList * factory_list, GSequence * avelements)
-{
- GList *dec_list = NULL, *tmp;
- GList *ave_list = NULL;
- GList *ave_free_list = NULL;
- GstAVElement *ave, *best_ave;
-
- g_return_val_if_fail (factory_list != NULL, NULL);
- g_return_val_if_fail (avelements != NULL, NULL);
-
- for (tmp = factory_list; tmp; tmp = tmp->next) {
- GstElementFactory *factory = (GstElementFactory *) tmp->data;
-
- /* if there are parsers or sink elements, add them first */
- if (gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_PARSER) ||
- gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_SINK)) {
- dec_list = g_list_prepend (dec_list, gst_object_ref (factory));
- } else {
- GSequenceIter *seq_iter;
-
- seq_iter =
- g_sequence_lookup (avelements, factory,
- (GCompareDataFunc) avelement_lookup_decoder, NULL);
- if (!seq_iter) {
- GstAVElement *ave = g_slice_new0 (GstAVElement);
-
- ave->dec = factory;
- ave->sink = NULL;
- /* There's at least raw */
- ave->n_comm_cf = 1;
-
- ave_list = g_list_prepend (ave_list, ave);
-
- /* We need to free these later */
- ave_free_list = g_list_prepend (ave_free_list, ave);
- continue;
- }
-
- /* Go to first iter with that decoder */
- do {
- GSequenceIter *tmp_seq_iter;
-
- tmp_seq_iter = g_sequence_iter_prev (seq_iter);
- if (!avelement_iter_is_equal (tmp_seq_iter, factory))
- break;
- seq_iter = tmp_seq_iter;
- } while (!g_sequence_iter_is_begin (seq_iter));
-
- /* Get the best ranked GstAVElement for that factory */
- best_ave = NULL;
- while (!g_sequence_iter_is_end (seq_iter)
- && avelement_iter_is_equal (seq_iter, factory)) {
- ave = g_sequence_get (seq_iter);
-
- if (!best_ave || avelement_compare (ave, best_ave) < 0)
- best_ave = ave;
-
- seq_iter = g_sequence_iter_next (seq_iter);
- }
- ave_list = g_list_prepend (ave_list, best_ave);
- }
- }
-
- /* Sort all GstAVElements by their relative ranks and insert
- * into the decoders list */
- ave_list = g_list_sort (ave_list, (GCompareFunc) avelement_compare);
- for (tmp = ave_list; tmp; tmp = tmp->next) {
- ave = (GstAVElement *) tmp->data;
- dec_list = g_list_prepend (dec_list, gst_object_ref (ave->dec));
- }
- g_list_free (ave_list);
- gst_plugin_feature_list_free (factory_list);
-
- for (tmp = ave_free_list; tmp; tmp = tmp->next)
- g_slice_free (GstAVElement, tmp->data);
- g_list_free (ave_free_list);
-
- dec_list = g_list_reverse (dec_list);
-
- return dec_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
- * work), we return the list of elements that can connect. */
-static GValueArray *
-autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
- GstCaps * caps, GstSourceGroup * group)
-{
- GstPlayBin3 *playbin;
- GList *factory_list, *tmp;
- GValueArray *result;
- gboolean unref_caps = FALSE;
- gboolean isaudiodeclist = FALSE;
- gboolean isvideodeclist = FALSE;
-
- if (!caps) {
- caps = gst_caps_new_any ();
- unref_caps = TRUE;
- }
-
- playbin = group->playbin;
-
- GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
- group, GST_DEBUG_PAD_NAME (pad), caps);
-
- /* filter out the elements based on the caps. */
- g_mutex_lock (&playbin->elements_lock);
- gst_play_bin3_update_elements_list (playbin);
- factory_list =
- gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
- gst_caps_is_fixed (caps));
- g_mutex_unlock (&playbin->elements_lock);
-
- GST_DEBUG_OBJECT (playbin, "found factories %p", factory_list);
- GST_PLUGIN_FEATURE_LIST_DEBUG (factory_list);
-
- /* check whether the caps are asking for a list of audio/video decoders */
- tmp = factory_list;
- if (!gst_caps_is_any (caps)) {
- for (; tmp; tmp = tmp->next) {
- GstElementFactory *factory = (GstElementFactory *) tmp->data;
-
- isvideodeclist = gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_DECODER |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
- isaudiodeclist = gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_DECODER |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
-
- if (isaudiodeclist || isvideodeclist)
- break;
- }
- }
-
- if (isaudiodeclist || isvideodeclist) {
- GSequence **ave_list;
- if (isaudiodeclist)
- ave_list = &playbin->aelements;
- else
- ave_list = &playbin->velements;
-
- g_mutex_lock (&playbin->elements_lock);
- /* sort factory_list based on the GstAVElement list priority */
- factory_list = create_decoders_list (factory_list, *ave_list);
- g_mutex_unlock (&playbin->elements_lock);
- }
-
- /* 2 additional elements for the already set audio/video sinks */
- result = g_value_array_new (g_list_length (factory_list) + 2);
-
- /* Check if we already have an audio/video sink and if this is the case
- * put it as the first element of the array */
- if (group->audio_sink) {
- GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
-
- if (factory && _factory_can_sink_caps (factory, caps)) {
- GValue val = { 0, };
-
- g_value_init (&val, G_TYPE_OBJECT);
- g_value_set_object (&val, factory);
- result = g_value_array_append (result, &val);
- g_value_unset (&val);
- }
- }
-
- if (group->video_sink) {
- GstElementFactory *factory = gst_element_get_factory (group->video_sink);
-
- if (factory && _factory_can_sink_caps (factory, caps)) {
- GValue val = { 0, };
-
- g_value_init (&val, G_TYPE_OBJECT);
- g_value_set_object (&val, factory);
- result = g_value_array_append (result, &val);
- g_value_unset (&val);
- }
- }
-
- for (tmp = factory_list; tmp; tmp = tmp->next) {
- GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
- GValue val = { 0, };
-
- if (group->audio_sink && gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_SINK |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
- continue;
- }
- if (group->video_sink && gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
- | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
- continue;
- }
-
- g_value_init (&val, G_TYPE_OBJECT);
- g_value_set_object (&val, factory);
- g_value_array_append (result, &val);
- g_value_unset (&val);
- }
- gst_plugin_feature_list_free (factory_list);
-
- if (unref_caps)
- gst_caps_unref (caps);
-
- return result;
-}
-#endif
-
static GstBusSyncReply
activate_sink_bus_handler (GstBus * bus, GstMessage * msg,
GstPlayBin3 * playbin)
return ret;
}
-#if 0 /* AUTOPLUG DISABLED */
-/* autoplug-continue decides, if a pad has raw caps that can be exposed
- * directly or if further decoding is necessary. We use this to expose
- * supported subtitles directly */
-
-/* FIXME 0.11: Remove the checks for ANY caps, a sink should specify
- * explicitly the caps it supports and if it claims to support ANY
- * caps it really should support everything */
-static gboolean
-autoplug_continue_cb (GstElement * element, GstPad * pad, GstCaps * caps,
- GstSourceGroup * group)
-{
- gboolean ret = TRUE;
- GstPad *sinkpad = NULL;
- gboolean activated_sink;
-
- GST_SOURCE_GROUP_LOCK (group);
-
- if (group->text_sink &&
- activate_sink (group->playbin, group->text_sink, &activated_sink)) {
- sinkpad = gst_element_get_static_pad (group->text_sink, "sink");
- if (sinkpad) {
- GstCaps *sinkcaps;
-
- sinkcaps = gst_pad_query_caps (sinkpad, NULL);
- if (!gst_caps_is_any (sinkcaps))
- ret = !gst_pad_query_accept_caps (sinkpad, caps);
- gst_caps_unref (sinkcaps);
- gst_object_unref (sinkpad);
- }
- if (activated_sink)
- gst_element_set_state (group->text_sink, GST_STATE_NULL);
- } else {
- GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
- ret = !gst_caps_is_subset (caps, subcaps);
- gst_caps_unref (subcaps);
- }
- /* If autoplugging can stop don't do additional checks */
- if (!ret)
- goto done;
-
- if (group->audio_sink &&
- activate_sink (group->playbin, group->audio_sink, &activated_sink)) {
-
- sinkpad = gst_element_get_static_pad (group->audio_sink, "sink");
- if (sinkpad) {
- GstCaps *sinkcaps;
-
- sinkcaps = gst_pad_query_caps (sinkpad, NULL);
- if (!gst_caps_is_any (sinkcaps))
- ret = !gst_pad_query_accept_caps (sinkpad, caps);
- gst_caps_unref (sinkcaps);
- gst_object_unref (sinkpad);
- }
- if (activated_sink)
- gst_element_set_state (group->audio_sink, GST_STATE_NULL);
- }
- if (!ret)
- goto done;
-
- if (group->video_sink
- && activate_sink (group->playbin, group->video_sink, &activated_sink)) {
- sinkpad = gst_element_get_static_pad (group->video_sink, "sink");
- if (sinkpad) {
- GstCaps *sinkcaps;
-
- sinkcaps = gst_pad_query_caps (sinkpad, NULL);
- if (!gst_caps_is_any (sinkcaps))
- ret = !gst_pad_query_accept_caps (sinkpad, caps);
- gst_caps_unref (sinkcaps);
- gst_object_unref (sinkpad);
- }
- if (activated_sink)
- gst_element_set_state (group->video_sink, GST_STATE_NULL);
- }
-
-done:
- GST_SOURCE_GROUP_UNLOCK (group);
-
- GST_DEBUG_OBJECT (group->playbin,
- "continue autoplugging group %p for %s:%s, %" GST_PTR_FORMAT ": %d",
- group, GST_DEBUG_PAD_NAME (pad), caps, ret);
-
- return ret;
-}
-
-static gboolean
-sink_accepts_caps (GstPlayBin3 * playbin, GstElement * sink, GstCaps * caps)
-{
- GstPad *sinkpad;
-
- if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
- /* Got the sink pad, now let's see if the element actually does accept the
- * caps that we have */
- if (!gst_pad_query_accept_caps (sinkpad, caps)) {
- gst_object_unref (sinkpad);
- return FALSE;
- }
- gst_object_unref (sinkpad);
- }
-
- return TRUE;
-}
-
-/* We are asked to select an element. See if the next element to check
- * is a sink. If this is the case, we see if the sink works by setting it to
- * READY. If the sink works, we return SELECT_EXPOSE to make decodebin
- * expose the raw pad so that we can setup the mixers. */
-static GstAutoplugSelectResult
-autoplug_select_cb (GstElement * decodebin, GstPad * pad,
- GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
-{
- GstPlayBin3 *playbin;
- GstElement *element;
- const gchar *klass;
- GstPlaySinkType type;
- GstElement **sinkp;
- GList *ave_list = NULL, *l;
- GstAVElement *ave = NULL;
- GSequence *ave_seq = NULL;
- GSequenceIter *seq_iter;
-
- playbin = group->playbin;
-
- GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
- group, GST_DEBUG_PAD_NAME (pad), caps);
-
- GST_DEBUG_OBJECT (playbin, "checking factory %s", GST_OBJECT_NAME (factory));
-
- /* if it's not a sink, we make sure the element is compatible with
- * the fixed sink */
- if (!gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_SINK)) {
- gboolean isvideodec = gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_DECODER |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
- gboolean isaudiodec = gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_DECODER |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
-
- if (!isvideodec && !isaudiodec)
- return GST_AUTOPLUG_SELECT_TRY;
-
- GST_SOURCE_GROUP_LOCK (group);
- g_mutex_lock (&playbin->elements_lock);
-
- if (isaudiodec) {
- ave_seq = playbin->aelements;
- sinkp = &group->audio_sink;
- } else {
- ave_seq = playbin->velements;
- sinkp = &group->video_sink;
- }
-
- seq_iter =
- g_sequence_lookup (ave_seq, factory,
- (GCompareDataFunc) avelement_lookup_decoder, NULL);
- if (seq_iter) {
- /* Go to first iter with that decoder */
- do {
- GSequenceIter *tmp_seq_iter;
-
- tmp_seq_iter = g_sequence_iter_prev (seq_iter);
- if (!avelement_iter_is_equal (tmp_seq_iter, factory))
- break;
- seq_iter = tmp_seq_iter;
- } while (!g_sequence_iter_is_begin (seq_iter));
-
- while (!g_sequence_iter_is_end (seq_iter)
- && avelement_iter_is_equal (seq_iter, factory)) {
- ave = g_sequence_get (seq_iter);
- ave_list = g_list_prepend (ave_list, ave);
- seq_iter = g_sequence_iter_next (seq_iter);
- }
-
- /* Sort all GstAVElements by their relative ranks and insert
- * into the decoders list */
- ave_list = g_list_sort (ave_list, (GCompareFunc) avelement_compare);
- } else {
- ave_list = g_list_prepend (ave_list, NULL);
- }
-
- /* if it is a decoder and we don't have a fixed sink, then find out
- * the matching audio/video sink from GstAVElements list */
- for (l = ave_list; l; l = l->next) {
- gboolean created_sink = FALSE;
-
- ave = (GstAVElement *) l->data;
-
- if (((isaudiodec && !group->audio_sink) ||
- (isvideodec && !group->video_sink))) {
- if (ave && ave->sink) {
- GST_DEBUG_OBJECT (playbin,
- "Trying to create sink '%s' for decoder '%s'",
- gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (ave->sink)),
- gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
- if ((*sinkp = gst_element_factory_create (ave->sink, NULL)) == NULL) {
- GST_WARNING_OBJECT (playbin,
- "Could not create an element from %s",
- gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (ave->sink)));
- continue;
- } else {
- if (!activate_sink (playbin, *sinkp, NULL)) {
- gst_object_unref (*sinkp);
- *sinkp = NULL;
- GST_WARNING_OBJECT (playbin,
- "Could not activate sink %s",
- gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (ave->sink)));
- continue;
- }
- gst_object_ref_sink (*sinkp);
- created_sink = TRUE;
- }
- }
- }
-
- /* 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 ((isaudiodec && group->audio_sink) || (isvideodec
- && group->video_sink)) {
- gboolean compatible = FALSE;
- GstPad *sinkpad;
- GstCaps *caps;
- GstElement *sink;
-
- sink = *sinkp;
-
- if ((sinkpad = gst_element_get_static_pad (sink, "sink"))) {
- GstPlayFlags flags = gst_play_bin3_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 it is not compatible, either continue with the next possible
- * sink or if we have a fixed sink, skip the decoder */
- if (created_sink) {
- gst_element_set_state (*sinkp, GST_STATE_NULL);
- gst_object_unref (*sinkp);
- *sinkp = NULL;
- } else {
- g_mutex_unlock (&playbin->elements_lock);
- GST_SOURCE_GROUP_UNLOCK (group);
- return GST_AUTOPLUG_SELECT_SKIP;
- }
- }
- }
- g_list_free (ave_list);
- g_mutex_unlock (&playbin->elements_lock);
- GST_SOURCE_GROUP_UNLOCK (group);
- return GST_AUTOPLUG_SELECT_TRY;
- }
-
- /* it's a sink, see if an instance of it actually works */
- GST_DEBUG_OBJECT (playbin, "we found a sink '%s'", GST_OBJECT_NAME (factory));
-
- klass =
- gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
-
- /* figure out the klass */
- if (strstr (klass, "Audio")) {
- GST_DEBUG_OBJECT (playbin, "we found an audio sink");
- type = GST_PLAY_SINK_TYPE_AUDIO;
- sinkp = &group->audio_sink;
- } else if (strstr (klass, "Video")) {
- GST_DEBUG_OBJECT (playbin, "we found a video sink");
- type = GST_PLAY_SINK_TYPE_VIDEO;
- sinkp = &group->video_sink;
- } else {
- /* unknown klass, skip this element */
- GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
- return GST_AUTOPLUG_SELECT_SKIP;
- }
-
- /* if we are asked to do visualisations and it's an audio sink, skip the
- * element. We can only do visualisations with raw sinks */
- if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
- if (type == GST_PLAY_SINK_TYPE_AUDIO) {
- GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
- return GST_AUTOPLUG_SELECT_SKIP;
- }
- }
-
- /* now see if we already have a sink element */
- GST_SOURCE_GROUP_LOCK (group);
- if (*sinkp && GST_STATE (*sinkp) >= GST_STATE_READY) {
- GstElement *sink = gst_object_ref (*sinkp);
-
- if (sink_accepts_caps (playbin, sink, caps)) {
- GST_DEBUG_OBJECT (playbin,
- "Existing sink '%s' accepts caps: %" GST_PTR_FORMAT,
- GST_ELEMENT_NAME (sink), caps);
- gst_object_unref (sink);
- GST_SOURCE_GROUP_UNLOCK (group);
- return GST_AUTOPLUG_SELECT_EXPOSE;
- } else {
- GST_DEBUG_OBJECT (playbin,
- "Existing sink '%s' does not accept caps: %" GST_PTR_FORMAT,
- GST_ELEMENT_NAME (sink), caps);
- gst_object_unref (sink);
- GST_SOURCE_GROUP_UNLOCK (group);
- return GST_AUTOPLUG_SELECT_SKIP;
- }
- }
- GST_DEBUG_OBJECT (playbin, "we have no pending sink, try to create '%s'",
- gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
-
- if ((*sinkp = gst_element_factory_create (factory, NULL)) == NULL) {
- GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
- gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
- GST_SOURCE_GROUP_UNLOCK (group);
- return GST_AUTOPLUG_SELECT_SKIP;
- }
-
- element = *sinkp;
-
- if (!activate_sink (playbin, element, NULL)) {
- GST_WARNING_OBJECT (playbin, "Could not activate sink %s",
- gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
- *sinkp = NULL;
- gst_object_unref (element);
- GST_SOURCE_GROUP_UNLOCK (group);
- return GST_AUTOPLUG_SELECT_SKIP;
- }
-
- /* Check if the selected sink actually supports the
- * caps and can be set to READY*/
- if (!sink_accepts_caps (playbin, element, caps)) {
- *sinkp = NULL;
- gst_element_set_state (element, GST_STATE_NULL);
- gst_object_unref (element);
- GST_SOURCE_GROUP_UNLOCK (group);
- return GST_AUTOPLUG_SELECT_SKIP;
- }
-
- /* remember the sink in the group now, the element is floating, we take
- * ownership now
- *
- * store the sink in the group, we will configure it later when we
- * reconfigure the sink */
- GST_DEBUG_OBJECT (playbin, "remember sink");
- gst_object_ref_sink (element);
- GST_SOURCE_GROUP_UNLOCK (group);
-
- /* tell decodebin to expose the pad because we are going to use this
- * sink */
- GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
-
- return GST_AUTOPLUG_SELECT_EXPOSE;
-}
-
-#define GST_PLAY_BIN3_FILTER_CAPS(filter,caps) G_STMT_START { \
- if ((filter)) { \
- GstCaps *intersection = \
- gst_caps_intersect_full ((filter), (caps), GST_CAPS_INTERSECT_FIRST); \
- gst_caps_unref ((caps)); \
- (caps) = intersection; \
- } \
-} G_STMT_END
-
-static gboolean
-autoplug_query_caps (GstElement * uridecodebin, GstPad * pad,
- GstElement * element, GstQuery * query, GstSourceGroup * group)
-{
- GstCaps *filter, *result = NULL;
- GstElement *sink;
- GstPad *sinkpad = NULL;
- GstElementFactory *factory;
- GstElementFactoryListType factory_type;
- gboolean have_sink = FALSE;
-
- GST_SOURCE_GROUP_LOCK (group);
- gst_query_parse_caps (query, &filter);
-
- factory = gst_element_get_factory (element);
- if (!factory)
- goto done;
-
- if (gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
- factory_type =
- GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE;
-
- if ((sink = group->video_sink)) {
- sinkpad = gst_element_get_static_pad (sink, "sink");
- if (sinkpad) {
- GstCaps *sinkcaps;
-
- sinkcaps = gst_pad_query_caps (sinkpad, filter);
- if (!gst_caps_is_any (sinkcaps)) {
- if (!result)
- result = sinkcaps;
- else
- result = gst_caps_merge (result, sinkcaps);
- } else {
- gst_caps_unref (sinkcaps);
- }
- gst_object_unref (sinkpad);
- }
- have_sink = TRUE;
- }
- } else if (gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
- factory_type = GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO;
-
- if ((sink = group->audio_sink)) {
- sinkpad = gst_element_get_static_pad (sink, "sink");
- if (sinkpad) {
- GstCaps *sinkcaps;
-
- sinkcaps = gst_pad_query_caps (sinkpad, filter);
- if (!gst_caps_is_any (sinkcaps)) {
- if (!result)
- result = sinkcaps;
- else
- result = gst_caps_merge (result, sinkcaps);
- } else {
- gst_caps_unref (sinkcaps);
- }
- gst_object_unref (sinkpad);
- }
- have_sink = TRUE;
- }
- } else if (gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE)) {
- factory_type = GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE;
-
- if ((sink = group->playbin->text_sink)) {
- sinkpad = gst_element_get_static_pad (sink, "sink");
- if (sinkpad) {
- GstCaps *sinkcaps;
-
- sinkcaps = gst_pad_query_caps (sinkpad, filter);
- if (!gst_caps_is_any (sinkcaps)) {
- if (!result)
- result = sinkcaps;
- else
- result = gst_caps_merge (result, sinkcaps);
- } else {
- gst_caps_unref (sinkcaps);
- }
- gst_object_unref (sinkpad);
- }
- have_sink = TRUE;
- } else {
- GstCaps *subcaps = gst_subtitle_overlay_create_factory_caps ();
- GST_PLAY_BIN3_FILTER_CAPS (filter, subcaps);
- if (!result)
- result = subcaps;
- else
- result = gst_caps_merge (result, subcaps);
- }
- } else {
- goto done;
- }
-
- if (!have_sink) {
- GValueArray *factories;
- gint i, n;
-
- factories = autoplug_factories_cb (uridecodebin, pad, NULL, group);
- n = factories->n_values;
- for (i = 0; i < n; i++) {
- GValue *v = g_value_array_get_nth (factories, i);
- GstElementFactory *f = g_value_get_object (v);
- const GList *templates;
- const GList *l;
- GstCaps *templ_caps;
-
- if (!gst_element_factory_list_is_type (f, factory_type))
- continue;
-
- templates = gst_element_factory_get_static_pad_templates (f);
-
- for (l = templates; l; l = l->next) {
- templ_caps = gst_static_pad_template_get_caps (l->data);
-
- if (!gst_caps_is_any (templ_caps)) {
- GST_PLAY_BIN3_FILTER_CAPS (filter, templ_caps);
- if (!result)
- result = templ_caps;
- else
- result = gst_caps_merge (result, templ_caps);
- } else {
- gst_caps_unref (templ_caps);
- }
- }
- }
- g_value_array_free (factories);
- }
-
-done:
- GST_SOURCE_GROUP_UNLOCK (group);
-
- if (!result)
- return FALSE;
-
- /* Add the actual decoder/parser/etc caps at the very end to
- * make sure we don't cause empty caps to be returned, e.g.
- * if a parser asks us but a decoder is required after it
- * because no sink can handle the format directly.
- */
- {
- GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD (pad));
-
- if (target) {
- GstCaps *target_caps = gst_pad_get_pad_template_caps (target);
- GST_PLAY_BIN3_FILTER_CAPS (filter, target_caps);
- if (!gst_caps_is_any (target_caps))
- result = gst_caps_merge (result, target_caps);
- gst_object_unref (target);
- }
- }
-
-
- gst_query_set_caps_result (query, result);
- gst_caps_unref (result);
-
- return TRUE;
-}
-
-static gboolean
-autoplug_query_context (GstElement * uridecodebin, GstPad * pad,
- GstElement * element, GstQuery * query, GstSourceGroup * group)
-{
- GstElement *sink;
- GstPad *sinkpad = NULL;
- GstElementFactory *factory;
- gboolean res = FALSE;
-
- GST_SOURCE_GROUP_LOCK (group);
-
- factory = gst_element_get_factory (element);
- if (!factory)
- goto done;
-
- if (gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
- GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
- if ((sink = group->video_sink)) {
- sinkpad = gst_element_get_static_pad (sink, "sink");
- if (sinkpad) {
- res = gst_pad_query (sinkpad, query);
- gst_object_unref (sinkpad);
- }
- }
- } else if (gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
- if ((sink = group->audio_sink)) {
- sinkpad = gst_element_get_static_pad (sink, "sink");
- if (sinkpad) {
- res = gst_pad_query (sinkpad, query);
- gst_object_unref (sinkpad);
- }
- }
- } else if (gst_element_factory_list_is_type (factory,
- GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE)) {
- if ((sink = group->playbin->text_sink)) {
- sinkpad = gst_element_get_static_pad (sink, "sink");
- if (sinkpad) {
- res = gst_pad_query (sinkpad, query);
- gst_object_unref (sinkpad);
- }
- }
- } else {
- goto done;
- }
-
-done:
- GST_SOURCE_GROUP_UNLOCK (group);
-
- return res;
-}
-
-static gboolean
-autoplug_query_cb (GstElement * uridecodebin, GstPad * pad,
- GstElement * element, GstQuery * query, GstSourceGroup * group)
-{
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_CAPS:
- return autoplug_query_caps (uridecodebin, pad, element, query, group);
- case GST_QUERY_CONTEXT:
- return autoplug_query_context (uridecodebin, pad, element, query, group);
- default:
- return FALSE;
- }
-}
-#endif
-
/* must be called with the group lock */
static gboolean
group_set_locked_state_unlocked (GstPlayBin3 * playbin, GstSourceGroup * group,
REMOVE_SIGNAL (group->uridecodebin, group->select_stream_id);
REMOVE_SIGNAL (group->uridecodebin, group->source_setup_id);
REMOVE_SIGNAL (group->uridecodebin, group->about_to_finish_id);
-#if 0
- REMOVE_SIGNAL (group->urisourcebin, group->autoplug_factories_id);
- REMOVE_SIGNAL (group->urisourcebin, group->autoplug_select_id);
- REMOVE_SIGNAL (group->urisourcebin, group->autoplug_continue_id);
- REMOVE_SIGNAL (group->urisourcebin, group->autoplug_query_id);
-#endif
gst_element_set_state (uridecodebin, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (playbin), uridecodebin);
if (playbin->active_stream_types != playbin->selected_stream_types)
reconfigure_output (playbin);
-#if 0
- /* delete any custom sinks we might have.
- * conditionally set them to null if they aren't inside playsink yet */
- if (group->audio_sink) {
- if (!gst_object_has_as_ancestor (GST_OBJECT_CAST (group->audio_sink),
- GST_OBJECT_CAST (playbin->playsink))) {
- gst_element_set_state (group->audio_sink, GST_STATE_NULL);
- }
- gst_object_unref (group->audio_sink);
- }
- group->audio_sink = NULL;
- if (group->video_sink) {
- if (!gst_object_has_as_ancestor (GST_OBJECT_CAST (group->video_sink),
- GST_OBJECT_CAST (playbin->playsink))) {
- gst_element_set_state (group->video_sink, GST_STATE_NULL);
- }
- gst_object_unref (group->video_sink);
- }
- group->video_sink = NULL;
- if (group->text_sink) {
- if (!gst_object_has_as_ancestor (GST_OBJECT_CAST (group->text_sink),
- GST_OBJECT_CAST (playbin->playsink))) {
- gst_element_set_state (group->text_sink, GST_STATE_NULL);
- }
- gst_object_unref (group->text_sink);
- }
- group->text_sink = NULL;
-#endif
-
if (group->uridecodebin) {
REMOVE_SIGNAL (group->uridecodebin, group->select_stream_id);
REMOVE_SIGNAL (group->uridecodebin, group->source_setup_id);
REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
-#if 0
- REMOVE_SIGNAL (group->urisourcebin, group->autoplug_factories_id);
- REMOVE_SIGNAL (group->urisourcebin, group->autoplug_select_id);
- REMOVE_SIGNAL (group->urisourcebin, group->autoplug_continue_id);
- REMOVE_SIGNAL (group->urisourcebin, group->autoplug_query_id);
-#endif
}
GST_SOURCE_GROUP_UNLOCK (group);