summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorSeungha Yang <sh.yang@lge.com>2017-03-16 17:52:04 +0900
committerEdward Hervey <bilboed@bilboed.com>2017-10-27 09:45:39 +0200
commita8e05cc9cc66bb55868d5950321d7e7f33312eca (patch)
tree157b6f0ac843d59f551a0e495778a2822d208494 /tools
parentb0c184e189df5133913d2dc7d57de15010b65493 (diff)
downloadgstreamer-plugins-base-a8e05cc9cc66bb55868d5950321d7e7f33312eca.tar.gz
gst-play: Support track change on playbin3
* playbin3 does not support {current,n}-{audio,video,text} properties, and they were replaced by GstStreams API. So, GstStreams API and select-stream event should be used for track change in case of playbin3. see also https://bugzilla.gnome.org/show_bug.cgi?id=769079 * By using commend line option "--use-playbin3", gst-play will use playbin3 regardless of "USE_PLAYBIN" env variable. https://bugzilla.gnome.org/show_bug.cgi?id=775469
Diffstat (limited to 'tools')
-rw-r--r--tools/gst-play.c283
1 files changed, 266 insertions, 17 deletions
diff --git a/tools/gst-play.c b/tools/gst-play.c
index 88c51f940..fcca5b7de 100644
--- a/tools/gst-play.c
+++ b/tools/gst-play.c
@@ -72,6 +72,14 @@ typedef struct
GstElement *playbin;
+ /* playbin3 variables */
+ gboolean is_playbin3;
+ GstStreamCollection *collection;
+ gchar *cur_audio_sid;
+ gchar *cur_video_sid;
+ gchar *cur_text_sid;
+ GMutex selection_lock;
+
GMainLoop *loop;
guint bus_watch;
guint timeout;
@@ -139,12 +147,18 @@ gst_play_printf (const gchar * format, ...)
static GstPlay *
play_new (gchar ** uris, const gchar * audio_sink, const gchar * video_sink,
gboolean gapless, gdouble initial_volume, gboolean verbose,
- const gchar * flags_string)
+ const gchar * flags_string, gboolean use_playbin3)
{
GstElement *sink, *playbin;
GstPlay *play;
- playbin = gst_element_factory_make ("playbin", "playbin");
+
+ if (use_playbin3) {
+ playbin = gst_element_factory_make ("playbin3", "playbin");
+ } else {
+ playbin = gst_element_factory_make ("playbin", "playbin");
+ }
+
if (playbin == NULL)
return NULL;
@@ -156,6 +170,16 @@ play_new (gchar ** uris, const gchar * audio_sink, const gchar * video_sink,
play->playbin = playbin;
+ if (use_playbin3) {
+ play->is_playbin3 = TRUE;
+ } else {
+ const gchar *env = g_getenv ("USE_PLAYBIN3");
+ if (env && g_str_has_prefix (env, "1"))
+ play->is_playbin3 = TRUE;
+ }
+
+ g_mutex_init (&play->selection_lock);
+
if (audio_sink != NULL) {
if (strchr (audio_sink, ' ') != NULL)
sink = gst_parse_bin_from_description (audio_sink, TRUE, NULL);
@@ -244,6 +268,15 @@ play_free (GstPlay * play)
g_main_loop_unref (play->loop);
g_strfreev (play->uris);
+
+ if (play->collection)
+ gst_object_unref (play->collection);
+ g_free (play->cur_audio_sid);
+ g_free (play->cur_video_sid);
+ g_free (play->cur_text_sid);
+
+ g_mutex_clear (&play->selection_lock);
+
g_free (play);
}
@@ -498,6 +531,63 @@ play_bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
g_free (val_str);
break;
}
+ case GST_MESSAGE_STREAM_COLLECTION:
+ {
+ GstStreamCollection *collection = NULL;
+ gst_message_parse_stream_collection (msg, &collection);
+
+ if (collection) {
+ g_mutex_lock (&play->selection_lock);
+ gst_object_replace ((GstObject **) & play->collection,
+ (GstObject *) collection);
+ g_mutex_unlock (&play->selection_lock);
+ }
+ break;
+ }
+ case GST_MESSAGE_STREAMS_SELECTED:
+ {
+ GstStreamCollection *collection = NULL;
+ guint i, len;
+
+ gst_message_parse_streams_selected (msg, &collection);
+ if (collection) {
+ g_mutex_lock (&play->selection_lock);
+ gst_object_replace ((GstObject **) & play->collection,
+ (GstObject *) collection);
+
+ /* Free all last stream-ids */
+ g_free (play->cur_audio_sid);
+ g_free (play->cur_video_sid);
+ g_free (play->cur_text_sid);
+ play->cur_audio_sid = NULL;
+ play->cur_video_sid = NULL;
+ play->cur_text_sid = NULL;
+
+ len = gst_message_streams_selected_get_size (msg);
+ for (i = 0; i < len; i++) {
+ GstStream *stream = gst_message_streams_selected_get_stream (msg, i);
+ if (stream) {
+ GstStreamType type = gst_stream_get_stream_type (stream);
+ const gchar *stream_id = gst_stream_get_stream_id (stream);
+
+ if (type & GST_STREAM_TYPE_AUDIO) {
+ play->cur_audio_sid = g_strdup (stream_id);
+ } else if (type & GST_STREAM_TYPE_VIDEO) {
+ play->cur_video_sid = g_strdup (stream_id);
+ } else if (type & GST_STREAM_TYPE_TEXT) {
+ play->cur_text_sid = g_strdup (stream_id);
+ } else {
+ g_print ("Unknown stream type with stream-id %s", stream_id);
+ }
+ gst_object_unref (stream);
+ }
+ }
+
+ gst_object_unref (collection);
+ g_mutex_unlock (&play->selection_lock);
+ }
+ break;
+ }
default:
if (gst_is_missing_plugin_message (msg)) {
gchar *desc;
@@ -943,6 +1033,44 @@ play_switch_trick_mode (GstPlay * play)
}
}
+static GstStream *
+play_get_nth_stream_in_collection (GstPlay * play, guint index,
+ GstPlayTrackType track_type)
+{
+ guint len, i, n_streams = 0;
+ GstStreamType target_type;
+
+ switch (track_type) {
+ case GST_PLAY_TRACK_TYPE_AUDIO:
+ target_type = GST_STREAM_TYPE_AUDIO;
+ break;
+ case GST_PLAY_TRACK_TYPE_VIDEO:
+ target_type = GST_STREAM_TYPE_VIDEO;
+ break;
+ case GST_PLAY_TRACK_TYPE_SUBTITLE:
+ target_type = GST_STREAM_TYPE_TEXT;
+ break;
+ default:
+ return NULL;
+ }
+
+ len = gst_stream_collection_get_size (play->collection);
+
+ for (i = 0; i < len; i++) {
+ GstStream *stream = gst_stream_collection_get_stream (play->collection, i);
+ GstStreamType type = gst_stream_get_stream_type (stream);
+
+ if (type & target_type) {
+ if (index == n_streams)
+ return stream;
+
+ n_streams++;
+ }
+ }
+
+ return NULL;
+}
+
static void
play_cycle_track_selection (GstPlay * play, GstPlayTrackType track_type)
{
@@ -950,6 +1078,48 @@ play_cycle_track_selection (GstPlay * play, GstPlayTrackType track_type)
gint cur = -1, n = -1;
guint flag, cur_flags;
+ /* playbin3 variables */
+ GList *selected_streams = NULL;
+ gint cur_audio_idx = -1, cur_video_idx = -1, cur_text_idx = -1;
+ gint nb_audio = 0, nb_video = 0, nb_text = 0;
+ guint len, i;
+
+ g_mutex_lock (&play->selection_lock);
+ if (play->is_playbin3) {
+ if (!play->collection) {
+ g_print ("No stream-collection\n");
+ g_mutex_unlock (&play->selection_lock);
+ return;
+ }
+
+ /* Check the total number of streams of each type */
+ len = gst_stream_collection_get_size (play->collection);
+ for (i = 0; i < len; i++) {
+ GstStream *stream =
+ gst_stream_collection_get_stream (play->collection, i);
+ if (stream) {
+ GstStreamType type = gst_stream_get_stream_type (stream);
+ const gchar *sid = gst_stream_get_stream_id (stream);
+
+ if (type & GST_STREAM_TYPE_AUDIO) {
+ if (play->cur_audio_sid && !g_strcmp0 (play->cur_audio_sid, sid))
+ cur_audio_idx = nb_audio;
+ nb_audio++;
+ } else if (type & GST_STREAM_TYPE_VIDEO) {
+ if (play->cur_video_sid && !g_strcmp0 (play->cur_video_sid, sid))
+ cur_video_idx = nb_video;
+ nb_video++;
+ } else if (type & GST_STREAM_TYPE_TEXT) {
+ if (play->cur_text_sid && !g_strcmp0 (play->cur_text_sid, sid))
+ cur_text_idx = nb_text;
+ nb_text++;
+ } else {
+ g_print ("Unknown stream type with stream-id %s", sid);
+ }
+ }
+ }
+ }
+
switch (track_type) {
case GST_PLAY_TRACK_TYPE_AUDIO:
prop_get = "get-audio-tags";
@@ -957,6 +1127,18 @@ play_cycle_track_selection (GstPlay * play, GstPlayTrackType track_type)
prop_n = "n-audio";
name = "audio";
flag = 0x2;
+ if (play->is_playbin3) {
+ n = nb_audio;
+ cur = cur_audio_idx;
+ if (play->cur_video_sid) {
+ selected_streams =
+ g_list_append (selected_streams, play->cur_video_sid);
+ }
+ if (play->cur_text_sid) {
+ selected_streams =
+ g_list_append (selected_streams, play->cur_text_sid);
+ }
+ }
break;
case GST_PLAY_TRACK_TYPE_VIDEO:
prop_get = "get-video-tags";
@@ -964,6 +1146,18 @@ play_cycle_track_selection (GstPlay * play, GstPlayTrackType track_type)
prop_n = "n-video";
name = "video";
flag = 0x1;
+ if (play->is_playbin3) {
+ n = nb_video;
+ cur = cur_video_idx;
+ if (play->cur_audio_sid) {
+ selected_streams =
+ g_list_append (selected_streams, play->cur_audio_sid);
+ }
+ if (play->cur_text_sid) {
+ selected_streams =
+ g_list_append (selected_streams, play->cur_text_sid);
+ }
+ }
break;
case GST_PLAY_TRACK_TYPE_SUBTITLE:
prop_get = "get-text-tags";
@@ -971,30 +1165,54 @@ play_cycle_track_selection (GstPlay * play, GstPlayTrackType track_type)
prop_n = "n-text";
name = "subtitle";
flag = 0x4;
+ if (play->is_playbin3) {
+ n = nb_text;
+ cur = cur_text_idx;
+ if (play->cur_audio_sid) {
+ selected_streams =
+ g_list_append (selected_streams, play->cur_audio_sid);
+ }
+ if (play->cur_video_sid) {
+ selected_streams =
+ g_list_append (selected_streams, play->cur_video_sid);
+ }
+ }
break;
default:
return;
}
- g_object_get (play->playbin, prop_cur, &cur, prop_n, &n, "flags", &cur_flags,
- NULL);
+ if (play->is_playbin3) {
+ if (n > 0) {
+ if (cur < 0)
+ cur = 0;
+ else
+ cur = (cur + 1) % (n + 1);
+ }
+ } else {
+ g_object_get (play->playbin, prop_cur, &cur, prop_n, &n, "flags",
+ &cur_flags, NULL);
+
+ if (!(cur_flags & flag))
+ cur = 0;
+ else
+ cur = (cur + 1) % (n + 1);
+ }
if (n < 1) {
g_print ("No %s tracks.\n", name);
+ g_mutex_unlock (&play->selection_lock);
} else {
gchar *lcode = NULL, *lname = NULL;
const gchar *lang = NULL;
GstTagList *tags = NULL;
- if (!(cur_flags & flag))
- cur = 0;
- else
- cur = (cur + 1) % (n + 1);
-
if (cur >= n && track_type != GST_PLAY_TRACK_TYPE_VIDEO) {
cur = -1;
g_print ("Disabling %s. \n", name);
- if (cur_flags & flag) {
+ if (play->is_playbin3) {
+ /* Just make it empty for the track type */
+ } else if (cur_flags & flag) {
cur_flags &= ~flag;
g_object_set (play->playbin, "flags", cur_flags, NULL);
}
@@ -1002,11 +1220,27 @@ play_cycle_track_selection (GstPlay * play, GstPlayTrackType track_type)
/* For video we only want to switch between streams, not disable it altogether */
if (cur >= n)
cur = 0;
- if (!(cur_flags & flag) && track_type != GST_PLAY_TRACK_TYPE_VIDEO) {
- cur_flags |= flag;
- g_object_set (play->playbin, "flags", cur_flags, NULL);
+
+ if (play->is_playbin3) {
+ GstStream *stream;
+
+ stream = play_get_nth_stream_in_collection (play, cur, track_type);
+ if (stream) {
+ selected_streams = g_list_append (selected_streams,
+ (gchar *) gst_stream_get_stream_id (stream));
+ tags = gst_stream_get_tags (stream);
+ } else {
+ g_print ("Collection has no stream for track %d of %d.\n",
+ cur + 1, n);
+ }
+ } else {
+ if (!(cur_flags & flag) && track_type != GST_PLAY_TRACK_TYPE_VIDEO) {
+ cur_flags |= flag;
+ g_object_set (play->playbin, "flags", cur_flags, NULL);
+ }
+ g_signal_emit_by_name (play->playbin, prop_get, cur, &tags);
}
- g_signal_emit_by_name (play->playbin, prop_get, cur, &tags);
+
if (tags != NULL) {
if (gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &lcode))
lang = gst_tag_get_language_name (lcode);
@@ -1020,10 +1254,20 @@ play_cycle_track_selection (GstPlay * play, GstPlayTrackType track_type)
else
g_print ("Switching to %s track %d of %d.\n", name, cur + 1, n);
}
- g_object_set (play->playbin, prop_cur, cur, NULL);
g_free (lcode);
g_free (lname);
+ g_mutex_unlock (&play->selection_lock);
+
+ if (play->is_playbin3) {
+ gst_element_send_event (play->playbin,
+ gst_event_new_select_streams (selected_streams));
+ } else {
+ g_object_set (play->playbin, prop_cur, cur, NULL);
+ }
}
+
+ if (selected_streams)
+ g_list_free (selected_streams);
}
static void
@@ -1184,6 +1428,7 @@ main (int argc, char **argv)
GError *err = NULL;
GOptionContext *ctx;
gchar *playlist_file = NULL;
+ gboolean use_playbin3 = FALSE;
GOptionEntry options[] = {
{"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
N_("Output status information and property notifications"), NULL},
@@ -1209,6 +1454,10 @@ main (int argc, char **argv)
N_("Playlist file containing input media files"), NULL},
{"quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet,
N_("Do not print any output (apart from errors)"), NULL},
+ {"use-playbin3", 0, 0, G_OPTION_ARG_NONE, &use_playbin3,
+ N_("Use playbin3 pipeline")
+ N_("(default varies depending on 'USE_PLAYBIN' env variable)"),
+ NULL},
{G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL},
{NULL}
};
@@ -1314,8 +1563,8 @@ main (int argc, char **argv)
shuffle_uris (uris, num);
/* prepare */
- play =
- play_new (uris, audio_sink, video_sink, gapless, volume, verbose, flags);
+ play = play_new (uris, audio_sink, video_sink, gapless, volume, verbose,
+ flags, use_playbin3);
if (play == NULL) {
g_printerr