summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Hervey <edward@centricular.com>2017-11-09 11:17:13 +0100
committerEdward Hervey <bilboed@bilboed.com>2018-02-10 12:24:09 +0100
commitb9e73d057572d4ba2584aa65b488e8b31b2e1017 (patch)
tree85125acac501ed944cbc92774313cb16ffd4c632
parentebf138e29ec848507b654f53070c076f61014385 (diff)
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).
-rw-r--r--gst/playback/gstplaybin3.c1589
1 files changed, 647 insertions, 942 deletions
diff --git a/gst/playback/gstplaybin3.c b/gst/playback/gstplaybin3.c
index 2a8528fee..de479ea70 100644
--- a/gst/playback/gstplaybin3.c
+++ b/gst/playback/gstplaybin3.c
@@ -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;
+}
+
+static GstStreamType
+get_stream_type_for_event (GstStreamCollection * collection, GstEvent * event)
+{
+ GList *stream_list = NULL;
+ GList *tmp;
+ GstStreamType res = 0;
+ guint i, len;
+
+ gst_event_parse_select_streams (event, &stream_list);
+ len = gst_stream_collection_get_size (collection);
+ for (tmp = stream_list; tmp; tmp = tmp->next) {
+ gchar *stid = (gchar *) tmp->data;
+
+ for (i = 0; i < len; i++) {
+ GstStream *stream = gst_stream_collection_get_stream (collection, i);
+ if (!g_strcmp0 (stid, gst_stream_get_stream_id (stream))) {
+ res |= gst_stream_get_stream_type (stream);
+ }
+ }
+ }
+ g_list_free_full (stream_list, g_free);
+
+ return res;
+}
+
static gboolean
gst_play_bin3_send_event (GstElement * element, GstEvent * event)
{
@@ -2225,6 +2210,7 @@ gst_play_bin3_send_event (GstElement * element, GstEvent * event)
if (GST_EVENT_TYPE (event) == GST_EVENT_SELECT_STREAMS) {
gboolean res;
+ GstSourceGroup *group;
GST_PLAY_BIN3_LOCK (playbin);
GST_LOG_OBJECT (playbin,
@@ -2232,14 +2218,32 @@ gst_play_bin3_send_event (GstElement * element, GstEvent * event)
/* This is probably already false, but it doesn't hurt to be sure */
playbin->do_stream_selections = FALSE;
+ group = get_source_group_for_streams (playbin, event);
+ if (group == NULL) {
+ GST_WARNING_OBJECT (playbin,
+ "Can't figure out to which uridecodebin the select-streams event should be sent to");
+ GST_PLAY_BIN3_UNLOCK (playbin);
+ return FALSE;
+ }
+
/* If we have custom combiners, we need to extend the selection with
* the list of all streams for that given type since we will be handling
* the selection with that combiner */
- event = update_select_streams_event (playbin, event);
+ event = update_select_streams_event (playbin, event, group);
+
+ if (group->collection) {
+ group->selected_stream_types =
+ get_stream_type_for_event (group->collection, event);
+ playbin->selected_stream_types =
+ playbin->groups[0].selected_stream_types | playbin->
+ groups[1].selected_stream_types;
+ if (playbin->active_stream_types != playbin->selected_stream_types)
+ reconfigure_output (playbin);
+ }
- /* Send this event directly to decodebin, so it works even
- * if decodebin didn't add any pads yet */
- res = gst_element_send_event (playbin->decodebin, event);
+ /* Send this event directly to uridecodebin, so it works even
+ * if uridecodebin didn't add any pads yet */
+ res = gst_element_send_event (group->uridecodebin, event);
GST_PLAY_BIN3_UNLOCK (playbin);
return res;
@@ -2263,7 +2267,7 @@ gst_play_bin3_send_event (GstElement * element, GstEvent * event)
/* Called with playbin lock held */
static void
-do_stream_selection (GstPlayBin3 * playbin)
+do_stream_selection (GstPlayBin3 * playbin, GstSourceGroup * group)
{
GstStreamCollection *collection;
guint i, nb_streams;
@@ -2271,7 +2275,10 @@ do_stream_selection (GstPlayBin3 * playbin)
gint nb_video = 0, nb_audio = 0, nb_text = 0;
GstStreamType chosen_stream_types = 0;
- collection = playbin->collection;
+ if (group == NULL)
+ return;
+
+ collection = group->collection;
if (collection == NULL) {
GST_LOG_OBJECT (playbin, "No stream collection. Not doing stream-select");
return;
@@ -2282,6 +2289,9 @@ do_stream_selection (GstPlayBin3 * playbin)
GST_INFO_OBJECT (playbin, "Empty collection received! Ignoring");
}
+ GST_DEBUG_OBJECT (playbin, "Doing selection on collection with %d streams",
+ nb_streams);
+
/* Iterate the collection and choose the streams that match
* either the current-* setting, or all streams of a type if there's
* a combiner for that type */
@@ -2292,6 +2302,8 @@ do_stream_selection (GstPlayBin3 * playbin)
gint pb_stream_type = -1;
gboolean select_this = FALSE;
+ GST_LOG_OBJECT (playbin, "Looking at stream #%d : %s", i, stream_id);
+
if (stream_type & GST_STREAM_TYPE_AUDIO) {
pb_stream_type = PLAYBIN_STREAM_AUDIO;
/* Select the stream if it's the current one or if there's a custom selector */
@@ -2332,11 +2344,36 @@ do_stream_selection (GstPlayBin3 * playbin)
}
if (streams) {
- GstEvent *ev = gst_event_new_select_streams (streams);
- gst_element_send_event (playbin->decodebin, ev);
+ if (group->uridecodebin) {
+ GstEvent *ev = gst_event_new_select_streams (streams);
+ gst_element_send_event (group->uridecodebin, ev);
+ }
g_list_free (streams);
}
- playbin->selected_stream_types = chosen_stream_types;
+
+ group->selected_stream_types = chosen_stream_types;
+ /* Update global selected_stream_types */
+ playbin->selected_stream_types =
+ playbin->groups[0].selected_stream_types | playbin->
+ groups[1].selected_stream_types;
+ if (playbin->active_stream_types != playbin->selected_stream_types)
+ reconfigure_output (playbin);
+}
+
+/* Return the GstSourceGroup to which this element belongs
+ * Can be NULL (if it belongs to playsink for example) */
+static GstSourceGroup *
+find_source_group_owner (GstPlayBin3 * playbin, GstObject * element)
+{
+ if (playbin->curr_group->uridecodebin
+ && gst_object_has_as_ancestor (element,
+ GST_OBJECT_CAST (playbin->curr_group->uridecodebin)))
+ return playbin->curr_group;
+ if (playbin->next_group->uridecodebin
+ && gst_object_has_as_ancestor (element,
+ GST_OBJECT_CAST (playbin->next_group->uridecodebin)))
+ return playbin->next_group;
+ return NULL;
}
static void
@@ -2389,67 +2426,33 @@ gst_play_bin3_handle_message (GstBin * bin, GstMessage * msg)
#endif
if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_STREAM_COLLECTION) {
GstStreamCollection *collection = NULL;
- GstObject *src = GST_MESSAGE_SRC (msg);
- gboolean pstate = playbin->do_stream_selections;
gst_message_parse_stream_collection (msg, &collection);
if (collection) {
+ gboolean pstate = playbin->do_stream_selections;
+ GstSourceGroup *target_group = NULL;
+
GST_PLAY_BIN3_LOCK (playbin);
GST_DEBUG_OBJECT (playbin,
- "STREAM_COLLECTION: Got a collection from %" GST_PTR_FORMAT, src);
- gst_object_replace ((GstObject **) & playbin->collection,
- (GstObject *) collection);
- update_combiner_info (playbin);
+ "STREAM_COLLECTION: Got a collection from %" GST_PTR_FORMAT,
+ msg->src);
+ target_group = find_source_group_owner (playbin, msg->src);
+ if (target_group)
+ gst_object_replace ((GstObject **) & target_group->collection,
+ (GstObject *) collection);
+ /* FIXME: Only do the following if it's the current group? */
+ if (target_group == playbin->curr_group)
+ update_combiner_info (playbin, target_group->collection);
if (pstate)
playbin->do_stream_selections = FALSE;
- do_stream_selection (playbin);
+ do_stream_selection (playbin, target_group);
if (pstate)
playbin->do_stream_selections = TRUE;
GST_PLAY_BIN3_UNLOCK (playbin);
gst_object_unref (collection);
}
- } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_STREAMS_SELECTED) {
- GstStreamCollection *collection = NULL;
- GstObject *src = GST_MESSAGE_SRC (msg);
- GstStreamType chosen_stream_types = 0;
- gboolean reconfigure_playsink = FALSE;
-
- gst_message_parse_streams_selected (msg, &collection);
- if (collection) {
- guint i, len;
- GST_PLAY_BIN3_LOCK (playbin);
- GST_DEBUG_OBJECT (playbin,
- "STREAMS_SELECTED: Got a collection from %" GST_PTR_FORMAT, src);
- gst_object_replace ((GstObject **) & playbin->collection,
- (GstObject *) collection);
- update_combiner_info (playbin);
- len = gst_message_streams_selected_get_size (msg);
- for (i = 0; i < len; i++) {
- GstStream *stream;
-
- stream = gst_message_streams_selected_get_stream (msg, i);
- set_selected_stream (playbin, stream);
- chosen_stream_types |= gst_stream_get_stream_type (stream);
- gst_object_unref (stream);
- }
-
- if (playbin->selected_stream_types != chosen_stream_types) {
- GST_DEBUG_OBJECT (playbin, "Chosen stream types are changed");
- reconfigure_playsink = TRUE;
- }
- playbin->selected_stream_types = chosen_stream_types;
- GST_PLAY_BIN3_UNLOCK (playbin);
-
- gst_object_unref (collection);
-
- if (reconfigure_playsink &&
- (playbin->selected_stream_types & ~playbin->active_stream_types &
- (GST_STREAM_TYPE_VIDEO | GST_STREAM_TYPE_AUDIO)) == 0) {
- no_more_pads_cb (playbin->decodebin, playbin);
- }
- }
}
if (msg)
@@ -2617,11 +2620,25 @@ update_video_multiview_caps (GstPlayBin3 * playbin, GstCaps * caps)
return out_caps;
}
+static SourcePad *
+find_source_pad (GstSourceGroup * group, GstPad * target)
+{
+ GList *tmp;
+
+ for (tmp = group->source_pads; tmp; tmp = tmp->next) {
+ SourcePad *res = (SourcePad *) tmp->data;
+ if (res->pad == target)
+ return res;
+ }
+ return NULL;
+}
+
static GstPadProbeReturn
_decodebin_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer udata)
{
GstPadProbeReturn ret = GST_PAD_PROBE_OK;
- GstPlayBin3 *playbin = (GstPlayBin3 *) udata;
+ GstSourceGroup *group = (GstSourceGroup *) udata;
+ GstPlayBin3 *playbin = group->playbin;
GstEvent *event = GST_PAD_PROBE_INFO_DATA (info);
switch (GST_EVENT_TYPE (event)) {
@@ -2652,20 +2669,219 @@ _decodebin_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer udata)
return ret;
}
+static void
+control_source_pad (GstSourceGroup * group, GstPad * pad)
+{
+ SourcePad *sourcepad = g_slice_new0 (SourcePad);
+
+ sourcepad->pad = pad;
+ sourcepad->event_probe_id =
+ gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+ _decodebin_event_probe, group, NULL);
+ group->source_pads = g_list_append (group->source_pads, sourcepad);
+}
+
+static void
+remove_combiner (GstPlayBin3 * playbin, GstSourceCombine * combine)
+{
+ gint n;
+
+ if (combine->combiner == NULL) {
+ GST_DEBUG_OBJECT (playbin, "No combiner element to remove");
+ return;
+ }
+
+ /* Go over all sink pads and release them ! */
+ for (n = 0; n < combine->channels->len; n++) {
+ GstPad *sinkpad = g_ptr_array_index (combine->channels, n);
+
+ gst_element_release_request_pad (combine->combiner, sinkpad);
+ gst_object_unref (sinkpad);
+ }
+ g_ptr_array_set_size (combine->channels, 0);
+
+ gst_element_set_state (combine->combiner, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN_CAST (playbin), combine->combiner);
+ combine->combiner = NULL;
+
+}
+
+/* Create the combiner element if needed for the given combine */
+static void
+create_combiner (GstPlayBin3 * playbin, GstSourceCombine * combine)
+{
+ GstElement *custom_combiner = NULL;
+
+ if (combine->combiner) {
+ GST_WARNING_OBJECT (playbin, "Combiner element already exists!");
+ return;
+ }
+
+ if (combine->stream_type == GST_STREAM_TYPE_VIDEO)
+ custom_combiner = playbin->video_stream_combiner;
+ else if (combine->stream_type == GST_STREAM_TYPE_AUDIO)
+ custom_combiner = playbin->audio_stream_combiner;
+ else if (combine->stream_type == GST_STREAM_TYPE_TEXT)
+ custom_combiner = playbin->text_stream_combiner;
+
+ combine->combiner = custom_combiner;
+
+ if (!combine->combiner) {
+ GST_DEBUG_OBJECT (playbin, "No custom combiner requested");
+ return;
+ }
+
+ combine->srcpad = gst_element_get_static_pad (combine->combiner, "src");
+
+ combine->has_active_pad =
+ g_object_class_find_property (G_OBJECT_GET_CLASS (combine->combiner),
+ "active-pad") != NULL;
+
+ if (combine->has_active_pad)
+ g_signal_connect (combine->combiner, "notify::active-pad",
+ G_CALLBACK (combiner_active_pad_changed), playbin);
+
+ GST_DEBUG_OBJECT (playbin, "adding new stream combiner %" GST_PTR_FORMAT,
+ combine->combiner);
+ gst_bin_add (GST_BIN_CAST (playbin), combine->combiner);
+ gst_element_sync_state_with_parent (combine->combiner);
+}
+
+static gboolean
+combiner_control_pad (GstPlayBin3 * playbin, GstSourceCombine * combine,
+ GstPad * srcpad)
+{
+ GstPadLinkReturn res;
+
+ GST_DEBUG_OBJECT (playbin, "srcpad %" GST_PTR_FORMAT, srcpad);
+
+ if (combine->combiner) {
+ GstPad *sinkpad =
+ gst_element_get_request_pad (combine->combiner, "sink_%u");
+
+ if (sinkpad == NULL)
+ goto request_pad_failed;
+
+ GST_DEBUG_OBJECT (playbin, "Got new combiner pad %" GST_PTR_FORMAT,
+ sinkpad);
+
+ /* find out which properties the sink pad supports */
+ combine->has_always_ok =
+ g_object_class_find_property (G_OBJECT_GET_CLASS (sinkpad),
+ "always-ok") != NULL;
+
+ /* store the pad in the array */
+ GST_DEBUG_OBJECT (playbin, "pad %" GST_PTR_FORMAT " added to array",
+ sinkpad);
+ g_ptr_array_add (combine->channels, sinkpad);
+
+ res = gst_pad_link (srcpad, sinkpad);
+ if (GST_PAD_LINK_FAILED (res))
+ goto failed_combiner_link;
+
+ GST_DEBUG_OBJECT (playbin,
+ "linked pad %" GST_PTR_FORMAT " to combiner %" GST_PTR_FORMAT, srcpad,
+ combine->combiner);
+
+ } else {
+ GST_LOG_OBJECT (playbin, "combine->sinkpad:%" GST_PTR_FORMAT,
+ combine->sinkpad);
+ g_assert (combine->sinkpad != NULL);
+ /* Connect directly to playsink */
+ if (gst_pad_is_linked (combine->sinkpad))
+ goto sinkpad_already_linked;
+
+ GST_DEBUG_OBJECT (playbin, "Linking new pad straight to playsink");
+ res = gst_pad_link (srcpad, combine->sinkpad);
+
+ if (res != GST_PAD_LINK_OK)
+ goto failed_sinkpad_link;
+ }
+
+ return TRUE;
+
+ /* Failure cases */
+request_pad_failed:
+ GST_ELEMENT_ERROR (playbin, CORE, PAD,
+ ("Internal playbin error."),
+ ("Failed to get request pad from combiner %p.", combine->combiner));
+ return FALSE;
+
+
+sinkpad_already_linked:
+ GST_ELEMENT_ERROR (playbin, CORE, PAD,
+ ("Internal playbin error."), ("playsink pad already used !"));
+ return FALSE;
+
+failed_sinkpad_link:
+ GST_ELEMENT_ERROR (playbin, CORE, PAD,
+ ("Internal playbin error."),
+ ("Failed to link pad to sink. Error %d", res));
+ return FALSE;
+
+failed_combiner_link:
+ GST_ELEMENT_ERROR (playbin, CORE, PAD,
+ ("Internal playbin error."),
+ ("Failed to link pad to combiner. Error %d", res));
+ return FALSE;
+}
+
+static void
+combiner_release_pad (GstPlayBin3 * playbin, GstSourceCombine * combine,
+ GstPad * pad)
+{
+ if (combine->combiner) {
+ GstPad *peer = gst_pad_get_peer (pad);
+
+ if (peer) {
+ GST_DEBUG_OBJECT (playbin, "Removing combiner pad %" GST_PTR_FORMAT,
+ peer);
+ g_ptr_array_remove (combine->channels, peer);
+
+ gst_element_release_request_pad (combine->combiner, peer);
+ gst_object_unref (peer);
+ }
+ } else {
+ /* Release direct link if present */
+ if (combine->sinkpad) {
+ GST_DEBUG_OBJECT (playbin, "Unlinking pad from playsink sinkpad");
+ gst_pad_unlink (pad, combine->sinkpad);
+ }
+ }
+}
+
+/* Call after pad was unlinked from (potential) combiner */
+static void
+release_source_pad (GstPlayBin3 * playbin, GstSourceGroup * group, GstPad * pad)
+{
+ SourcePad *sourcepad;
+
+ sourcepad = find_source_pad (group, pad);
+ if (!sourcepad) {
+ GST_DEBUG_OBJECT (playbin, "Not a pad controlled by us ?");
+ return;
+ }
+
+ if (sourcepad->event_probe_id) {
+ gst_pad_remove_probe (pad, sourcepad->event_probe_id);
+ sourcepad->event_probe_id = 0;
+ }
+
+ /* Remove from list of controlled pads and check again for EOS status */
+ group->source_pads = g_list_remove (group->source_pads, sourcepad);
+ g_slice_free (SourcePad, sourcepad);
+}
+
/* this function is called when a new pad is added to decodebin. We check the
* type of the pad and add it to the combiner element
*/
static void
-pad_added_cb (GstElement * decodebin, GstPad * pad, GstPlayBin3 * playbin)
+pad_added_cb (GstElement * uridecodebin, GstPad * pad, GstSourceGroup * group)
{
- GstPad *sinkpad;
- GstPadLinkReturn res;
GstSourceCombine *combine = NULL;
- GstStreamType stream_type;
gint pb_stream_type = -1;
- GstElement *custom_combiner = NULL;
- gulong event_probe_handler;
gchar *pad_name;
+ GstPlayBin3 *playbin = group->playbin;
GST_PLAY_BIN3_SHUTDOWN_LOCK (playbin, shutdown);
@@ -2677,17 +2893,11 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstPlayBin3 * playbin)
/* major type of the pad, this determines the combiner to use,
try exact match first */
if (g_str_has_prefix (pad_name, "video")) {
- stream_type = GST_STREAM_TYPE_VIDEO;
pb_stream_type = PLAYBIN_STREAM_VIDEO;
- custom_combiner = playbin->video_stream_combiner;
} else if (g_str_has_prefix (pad_name, "audio")) {
- stream_type = GST_STREAM_TYPE_AUDIO;
pb_stream_type = PLAYBIN_STREAM_AUDIO;
- custom_combiner = playbin->audio_stream_combiner;
} else if (g_str_has_prefix (pad_name, "text")) {
- stream_type = GST_STREAM_TYPE_TEXT;
pb_stream_type = PLAYBIN_STREAM_TEXT;
- custom_combiner = playbin->text_stream_combiner;
}
g_free (pad_name);
@@ -2701,105 +2911,12 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstPlayBin3 * playbin)
combine = &playbin->combiner[pb_stream_type];
- if (custom_combiner && combine->combiner == NULL) {
- combine->combiner = custom_combiner;
- /* find out which properties the stream combiner supports */
- combine->has_active_pad =
- g_object_class_find_property (G_OBJECT_GET_CLASS (combine->combiner),
- "active-pad") != NULL;
+ combiner_control_pad (playbin, combine, pad);
- if (combine->has_active_pad)
- g_signal_connect (combine->combiner, "notify::active-pad",
- G_CALLBACK (combiner_active_pad_changed), playbin);
-
- GST_DEBUG_OBJECT (playbin, "adding new stream combiner %p",
- combine->combiner);
- gst_element_set_state (combine->combiner, GST_STATE_PAUSED);
- gst_bin_add (GST_BIN_CAST (playbin), combine->combiner);
- }
+ control_source_pad (group, pad);
GST_PLAY_BIN3_SHUTDOWN_UNLOCK (playbin);
- if (combine->srcpad == NULL) {
- if (combine->combiner) {
- /* save source pad of the combiner */
- combine->srcpad = gst_element_get_static_pad (combine->combiner, "src");
- } else {
- /* no combiner, use the pad as the source pad then */
- combine->srcpad = gst_object_ref (pad);
- }
-
- /* block the combiner srcpad. It's possible that multiple source elements
- * pushing data into the combiners before we have a chance to collect all
- * streams and connect the sinks, resulting in not-linked errors. After we
- * configure the sinks we will unblock them all. */
- GST_DEBUG_OBJECT (playbin, "blocking %" GST_PTR_FORMAT, combine->srcpad);
- combine->block_id =
- gst_pad_add_probe (combine->srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
- block_serialized_data_cb, NULL, NULL);
- }
-
- /* get sinkpad for the new stream */
- if (combine->combiner) {
- if ((sinkpad = gst_element_get_request_pad (combine->combiner, "sink_%u"))) {
- GST_DEBUG_OBJECT (playbin, "got pad %s:%s from combiner",
- GST_DEBUG_PAD_NAME (sinkpad));
-
- /* find out which properties the sink pad supports */
- combine->has_always_ok =
- g_object_class_find_property (G_OBJECT_GET_CLASS (sinkpad),
- "always-ok") != NULL;
-
- /* store the combiner for the pad */
- g_object_set_data (G_OBJECT (sinkpad), "playbin.combine", combine);
-
- /* store the pad in the array */
- GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
- g_ptr_array_add (combine->channels, sinkpad);
-
- res = gst_pad_link (pad, sinkpad);
- if (GST_PAD_LINK_FAILED (res))
- goto link_failed;
-
- /* store combiner pad so we can release it */
- g_object_set_data (G_OBJECT (pad), "playbin.sinkpad", sinkpad);
-
- GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to combiner %p",
- GST_DEBUG_PAD_NAME (pad), combine->combiner);
- } else {
- goto request_pad_failed;
- }
- } else {
- /* no combiner, don't configure anything, we'll link the new pad directly to
- * the sink. */
- sinkpad = NULL;
-
- /* store the combiner for the pad */
- g_object_set_data (G_OBJECT (pad), "playbin.combine", combine);
- }
-
- event_probe_handler =
- gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
- _decodebin_event_probe, playbin, NULL);
- g_object_set_data (G_OBJECT (pad), "playbin.event_probe_id",
- ULONG_TO_POINTER (event_probe_handler));
-
- playbin->active_stream_types |= stream_type;
-
- /* If we're expecting either audio or video,
- * wait for them to appear before configuring playsink */
- if ((playbin->active_stream_types & GST_STREAM_TYPE_TEXT) &&
- !(playbin->active_stream_types & GST_STREAM_TYPE_VIDEO)) {
- GST_LOG_OBJECT (playbin, "Have text stream but no video yet, Wating");
- } else if ((playbin->selected_stream_types & ~playbin->active_stream_types &
- (GST_STREAM_TYPE_VIDEO | GST_STREAM_TYPE_AUDIO))
- == 0) {
- no_more_pads (playbin);
- } else {
- GST_LOG_OBJECT (playbin, "Active stream types 0x%x, want 0x%x. Waiting",
- playbin->active_stream_types, playbin->selected_stream_types);
- }
-
return;
/* ERRORS */
@@ -2807,18 +2924,6 @@ unknown_type:
GST_DEBUG_OBJECT (playbin, "Ignoring pad with unknown type");
return;
-link_failed:
- {
- GST_ERROR_OBJECT (playbin,
- "failed to link pad %s:%s to combiner, reason %s (%d)",
- GST_DEBUG_PAD_NAME (pad), gst_pad_link_get_name (res), res);
- return;
- }
-request_pad_failed:
- GST_ELEMENT_ERROR (playbin, CORE, PAD,
- ("Internal playbin error."),
- ("Failed to get request pad from combiner %p.", combine->combiner));
- return;
shutdown:
{
GST_DEBUG ("ignoring, we are shutting down. Pad will be left unlinked");
@@ -2830,109 +2935,40 @@ shutdown:
/* called when a pad is removed from the decodebin. We unlink the pad from
* the combiner. This will make the combiner select a new pad. */
static void
-pad_removed_cb (GstElement * decodebin, GstPad * pad, GstPlayBin3 * playbin)
+pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
{
- GstPad *peer;
- GstElement *combiner;
GstSourceCombine *combine;
- gulong event_probe_handler;
- GstStreamType stream_type = GST_STREAM_TYPE_UNKNOWN;
- gchar *pad_name;
-
- if (GST_PAD_IS_SINK (pad))
- return;
+ GstPlayBin3 *playbin = group->playbin;
GST_DEBUG_OBJECT (playbin,
"decoded pad %s:%s removed", GST_DEBUG_PAD_NAME (pad));
GST_PLAY_BIN3_LOCK (playbin);
- if ((event_probe_handler =
- POINTER_TO_ULONG (g_object_get_data (G_OBJECT (pad),
- "playbin.event_probe_id")))) {
- gst_pad_remove_probe (pad, event_probe_handler);
- g_object_set_data (G_OBJECT (pad), "playbin.event_probe_id", NULL);
- }
-
- pad_name = gst_object_get_name (GST_OBJECT (pad));
-
- if (g_str_has_prefix (pad_name, "video")) {
- stream_type = GST_STREAM_TYPE_VIDEO;
- } else if (g_str_has_prefix (pad_name, "audio")) {
- stream_type = GST_STREAM_TYPE_AUDIO;
- } else if (g_str_has_prefix (pad_name, "text")) {
- stream_type = GST_STREAM_TYPE_TEXT;
- }
-
- g_free (pad_name);
-
- if ((combine = g_object_get_data (G_OBJECT (pad), "playbin.combine"))) {
- g_assert (combine->combiner == NULL);
- g_assert (combine->srcpad == pad);
- source_combine_remove_pads (playbin, combine);
- playbin->active_stream_types &= ~stream_type;
- goto exit;
- }
-
- /* get the combiner sinkpad */
- if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin.sinkpad")))
- goto not_linked;
-
- /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
- gst_pad_unlink (pad, peer);
-
- /* get combiner */
- combiner = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
- g_assert (combiner != NULL);
-
- if ((combine = g_object_get_data (G_OBJECT (peer), "playbin.combine"))) {
- /* remove the pad from the array */
- g_ptr_array_remove (combine->channels, peer);
- GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
-
- if (!combine->channels->len && combine->combiner) {
- GST_DEBUG_OBJECT (playbin, "all combiner sinkpads removed");
- GST_DEBUG_OBJECT (playbin, "removing combiner %p", combine->combiner);
- source_combine_remove_pads (playbin, combine);
- gst_element_set_state (combine->combiner, GST_STATE_NULL);
- gst_bin_remove (GST_BIN_CAST (playbin), combine->combiner);
- combine->combiner = NULL;
- playbin->active_stream_types &= ~stream_type;
- }
- }
+ /* Get combiner for pad */
+ if (g_str_has_prefix (GST_PAD_NAME (pad), "video"))
+ combine = &playbin->combiner[PLAYBIN_STREAM_VIDEO];
+ else if (g_str_has_prefix (GST_PAD_NAME (pad), "audio"))
+ combine = &playbin->combiner[PLAYBIN_STREAM_AUDIO];
+ else if (g_str_has_prefix (GST_PAD_NAME (pad), "text"))
+ combine = &playbin->combiner[PLAYBIN_STREAM_TEXT];
+ else
+ return;
- /* release the pad to the combiner, this will make the combiner choose a new
- * pad. */
- gst_element_release_request_pad (combiner, peer);
- gst_object_unref (peer);
+ combiner_release_pad (playbin, combine, pad);
+ release_source_pad (playbin, group, pad);
- gst_object_unref (combiner);
-exit:
GST_PLAY_BIN3_UNLOCK (playbin);
-
- if ((playbin->selected_stream_types & ~playbin->active_stream_types &
- (GST_STREAM_TYPE_VIDEO | GST_STREAM_TYPE_AUDIO))
- == 0) {
- no_more_pads (playbin);
- }
-
- return;
-
- /* ERRORS */
-not_linked:
- {
- GST_DEBUG_OBJECT (playbin, "pad not linked");
- goto exit;
- }
}
static gint
select_stream_cb (GstElement * decodebin, GstStreamCollection * collection,
- GstStream * stream, GstPlayBin3 * playbin)
+ GstStream * stream, GstSourceGroup * group)
{
GstStreamType stype = gst_stream_get_stream_type (stream);
GstElement *combiner = NULL;
+ GstPlayBin3 *playbin = group->playbin;
if (stype & GST_STREAM_TYPE_AUDIO)
combiner = playbin->audio_stream_combiner;
@@ -2950,190 +2986,129 @@ select_stream_cb (GstElement * decodebin, GstStreamCollection * collection,
return -1;
}
-/* we get called when all pads are available and we must connect the sinks to
- * them.
- * The main purpose of the code is to see if we have video/audio and subtitles
- * and pick the right pipelines to display them.
- *
- * The combiners installed on the group tell us about the presence of
- * audio/video and subtitle streams. This allows us to see if we need
- * visualisation, video or/and audio.
+/* We get called when the selected stream types change and
+ * reconfiguration of output (i.e. playsink and potential combiners)
+ * are required.
*/
static void
-no_more_pads (GstPlayBin3 * playbin)
+reconfigure_output (GstPlayBin3 * playbin)
{
- GstSourceGroup *group;
GstPadLinkReturn res;
gint i;
- gboolean configure;
- GST_DEBUG_OBJECT (playbin, "no more pads");
+ g_assert (playbin->selected_stream_types != playbin->active_stream_types);
- GST_PLAY_BIN3_SHUTDOWN_LOCK (playbin, shutdown);
+ GST_DEBUG_OBJECT (playbin, "selected_stream_types : %" STREAM_TYPES_FORMAT,
+ STREAM_TYPES_ARGS (playbin->selected_stream_types));
+ GST_DEBUG_OBJECT (playbin, "active_stream_types : %" STREAM_TYPES_FORMAT,
+ STREAM_TYPES_ARGS (playbin->active_stream_types));
GST_PLAY_BIN3_LOCK (playbin);
- group = playbin->curr_group;
+ /* Make sure combiners/playsink are in sync with selected stream types */
for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
GstSourceCombine *combine = &playbin->combiner[i];
-
- /* check if the specific media type was detected and thus has a combiner
- * created for it. If there is the media type, get a sinkpad from the sink
- * and link it. We only do this if we have not yet requested the sinkpad
- * before. */
- if (combine->srcpad && combine->sinkpad == NULL) {
- GST_DEBUG_OBJECT (playbin, "requesting new sink pad %d", combine->type);
- combine->sinkpad =
- gst_play_sink_request_pad (playbin->playsink, combine->type);
- gst_object_ref (combine->sinkpad);
- } else if (combine->srcpad && combine->sinkpad) {
- GST_DEBUG_OBJECT (playbin, "re-using sink pad %d", combine->type);
- } else if (combine->sinkpad && combine->srcpad == NULL) {
- GST_DEBUG_OBJECT (playbin, "releasing sink pad %d", combine->type);
- gst_play_sink_release_pad (playbin->playsink, combine->sinkpad);
- gst_object_unref (combine->sinkpad);
- combine->sinkpad = NULL;
- }
- if (combine->sinkpad && combine->srcpad &&
- !gst_pad_is_linked (combine->srcpad)) {
- res = gst_pad_link (combine->srcpad, combine->sinkpad);
- GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
- combine->media_type, res);
- if (res != GST_PAD_LINK_OK) {
- GST_ELEMENT_ERROR (playbin, CORE, PAD,
- ("Internal playbin error."),
- ("Failed to link combiner to sink. Error %d", res));
+ gboolean is_selected =
+ (combine->stream_type & playbin->selected_stream_types) ==
+ combine->stream_type;
+ gboolean is_active =
+ (combine->stream_type & playbin->active_stream_types) ==
+ combine->stream_type;
+
+ GST_DEBUG_OBJECT (playbin, "Stream type status: '%s' %s %s",
+ combine->media_type, is_selected ? "selected" : "NOT selected",
+ is_active ? "active" : "NOT active");
+ /* FIXME : Remove asserts below once enough testing has been done */
+
+ if (is_selected && is_active) {
+ GST_DEBUG_OBJECT (playbin, "Stream type '%s' already active",
+ combine->media_type);
+ } else if (is_active && !is_selected) {
+ GST_DEBUG_OBJECT (playbin, "Stream type '%s' is no longer requested",
+ combine->media_type);
+
+ /* Unlink combiner from sink */
+ if (combine->srcpad) {
+ GST_LOG_OBJECT (playbin, "Unlinking from sink");
+ if (combine->sinkpad)
+ gst_pad_unlink (combine->srcpad, combine->sinkpad);
+ gst_object_unref (combine->srcpad);
+ combine->srcpad = NULL;
}
- }
- }
- GST_PLAY_BIN3_UNLOCK (playbin);
-
- GST_SOURCE_GROUP_LOCK (group);
- GST_DEBUG_OBJECT (playbin, "pending %d > %d", group->pending,
- group->pending - 1);
-
- if (group->pending > 0)
- group->pending--;
-
- if (group->pending == 0) {
- /* we are the last group to complete, we will configure the output and then
- * signal the other waiters. */
- GST_LOG_OBJECT (playbin, "last group complete");
- configure = TRUE;
- } else {
- GST_LOG_OBJECT (playbin, "have more pending groups");
- configure = FALSE;
- }
- GST_SOURCE_GROUP_UNLOCK (group);
- if (configure) {
- /* if we have custom sinks, configure them now */
- GST_SOURCE_GROUP_LOCK (group);
-
- if (group->audio_sink) {
- GST_INFO_OBJECT (playbin, "setting custom audio sink %" GST_PTR_FORMAT,
- group->audio_sink);
- gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_AUDIO,
- group->audio_sink);
- }
-
- if (group->video_sink) {
- GST_INFO_OBJECT (playbin, "setting custom video sink %" GST_PTR_FORMAT,
- group->video_sink);
- gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_VIDEO,
- group->video_sink);
- }
+ if (combine->sinkpad) {
+ /* Release playsink sink pad */
+ GST_LOG_OBJECT (playbin, "Releasing playsink pad");
+ gst_play_sink_release_pad (playbin->playsink, combine->sinkpad);
+ gst_object_unref (combine->sinkpad);
+ combine->sinkpad = NULL;
+ }
- if (group->text_sink) {
- GST_INFO_OBJECT (playbin, "setting custom text sink %" GST_PTR_FORMAT,
- group->text_sink);
- gst_play_sink_set_sink (playbin->playsink, GST_PLAY_SINK_TYPE_TEXT,
- group->text_sink);
- }
+ /* Release combiner */
+ GST_FIXME_OBJECT (playbin, "Release combiner");
+ remove_combiner (playbin, combine);
+ } else if (!is_active && is_selected) {
+ GST_DEBUG_OBJECT (playbin, "Stream type '%s' is now requested",
+ combine->media_type);
- GST_SOURCE_GROUP_UNLOCK (group);
+ /* If we are shutting down, do *not* add more combiners */
+ if (g_atomic_int_get (&playbin->shutdown))
+ continue;
- /* signal the other combiners that they can continue now. */
- GST_PLAY_BIN3_LOCK (playbin);
- /* unblock all combiners */
- for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
- GstSourceCombine *combine = &playbin->combiner[i];
+ g_assert (combine->sinkpad == NULL);
- if (combine->srcpad) {
- GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
- combine->srcpad);
- if (combine->block_id) {
- gst_pad_remove_probe (combine->srcpad, combine->block_id);
- combine->block_id = 0;
+ /* Request playsink sink pad */
+ combine->sinkpad =
+ gst_play_sink_request_pad (playbin->playsink, combine->type);
+ gst_object_ref (combine->sinkpad);
+ /* Create combiner if needed and link it */
+ create_combiner (playbin, combine);
+ if (combine->combiner) {
+ res = gst_pad_link (combine->srcpad, combine->sinkpad);
+ GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d",
+ combine->media_type, res);
+ if (res != GST_PAD_LINK_OK) {
+ GST_ELEMENT_ERROR (playbin, CORE, PAD,
+ ("Internal playbin error."),
+ ("Failed to link combiner to sink. Error %d", res));
}
+
}
}
- GST_PLAY_BIN3_UNLOCK (playbin);
- gst_play_sink_reconfigure (playbin->playsink);
}
- GST_PLAY_BIN3_SHUTDOWN_UNLOCK (playbin);
+ playbin->active_stream_types = playbin->selected_stream_types;
- if (configure) {
- do_async_done (playbin);
- }
+ GST_PLAY_BIN3_UNLOCK (playbin);
- return;
+ gst_play_sink_reconfigure (playbin->playsink);
-shutdown:
- {
- GST_DEBUG ("ignoring, we are shutting down");
- /* Request a flushing pad from playsink that we then link to the combiner.
- * Then we unblock the combiners so that they stop with a WRONG_STATE
- * instead of a NOT_LINKED error.
- */
- GST_PLAY_BIN3_LOCK (playbin);
- for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
- GstSourceCombine *combine = &playbin->combiner[i];
+ do_async_done (playbin);
- if (combine->srcpad) {
- if (combine->sinkpad == NULL) {
- GST_DEBUG_OBJECT (playbin, "requesting new flushing sink pad");
- combine->sinkpad =
- gst_play_sink_request_pad (playbin->playsink,
- GST_PLAY_SINK_TYPE_FLUSHING);
- gst_object_ref (combine->sinkpad);
- res = gst_pad_link (combine->srcpad, combine->sinkpad);
- GST_DEBUG_OBJECT (playbin, "linked flushing, result: %d", res);
- }
- GST_DEBUG_OBJECT (playbin, "unblocking %" GST_PTR_FORMAT,
- combine->srcpad);
- if (combine->block_id) {
- gst_pad_remove_probe (combine->srcpad, combine->block_id);
- combine->block_id = 0;
- }
- }
- }
- GST_PLAY_BIN3_UNLOCK (playbin);
- return;
- }
+ GST_DEBUG_OBJECT (playbin, "selected_stream_types : %" STREAM_TYPES_FORMAT,
+ STREAM_TYPES_ARGS (playbin->selected_stream_types));
+ GST_DEBUG_OBJECT (playbin, "active_stream_types : %" STREAM_TYPES_FORMAT,
+ STREAM_TYPES_ARGS (playbin->active_stream_types));
+
+ return;
}
-/* FIXME : DISABLED UNTIL GAPLESS IS IMPLEMENTED */
-#if 0
static void
-drained_cb (GstElement * decodebin, GstSourceGroup * group)
+about_to_finish_cb (GstElement * uridecodebin, GstSourceGroup * group)
{
- GstPlayBin3 *playbin;
-
- playbin = group->playbin;
-
+ GstPlayBin3 *playbin = group->playbin;
GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
/* after this call, we should have a next group to activate or we EOS */
g_signal_emit (G_OBJECT (playbin),
gst_play_bin3_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
+#if 0
/* now activate the next group. If the app did not set a uri, this will
* fail and we can do EOS */
- setup_next_source (playbin, GST_STATE_PAUSED);
-}
+ setup_next_source (playbin);
#endif
+}
#if 0 /* AUTOPLUG DISABLED */
/* Like gst_element_factory_can_sink_any_caps() but doesn't
@@ -4248,10 +4223,8 @@ group_set_locked_state_unlocked (GstPlayBin3 * playbin, GstSourceGroup * group,
{
GST_DEBUG_OBJECT (playbin, "locked_state %d on group %p", locked, group);
- if (group->urisourcebin)
- gst_element_set_locked_state (group->urisourcebin, locked);
- if (group->suburisourcebin)
- gst_element_set_locked_state (group->suburisourcebin, locked);
+ if (group->uridecodebin)
+ gst_element_set_locked_state (group->uridecodebin, locked);
return TRUE;
}
@@ -4281,149 +4254,6 @@ make_or_reuse_element (GstPlayBin3 * playbin, const gchar * name,
return TRUE;
}
-static void
-urisrc_pad_added (GstElement * urisrc, GstPad * pad, GstSourceGroup * group)
-{
- GstPadLinkReturn res;
- GstPad *sinkpad = NULL;
- GstPlayBin3 *playbin;
-
- GST_SOURCE_GROUP_LOCK (group);
- playbin = group->playbin;
- if (urisrc == group->urisourcebin) {
- /* Primary stream, link to the main pad of decodebin3 */
- sinkpad = gst_element_get_static_pad (playbin->decodebin, "sink");
- if (gst_pad_is_linked (sinkpad)) {
- gst_object_unref (GST_OBJECT (sinkpad));
- sinkpad = NULL;
- }
- }
- GST_SOURCE_GROUP_UNLOCK (group);
-
- if (sinkpad == NULL) {
- /* Auxiliary stream, request a new pad from decodebin */
- if ((sinkpad = gst_element_get_request_pad (playbin->decodebin, "sink_%u"))) {
- g_object_set_data (G_OBJECT (pad), "playbin.sinkpad", sinkpad);
- }
- }
- if (sinkpad) {
- GST_DEBUG_OBJECT (playbin, "New pad %" GST_PTR_FORMAT
- " from urisourcebin %" GST_PTR_FORMAT " linking to %"
- GST_PTR_FORMAT, pad, urisrc, sinkpad);
-
- res = gst_pad_link (pad, sinkpad);
- gst_object_unref (sinkpad);
-
- if (GST_PAD_LINK_FAILED (res))
- goto link_failed;
- }
- return;
-
-link_failed:
- {
- GST_ERROR_OBJECT (playbin,
- "failed to link pad %s:%s to decodebin, reason %s (%d)",
- GST_DEBUG_PAD_NAME (pad), gst_pad_link_get_name (res), res);
- return;
- }
-}
-
-static void
-urisrc_pad_removed_cb (GstElement * urisrc, GstPad * pad,
- GstSourceGroup * group)
-{
-}
-
-/* must be called with PLAY_BIN_LOCK */
-static GstStateChangeReturn
-activate_decodebin (GstPlayBin3 * playbin, GstState target)
-{
- GstStateChangeReturn state_ret;
- GstElement *decodebin = NULL;
-
- if (playbin->decodebin_active)
- return GST_STATE_CHANGE_SUCCESS;
-
- GST_LOG_OBJECT (playbin, "Adding and activating decodebin");
-
- if (!make_or_reuse_element (playbin, "decodebin3", &playbin->decodebin))
- goto no_decodebin;
- decodebin = playbin->decodebin;
-
- /* connect pads and other things */
- playbin->db_pad_added_id = g_signal_connect (decodebin, "pad-added",
- G_CALLBACK (pad_added_cb), playbin);
- playbin->db_pad_removed_id = g_signal_connect (decodebin, "pad-removed",
- G_CALLBACK (pad_removed_cb), playbin);
- playbin->db_select_stream_id = g_signal_connect (decodebin, "select-stream",
- G_CALLBACK (select_stream_cb), playbin);
- /* is called when the decodebin is out of data and we can switch to the
- * next uri */
-#if 0
- /* FIXME: Re-enable if/when decodebin3 supports 'drained' */
- playbin->db_drained_id =
- g_signal_connect (decodebin, "drained", G_CALLBACK (drained_cb), playbin);
-#endif
-
- gst_element_set_locked_state (decodebin, TRUE);
- if ((state_ret =
- gst_element_set_state (decodebin,
- target)) == GST_STATE_CHANGE_FAILURE)
- goto decodebin_failure;
- gst_element_set_locked_state (decodebin, FALSE);
-
- playbin->decodebin_active = TRUE;
-
- return state_ret;
-
-
-no_decodebin:
- {
- GstMessage *msg;
-
- msg =
- gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
- "decodebin3");
- gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
-
- GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
- (_("Could not create \"decodebin3\" element.")), (NULL));
-
- goto error_cleanup;
- }
-decodebin_failure:
- {
- GST_DEBUG_OBJECT (playbin, "failed state change of decodebin");
- goto error_cleanup;
- }
-error_cleanup:{
- if (decodebin) {
- REMOVE_SIGNAL (playbin->decodebin, playbin->db_pad_added_id);
- REMOVE_SIGNAL (playbin->decodebin, playbin->db_pad_removed_id);
- REMOVE_SIGNAL (playbin->decodebin, playbin->db_drained_id);
- REMOVE_SIGNAL (playbin->decodebin, playbin->db_select_stream_id);
- gst_element_set_state (decodebin, GST_STATE_NULL);
- gst_bin_remove (GST_BIN_CAST (playbin), decodebin);
- }
- return GST_STATE_CHANGE_FAILURE;
- }
-}
-
-/* must be called with PLAY_BIN_LOCK */
-static void
-deactivate_decodebin (GstPlayBin3 * playbin)
-{
- if (playbin->decodebin) {
- GST_LOG_OBJECT (playbin, "Deactivating and removing decodebin");
- REMOVE_SIGNAL (playbin->decodebin, playbin->db_pad_added_id);
- REMOVE_SIGNAL (playbin->decodebin, playbin->db_pad_removed_id);
- REMOVE_SIGNAL (playbin->decodebin, playbin->db_drained_id);
- REMOVE_SIGNAL (playbin->decodebin, playbin->db_select_stream_id);
- gst_bin_remove (GST_BIN_CAST (playbin), playbin->decodebin);
- playbin->decodebin_active = FALSE;
- playbin->active_stream_types = 0;
- }
-}
static void
source_setup_cb (GstElement * element, GstElement * source,
@@ -4435,10 +4265,9 @@ source_setup_cb (GstElement * element, GstElement * source,
/* must be called with PLAY_BIN_LOCK */
static GstStateChangeReturn
-activate_group (GstPlayBin3 * playbin, GstSourceGroup * group, GstState target)
+activate_group (GstPlayBin3 * playbin, GstSourceGroup * group)
{
- GstElement *urisrcbin = NULL;
- GstElement *suburisrcbin = NULL;
+ GstElement *uridecodebin = NULL;
GstPlayFlags flags;
gboolean audio_sink_activated = FALSE;
gboolean video_sink_activated = FALSE;
@@ -4505,13 +4334,13 @@ activate_group (GstPlayBin3 * playbin, GstSourceGroup * group, GstState target)
}
- if (!make_or_reuse_element (playbin, "urisourcebin", &group->urisourcebin))
- goto no_urisrcbin;
- urisrcbin = group->urisourcebin;
+ if (!make_or_reuse_element (playbin, "uridecodebin3", &group->uridecodebin))
+ goto no_uridecodebin;
+ uridecodebin = group->uridecodebin;
flags = gst_play_sink_get_flags (playbin->playsink);
- g_object_set (urisrcbin,
+ g_object_set (uridecodebin,
/* configure connection speed */
"connection-speed", playbin->connection_speed / 1000,
/* configure uri */
@@ -4525,105 +4354,30 @@ activate_group (GstPlayBin3 * playbin, GstSourceGroup * group, GstState target)
"buffer-size", playbin->buffer_size,
"ring-buffer-max-size", playbin->ring_buffer_max_size, NULL);
- /* we have 1 pending no-more-pads */
- group->pending = 1;
-
- group->urisrc_source_setup_id = g_signal_connect (urisrcbin, "source-setup",
+ group->pad_added_id = g_signal_connect (uridecodebin, "pad-added",
+ G_CALLBACK (pad_added_cb), group);
+ group->pad_removed_id = g_signal_connect (uridecodebin,
+ "pad-removed", G_CALLBACK (pad_removed_cb), group);
+ group->select_stream_id = g_signal_connect (uridecodebin, "select-stream",
+ G_CALLBACK (select_stream_cb), group);
+ group->source_setup_id = g_signal_connect (uridecodebin, "source-setup",
G_CALLBACK (source_setup_cb), group);
+ group->about_to_finish_id =
+ g_signal_connect (uridecodebin, "about-to-finish",
+ G_CALLBACK (about_to_finish_cb), group);
-#if 0 /* AUTOPLUG DISABLED */
- /* will be called when a new media type is found. We return a list of decoders
- * including sinks for decodebin to try */
- group->autoplug_factories_id =
- g_signal_connect (urisrcbin, "autoplug-factories",
- G_CALLBACK (autoplug_factories_cb), group);
- group->autoplug_select_id =
- g_signal_connect (urisrcbin, "autoplug-select",
- G_CALLBACK (autoplug_select_cb), group);
- group->autoplug_continue_id =
- g_signal_connect (urisrcbin, "autoplug-continue",
- G_CALLBACK (autoplug_continue_cb), group);
- group->autoplug_query_id =
- g_signal_connect (urisrcbin, "autoplug-query",
- G_CALLBACK (autoplug_query_cb), group);
-#endif
-
- group->urisrc_pad_added_id = g_signal_connect (urisrcbin, "pad-added",
- G_CALLBACK (urisrc_pad_added), group);
- group->urisrc_pad_removed_id = g_signal_connect (urisrcbin,
- "pad-removed", G_CALLBACK (urisrc_pad_removed_cb), group);
-
- if (group->suburi) {
- /* subtitles */
- if (!make_or_reuse_element (playbin, "urisourcebin",
- &group->suburisourcebin))
- goto no_urisrcbin;
- suburisrcbin = group->suburisourcebin;
-
- g_object_set (suburisrcbin,
- /* configure connection speed */
- "connection-speed", playbin->connection_speed,
- /* configure uri */
- "uri", group->suburi, NULL);
-
- /* connect pads and other things */
- group->sub_pad_added_id = g_signal_connect (suburisrcbin, "pad-added",
- G_CALLBACK (urisrc_pad_added), group);
- group->sub_pad_removed_id = g_signal_connect (suburisrcbin,
- "pad-removed", G_CALLBACK (urisrc_pad_removed_cb), group);
-
-#if 0
- group->sub_autoplug_continue_id =
- g_signal_connect (suburisrcbin, "autoplug-continue",
- G_CALLBACK (autoplug_continue_cb), group);
-
- group->sub_autoplug_query_id =
- g_signal_connect (suburisrcbin, "autoplug-query",
- G_CALLBACK (autoplug_query_cb), group);
-#endif
-
- /* we have 2 pending no-more-pads */
- group->pending = 2;
- group->sub_pending = TRUE;
- } else {
- group->sub_pending = FALSE;
- }
+ if (group->suburi)
+ g_object_set (group->uridecodebin, "suburi", group->suburi, NULL);
/* release the group lock before setting the state of the source bins, they
* might fire signals in this thread that we need to handle with the
* group_lock taken. */
GST_SOURCE_GROUP_UNLOCK (group);
- if (suburisrcbin) {
- if (gst_element_set_state (suburisrcbin,
- target) == GST_STATE_CHANGE_FAILURE) {
- GST_DEBUG_OBJECT (playbin,
- "failed state change of subtitle urisourcebin");
- GST_SOURCE_GROUP_LOCK (group);
-
- REMOVE_SIGNAL (suburisrcbin, group->sub_pad_added_id);
- REMOVE_SIGNAL (suburisrcbin, group->sub_pad_removed_id);
-#if 0
- REMOVE_SIGNAL (suburisrcbin, group->sub_autoplug_continue_id);
- REMOVE_SIGNAL (suburisrcbin, group->sub_autoplug_query_id);
-#endif
- /* Might already be removed because of an error message */
- if (GST_OBJECT_PARENT (suburisrcbin) == GST_OBJECT_CAST (playbin))
- gst_bin_remove (GST_BIN_CAST (playbin), suburisrcbin);
- if (group->sub_pending) {
- group->pending--;
- group->sub_pending = FALSE;
- }
- gst_element_set_state (suburisrcbin, GST_STATE_READY);
- g_free (group->suburi);
- group->suburi = NULL;
- GST_SOURCE_GROUP_UNLOCK (group);
- }
- }
if ((state_ret =
- gst_element_set_state (urisrcbin,
- target)) == GST_STATE_CHANGE_FAILURE)
- goto urisrcbin_failure;
+ gst_element_set_state (uridecodebin,
+ GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE)
+ goto uridecodebin_failure;
GST_SOURCE_GROUP_LOCK (group);
/* allow state changes of the playbin affect the group elements now */
@@ -4634,26 +4388,26 @@ activate_group (GstPlayBin3 * playbin, GstSourceGroup * group, GstState target)
return state_ret;
/* ERRORS */
-no_urisrcbin:
+no_uridecodebin:
{
GstMessage *msg;
GST_SOURCE_GROUP_UNLOCK (group);
msg =
gst_missing_element_message_new (GST_ELEMENT_CAST (playbin),
- "urisourcebin");
+ "uridecodebin3");
gst_element_post_message (GST_ELEMENT_CAST (playbin), msg);
GST_ELEMENT_ERROR (playbin, CORE, MISSING_PLUGIN,
- (_("Could not create \"urisourcebin\" element.")), (NULL));
+ (_("Could not create \"uridecodebin3\" element.")), (NULL));
GST_SOURCE_GROUP_LOCK (group);
goto error_cleanup;
}
-urisrcbin_failure:
+uridecodebin_failure:
{
- GST_DEBUG_OBJECT (playbin, "failed state change of urisrcbin");
+ GST_DEBUG_OBJECT (playbin, "failed state change of uridecodebin");
GST_SOURCE_GROUP_LOCK (group);
goto error_cleanup;
}
@@ -4665,6 +4419,8 @@ sink_failure:
error_cleanup:
{
+ group->selected_stream_types = 0;
+
/* delete any custom sinks we might have */
if (group->audio_sink) {
/* If this is a automatically created sink set it to NULL */
@@ -4690,10 +4446,12 @@ error_cleanup:
}
group->text_sink = NULL;
- if (urisrcbin) {
- REMOVE_SIGNAL (group->urisourcebin, group->urisrc_pad_added_id);
- REMOVE_SIGNAL (group->urisourcebin, group->urisrc_pad_removed_id);
- REMOVE_SIGNAL (group->urisourcebin, group->urisrc_source_setup_id);
+ if (uridecodebin) {
+ REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
+ REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
+ 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);
@@ -4701,8 +4459,8 @@ error_cleanup:
REMOVE_SIGNAL (group->urisourcebin, group->autoplug_query_id);
#endif
- gst_element_set_state (urisrcbin, GST_STATE_NULL);
- gst_bin_remove (GST_BIN_CAST (playbin), urisrcbin);
+ gst_element_set_state (uridecodebin, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN_CAST (playbin), uridecodebin);
}
GST_SOURCE_GROUP_UNLOCK (group);
@@ -4711,13 +4469,11 @@ error_cleanup:
}
}
-/* unlink a group of urisrcbin from the decodebin.
+/* unlink a group of uridecodebin from the decodebin.
* must be called with PLAY_BIN_LOCK */
static gboolean
deactivate_group (GstPlayBin3 * playbin, GstSourceGroup * group)
{
- gint i;
-
g_return_val_if_fail (group->active, FALSE);
g_return_val_if_fail (group->valid, FALSE);
@@ -4725,32 +4481,15 @@ deactivate_group (GstPlayBin3 * playbin, GstSourceGroup * group)
GST_SOURCE_GROUP_LOCK (group);
group->active = FALSE;
- for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
- GstSourceCombine *combine = &playbin->combiner[i];
-
- GST_DEBUG_OBJECT (playbin, "unlinking combiner %s", combine->media_type);
-
- if (combine->srcpad) {
- source_combine_remove_pads (playbin, combine);
- }
-
- if (combine->combiner) {
- gint n;
-
- /* release and unref requests pad from the combiner */
- for (n = 0; n < combine->channels->len; n++) {
- GstPad *sinkpad = g_ptr_array_index (combine->channels, n);
- gst_element_release_request_pad (combine->combiner, sinkpad);
- gst_object_unref (sinkpad);
- }
- g_ptr_array_set_size (combine->channels, 0);
+ group->selected_stream_types = 0;
+ /* Update global selected_stream_types */
+ playbin->selected_stream_types =
+ playbin->groups[0].selected_stream_types | playbin->
+ groups[1].selected_stream_types;
+ if (playbin->active_stream_types != playbin->selected_stream_types)
+ reconfigure_output (playbin);
- gst_element_set_state (combine->combiner, GST_STATE_NULL);
- gst_bin_remove (GST_BIN_CAST (playbin), combine->combiner);
- combine->combiner = NULL;
- }
- }
#if 0
/* delete any custom sinks we might have.
* conditionally set them to null if they aren't inside playsink yet */
@@ -4780,30 +4519,20 @@ deactivate_group (GstPlayBin3 * playbin, GstSourceGroup * group)
group->text_sink = NULL;
#endif
- if (group->urisourcebin) {
- REMOVE_SIGNAL (group->urisourcebin, group->urisrc_pad_added_id);
- REMOVE_SIGNAL (group->urisourcebin, group->urisrc_pad_removed_id);
- REMOVE_SIGNAL (group->urisourcebin, group->urisrc_source_setup_id);
+ if (group->uridecodebin) {
+ REMOVE_SIGNAL (group->uridecodebin, group->pad_added_id);
+ REMOVE_SIGNAL (group->uridecodebin, group->pad_removed_id);
+ 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_bin_remove (GST_BIN_CAST (playbin), group->urisourcebin);
- }
-
- if (group->suburisourcebin) {
- REMOVE_SIGNAL (group->suburisourcebin, group->sub_pad_added_id);
- REMOVE_SIGNAL (group->suburisourcebin, group->sub_pad_removed_id);
-#if 0
- REMOVE_SIGNAL (group->suburisourcebin, group->sub_autoplug_continue_id);
- REMOVE_SIGNAL (group->suburisourcebin, group->sub_autoplug_query_id);
-#endif
-
- /* Might already be removed because of errors */
- if (GST_OBJECT_PARENT (group->suburisourcebin) == GST_OBJECT_CAST (playbin))
- gst_bin_remove (GST_BIN_CAST (playbin), group->suburisourcebin);
+ gst_element_set_state (group->uridecodebin, GST_STATE_NULL);
+ gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
}
GST_SOURCE_GROUP_UNLOCK (group);
@@ -4815,7 +4544,7 @@ deactivate_group (GstPlayBin3 * playbin, GstSourceGroup * group)
* configured. It swaps out the current_group and activates the valid
* next_group. */
static GstStateChangeReturn
-setup_next_source (GstPlayBin3 * playbin, GstState target)
+setup_next_source (GstPlayBin3 * playbin)
{
GstSourceGroup *new_group, *old_group;
GstStateChangeReturn state_ret;
@@ -4842,15 +4571,9 @@ setup_next_source (GstPlayBin3 * playbin, GstState target)
playbin->curr_group = new_group;
playbin->next_group = old_group;
- /* Get decodebin ready now */
- if ((state_ret =
- activate_decodebin (playbin, target)) == GST_STATE_CHANGE_FAILURE)
- goto activate_failed;
-
/* activate the new group */
- if ((state_ret =
- activate_group (playbin, new_group,
- target)) == GST_STATE_CHANGE_FAILURE)
+ state_ret = activate_group (playbin, new_group);
+ if (state_ret == GST_STATE_CHANGE_FAILURE)
goto activate_failed;
GST_PLAY_BIN3_UNLOCK (playbin);
@@ -4861,8 +4584,6 @@ setup_next_source (GstPlayBin3 * playbin, GstState target)
no_next_group:
{
GST_DEBUG_OBJECT (playbin, "no next group");
- if (target == GST_STATE_READY && new_group && new_group->uri == NULL)
- GST_ELEMENT_ERROR (playbin, RESOURCE, NOT_FOUND, ("No URI set"), (NULL));
GST_PLAY_BIN3_UNLOCK (playbin);
return GST_STATE_CHANGE_FAILURE;
}
@@ -4952,8 +4673,9 @@ gst_play_bin3_change_state (GstElement * element, GstStateChange transition)
break;
case GST_STATE_CHANGE_READY_TO_NULL:
/* we go async to PAUSED, so if that fails, we never make it to PAUSED
- * and no state change PAUSED to READY passes here,
- * though it is a nice-to-have ... */
+ * and we will never be called with the GST_STATE_CHANGE_PAUSED_TO_READY.
+ * Make sure we do go through the same steps (see above) for
+ * proper cleanup */
if (!g_atomic_int_get (&playbin->shutdown)) {
do_save = TRUE;
goto async_down;
@@ -4972,9 +4694,7 @@ gst_play_bin3_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
- if ((ret =
- setup_next_source (playbin,
- GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE)
+ if ((ret = setup_next_source (playbin)) == GST_STATE_CHANGE_FAILURE)
goto failure;
if (ret == GST_STATE_CHANGE_SUCCESS)
ret = GST_STATE_CHANGE_ASYNC;
@@ -4994,35 +4714,20 @@ gst_play_bin3_change_state (GstElement * element, GstStateChange transition)
/* also do missed state change down to READY */
if (do_save)
save_current_group (playbin);
- /* Deactive the groups, set the urisrcbins to NULL
- * and unref them.
- */
+ /* Deactive the groups, set uridecodebin to NULL and unref it */
for (i = 0; i < 2; i++) {
if (playbin->groups[i].active && playbin->groups[i].valid) {
deactivate_group (playbin, &playbin->groups[i]);
playbin->groups[i].valid = FALSE;
}
- if (playbin->groups[i].urisourcebin) {
- gst_element_set_state (playbin->groups[i].urisourcebin,
+ if (playbin->groups[i].uridecodebin) {
+ gst_element_set_state (playbin->groups[i].uridecodebin,
GST_STATE_NULL);
- gst_object_unref (playbin->groups[i].urisourcebin);
- playbin->groups[i].urisourcebin = NULL;
+ gst_object_unref (playbin->groups[i].uridecodebin);
+ playbin->groups[i].uridecodebin = NULL;
}
- if (playbin->groups[i].suburisourcebin) {
- gst_element_set_state (playbin->groups[i].suburisourcebin,
- GST_STATE_NULL);
- gst_object_unref (playbin->groups[i].suburisourcebin);
- playbin->groups[i].suburisourcebin = NULL;
- }
- }
-
- deactivate_decodebin (playbin);
- if (playbin->decodebin) {
- gst_object_unref (playbin->decodebin);
- playbin->decodebin = NULL;
- playbin->decodebin_active = FALSE;
}
/* Set our sinks back to NULL, they might not be child of playbin */