playbin: Add support for custom stream-combiners

This allows to chose something else than input-selector
for multiple audio/video/text streams, e.g. an adder could
be used for audio.

It is needed for example to implement some of the more
advanced HTML5 video features.

https://bugzilla.gnome.org/show_bug.cgi?id=698851
This commit is contained in:
Brendan Long 2013-05-17 17:23:46 -06:00 committed by Sebastian Dröge
parent 14192c031a
commit ba5f6cfe72

View file

@ -271,6 +271,11 @@ struct _GstSourceSelect
* is linked * is linked
*/ */
gulong block_id; gulong block_id;
gboolean has_active_pad; /* stream combiner has the "active-pad" property */
gboolean has_always_ok; /* stream combiner's sink pads have the "always-ok" property */
gboolean has_tags; /* stream combiner's sink pads have the "tags" property */
}; };
#define GST_SOURCE_GROUP_GET_LOCK(group) (&((GstSourceGroup*)(group))->lock) #define GST_SOURCE_GROUP_GET_LOCK(group) (&((GstSourceGroup*)(group))->lock)
@ -441,6 +446,10 @@ struct _GstPlayBin
GstElement *video_sink; /* configured video sink, or NULL */ GstElement *video_sink; /* configured video sink, or NULL */
GstElement *text_sink; /* configured text sink, or NULL */ GstElement *text_sink; /* configured text sink, or NULL */
GstElement *audio_stream_combiner; /* configured audio stream combiner, or NULL */
GstElement *video_stream_combiner; /* configured video stream combiner, or NULL */
GstElement *text_stream_combiner; /* configured text stream combiner, or NULL */
GSequence *aelements; /* a list of GstAVElements for audio stream */ GSequence *aelements; /* a list of GstAVElements for audio stream */
GSequence *velements; /* a list of GstAVElements for video stream */ GSequence *velements; /* a list of GstAVElements for video stream */
@ -533,6 +542,9 @@ enum
PROP_VIDEO_SINK, PROP_VIDEO_SINK,
PROP_VIS_PLUGIN, PROP_VIS_PLUGIN,
PROP_TEXT_SINK, PROP_TEXT_SINK,
PROP_VIDEO_STREAM_COMBINER,
PROP_AUDIO_STREAM_COMBINER,
PROP_TEXT_STREAM_COMBINER,
PROP_VOLUME, PROP_VOLUME,
PROP_MUTE, PROP_MUTE,
PROP_SAMPLE, PROP_SAMPLE,
@ -826,6 +838,36 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
g_param_spec_object ("text-sink", "Text plugin", g_param_spec_object ("text-sink", "Text plugin",
"the text output element to use (NULL = default subtitleoverlay)", "the text output element to use (NULL = default subtitleoverlay)",
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstPlayBin:video-stream-combiner
*
* Get or set the current video stream combiner. By default, an input-selector
* is created and deleted as-needed.
*/
g_object_class_install_property (gobject_klass, PROP_VIDEO_STREAM_COMBINER,
g_param_spec_object ("video-stream-combiner", "Video stream combiner",
"Current video stream combiner (NULL = input-selector)",
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstPlayBin:audio-stream-combiner
*
* Get or set the current audio stream combiner. By default, an input-selector
* is created and deleted as-needed.
*/
g_object_class_install_property (gobject_klass, PROP_AUDIO_STREAM_COMBINER,
g_param_spec_object ("audio-stream-combiner", "Audio stream combiner",
"Current audio stream combiner (NULL = input-selector)",
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstPlayBin:text-stream-combiner
*
* Get or set the current text stream combiner. By default, an input-selector
* is created and deleted as-needed.
*/
g_object_class_install_property (gobject_klass, PROP_TEXT_STREAM_COMBINER,
g_param_spec_object ("text-stream-combiner", "Text stream combiner",
"Current text stream combiner (NULL = input-selector)",
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/** /**
* GstPlayBin:volume: * GstPlayBin:volume:
@ -1629,12 +1671,13 @@ gst_play_bin_get_text_pad (GstPlayBin * playbin, gint stream)
static GstTagList * static GstTagList *
get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream) get_tags (GstPlayBin * playbin, GstSourceGroup * group, GPtrArray * channels,
gint stream)
{ {
GstTagList *result; GstTagList *result;
GstPad *sinkpad; GstPad *sinkpad;
if (!channels || stream >= channels->len) if (!channels || stream >= channels->len || !group->selector[stream].has_tags)
return NULL; return NULL;
sinkpad = g_ptr_array_index (channels, stream); sinkpad = g_ptr_array_index (channels, stream);
@ -1651,7 +1694,7 @@ gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
GST_PLAY_BIN_LOCK (playbin); GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin); group = get_group (playbin);
result = get_tags (playbin, group->video_channels, stream); result = get_tags (playbin, group, group->video_channels, stream);
GST_PLAY_BIN_UNLOCK (playbin); GST_PLAY_BIN_UNLOCK (playbin);
return result; return result;
@ -1665,7 +1708,7 @@ gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
GST_PLAY_BIN_LOCK (playbin); GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin); group = get_group (playbin);
result = get_tags (playbin, group->audio_channels, stream); result = get_tags (playbin, group, group->audio_channels, stream);
GST_PLAY_BIN_UNLOCK (playbin); GST_PLAY_BIN_UNLOCK (playbin);
return result; return result;
@ -1679,7 +1722,7 @@ gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
GST_PLAY_BIN_LOCK (playbin); GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin); group = get_group (playbin);
result = get_tags (playbin, group->text_channels, stream); result = get_tags (playbin, group, group->text_channels, stream);
GST_PLAY_BIN_UNLOCK (playbin); GST_PLAY_BIN_UNLOCK (playbin);
return result; return result;
@ -1693,7 +1736,8 @@ gst_play_bin_convert_sample (GstPlayBin * playbin, GstCaps * caps)
/* Returns current stream number, or -1 if none has been selected yet */ /* Returns current stream number, or -1 if none has been selected yet */
static int static int
get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels) get_current_stream_number (GstPlayBin * playbin, GstSourceSelect * select,
GPtrArray * channels)
{ {
/* Internal API cleanup would make this easier... */ /* Internal API cleanup would make this easier... */
int i; int i;
@ -1701,6 +1745,12 @@ get_current_stream_number (GstPlayBin * playbin, GPtrArray * channels)
GstObject *selector = NULL; GstObject *selector = NULL;
int ret = -1; int ret = -1;
if (!select->has_active_pad) {
GST_WARNING_OBJECT (playbin,
"selector doesn't have the \"active-pad\" property");
return ret;
}
for (i = 0; i < channels->len; i++) { for (i = 0; i < channels->len; i++) {
pad = g_ptr_array_index (channels, i); pad = g_ptr_array_index (channels, i);
if ((selector = gst_pad_get_parent (pad))) { if ((selector = gst_pad_get_parent (pad))) {
@ -1756,6 +1806,8 @@ gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
playbin->current_video, stream); playbin->current_video, stream);
group = get_group (playbin); group = get_group (playbin);
if (!group->selector[PLAYBIN_STREAM_VIDEO].has_active_pad)
goto no_active_pad;
if (!(channels = group->video_channels)) if (!(channels = group->video_channels))
goto no_channels; goto no_channels;
@ -1793,6 +1845,13 @@ gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
} }
return TRUE; return TRUE;
no_active_pad:
{
GST_PLAY_BIN_UNLOCK (playbin);
GST_WARNING_OBJECT (playbin,
"can't switch video, the stream combiner's sink pads don't have the \"active-pad\" property");
return FALSE;
}
no_channels: no_channels:
{ {
GST_PLAY_BIN_UNLOCK (playbin); GST_PLAY_BIN_UNLOCK (playbin);
@ -1814,6 +1873,8 @@ gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
playbin->current_audio, stream); playbin->current_audio, stream);
group = get_group (playbin); group = get_group (playbin);
if (!group->selector[PLAYBIN_STREAM_AUDIO].has_active_pad)
goto no_active_pad;
if (!(channels = group->audio_channels)) if (!(channels = group->audio_channels))
goto no_channels; goto no_channels;
@ -1850,6 +1911,13 @@ gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
} }
return TRUE; return TRUE;
no_active_pad:
{
GST_PLAY_BIN_UNLOCK (playbin);
GST_WARNING_OBJECT (playbin,
"can't switch audio, the stream combiner's sink pads don't have the \"active-pad\" property");
return FALSE;
}
no_channels: no_channels:
{ {
GST_PLAY_BIN_UNLOCK (playbin); GST_PLAY_BIN_UNLOCK (playbin);
@ -1962,6 +2030,8 @@ gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
playbin->current_text, stream); playbin->current_text, stream);
group = get_group (playbin); group = get_group (playbin);
if (!group->selector[PLAYBIN_STREAM_TEXT].has_active_pad)
goto no_active_pad;
if (!(channels = group->text_channels)) if (!(channels = group->text_channels))
goto no_channels; goto no_channels;
@ -2048,6 +2118,13 @@ gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
} }
return TRUE; return TRUE;
no_active_pad:
{
GST_PLAY_BIN_UNLOCK (playbin);
GST_WARNING_OBJECT (playbin,
"can't switch text, the stream combiner's sink pads don't have the \"active-pad\" property");
return FALSE;
}
no_channels: no_channels:
{ {
GST_PLAY_BIN_UNLOCK (playbin); GST_PLAY_BIN_UNLOCK (playbin);
@ -2077,6 +2154,30 @@ gst_play_bin_set_sink (GstPlayBin * playbin, GstElement ** elem,
GST_PLAY_BIN_UNLOCK (playbin); GST_PLAY_BIN_UNLOCK (playbin);
} }
static void
gst_play_bin_set_stream_combiner (GstPlayBin * playbin, GstElement ** elem,
const gchar * dbg, GstElement * combiner)
{
GST_INFO_OBJECT (playbin, "Setting %s stream combiner to %" GST_PTR_FORMAT,
dbg, combiner);
GST_PLAY_BIN_LOCK (playbin);
if (*elem != combiner) {
GstElement *old;
old = *elem;
if (combiner)
gst_object_ref_sink (combiner);
*elem = combiner;
if (old)
gst_object_unref (old);
}
GST_LOG_OBJECT (playbin, "%s stream combiner now %" GST_PTR_FORMAT, dbg,
*elem);
GST_PLAY_BIN_UNLOCK (playbin);
}
static void static void
gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding) gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
{ {
@ -2142,6 +2243,18 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
gst_play_bin_set_sink (playbin, &playbin->text_sink, "text", gst_play_bin_set_sink (playbin, &playbin->text_sink, "text",
g_value_get_object (value)); g_value_get_object (value));
break; break;
case PROP_VIDEO_STREAM_COMBINER:
gst_play_bin_set_stream_combiner (playbin,
&playbin->video_stream_combiner, "video", g_value_get_object (value));
break;
case PROP_AUDIO_STREAM_COMBINER:
gst_play_bin_set_stream_combiner (playbin,
&playbin->audio_stream_combiner, "audio", g_value_get_object (value));
break;
case PROP_TEXT_STREAM_COMBINER:
gst_play_bin_set_stream_combiner (playbin,
&playbin->text_stream_combiner, "text", g_value_get_object (value));
break;
case PROP_VOLUME: case PROP_VOLUME:
gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value)); gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
break; break;
@ -2200,6 +2313,22 @@ gst_play_bin_get_current_sink (GstPlayBin * playbin, GstElement ** elem,
return sink; return sink;
} }
static GstElement *
gst_play_bin_get_current_stream_combiner (GstPlayBin * playbin,
GstElement ** elem, const gchar * dbg, int stream_type)
{
GstElement *combiner;
GST_PLAY_BIN_LOCK (playbin);
if ((combiner = playbin->curr_group->selector[stream_type].selector))
gst_object_ref (combiner);
else if ((combiner = *elem))
gst_object_ref (combiner);
GST_PLAY_BIN_UNLOCK (playbin);
return combiner;
}
static void static void
gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value, gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec) GParamSpec * pspec)
@ -2334,6 +2463,21 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
gst_play_bin_get_current_sink (playbin, &playbin->text_sink, gst_play_bin_get_current_sink (playbin, &playbin->text_sink,
"text", GST_PLAY_SINK_TYPE_TEXT)); "text", GST_PLAY_SINK_TYPE_TEXT));
break; break;
case PROP_VIDEO_STREAM_COMBINER:
g_value_take_object (value,
gst_play_bin_get_current_stream_combiner (playbin,
&playbin->video_stream_combiner, "video", PLAYBIN_STREAM_VIDEO));
break;
case PROP_AUDIO_STREAM_COMBINER:
g_value_take_object (value,
gst_play_bin_get_current_stream_combiner (playbin,
&playbin->audio_stream_combiner, "audio", PLAYBIN_STREAM_VIDEO));
break;
case PROP_TEXT_STREAM_COMBINER:
g_value_take_object (value,
gst_play_bin_get_current_stream_combiner (playbin,
&playbin->text_stream_combiner, "text", PLAYBIN_STREAM_VIDEO));
break;
case PROP_VOLUME: case PROP_VOLUME:
g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink)); g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
break; break;
@ -2634,7 +2778,7 @@ selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
case GST_PLAY_SINK_TYPE_VIDEO_RAW: case GST_PLAY_SINK_TYPE_VIDEO_RAW:
property = "current-video"; property = "current-video";
playbin->current_video = get_current_stream_number (playbin, playbin->current_video = get_current_stream_number (playbin,
group->video_channels); select, group->video_channels);
if (playbin->video_pending_flush_finish) { if (playbin->video_pending_flush_finish) {
playbin->video_pending_flush_finish = FALSE; playbin->video_pending_flush_finish = FALSE;
@ -2648,7 +2792,7 @@ selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
case GST_PLAY_SINK_TYPE_AUDIO_RAW: case GST_PLAY_SINK_TYPE_AUDIO_RAW:
property = "current-audio"; property = "current-audio";
playbin->current_audio = get_current_stream_number (playbin, playbin->current_audio = get_current_stream_number (playbin,
group->audio_channels); select, group->audio_channels);
if (playbin->audio_pending_flush_finish) { if (playbin->audio_pending_flush_finish) {
playbin->audio_pending_flush_finish = FALSE; playbin->audio_pending_flush_finish = FALSE;
@ -2661,7 +2805,7 @@ selector_active_pad_changed (GObject * selector, GParamSpec * pspec,
case GST_PLAY_SINK_TYPE_TEXT: case GST_PLAY_SINK_TYPE_TEXT:
property = "current-text"; property = "current-text";
playbin->current_text = get_current_stream_number (playbin, playbin->current_text = get_current_stream_number (playbin,
group->text_channels); select, group->text_channels);
if (playbin->text_pending_flush_finish) { if (playbin->text_pending_flush_finish) {
playbin->text_pending_flush_finish = FALSE; playbin->text_pending_flush_finish = FALSE;
@ -2779,6 +2923,7 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
GstSourceSelect *select = NULL; GstSourceSelect *select = NULL;
gint i, pass; gint i, pass;
gboolean changed = FALSE; gboolean changed = FALSE;
GstElement *custom_combiner = NULL;
playbin = group->playbin; playbin = group->playbin;
@ -2808,6 +2953,16 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
gst_caps_unref (media_caps); gst_caps_unref (media_caps);
} }
} }
/* get custom stream combiner if there is one */
if (select) {
if (i == PLAYBIN_STREAM_AUDIO) {
custom_combiner = playbin->audio_stream_combiner;
} else if (i == PLAYBIN_STREAM_TEXT) {
custom_combiner = playbin->text_stream_combiner;
} else if (i == PLAYBIN_STREAM_VIDEO) {
custom_combiner = playbin->video_stream_combiner;
}
}
} }
/* no selector found for the media type, don't bother linking it to a /* no selector found for the media type, don't bother linking it to a
* selector. This will leave the pad unlinked and thus ignored. */ * selector. This will leave the pad unlinked and thus ignored. */
@ -2818,7 +2973,11 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
if (select->selector == NULL && playbin->have_selector) { if (select->selector == NULL && playbin->have_selector) {
/* no selector, create one */ /* no selector, create one */
GST_DEBUG_OBJECT (playbin, "creating new input selector"); GST_DEBUG_OBJECT (playbin, "creating new input selector");
select->selector = gst_element_factory_make ("input-selector", NULL); if (custom_combiner)
select->selector = gst_object_ref (custom_combiner);
else
select->selector = gst_element_factory_make ("input-selector", NULL);
if (select->selector == NULL) { if (select->selector == NULL) {
/* post the missing selector message only once */ /* post the missing selector message only once */
playbin->have_selector = FALSE; playbin->have_selector = FALSE;
@ -2829,15 +2988,23 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
(_("Missing element '%s' - check your GStreamer installation."), (_("Missing element '%s' - check your GStreamer installation."),
"input-selector"), (NULL)); "input-selector"), (NULL));
} else { } else {
/* sync-mode=1, use clock */ /* find out which properties the stream combiner supports */
if (select->type == GST_PLAY_SINK_TYPE_TEXT) select->has_active_pad =
g_object_set (select->selector, "sync-streams", TRUE, g_object_class_find_property (G_OBJECT_GET_CLASS (select->selector),
"sync-mode", 1, "cache-buffers", TRUE, NULL); "active-pad") != NULL;
else
g_object_set (select->selector, "sync-streams", TRUE, NULL);
g_signal_connect (select->selector, "notify::active-pad", if (!custom_combiner) {
G_CALLBACK (selector_active_pad_changed), playbin); /* sync-mode=1, use clock */
if (select->type == GST_PLAY_SINK_TYPE_TEXT)
g_object_set (select->selector, "sync-streams", TRUE,
"sync-mode", 1, "cache-buffers", TRUE, NULL);
else
g_object_set (select->selector, "sync-streams", TRUE, NULL);
}
if (select->has_active_pad)
g_signal_connect (select->selector, "notify::active-pad",
G_CALLBACK (selector_active_pad_changed), playbin);
GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector); GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
gst_bin_add (GST_BIN_CAST (playbin), select->selector); gst_bin_add (GST_BIN_CAST (playbin), select->selector);
@ -2867,29 +3034,40 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
/* get sinkpad for the new stream */ /* get sinkpad for the new stream */
if (select->selector) { if (select->selector) {
if ((sinkpad = gst_element_get_request_pad (select->selector, "sink_%u"))) { if ((sinkpad = gst_element_get_request_pad (select->selector, "sink_%u"))) {
gulong notify_tags_handler = 0;
NotifyTagsData *ntdata;
GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector", GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
GST_DEBUG_PAD_NAME (sinkpad)); GST_DEBUG_PAD_NAME (sinkpad));
/* find out which properties the sink pad supports */
select->has_always_ok =
g_object_class_find_property (G_OBJECT_GET_CLASS (sinkpad),
"always-ok") != NULL;
select->has_tags =
g_object_class_find_property (G_OBJECT_GET_CLASS (sinkpad),
"tags") != NULL;
/* store the selector for the pad */ /* store the selector for the pad */
g_object_set_data (G_OBJECT (sinkpad), "playbin.select", select); g_object_set_data (G_OBJECT (sinkpad), "playbin.select", select);
/* connect to the notify::tags signal for our if (select->has_tags) {
* own *-tags-changed signals gulong notify_tags_handler = 0;
*/ NotifyTagsData *ntdata;
ntdata = g_new0 (NotifyTagsData, 1);
ntdata->playbin = playbin;
ntdata->stream_id = select->channels->len;
ntdata->type = select->type;
notify_tags_handler = /* connect to the notify::tags signal for our
g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags", * own *-tags-changed signals
G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free, */
(GConnectFlags) 0); ntdata = g_new0 (NotifyTagsData, 1);
g_object_set_data (G_OBJECT (sinkpad), "playbin.notify_tags_handler", ntdata->playbin = playbin;
(gpointer) (guintptr) notify_tags_handler); ntdata->stream_id = select->channels->len;
ntdata->type = select->type;
notify_tags_handler =
g_signal_connect_data (G_OBJECT (sinkpad), "notify::tags",
G_CALLBACK (notify_tags_cb), ntdata, (GClosureNotify) g_free,
(GConnectFlags) 0);
g_object_set_data (G_OBJECT (sinkpad), "playbin.notify_tags_handler",
(gpointer) (guintptr) notify_tags_handler);
}
/* store the pad in the array */ /* store the pad in the array */
GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad); GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
@ -2926,34 +3104,35 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
if (changed) { if (changed) {
int signal; int signal;
gboolean always_ok = (decodebin == group->suburidecodebin);
switch (select->type) { switch (select->type) {
case GST_PLAY_SINK_TYPE_VIDEO: case GST_PLAY_SINK_TYPE_VIDEO:
case GST_PLAY_SINK_TYPE_VIDEO_RAW: case GST_PLAY_SINK_TYPE_VIDEO_RAW:
/* we want to return NOT_LINKED for unselected pads but only for pads
* from the normal uridecodebin. This makes sure that subtitle streams
* are not raced past audio/video from decodebin's multiqueue.
* For pads from suburidecodebin OK should always be returned, otherwise
* it will most likely stop. */
g_object_set (sinkpad, "always-ok", always_ok, NULL);
signal = SIGNAL_VIDEO_CHANGED; signal = SIGNAL_VIDEO_CHANGED;
break; break;
case GST_PLAY_SINK_TYPE_AUDIO: case GST_PLAY_SINK_TYPE_AUDIO:
case GST_PLAY_SINK_TYPE_AUDIO_RAW: case GST_PLAY_SINK_TYPE_AUDIO_RAW:
g_object_set (sinkpad, "always-ok", always_ok, NULL);
signal = SIGNAL_AUDIO_CHANGED; signal = SIGNAL_AUDIO_CHANGED;
break; break;
case GST_PLAY_SINK_TYPE_TEXT: case GST_PLAY_SINK_TYPE_TEXT:
g_object_set (sinkpad, "always-ok", always_ok, NULL);
signal = SIGNAL_TEXT_CHANGED; signal = SIGNAL_TEXT_CHANGED;
break; break;
default: default:
signal = -1; signal = -1;
} }
if (signal >= 0) if (signal >= 0) {
/* we want to return NOT_LINKED for unselected pads but only for pads
* from the normal uridecodebin. This makes sure that subtitle streams
* are not raced past audio/video from decodebin's multiqueue.
* For pads from suburidecodebin OK should always be returned, otherwise
* it will most likely stop. */
if (select->has_always_ok) {
gboolean always_ok = (decodebin == group->suburidecodebin);
g_object_set (sinkpad, "always-ok", always_ok, NULL);
}
g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL); g_signal_emit (G_OBJECT (playbin), gst_play_bin_signals[signal], 0, NULL);
}
} }
done: done:
@ -3007,14 +3186,16 @@ pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
goto not_linked; goto not_linked;
if ((select = g_object_get_data (G_OBJECT (peer), "playbin.select"))) { if ((select = g_object_get_data (G_OBJECT (peer), "playbin.select"))) {
gulong notify_tags_handler; if (select->has_tags) {
gulong notify_tags_handler;
notify_tags_handler = notify_tags_handler =
(guintptr) g_object_get_data (G_OBJECT (peer), (guintptr) g_object_get_data (G_OBJECT (peer),
"playbin.notify_tags_handler"); "playbin.notify_tags_handler");
if (notify_tags_handler != 0) if (notify_tags_handler != 0)
g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler); g_signal_handler_disconnect (G_OBJECT (peer), notify_tags_handler);
g_object_set_data (G_OBJECT (peer), "playbin.notify_tags_handler", NULL); g_object_set_data (G_OBJECT (peer), "playbin.notify_tags_handler", NULL);
}
/* remove the pad from the array */ /* remove the pad from the array */
g_ptr_array_remove (select->channels, peer); g_ptr_array_remove (select->channels, peer);