Commit b9e73d05 authored by Edward Hervey's avatar Edward Hervey Committed by Edward Hervey
Browse files

playbin3: Use uridecodebin3 and link/reconfigure immediately

Apologies for the big commit, but it wasn't really possible to split it
in anything smaller.

* Switch to uridecodebin3 instead of managing urisourcebin and decodebin3
ourselves. No major architectural change with this.

* Reconfigure sinks/outputs when needed. This is possible thanks to the
various streams-related API. Instead of blocking new pads and waiting
for a (fake) no-more-pads to decide what to connect, we instead reconfigure
playsink and the combiners to whatever types are currently selected. All of
this is done in reconfigure_output().
  New pads are immediately connected to (combiners and) sinks, allowing
immediate negotiation and usage.

* Since elements are always connected, the "cached-duration" feature is gone
and queries can reach the target elements.

* The auto-plugging related code is currently disabled entirely until
we get the new proper API.

* Store collections at the GstSourceGroup level and not globally

* And more comments a bit everywhere

NOTE: gapless is still not functional, but this opens the way to be able
to handle it in a streams-aware fashion (where several uridecodebin3 can
be active at the same time).
parent ebf138e2
......@@ -20,7 +20,6 @@
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:element-playbin3
* @title: playbin3
......@@ -200,10 +199,6 @@
*
*/
/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
* with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
......@@ -243,26 +238,30 @@ typedef struct _GstPlayBin3 GstPlayBin3;
typedef struct _GstPlayBin3Class GstPlayBin3Class;
typedef struct _GstSourceGroup GstSourceGroup;
typedef struct _GstSourceCombine GstSourceCombine;
typedef struct _SourcePad SourcePad;
typedef GstCaps *(*SourceCombineGetMediaCapsFunc) (void);
/* has the info for a combiner and provides the link to the sink */
/* GstSourceCombine controls all the information regarding a certain
* media type.
*
* It can control a custom combiner element (by default none)
*/
struct _GstSourceCombine
{
const gchar *media_type; /* the media type for the combiner */
SourceCombineGetMediaCapsFunc get_media_caps; /* more complex caps for the combiner */
GstPlaySinkType type; /* the sink pad type of the combiner */
GstStreamType stream_type; /* The GstStreamType of the combiner */
GstElement *combiner; /* the combiner */
GPtrArray *channels;
GPtrArray *channels; /* Array of GstPad ? */
GstPad *srcpad; /* the source pad of the combiner */
GstPad *sinkpad; /* the sinkpad of the sink when the combiner
* is linked
*/
gulong block_id;
* is linked */
GPtrArray *streams; /* Sorted array of GstStream for the given type */
gint current_stream; /* Currently selected GstStream */
gboolean has_active_pad; /* stream combiner has the "active-pad" property */
......@@ -286,6 +285,14 @@ static const gchar *stream_type_names[] = {
"audio", "video", "text"
};
#define STREAM_TYPES_FORMAT "s%s%s"
#define STREAM_TYPES_ARGS(s) (s) & GST_STREAM_TYPE_AUDIO ? "audio " : "", \
(s) & GST_STREAM_TYPE_VIDEO ? "video " : "", \
(s) & GST_STREAM_TYPE_TEXT ? "text " : ""
#if 0 /* AUTOPLUG DISABLED */
static void avelements_free (gpointer data);
static GSequence *avelements_create (GstPlayBin3 * playbin,
......@@ -302,6 +309,13 @@ typedef struct
guint n_comm_cf; /* number of common caps features */
} GstAVElement;
/* a structure to hold information about a uridecodebin pad */
struct _SourcePad
{
GstPad *pad; /* The controlled pad */
gulong event_probe_id;
};
/* a structure to hold the objects for decoding a uri and the subtitle uri
*/
struct _GstSourceGroup
......@@ -316,12 +330,12 @@ struct _GstSourceGroup
/* properties */
gchar *uri;
gchar *suburi;
GValueArray *streaminfo;
/* urisourcebins for uri and subtitle uri */
/* FIXME: Just make this an array of uris */
GstElement *urisourcebin;
GstElement *suburisourcebin;
/* Bit-wise set of stream types we have requested from uridecodebin3 */
GstStreamType selected_stream_types;
/* uridecodebin to handle uri and suburi */
GstElement *uridecodebin;
/* Active sinks for each media type. These are initialized with
* the configured or currently used sink, otherwise
......@@ -331,13 +345,16 @@ struct _GstSourceGroup
GstElement *video_sink;
GstElement *text_sink;
gint pending;
gboolean sub_pending;
/* List of source pads */
GList *source_pads;
/* uridecodebin signals */
gulong pad_added_id;
gulong pad_removed_id;
gulong select_stream_id;
gulong source_setup_id;
gulong about_to_finish_id;
/* primary uri signals */
gulong urisrc_pad_added_id;
gulong urisrc_pad_removed_id;
gulong urisrc_source_setup_id;
#if 0 /* AUTOPLUG DISABLED */
gulong autoplug_factories_id;
gulong autoplug_select_id;
......@@ -345,17 +362,11 @@ struct _GstSourceGroup
gulong autoplug_query_id;
#endif
/* subtitle uri signals */
gulong sub_pad_added_id;
gulong sub_pad_removed_id;
#if 0 /* AUTOPLUG DISABLED */
gulong sub_autoplug_continue_id;
gulong sub_autoplug_query_id;
#endif
gboolean stream_changed_pending;
gulong block_id;
/* Active stream collection */
GstStreamCollection *collection;
gboolean stream_changed_pending;
/* buffering message stored for after switching */
GstMessage *pending_buffering_msg;
......@@ -370,20 +381,20 @@ struct _GstSourceGroup
#define GST_PLAY_BIN3_DYN_UNLOCK(bin) g_mutex_unlock (&(bin)->dyn_lock)
/* lock for shutdown */
#define GST_PLAY_BIN3_SHUTDOWN_LOCK(bin,label) \
G_STMT_START { \
if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
goto label; \
GST_PLAY_BIN3_DYN_LOCK (bin); \
if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
GST_PLAY_BIN3_DYN_UNLOCK (bin); \
goto label; \
} \
} G_STMT_END
#define GST_PLAY_BIN3_SHUTDOWN_LOCK(bin,label) \
G_STMT_START { \
if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) \
goto label; \
GST_PLAY_BIN3_DYN_LOCK (bin); \
if (G_UNLIKELY (g_atomic_int_get (&bin->shutdown))) { \
GST_PLAY_BIN3_DYN_UNLOCK (bin); \
goto label; \
} \
} G_STMT_END
/* unlock for shutdown */
#define GST_PLAY_BIN3_SHUTDOWN_UNLOCK(bin) \
GST_PLAY_BIN3_DYN_UNLOCK (bin); \
#define GST_PLAY_BIN3_SHUTDOWN_UNLOCK(bin) \
GST_PLAY_BIN3_DYN_UNLOCK (bin); \
/**
* GstPlayBin3:
......@@ -401,24 +412,20 @@ struct _GstPlayBin3
GstSourceGroup *curr_group; /* pointer to the currently playing group */
GstSourceGroup *next_group; /* pointer to the next group */
/* combiners for different streams */
/* Array of GstPad controlled by each combiner */
GPtrArray *channels[PLAYBIN_STREAM_LAST]; /* links to combiner pads */
/* combiners for different streams */
GstSourceCombine combiner[PLAYBIN_STREAM_LAST];
/* A global decodebin3 that's used to actually do decoding */
gboolean decodebin_active;
GstElement *decodebin;
/* Bit-wise set of stream types we have
* requested from decodebin vs stream types
* decodebin has provided */
/* Bit-wise set of stream types we have requested from uridecodebin3.
* Calculated as the combination of the 'selected_stream_types' of
* each sourcegroup */
GstStreamType selected_stream_types;
GstStreamType active_stream_types;
/* Decodebin signals */
gulong db_pad_added_id;
gulong db_pad_removed_id;
gulong db_drained_id;
gulong db_select_stream_id;
/* Bit-wise set of configured output stream types (i.e. active
playsink inputs and combiners) */
GstStreamType active_stream_types;
/* properties */
guint64 connection_speed; /* connection speed in bits/sec (0 = unknown) */
......@@ -477,9 +484,6 @@ struct _GstPlayBin3
GSequence *velements; /* a list of GstAVElements for video stream */
guint64 ring_buffer_max_size; /* 0 means disabled */
/* Active stream collection */
GstStreamCollection *collection;
};
struct _GstPlayBin3Class
......@@ -585,28 +589,27 @@ static gboolean gst_play_bin3_send_event (GstElement * element,
static GstSample *gst_play_bin3_convert_sample (GstPlayBin3 * playbin,
GstCaps * caps);
static GstStateChangeReturn setup_next_source (GstPlayBin3 * playbin,
GstState target);
static GstStateChangeReturn setup_next_source (GstPlayBin3 * playbin);
static void no_more_pads (GstPlayBin3 * playbin);
static void reconfigure_output (GstPlayBin3 * playbin);
static void pad_removed_cb (GstElement * decodebin, GstPad * pad,
GstPlayBin3 * playbin);
GstSourceGroup * group);
static gint select_stream_cb (GstElement * decodebin,
GstStreamCollection * collection, GstStream * stream,
GstPlayBin3 * playbin);
GstSourceGroup * group);
static void do_stream_selection (GstPlayBin3 * playbin);
static void do_stream_selection (GstPlayBin3 * playbin, GstSourceGroup * group);
static GstElementClass *parent_class;
static guint gst_play_bin3_signals[LAST_SIGNAL] = { 0 };
#define REMOVE_SIGNAL(obj,id) \
if (id) { \
g_signal_handler_disconnect (obj, id); \
id = 0; \
}
#define REMOVE_SIGNAL(obj,id) \
if (id) { \
g_signal_handler_disconnect (obj, id); \
id = 0; \
}
static void gst_play_bin3_overlay_init (gpointer g_iface,
gpointer g_iface_data);
......@@ -1072,35 +1075,38 @@ init_combiners (GstPlayBin3 * playbin)
playbin->combiner[PLAYBIN_STREAM_AUDIO].media_type = "audio";
playbin->combiner[PLAYBIN_STREAM_AUDIO].type = GST_PLAY_SINK_TYPE_AUDIO;
playbin->combiner[PLAYBIN_STREAM_AUDIO].stream_type = GST_STREAM_TYPE_AUDIO;
playbin->combiner[PLAYBIN_STREAM_AUDIO].channels = playbin->channels[0];
playbin->combiner[PLAYBIN_STREAM_AUDIO].streams =
g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
playbin->combiner[PLAYBIN_STREAM_AUDIO].current_stream = -1;
playbin->combiner[PLAYBIN_STREAM_VIDEO].media_type = "video";
playbin->combiner[PLAYBIN_STREAM_VIDEO].type = GST_PLAY_SINK_TYPE_VIDEO;
playbin->combiner[PLAYBIN_STREAM_VIDEO].stream_type = GST_STREAM_TYPE_VIDEO;
playbin->combiner[PLAYBIN_STREAM_VIDEO].channels = playbin->channels[1];
playbin->combiner[PLAYBIN_STREAM_VIDEO].streams =
g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
playbin->combiner[PLAYBIN_STREAM_VIDEO].current_stream = -1;
playbin->combiner[PLAYBIN_STREAM_TEXT].media_type = "text";
playbin->combiner[PLAYBIN_STREAM_TEXT].get_media_caps =
gst_subtitle_overlay_create_factory_caps;
playbin->combiner[PLAYBIN_STREAM_TEXT].type = GST_PLAY_SINK_TYPE_TEXT;
playbin->combiner[PLAYBIN_STREAM_TEXT].stream_type = GST_STREAM_TYPE_TEXT;
playbin->combiner[PLAYBIN_STREAM_TEXT].channels = playbin->channels[2];
playbin->combiner[PLAYBIN_STREAM_TEXT].streams =
g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
playbin->combiner[PLAYBIN_STREAM_TEXT].current_stream = -1;
}
/* Update the combiner information to be in sync with the current collection */
/* Update the combiner information to be in sync with the current collection
*
* FIXME : "current" collection doesn't mean anything until we have a "combined"
* collection of all groups */
static void
update_combiner_info (GstPlayBin3 * playbin)
update_combiner_info (GstPlayBin3 * playbin, GstStreamCollection * collection)
{
guint i, len;
if (playbin->collection == NULL)
if (collection == NULL)
return;
GST_DEBUG_OBJECT (playbin, "Updating combiner info");
......@@ -1111,18 +1117,14 @@ update_combiner_info (GstPlayBin3 * playbin)
g_ptr_array_free (playbin->combiner[PLAYBIN_STREAM_TEXT].streams, TRUE);
playbin->combiner[PLAYBIN_STREAM_AUDIO].streams =
g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
playbin->combiner[PLAYBIN_STREAM_AUDIO].current_stream = -1;
playbin->combiner[PLAYBIN_STREAM_VIDEO].streams =
g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
playbin->combiner[PLAYBIN_STREAM_VIDEO].current_stream = -1;
playbin->combiner[PLAYBIN_STREAM_TEXT].streams =
g_ptr_array_new_with_free_func ((GDestroyNotify) gst_object_unref);
playbin->combiner[PLAYBIN_STREAM_TEXT].current_stream = -1;
len = gst_stream_collection_get_size (playbin->collection);
len = gst_stream_collection_get_size (collection);
for (i = 0; i < len; i++) {
GstStream *stream =
gst_stream_collection_get_stream (playbin->collection, i);
GstStream *stream = gst_stream_collection_get_stream (collection, i);
GstStreamType stype = gst_stream_get_stream_type (stream);
if (stype & GST_STREAM_TYPE_AUDIO) {
......@@ -1145,41 +1147,6 @@ update_combiner_info (GstPlayBin3 * playbin)
playbin->combiner[PLAYBIN_STREAM_TEXT].streams->len);
}
/* Set the given stream as the selected stream */
static void
set_selected_stream (GstPlayBin3 * playbin, GstStream * stream)
{
GstSourceCombine *combine = NULL;
GstStreamType stype = gst_stream_get_stream_type (stream);
if (stype & GST_STREAM_TYPE_AUDIO)
combine = &playbin->combiner[PLAYBIN_STREAM_AUDIO];
else if (stype & GST_STREAM_TYPE_VIDEO)
combine = &playbin->combiner[PLAYBIN_STREAM_VIDEO];
else if (stype & GST_STREAM_TYPE_TEXT)
combine = &playbin->combiner[PLAYBIN_STREAM_TEXT];
if (combine) {
if (combine->combiner == NULL) {
guint i, len;
GST_DEBUG_OBJECT (playbin, "Called for %s (%p)",
gst_stream_get_stream_id (stream), combine->combiner);
combine->current_stream = -1;
len = combine->streams->len;
for (i = 0; i < len; i++) {
GstStream *cand = g_ptr_array_index (combine->streams, i);
if (cand == stream) {
GST_DEBUG_OBJECT (playbin, "Setting current to %d", i);
combine->current_stream = i;
break;
}
}
}
}
}
static void
init_group (GstPlayBin3 * playbin, GstSourceGroup * group)
{
......@@ -1203,6 +1170,8 @@ free_group (GstPlayBin3 * playbin, GstSourceGroup * group)
gst_message_unref (group->pending_buffering_msg);
group->pending_buffering_msg = NULL;
gst_object_replace ((GstObject **) & group->collection, NULL);
gst_object_replace ((GstObject **) & group->audio_sink, NULL);
gst_object_replace ((GstObject **) & group->video_sink, NULL);
gst_object_replace ((GstObject **) & group->text_sink, NULL);
......@@ -1400,9 +1369,6 @@ gst_play_bin3_finalize (GObject * object)
g_ptr_array_free (playbin->combiner[PLAYBIN_STREAM_VIDEO].streams, TRUE);
g_ptr_array_free (playbin->combiner[PLAYBIN_STREAM_TEXT].streams, TRUE);
if (playbin->decodebin)
gst_object_unref (playbin->decodebin);
if (playbin->elements)
gst_plugin_feature_list_free (playbin->elements);
......@@ -1412,9 +1378,6 @@ gst_play_bin3_finalize (GObject * object)
if (playbin->velements)
g_sequence_free (playbin->velements);
if (playbin->collection)
gst_object_unref (playbin->collection);
g_rec_mutex_clear (&playbin->lock);
g_mutex_clear (&playbin->dyn_lock);
g_mutex_clear (&playbin->elements_lock);
......@@ -1545,43 +1508,6 @@ gst_play_bin3_convert_sample (GstPlayBin3 * playbin, GstCaps * caps)
return gst_play_sink_convert_sample (playbin->playsink, caps);
}
/* Returns current stream number, or -1 if none has been selected yet */
static int
get_current_stream_number (GstPlayBin3 * playbin, GstSourceCombine * combine,
GPtrArray * channels)
{
/* Internal API cleanup would make this easier... */
int i;
GstPad *pad, *current;
GstObject *combiner = NULL;
int ret = -1;
if (!combine->has_active_pad) {
GST_WARNING_OBJECT (playbin,
"combiner doesn't have the \"active-pad\" property");
return ret;
}
for (i = 0; i < channels->len; i++) {
pad = g_ptr_array_index (channels, i);
if ((combiner = gst_pad_get_parent (pad))) {
g_object_get (combiner, "active-pad", &current, NULL);
gst_object_unref (combiner);
if (pad == current) {
gst_object_unref (current);
ret = i;
break;
}
if (current)
gst_object_unref (current);
}
}
return ret;
}
static gboolean
gst_play_bin3_send_custom_event (GstObject * combiner, const gchar * event_name)
{
......@@ -1628,7 +1554,7 @@ gst_play_bin3_set_current_stream (GstPlayBin3 * playbin,
if (combine->combiner == NULL) {
/* FIXME: Check that the current_value is within range */
*current_value = stream;
do_stream_selection (playbin);
do_stream_selection (playbin, playbin->curr_group);
GST_PLAY_BIN3_UNLOCK (playbin);
return TRUE;
}
......@@ -1718,35 +1644,6 @@ gst_play_bin3_set_current_text_stream (GstPlayBin3 * playbin, gint stream)
&playbin->current_text, stream, &playbin->text_pending_flush_finish);
}
static void
source_combine_remove_pads (GstPlayBin3 * playbin, GstSourceCombine * combine)
{
if (combine->sinkpad) {
GST_LOG_OBJECT (playbin, "unlinking from sink");
gst_pad_unlink (combine->srcpad, combine->sinkpad);
/* release back */
GST_LOG_OBJECT (playbin, "release sink pad");
gst_play_sink_release_pad (playbin->playsink, combine->sinkpad);
gst_object_unref (combine->sinkpad);
combine->sinkpad = NULL;
}
gst_object_unref (combine->srcpad);
combine->srcpad = NULL;
}
static GstPadProbeReturn
block_serialized_data_cb (GstPad * pad, GstPadProbeInfo * info,
gpointer user_data)
{
if (GST_IS_EVENT (info->data) && !GST_EVENT_IS_SERIALIZED (info->data)) {
GST_DEBUG_OBJECT (pad, "Letting non-serialized event %s pass",
GST_EVENT_TYPE_NAME (info->data));
return GST_PAD_PROBE_PASS;
}
return GST_PAD_PROBE_OK;
}
static void
gst_play_bin3_set_sink (GstPlayBin3 * playbin, GstPlaySinkType type,
......@@ -1810,8 +1707,8 @@ gst_play_bin3_set_property (GObject * object, guint prop_id,
gst_play_bin3_set_flags (playbin, g_value_get_flags (value));
if (playbin->curr_group) {
GST_SOURCE_GROUP_LOCK (playbin->curr_group);
if (playbin->curr_group->urisourcebin) {
g_object_set (playbin->curr_group->urisourcebin, "download",
if (playbin->curr_group->uridecodebin) {
g_object_set (playbin->curr_group->uridecodebin, "download",
(g_value_get_flags (value) & GST_PLAY_FLAG_DOWNLOAD) != 0, NULL);
}
GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
......@@ -1885,8 +1782,8 @@ gst_play_bin3_set_property (GObject * object, guint prop_id,
playbin->ring_buffer_max_size = g_value_get_uint64 (value);
if (playbin->curr_group) {
GST_SOURCE_GROUP_LOCK (playbin->curr_group);
if (playbin->curr_group->urisourcebin) {
g_object_set (playbin->curr_group->urisourcebin,
if (playbin->curr_group->uridecodebin) {
g_object_set (playbin->curr_group->uridecodebin,
"ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
}
GST_SOURCE_GROUP_UNLOCK (playbin->curr_group);
......@@ -2130,17 +2027,16 @@ get_combiner_stream_id (GstPlayBin3 * playbin, GstSourceCombine * combine,
static GList *
extend_list_of_streams (GstPlayBin3 * playbin, GstStreamType stype,
GList * list)
GList * list, GstStreamCollection * collection)
{
GList *tmp, *res;
gint i, nb;
res = list;
nb = gst_stream_collection_get_size (playbin->collection);
nb = gst_stream_collection_get_size (collection);
for (i = 0; i < nb; i++) {
GstStream *stream =
gst_stream_collection_get_stream (playbin->collection, i);
GstStream *stream = gst_stream_collection_get_stream (collection, i);
GstStreamType curtype = gst_stream_get_stream_type (stream);
if (stype == curtype) {
gboolean already_there = FALSE;
......@@ -2163,7 +2059,8 @@ extend_list_of_streams (GstPlayBin3 * playbin, GstStreamType stype,
}
static GstEvent *
update_select_streams_event (GstPlayBin3 * playbin, GstEvent * event)
update_select_streams_event (GstPlayBin3 * playbin, GstEvent * event,
GstSourceGroup * group)
{
GList *streams = NULL;
GList *to_use;
......@@ -2177,13 +2074,21 @@ update_select_streams_event (GstPlayBin3 * playbin, GstEvent * event)
return event;
}
if (!group->collection) {
GST_DEBUG_OBJECT (playbin,
"No stream collection for group, no need to modify SELECT_STREAMS event");
return event;
}
gst_event_parse_select_streams (event, &streams);
to_use = g_list_copy_deep (streams, (GCopyFunc) g_strdup, NULL);
/* For each combiner, we want to add all streams of that type to the
* selection */
if (playbin->audio_stream_combiner) {
to_use = extend_list_of_streams (playbin, GST_STREAM_TYPE_AUDIO, to_use);
to_use =
extend_list_of_streams (playbin, GST_STREAM_TYPE_AUDIO, to_use,
group->collection);
combine_id =
get_combiner_stream_id (playbin,
&playbin->combiner[PLAYBIN_STREAM_AUDIO], streams);
......@@ -2191,7 +2096,9 @@ update_select_streams_event (GstPlayBin3 * playbin, GstEvent * event)
gst_play_bin3_set_current_audio_stream (playbin, combine_id);
}
if (playbin->video_stream_combiner) {
to_use = extend_list_of_streams (playbin, GST_STREAM_TYPE_VIDEO, to_use);
to_use =
extend_list_of_streams (playbin, GST_STREAM_TYPE_VIDEO, to_use,
group->collection);
combine_id =
get_combiner_stream_id (playbin,
&playbin->combiner[PLAYBIN_STREAM_VIDEO], streams);
......@@ -2199,7 +2106,9 @@ update_select_streams_event (GstPlayBin3 * playbin, GstEvent * event)
gst_play_bin3_set_current_video_stream (playbin, combine_id);
}
if (playbin->text_stream_combiner) {
to_use = extend_list_of_streams (playbin, GST_STREAM_TYPE_TEXT, to_use);
to_use =
extend_list_of_streams (playbin, GST_STREAM_TYPE_TEXT, to_use,
group->collection);
combine_id =
get_combiner_stream_id (playbin,
&playbin->combiner[PLAYBIN_STREAM_TEXT], streams);
......@@ -2218,6 +2127,82 @@ update_select_streams_event (GstPlayBin3 * playbin, GstEvent * event)
return event;
}
/* Returns TRUE if the given list of streams belongs to the stream collection */
static gboolean
gst_streams_belong_to_collection (GList * streams,
GstStreamCollection * collection)
{
GList *tmp;
guint i, nb;
if (streams == NULL || collection == NULL)
return FALSE;
nb = gst_stream_collection_get_size (collection);
if (nb == 0)
return FALSE;
for (tmp = streams; tmp; tmp = tmp->next) {
const gchar *cand = (const gchar *) tmp->data;
gboolean found = FALSE;
for (i = 0; i < nb; i++) {
GstStream *stream = gst_stream_collection_get_stream (collection, i);
if (!g_strcmp0 (cand, gst_stream_get_stream_id (stream))) {
found = TRUE;
break;
}
}
if (!found)
return FALSE;
}
return TRUE;
}
static GstSourceGroup *
get_source_group_for_streams (GstPlayBin3 * playbin, GstEvent * event)
{
GList *streams;
GstSourceGroup *res = NULL;
gst_event_parse_select_streams (event, &streams);
if (playbin->curr_group->collection &&
gst_streams_belong_to_collection (streams,
playbin->curr_group->collection))
res = playbin->curr_group;
else if (playbin->next_group->collection &&
gst_streams_belong_to_collection (streams,
playbin->next_group->collection))
res = playbin->next_group;
g_list_free_full (streams, g_free);
return res;