mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-11 01:45:33 +00:00
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
This commit is contained in:
parent
b0c184e189
commit
a8e05cc9cc
1 changed files with 267 additions and 18 deletions
275
tools/gst-play.c
275
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;
|
||||
|
||||
|
||||
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 (n < 1) {
|
||||
g_print ("No %s tracks.\n", name);
|
||||
if (play->is_playbin3) {
|
||||
if (n > 0) {
|
||||
if (cur < 0)
|
||||
cur = 0;
|
||||
else
|
||||
cur = (cur + 1) % (n + 1);
|
||||
}
|
||||
} else {
|
||||
gchar *lcode = NULL, *lname = NULL;
|
||||
const gchar *lang = NULL;
|
||||
GstTagList *tags = NULL;
|
||||
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 >= 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 (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);
|
||||
}
|
||||
|
||||
if (tags != NULL) {
|
||||
if (gst_tag_list_get_string (tags, GST_TAG_LANGUAGE_CODE, &lcode))
|
||||
lang = gst_tag_get_language_name (lcode);
|
||||
|
@ -1020,12 +1254,22 @@ 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
|
||||
print_keyboard_help (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
|
||||
|
|
Loading…
Reference in a new issue