gst/playback/gstplaybin2.c: Update some docs.

Original commit message from CVS:
* gst/playback/gstplaybin2.c: (gst_play_bin_class_init),
(init_group), (free_group), (gst_play_bin_init),
(gst_play_bin_finalize), (gst_play_bin_set_uri),
(gst_play_bin_set_suburi), (gst_play_bin_get_video_tags),
(gst_play_bin_get_audio_tags), (gst_play_bin_get_text_tags),
(gst_play_bin_set_current_video_stream),
(gst_play_bin_set_current_audio_stream),
(gst_play_bin_set_current_text_stream),
(gst_play_bin_set_encoding), (gst_play_bin_set_property),
(gst_play_bin_get_property), (pad_added_cb), (pad_removed_cb),
(no_more_pads_cb), (perform_eos), (autoplug_select_cb),
(activate_group), (deactivate_group), (setup_next_source),
(save_current_group), (gst_play_bin_change_state):
Update some docs.
Add new locks and conds to protect pipeline creation and group
switching.
Implement the sub-uri property.
Keep track of pending uridecodebin creation and configure the output
pipeline after all streams are configured.
Propagate subtitle encoding to the uridecodebins.
Implement getting the video/audio/visualisation elements.
Use input-selector for stream switching.
If we are asked to do visualisation, prefer to autoplug raw sinks
instead of sinks that accept encoded data.
This commit is contained in:
Wim Taymans 2008-03-24 12:26:30 +00:00
parent cd1fed3345
commit ad1cbe1edd
2 changed files with 279 additions and 57 deletions

View file

@ -1,3 +1,30 @@
2008-03-24 Wim Taymans <wim.taymans@collabora.co.uk>
* gst/playback/gstplaybin2.c: (gst_play_bin_class_init),
(init_group), (free_group), (gst_play_bin_init),
(gst_play_bin_finalize), (gst_play_bin_set_uri),
(gst_play_bin_set_suburi), (gst_play_bin_get_video_tags),
(gst_play_bin_get_audio_tags), (gst_play_bin_get_text_tags),
(gst_play_bin_set_current_video_stream),
(gst_play_bin_set_current_audio_stream),
(gst_play_bin_set_current_text_stream),
(gst_play_bin_set_encoding), (gst_play_bin_set_property),
(gst_play_bin_get_property), (pad_added_cb), (pad_removed_cb),
(no_more_pads_cb), (perform_eos), (autoplug_select_cb),
(activate_group), (deactivate_group), (setup_next_source),
(save_current_group), (gst_play_bin_change_state):
Update some docs.
Add new locks and conds to protect pipeline creation and group
switching.
Implement the sub-uri property.
Keep track of pending uridecodebin creation and configure the output
pipeline after all streams are configured.
Propagate subtitle encoding to the uridecodebins.
Implement getting the video/audio/visualisation elements.
Use input-selector for stream switching.
If we are asked to do visualisation, prefer to autoplug raw sinks
instead of sinks that accept encoded data.
2008-03-24 Wim Taymans <wim.taymans@collabora.co.uk>
* gst/playback/gstplaysink.c: (gst_play_sink_class_init),

View file

@ -36,10 +36,11 @@
* visualisations for audio files
* </listitem>
* <listitem>
* subtitle support for video files
* subtitle support for video files. Subtitles can be store in external
* files.
* </listitem>
* <listitem>
* stream selection between different audio/subtitles streams
* stream selection between different video/audio/subtitles streams
* </listitem>
* <listitem>
* meta info (tag) extraction
@ -51,7 +52,7 @@
* buffering when playing streams over a network
* </listitem>
* <listitem>
* volume control
* volume control with mute option
* </listitem>
* </itemizedlist>
* </para>
@ -284,12 +285,24 @@ struct _GstSourceSelect
GstPad *sinkpad; /* the sinkpad of the sink when the selector is linked */
};
#define GST_SOURCE_GROUP_GET_LOCK(group) (((GstSourceGroup*)(group))->lock)
#define GST_SOURCE_GROUP_GET_COND(group) (((GstSourceGroup*)(group))->cond)
#define GST_SOURCE_GROUP_LOCK(group) (g_mutex_lock (GST_SOURCE_GROUP_GET_LOCK(group)))
#define GST_SOURCE_GROUP_UNLOCK(group) (g_mutex_unlock (GST_SOURCE_GROUP_GET_LOCK(group)))
#define GST_SOURCE_GROUP_WAIT(group) (g_cond_wait \
(GST_SOURCE_GROUP_GET_COND (group),GST_SOURCE_GROUP_GET_LOCK(group)))
#define GST_SOURCE_GROUP_BROADCAST(group) (g_cond_broadcast \
(GST_SOURCE_GROUP_GET_COND (group)))
/* a structure to hold the objects for decoding a uri and the subtitle uri
*/
struct _GstSourceGroup
{
GstPlayBin *playbin;
GMutex *lock;
GCond *cond;
gboolean valid; /* the group has valid info to start playback */
gboolean active; /* the group is active */
@ -298,7 +311,6 @@ struct _GstSourceGroup
gchar *suburi;
GValueArray *streaminfo;
GstElement *source;
gchar *subencoding; /* encoding to propagate to the subtitle elements */
GPtrArray *video_channels; /* links to selector pads */
GPtrArray *audio_channels; /* links to selector pads */
@ -307,15 +319,22 @@ struct _GstSourceGroup
/* uridecodebins for uri and subtitle uri */
GstElement *uridecodebin;
GstElement *suburidecodebin;
gint pending;
/* selectors for different streams */
GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
};
#define GST_PLAY_BIN_GET_LOCK(bin) (((GstPlayBin*)(bin))->lock)
#define GST_PLAY_BIN_LOCK(bin) (g_mutex_lock (GST_PLAY_BIN_GET_LOCK(bin)))
#define GST_PLAY_BIN_UNLOCK(bin) (g_mutex_unlock (GST_PLAY_BIN_GET_LOCK(bin)))
struct _GstPlayBin
{
GstPipeline parent;
GMutex *lock; /* to protect group switching */
/* the groups, we use a double buffer to switch between current and next */
GstSourceGroup groups[2]; /* array with group info */
GstSourceGroup *curr_group; /* pointer to the currently playing group */
@ -328,6 +347,7 @@ struct _GstPlayBin
gint current_video; /* the currently selected stream */
gint current_audio; /* the currently selected stream */
gint current_text; /* the currently selected stream */
gchar *encoding; /* subtitle encoding */
/* our play sink */
GstPlaySink *playsink;
@ -552,7 +572,6 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
g_param_spec_object ("source", "Source", "Source element",
GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/**
* GstPlayBin:flags
*
@ -639,7 +658,7 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
g_param_spec_object ("vis-plugin", "Vis plugin",
"the visualization element to use (NULL = none)",
"the visualization element to use (NULL = default)",
GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_klass, PROP_VOLUME,
@ -818,6 +837,8 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group)
group->video_channels = g_ptr_array_new ();
group->audio_channels = g_ptr_array_new ();
group->text_channels = g_ptr_array_new ();
group->lock = g_mutex_new ();
group->cond = g_cond_new ();
/* init selectors */
group->playbin = playbin;
group->selector[0].media = "audio/x-raw-";
@ -837,11 +858,23 @@ init_group (GstPlayBin * playbin, GstSourceGroup * group)
group->selector[4].channels = group->text_channels;
}
static void
free_group (GstPlayBin * playbin, GstSourceGroup * group)
{
g_ptr_array_free (group->video_channels, TRUE);
g_ptr_array_free (group->audio_channels, TRUE);
g_ptr_array_free (group->text_channels, TRUE);
g_mutex_free (group->lock);
g_cond_free (group->cond);
}
static void
gst_play_bin_init (GstPlayBin * playbin)
{
GstFactoryListType type;
playbin->lock = g_mutex_new ();
/* init groups */
playbin->curr_group = &playbin->groups[0];
playbin->next_group = &playbin->groups[1];
@ -861,6 +894,7 @@ gst_play_bin_init (GstPlayBin * playbin)
playbin->current_video = DEFAULT_CURRENT_VIDEO;
playbin->current_audio = DEFAULT_CURRENT_AUDIO;
playbin->current_text = DEFAULT_CURRENT_TEXT;
playbin->encoding = g_strdup (DEFAULT_SUBTITLE_ENCODING);
}
static void
@ -870,7 +904,12 @@ gst_play_bin_finalize (GObject * object)
playbin = GST_PLAY_BIN (object);
free_group (playbin, &playbin->groups[0]);
free_group (playbin, &playbin->groups[1]);
g_value_array_free (playbin->elements);
g_free (playbin->encoding);
g_mutex_free (playbin->lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@ -885,17 +924,19 @@ gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
return;
}
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = playbin->next_group;
GST_SOURCE_GROUP_LOCK (group);
/* if we have no previous uri, or the new uri is different from the
* old one, replug */
g_free (group->uri);
group->uri = g_strdup (uri);
group->valid = TRUE;
GST_SOURCE_GROUP_UNLOCK (group);
GST_DEBUG ("setting new uri to %s", uri);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
}
static void
@ -903,9 +944,10 @@ gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
{
GstSourceGroup *group;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = playbin->next_group;
GST_SOURCE_GROUP_LOCK (group);
if ((!suburi && !group->suburi) ||
(suburi && group->suburi && !strcmp (group->suburi, suburi)))
goto done;
@ -916,11 +958,12 @@ gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
GST_DEBUG ("setting new .sub uri to %s", suburi);
done:
GST_OBJECT_UNLOCK (playbin);
GST_SOURCE_GROUP_UNLOCK (group);
GST_PLAY_BIN_UNLOCK (playbin);
}
/* get the currently playing group or if nothing is playing, the next
* group. Must be called with the LOCK. */
* group. Must be called with the PLAY_BIN_LOCK. */
static GstSourceGroup *
get_group (GstPlayBin * playbin)
{
@ -953,10 +996,10 @@ gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
GstTagList *result;
GstSourceGroup *group;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
result = get_tags (playbin, group->video_channels, stream);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
return result;
}
@ -967,10 +1010,10 @@ gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
GstTagList *result;
GstSourceGroup *group;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
result = get_tags (playbin, group->audio_channels, stream);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
return result;
}
@ -981,10 +1024,10 @@ gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
GstTagList *result;
GstSourceGroup *group;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
result = get_tags (playbin, group->text_channels, stream);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
return result;
}
@ -1012,7 +1055,7 @@ gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
GPtrArray *channels;
GstPad *sinkpad;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
if (!(channels = group->video_channels))
goto no_channels;
@ -1026,7 +1069,7 @@ gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
if (sinkpad)
gst_object_ref (sinkpad);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
if (sinkpad) {
GstObject *selector;
@ -1042,7 +1085,7 @@ gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
no_channels:
{
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
return FALSE;
}
}
@ -1054,7 +1097,7 @@ gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
GPtrArray *channels;
GstPad *sinkpad;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
if (!(channels = group->audio_channels))
goto no_channels;
@ -1068,7 +1111,7 @@ gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
if (sinkpad)
gst_object_ref (sinkpad);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
if (sinkpad) {
GstObject *selector;
@ -1084,7 +1127,7 @@ gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
no_channels:
{
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
return FALSE;
}
}
@ -1096,7 +1139,7 @@ gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
GPtrArray *channels;
GstPad *sinkpad;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
if (!(channels = group->text_channels))
goto no_channels;
@ -1110,7 +1153,7 @@ gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
if (sinkpad)
gst_object_ref (sinkpad);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
if (sinkpad) {
GstObject *selector;
@ -1126,11 +1169,32 @@ gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
no_channels:
{
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
return FALSE;
}
}
static void
gst_play_bin_set_encoding (GstPlayBin * playbin, const gchar * encoding)
{
GstElement *elem;
GST_PLAY_BIN_LOCK (playbin);
g_free (playbin->encoding);
playbin->encoding = g_strdup (encoding);
/* set subtitles on all current and next decodebins. */
if ((elem = playbin->groups[0].uridecodebin))
g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
if ((elem = playbin->groups[0].suburidecodebin))
g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
if ((elem = playbin->groups[1].uridecodebin))
g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
if ((elem = playbin->groups[1].suburidecodebin))
g_object_set (G_OBJECT (elem), "subtitle-encoding", encoding, NULL);
GST_PLAY_BIN_UNLOCK (playbin);
}
static void
gst_play_bin_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
@ -1148,6 +1212,7 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
break;
case PROP_FLAGS:
gst_play_sink_set_flags (playbin->playsink, g_value_get_flags (value));
gst_play_sink_reconfigure (playbin->playsink);
break;
case PROP_CURRENT_VIDEO:
gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
@ -1159,10 +1224,15 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
break;
case PROP_SUBTITLE_ENCODING:
gst_play_bin_set_encoding (playbin, g_value_get_string (value));
break;
case PROP_VIDEO_SINK:
gst_play_sink_set_video_sink (playbin->playsink,
g_value_get_object (value));
break;
case PROP_AUDIO_SINK:
gst_play_sink_set_audio_sink (playbin->playsink,
g_value_get_object (value));
break;
case PROP_VIS_PLUGIN:
gst_play_sink_set_vis_plugin (playbin->playsink,
@ -1175,11 +1245,13 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
break;
case PROP_FONT_DESC:
gst_play_sink_set_font_desc (playbin->playsink,
g_value_get_string (value));
break;
case PROP_CONNECTION_SPEED:
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
playbin->connection_speed = g_value_get_uint (value) * 1000;
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -1200,20 +1272,20 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
{
GstSourceGroup *group;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
g_value_set_string (value, group->uri);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
}
case PROP_SUBURI:
{
GstSourceGroup *group;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
g_value_set_string (value, group->suburi);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
}
case PROP_SOURCE:
@ -1226,59 +1298,68 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
GstSourceGroup *group;
gint n_video;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
n_video = (group->video_channels ? group->video_channels->len : 0);
g_value_set_int (value, n_video);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
}
case PROP_CURRENT_VIDEO:
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
g_value_set_int (value, playbin->current_video);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
case PROP_N_AUDIO:
{
GstSourceGroup *group;
gint n_audio;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
n_audio = (group->audio_channels ? group->audio_channels->len : 0);
g_value_set_int (value, n_audio);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
}
case PROP_CURRENT_AUDIO:
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
g_value_set_int (value, playbin->current_audio);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
case PROP_N_TEXT:
{
GstSourceGroup *group;
gint n_text;
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
group = get_group (playbin);
n_text = (group->text_channels ? group->text_channels->len : 0);
g_value_set_int (value, n_text);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
}
case PROP_CURRENT_TEXT:
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
g_value_set_int (value, playbin->current_text);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
case PROP_SUBTITLE_ENCODING:
GST_PLAY_BIN_LOCK (playbin);
g_value_set_string (value, playbin->encoding);
GST_PLAY_BIN_UNLOCK (playbin);
break;
case PROP_VIDEO_SINK:
g_value_set_object (value,
gst_play_sink_get_video_sink (playbin->playsink));
break;
case PROP_AUDIO_SINK:
g_value_set_object (value,
gst_play_sink_get_audio_sink (playbin->playsink));
break;
case PROP_VIS_PLUGIN:
g_value_set_object (value,
gst_play_sink_get_vis_plugin (playbin->playsink));
break;
case PROP_VOLUME:
g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
@ -1290,11 +1371,13 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
gst_value_take_buffer (value, gst_play_bin_convert_frame (playbin, NULL));
break;
case PROP_FONT_DESC:
g_value_take_string (value,
gst_play_sink_get_font_desc (playbin->playsink));
break;
case PROP_CONNECTION_SPEED:
GST_OBJECT_LOCK (playbin);
GST_PLAY_BIN_LOCK (playbin);
g_value_set_uint (value, playbin->connection_speed / 1000);
GST_OBJECT_UNLOCK (playbin);
GST_PLAY_BIN_UNLOCK (playbin);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -1366,10 +1449,11 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
if (select == NULL)
goto unknown_type;
GST_SOURCE_GROUP_LOCK (group);
if (select->selector == NULL) {
/* no selector, create one */
GST_DEBUG_OBJECT (playbin, "creating new selector");
select->selector = g_object_new (GST_TYPE_STREAM_SELECTOR, NULL);
select->selector = gst_element_factory_make ("input-selector", NULL);
if (select->selector == NULL)
goto no_selector;
@ -1402,6 +1486,7 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
}
GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
GST_DEBUG_PAD_NAME (pad), select->selector);
GST_SOURCE_GROUP_UNLOCK (group);
return;
@ -1416,6 +1501,7 @@ no_selector:
{
GST_ERROR_OBJECT (playbin, "could not create selector for pad %s:%s",
GST_DEBUG_PAD_NAME (pad));
GST_SOURCE_GROUP_UNLOCK (group);
return;
}
link_failed:
@ -1423,6 +1509,7 @@ link_failed:
GST_ERROR_OBJECT (playbin,
"failed to link pad %s:%s to selector, reason %d",
GST_DEBUG_PAD_NAME (pad), res);
GST_SOURCE_GROUP_UNLOCK (group);
return;
}
}
@ -1442,6 +1529,7 @@ pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
GST_DEBUG_OBJECT (playbin,
"pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
GST_SOURCE_GROUP_LOCK (group);
/* get the selector sinkpad */
if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
goto not_linked;
@ -1466,6 +1554,7 @@ pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
gst_element_release_request_pad (selector, peer);
gst_object_unref (selector);
GST_SOURCE_GROUP_UNLOCK (group);
return;
@ -1473,11 +1562,13 @@ pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
not_linked:
{
GST_DEBUG_OBJECT (playbin, "pad not linked");
GST_SOURCE_GROUP_UNLOCK (group);
return;
}
no_selector:
{
GST_DEBUG_OBJECT (playbin, "selector not found");
GST_SOURCE_GROUP_UNLOCK (group);
return;
}
}
@ -1497,15 +1588,21 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
GstPlayBin *playbin;
GstPadLinkReturn res;
gint i;
gboolean configure;
playbin = group->playbin;
GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
GST_SOURCE_GROUP_LOCK (group);
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
if (select->selector) {
/* check if the specific media type was detected and thus has a selector
* 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 (select->selector && select->sinkpad == NULL) {
select->sinkpad =
gst_play_sink_request_pad (playbin->playsink, select->type);
res = gst_pad_link (select->srcpad, select->sinkpad);
@ -1513,8 +1610,33 @@ no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
res);
}
}
/* configure the modes now */
gst_play_sink_reconfigure (playbin->playsink);
group->pending--;
if (group->pending == 0) {
/* we are the last group to complete, we will configure the output and then
* signal the other waiters. */
configure = TRUE;
} else {
configure = FALSE;
/* check if there are more decodebins to wait for */
while (group->pending) {
GST_DEBUG_OBJECT (playbin, "%d pending in group %p, waiting",
group->pending, group);
/* FIXME, unlock when shutting down */
GST_SOURCE_GROUP_WAIT (group);
}
}
GST_SOURCE_GROUP_UNLOCK (group);
if (configure) {
/* we configure the modes if we were the last decodebin to complete. */
gst_play_sink_reconfigure (playbin->playsink);
/* signal the other decodebins that they can continue now. */
GST_SOURCE_GROUP_LOCK (group);
GST_DEBUG_OBJECT (playbin, "signal other decodebins");
GST_SOURCE_GROUP_BROADCAST (group);
GST_SOURCE_GROUP_UNLOCK (group);
}
}
/* send an EOS event to all of the selectors */
@ -1527,6 +1649,8 @@ perform_eos (GstPlayBin * playbin, GstSourceGroup * group)
GST_DEBUG_OBJECT (playbin, "doing EOS in group %p", group);
event = gst_event_new_eos ();
GST_SOURCE_GROUP_LOCK (group);
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
@ -1536,6 +1660,8 @@ perform_eos (GstPlayBin * playbin, GstSourceGroup * group)
gst_pad_push_event (select->srcpad, event);
}
}
GST_SOURCE_GROUP_UNLOCK (group);
gst_event_unref (event);
}
@ -1592,8 +1718,8 @@ autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
/* We are asked to select an element. See if the next element to check
* is a sink. If this is the case, we see if the sink works by setting it to
* READY. If the sink works, we return -2 to make decodebin expose the raw pad
* so that we can setup the mixers. */
* READY. If the sink works, we return SELECT_EXPOSE to make decodebin
* expose the raw pad so that we can setup the mixers. */
static GstAutoplugSelectResult
autoplug_select_cb (GstElement * decodebin, GstPad * pad,
GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
@ -1617,6 +1743,17 @@ autoplug_select_cb (GstElement * decodebin, GstPad * pad,
/* it's a sink, see if an instance of it actually works */
GST_DEBUG_OBJECT (playbin, "we found a sink");
klass = gst_element_factory_get_klass (factory);
/* if we are asked to do visualisations and it's an audio sink, skip the
* element. We can only do visualisations with raw sinks */
if (gst_play_sink_get_flags (playbin->playsink) & GST_PLAY_FLAG_VIS) {
if (strstr (klass, "Audio")) {
GST_DEBUG_OBJECT (playbin, "skip audio sink because of vis");
return GST_AUTOPLUG_SELECT_SKIP;
}
}
if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
@ -1634,16 +1771,15 @@ autoplug_select_cb (GstElement * decodebin, GstPad * pad,
return GST_AUTOPLUG_SELECT_SKIP;
}
/* at this point, we have the sink working, configure it in playsink */
klass = gst_element_factory_get_klass (factory);
/* get klass to figure out if it's audio or video */
if (strstr (klass, "Audio")) {
GST_DEBUG_OBJECT (playbin, "configure audio sink");
gst_play_sink_set_audio_sink (playbin->playsink, element);
g_object_notify (G_OBJECT (playbin), "audio-sink");
} else if (strstr (klass, "Video")) {
GST_DEBUG_OBJECT (playbin, "configure video sink");
gst_play_sink_set_video_sink (playbin->playsink, element);
g_object_notify (G_OBJECT (playbin), "video-sink");
} else {
GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
}
@ -1655,14 +1791,17 @@ autoplug_select_cb (GstElement * decodebin, GstPad * pad,
return GST_AUTOPLUG_SELECT_EXPOSE;
}
/* must be called with PLAY_BIN_LOCK */
static gboolean
activate_group (GstPlayBin * playbin, GstSourceGroup * group)
{
GstElement *uridecodebin;
GstElement *suburidecodebin;
g_return_val_if_fail (group->valid, FALSE);
g_return_val_if_fail (!group->active, FALSE);
GST_SOURCE_GROUP_LOCK (group);
if (group->uridecodebin) {
gst_element_set_state (group->uridecodebin, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
@ -1676,6 +1815,8 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group)
/* configure connection speed */
g_object_set (uridecodebin, "connection-speed", playbin->connection_speed,
NULL);
/* configure subtitle encoding */
g_object_set (uridecodebin, "subtitle-encoding", playbin->encoding, NULL);
/* configure uri */
g_object_set (uridecodebin, "uri", group->uri, NULL);
@ -1686,6 +1827,9 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group)
group);
g_signal_connect (uridecodebin, "no-more-pads", G_CALLBACK (no_more_pads_cb),
group);
/* we have 1 pending no-more-pads */
group->pending = 1;
/* is called when the uridecodebin is out of data and we can switch to the
* next uri */
g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb), group);
@ -1702,20 +1846,60 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group)
gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
group->uridecodebin = uridecodebin;
if (group->suburi) {
/* subtitles */
if (group->suburidecodebin) {
gst_element_set_state (group->suburidecodebin, GST_STATE_NULL);
gst_bin_remove (GST_BIN_CAST (playbin), group->suburidecodebin);
group->suburidecodebin = NULL;
}
suburidecodebin = gst_element_factory_make ("uridecodebin", NULL);
if (!suburidecodebin)
goto no_decodebin;
/* configure connection speed */
g_object_set (suburidecodebin, "connection-speed",
playbin->connection_speed, NULL);
/* configure subtitle encoding */
g_object_set (suburidecodebin, "subtitle-encoding", playbin->encoding,
NULL);
/* configure uri */
g_object_set (suburidecodebin, "uri", group->suburi, NULL);
/* */
gst_bin_add (GST_BIN_CAST (playbin), suburidecodebin);
group->suburidecodebin = suburidecodebin;
/* connect pads and other things */
g_signal_connect (suburidecodebin, "pad-added", G_CALLBACK (pad_added_cb),
group);
g_signal_connect (suburidecodebin, "pad-removed",
G_CALLBACK (pad_removed_cb), group);
g_signal_connect (suburidecodebin, "no-more-pads",
G_CALLBACK (no_more_pads_cb), group);
/* we have 2 pending no-more-pads */
group->pending = 2;
gst_element_set_state (suburidecodebin, GST_STATE_PAUSED);
}
gst_element_set_state (uridecodebin, GST_STATE_PAUSED);
group->active = TRUE;
GST_SOURCE_GROUP_UNLOCK (group);
return TRUE;
/* ERRORS */
no_decodebin:
{
GST_SOURCE_GROUP_UNLOCK (group);
return FALSE;
}
}
/* unlink a group of uridecodebins from the sink */
/* unlink a group of uridecodebins from the sink.
* must be called with PLAY_BIN_LOCK */
static gboolean
deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
{
@ -1726,6 +1910,8 @@ deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
GST_SOURCE_GROUP_LOCK (group);
group->active = FALSE;
for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
GstSourceSelect *select = &group->selector[i];
@ -1746,7 +1932,7 @@ deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
select->selector = NULL;
}
group->active = FALSE;
GST_SOURCE_GROUP_UNLOCK (group);
return TRUE;
}
@ -1762,6 +1948,7 @@ setup_next_source (GstPlayBin * playbin)
GST_DEBUG_OBJECT (playbin, "setup sources");
/* see if there is a next group */
GST_PLAY_BIN_LOCK (playbin);
new_group = playbin->next_group;
if (!new_group || !new_group->valid)
goto no_next_group;
@ -1781,6 +1968,7 @@ setup_next_source (GstPlayBin * playbin)
/* swap old and new */
playbin->curr_group = new_group;
playbin->next_group = old_group;
GST_PLAY_BIN_UNLOCK (playbin);
return TRUE;
@ -1788,11 +1976,13 @@ setup_next_source (GstPlayBin * playbin)
no_next_group:
{
GST_DEBUG_OBJECT (playbin, "no next group");
GST_PLAY_BIN_UNLOCK (playbin);
return FALSE;
}
activate_failed:
{
GST_DEBUG_OBJECT (playbin, "activate failed");
GST_PLAY_BIN_UNLOCK (playbin);
return FALSE;
}
}
@ -1808,6 +1998,7 @@ save_current_group (GstPlayBin * playbin)
GST_DEBUG_OBJECT (playbin, "save current group");
/* see if there is a current group */
GST_PLAY_BIN_LOCK (playbin);
curr_group = playbin->curr_group;
if (curr_group && curr_group->valid) {
/* unlink our pads with the sink */
@ -1816,6 +2007,7 @@ save_current_group (GstPlayBin * playbin)
/* swap old and new */
playbin->curr_group = playbin->next_group;
playbin->next_group = curr_group;
GST_PLAY_BIN_UNLOCK (playbin);
return TRUE;
}
@ -1833,6 +2025,9 @@ gst_play_bin_change_state (GstElement * element, GstStateChange transition)
if (!setup_next_source (playbin))
goto source_failed;
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
/* FIXME unlock our waiting groups */
break;
default:
break;
}