tools: play: use cubic volume factor when adjusting volume
[platform/upstream/gst-plugins-base.git] / tools / gst-play.c
1 /* GStreamer command line playback testing utility
2  *
3  * Copyright (C) 2013-2014 Tim-Philipp Müller <tim centricular net>
4  * Copyright (C) 2013 Collabora Ltd.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <locale.h>
27
28 #include <gst/gst.h>
29 #include <gst/gst-i18n-app.h>
30 #include <gst/audio/audio.h>
31 #include <gst/pbutils/pbutils.h>
32 #include <gst/math-compat.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36
37 #include "gst-play-kb.h"
38
39 #define VOLUME_STEPS 20
40
41 GST_DEBUG_CATEGORY (play_debug);
42 #define GST_CAT_DEFAULT play_debug
43
44 typedef struct
45 {
46   gchar **uris;
47   guint num_uris;
48   gint cur_idx;
49
50   GstElement *playbin;
51
52   GMainLoop *loop;
53   guint bus_watch;
54   guint timeout;
55
56   /* missing plugin messages */
57   GList *missing;
58
59   gboolean buffering;
60   gboolean is_live;
61
62   GstState desired_state;       /* as per user interaction, PAUSED or PLAYING */
63
64   /* configuration */
65   gboolean gapless;
66 } GstPlay;
67
68 static gboolean play_bus_msg (GstBus * bus, GstMessage * msg, gpointer data);
69 static gboolean play_next (GstPlay * play);
70 static gboolean play_prev (GstPlay * play);
71 static gboolean play_timeout (gpointer user_data);
72 static void play_about_to_finish (GstElement * playbin, gpointer user_data);
73 static void play_reset (GstPlay * play);
74 static void play_set_relative_volume (GstPlay * play, gdouble volume_step);
75
76 static GstPlay *
77 play_new (gchar ** uris, const gchar * audio_sink, const gchar * video_sink,
78     gboolean gapless, gdouble initial_volume)
79 {
80   GstElement *sink;
81   GstPlay *play;
82
83   play = g_new0 (GstPlay, 1);
84
85   play->uris = uris;
86   play->num_uris = g_strv_length (uris);
87   play->cur_idx = -1;
88
89   play->playbin = gst_element_factory_make ("playbin", "playbin");
90
91   if (audio_sink != NULL) {
92     if (strchr (audio_sink, ' ') != NULL)
93       sink = gst_parse_bin_from_description (audio_sink, TRUE, NULL);
94     else
95       sink = gst_element_factory_make (audio_sink, NULL);
96
97     if (sink != NULL)
98       g_object_set (play->playbin, "audio-sink", sink, NULL);
99     else
100       g_warning ("Couldn't create specified audio sink '%s'", audio_sink);
101   }
102   if (video_sink != NULL) {
103     if (strchr (video_sink, ' ') != NULL)
104       sink = gst_parse_bin_from_description (video_sink, TRUE, NULL);
105     else
106       sink = gst_element_factory_make (video_sink, NULL);
107
108     if (sink != NULL)
109       g_object_set (play->playbin, "video-sink", sink, NULL);
110     else
111       g_warning ("Couldn't create specified video sink '%s'", video_sink);
112   }
113
114   play->loop = g_main_loop_new (NULL, FALSE);
115
116   play->bus_watch = gst_bus_add_watch (GST_ELEMENT_BUS (play->playbin),
117       play_bus_msg, play);
118
119   /* FIXME: make configurable incl. 0 for disable */
120   play->timeout = g_timeout_add (100, play_timeout, play);
121
122   play->missing = NULL;
123   play->buffering = FALSE;
124   play->is_live = FALSE;
125
126   play->desired_state = GST_STATE_PLAYING;
127
128   play->gapless = gapless;
129   if (gapless) {
130     g_signal_connect (play->playbin, "about-to-finish",
131         G_CALLBACK (play_about_to_finish), play);
132   }
133
134   play_set_relative_volume (play, initial_volume - 1.0);
135
136   return play;
137 }
138
139 static void
140 play_free (GstPlay * play)
141 {
142   play_reset (play);
143
144   gst_element_set_state (play->playbin, GST_STATE_NULL);
145   gst_object_unref (play->playbin);
146
147   g_source_remove (play->bus_watch);
148   g_source_remove (play->timeout);
149   g_main_loop_unref (play->loop);
150
151   g_strfreev (play->uris);
152   g_free (play);
153 }
154
155 /* reset for new file/stream */
156 static void
157 play_reset (GstPlay * play)
158 {
159   g_list_foreach (play->missing, (GFunc) gst_message_unref, NULL);
160   play->missing = NULL;
161
162   play->buffering = FALSE;
163   play->is_live = FALSE;
164 }
165
166 static void
167 play_set_relative_volume (GstPlay * play, gdouble volume_step)
168 {
169   gdouble volume;
170
171   volume = gst_stream_volume_get_volume (GST_STREAM_VOLUME (play->playbin),
172       GST_STREAM_VOLUME_FORMAT_CUBIC);
173
174   volume = round ((volume + volume_step) * VOLUME_STEPS) / VOLUME_STEPS;
175   volume = CLAMP (volume, 0.0, 10.0);
176
177   gst_stream_volume_set_volume (GST_STREAM_VOLUME (play->playbin),
178       GST_STREAM_VOLUME_FORMAT_CUBIC, volume);
179
180   g_print ("Volume: %.0f%%                  \n", volume * 100);
181 }
182
183 /* returns TRUE if something was installed and we should restart playback */
184 static gboolean
185 play_install_missing_plugins (GstPlay * play)
186 {
187   /* FIXME: implement: try to install any missing plugins we haven't
188    * tried to install before */
189   return FALSE;
190 }
191
192 static gboolean
193 play_bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
194 {
195   GstPlay *play = user_data;
196
197   switch (GST_MESSAGE_TYPE (msg)) {
198     case GST_MESSAGE_ASYNC_DONE:
199
200       /* dump graph on preroll */
201       GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (play->playbin),
202           GST_DEBUG_GRAPH_SHOW_ALL, "gst-play.async-done");
203
204       g_print ("Prerolled.\r");
205       if (play->missing != NULL && play_install_missing_plugins (play)) {
206         g_print ("New plugins installed, trying again...\n");
207         --play->cur_idx;
208         play_next (play);
209       }
210       break;
211     case GST_MESSAGE_BUFFERING:{
212       gint percent;
213
214       if (!play->buffering)
215         g_print ("\n");
216
217       gst_message_parse_buffering (msg, &percent);
218       g_print ("%s %d%%  \r", _("Buffering..."), percent);
219
220       if (percent == 100) {
221         /* a 100% message means buffering is done */
222         if (play->buffering) {
223           play->buffering = FALSE;
224           /* no state management needed for live pipelines */
225           if (!play->is_live)
226             gst_element_set_state (play->playbin, play->desired_state);
227         }
228       } else {
229         /* buffering... */
230         if (!play->buffering) {
231           if (!play->is_live)
232             gst_element_set_state (play->playbin, GST_STATE_PAUSED);
233           play->buffering = TRUE;
234         }
235       }
236       break;
237     }
238     case GST_MESSAGE_CLOCK_LOST:{
239       g_print (_("Clock lost, selecting a new one\n"));
240       gst_element_set_state (play->playbin, GST_STATE_PAUSED);
241       gst_element_set_state (play->playbin, GST_STATE_PLAYING);
242       break;
243     }
244     case GST_MESSAGE_LATENCY:
245       g_print ("Redistribute latency...\n");
246       gst_bin_recalculate_latency (GST_BIN (play->playbin));
247       break;
248     case GST_MESSAGE_REQUEST_STATE:{
249       GstState state;
250       gchar *name;
251
252       name = gst_object_get_path_string (GST_MESSAGE_SRC (msg));
253
254       gst_message_parse_request_state (msg, &state);
255
256       g_print ("Setting state to %s as requested by %s...\n",
257           gst_element_state_get_name (state), name);
258
259       gst_element_set_state (play->playbin, state);
260       g_free (name);
261       break;
262     }
263     case GST_MESSAGE_EOS:
264       /* print final position at end */
265       play_timeout (play);
266       g_print ("\n");
267       /* and switch to next item in list */
268       if (!play_next (play)) {
269         g_print ("Reached end of play list.\n");
270         g_main_loop_quit (play->loop);
271       }
272       break;
273     case GST_MESSAGE_WARNING:{
274       GError *err;
275       gchar *dbg = NULL;
276
277       /* dump graph on warning */
278       GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (play->playbin),
279           GST_DEBUG_GRAPH_SHOW_ALL, "gst-play.warning");
280
281       gst_message_parse_warning (msg, &err, &dbg);
282       g_printerr ("WARNING %s\n", err->message);
283       if (dbg != NULL)
284         g_printerr ("WARNING debug information: %s\n", dbg);
285       g_error_free (err);
286       g_free (dbg);
287       break;
288     }
289     case GST_MESSAGE_ERROR:{
290       GError *err;
291       gchar *dbg;
292
293       /* dump graph on error */
294       GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (play->playbin),
295           GST_DEBUG_GRAPH_SHOW_ALL, "gst-play.error");
296
297       gst_message_parse_error (msg, &err, &dbg);
298       g_printerr ("ERROR %s for %s\n", err->message, play->uris[play->cur_idx]);
299       if (dbg != NULL)
300         g_printerr ("ERROR debug information: %s\n", dbg);
301       g_error_free (err);
302       g_free (dbg);
303
304       /* flush any other error messages from the bus and clean up */
305       gst_element_set_state (play->playbin, GST_STATE_NULL);
306
307       if (play->missing != NULL && play_install_missing_plugins (play)) {
308         g_print ("New plugins installed, trying again...\n");
309         --play->cur_idx;
310         play_next (play);
311         break;
312       }
313       /* try next item in list then */
314       if (!play_next (play)) {
315         g_print ("Reached end of play list.\n");
316         g_main_loop_quit (play->loop);
317       }
318       break;
319     }
320     default:
321       if (gst_is_missing_plugin_message (msg)) {
322         gchar *desc;
323
324         desc = gst_missing_plugin_message_get_description (msg);
325         g_print ("Missing plugin: %s\n", desc);
326         g_free (desc);
327         play->missing = g_list_append (play->missing, gst_message_ref (msg));
328       }
329       break;
330   }
331
332   return TRUE;
333 }
334
335 static gboolean
336 play_timeout (gpointer user_data)
337 {
338   GstPlay *play = user_data;
339   gint64 pos = -1, dur = -1;
340   gchar status[64] = { 0, };
341
342   if (play->buffering)
343     return TRUE;
344
345   gst_element_query_position (play->playbin, GST_FORMAT_TIME, &pos);
346   gst_element_query_duration (play->playbin, GST_FORMAT_TIME, &dur);
347
348   if (play->desired_state == GST_STATE_PAUSED)
349     g_snprintf (status, sizeof (status), "Paused");
350   else
351     memset (status, ' ', sizeof (status) - 1);
352
353   if (pos >= 0 && dur > 0) {
354     gchar dstr[32], pstr[32];
355
356     /* FIXME: pretty print in nicer format */
357     g_snprintf (pstr, 32, "%" GST_TIME_FORMAT, GST_TIME_ARGS (pos));
358     pstr[9] = '\0';
359     g_snprintf (dstr, 32, "%" GST_TIME_FORMAT, GST_TIME_ARGS (dur));
360     dstr[9] = '\0';
361     g_print ("%s / %s %s\r", pstr, dstr, status);
362   }
363
364   return TRUE;
365 }
366
367 static gchar *
368 play_uri_get_display_name (GstPlay * play, const gchar * uri)
369 {
370   gchar *loc;
371
372   if (gst_uri_has_protocol (uri, "file")) {
373     loc = g_filename_from_uri (uri, NULL, NULL);
374   } else if (gst_uri_has_protocol (uri, "pushfile")) {
375     loc = g_filename_from_uri (uri + 4, NULL, NULL);
376   } else {
377     loc = g_strdup (uri);
378   }
379
380   /* Maybe additionally use glib's filename to display name function */
381   return loc;
382 }
383
384 static void
385 play_uri (GstPlay * play, const gchar * next_uri)
386 {
387   GstStateChangeReturn sret;
388   gchar *loc;
389
390   gst_element_set_state (play->playbin, GST_STATE_READY);
391   play_reset (play);
392
393   loc = play_uri_get_display_name (play, next_uri);
394   g_print ("Now playing %s\n", loc);
395   g_free (loc);
396
397   g_object_set (play->playbin, "uri", next_uri, NULL);
398
399   sret = gst_element_set_state (play->playbin, GST_STATE_PAUSED);
400   switch (sret) {
401     case GST_STATE_CHANGE_FAILURE:
402       /* ignore, we should get an error message posted on the bus */
403       break;
404     case GST_STATE_CHANGE_NO_PREROLL:
405       g_print ("Pipeline is live.\n");
406       play->is_live = TRUE;
407       break;
408     case GST_STATE_CHANGE_ASYNC:
409       g_print ("Prerolling...\r");
410       break;
411     default:
412       break;
413   }
414   if (play->desired_state != GST_STATE_PAUSED)
415     sret = gst_element_set_state (play->playbin, play->desired_state);
416 }
417
418 /* returns FALSE if we have reached the end of the playlist */
419 static gboolean
420 play_next (GstPlay * play)
421 {
422   if ((play->cur_idx + 1) >= play->num_uris)
423     return FALSE;
424
425   play_uri (play, play->uris[++play->cur_idx]);
426   return TRUE;
427 }
428
429 /* returns FALSE if we have reached the beginning of the playlist */
430 static gboolean
431 play_prev (GstPlay * play)
432 {
433   if (play->cur_idx == 0 || play->num_uris <= 1)
434     return FALSE;
435
436   play_uri (play, play->uris[--play->cur_idx]);
437   return TRUE;
438 }
439
440 static void
441 play_about_to_finish (GstElement * playbin, gpointer user_data)
442 {
443   GstPlay *play = user_data;
444   const gchar *next_uri;
445   gchar *loc;
446   guint next_idx;
447
448   if (!play->gapless)
449     return;
450
451   next_idx = play->cur_idx + 1;
452   if (next_idx >= play->num_uris)
453     return;
454
455   next_uri = play->uris[next_idx];
456   loc = play_uri_get_display_name (play, next_uri);
457   g_print ("About to finish, preparing next title: %s\n", loc);
458   g_free (loc);
459
460   g_object_set (play->playbin, "uri", next_uri, NULL);
461   play->cur_idx = next_idx;
462 }
463
464 static void
465 do_play (GstPlay * play)
466 {
467   gint i;
468
469   /* dump playlist */
470   for (i = 0; i < play->num_uris; ++i)
471     GST_INFO ("%4u : %s", i, play->uris[i]);
472
473   if (!play_next (play))
474     return;
475
476   g_main_loop_run (play->loop);
477 }
478
479 static void
480 add_to_playlist (GPtrArray * playlist, const gchar * filename)
481 {
482   GDir *dir;
483   gchar *uri;
484
485   if (gst_uri_is_valid (filename)) {
486     g_ptr_array_add (playlist, g_strdup (filename));
487     return;
488   }
489
490   if ((dir = g_dir_open (filename, 0, NULL))) {
491     const gchar *entry;
492
493     /* FIXME: sort entries for each directory? */
494     while ((entry = g_dir_read_name (dir))) {
495       gchar *path;
496
497       path = g_strconcat (filename, G_DIR_SEPARATOR_S, entry, NULL);
498       add_to_playlist (playlist, path);
499       g_free (path);
500     }
501
502     g_dir_close (dir);
503     return;
504   }
505
506   uri = gst_filename_to_uri (filename, NULL);
507   if (uri != NULL)
508     g_ptr_array_add (playlist, uri);
509   else
510     g_warning ("Could not make URI out of filename '%s'", filename);
511 }
512
513 static void
514 shuffle_uris (gchar ** uris, guint num)
515 {
516   gchar *tmp;
517   guint i, j;
518
519   if (num < 2)
520     return;
521
522   for (i = 0; i < num; i++) {
523     /* gets equally distributed random number in 0..num-1 [0;num[ */
524     j = g_random_int_range (0, num);
525     tmp = uris[j];
526     uris[j] = uris[i];
527     uris[i] = tmp;
528   }
529 }
530
531 static void
532 restore_terminal (void)
533 {
534   gst_play_kb_set_key_handler (NULL, NULL);
535 }
536
537 static void
538 toggle_paused (GstPlay * play)
539 {
540   if (play->desired_state == GST_STATE_PLAYING)
541     play->desired_state = GST_STATE_PAUSED;
542   else
543     play->desired_state = GST_STATE_PLAYING;
544
545   if (!play->buffering) {
546     gst_element_set_state (play->playbin, play->desired_state);
547   } else if (play->desired_state == GST_STATE_PLAYING) {
548     g_print ("\nWill play as soon as buffering finishes)\n");
549   }
550 }
551
552 static void
553 relative_seek (GstPlay * play, gdouble percent)
554 {
555   GstQuery *query;
556   gboolean seekable = FALSE;
557   gint64 dur = -1, pos = -1;
558
559   g_return_if_fail (percent >= -1.0 && percent <= 1.0);
560
561   if (!gst_element_query_position (play->playbin, GST_FORMAT_TIME, &pos))
562     goto seek_failed;
563
564   query = gst_query_new_seeking (GST_FORMAT_TIME);
565   if (!gst_element_query (play->playbin, query)) {
566     gst_query_unref (query);
567     goto seek_failed;
568   }
569
570   gst_query_parse_seeking (query, NULL, &seekable, NULL, &dur);
571   gst_query_unref (query);
572
573   if (!seekable || dur <= 0)
574     goto seek_failed;
575
576   pos = pos + dur * percent;
577   if (pos > dur) {
578     if (!play_next (play)) {
579       g_print ("\nReached end of play list.\n");
580       g_main_loop_quit (play->loop);
581     }
582   } else {
583     if (pos < 0)
584       pos = 0;
585     if (!gst_element_seek_simple (play->playbin, GST_FORMAT_TIME,
586             GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, pos))
587       goto seek_failed;
588   }
589
590   return;
591
592 seek_failed:
593   {
594     g_print ("\nCould not seek.\n");
595   }
596 }
597
598 static void
599 keyboard_cb (const gchar * key_input, gpointer user_data)
600 {
601   GstPlay *play = (GstPlay *) user_data;
602
603   switch (g_ascii_tolower (key_input[0])) {
604     case ' ':
605       toggle_paused (play);
606       break;
607     case 'q':
608     case 'Q':
609       g_main_loop_quit (play->loop);
610       break;
611     case '>':
612       if (!play_next (play)) {
613         g_print ("\nReached end of play list.\n");
614         g_main_loop_quit (play->loop);
615       }
616       break;
617     case '<':
618       play_prev (play);
619       break;
620     case 27:                   /* ESC */
621       if (key_input[1] == '\0') {
622         g_main_loop_quit (play->loop);
623         break;
624       }
625       /* fall through */
626     default:
627       if (strcmp (key_input, GST_PLAY_KB_ARROW_RIGHT) == 0) {
628         relative_seek (play, +0.08);
629       } else if (strcmp (key_input, GST_PLAY_KB_ARROW_LEFT) == 0) {
630         relative_seek (play, -0.01);
631       } else if (strcmp (key_input, GST_PLAY_KB_ARROW_UP) == 0) {
632         play_set_relative_volume (play, +1.0 / VOLUME_STEPS);
633       } else if (strcmp (key_input, GST_PLAY_KB_ARROW_DOWN) == 0) {
634         play_set_relative_volume (play, -1.0 / VOLUME_STEPS);
635       } else {
636         GST_INFO ("keyboard input:");
637         for (; *key_input != '\0'; ++key_input)
638           GST_INFO ("  code %3d", *key_input);
639       }
640       break;
641   }
642 }
643
644 int
645 main (int argc, char **argv)
646 {
647   GstPlay *play;
648   GPtrArray *playlist;
649   gboolean print_version = FALSE;
650   gboolean interactive = FALSE; /* FIXME: maybe enable by default? */
651   gboolean gapless = FALSE;
652   gboolean shuffle = FALSE;
653   gdouble volume = 1.0;
654   gchar **filenames = NULL;
655   gchar *audio_sink = NULL;
656   gchar *video_sink = NULL;
657   gchar **uris;
658   guint num, i;
659   GError *err = NULL;
660   GOptionContext *ctx;
661   gchar *playlist_file = NULL;
662   GOptionEntry options[] = {
663     {"version", 0, 0, G_OPTION_ARG_NONE, &print_version,
664         N_("Print version information and exit"), NULL},
665     {"videosink", 0, 0, G_OPTION_ARG_STRING, &video_sink,
666         N_("Video sink to use (default is autovideosink)"), NULL},
667     {"audiosink", 0, 0, G_OPTION_ARG_STRING, &audio_sink,
668         N_("Audio sink to use (default is autoaudiosink)"), NULL},
669     {"gapless", 0, 0, G_OPTION_ARG_NONE, &gapless,
670         N_("Enable gapless playback"), NULL},
671     {"shuffle", 0, 0, G_OPTION_ARG_NONE, &shuffle,
672         N_("Shuffle playlist"), NULL},
673     {"interactive", 0, 0, G_OPTION_ARG_NONE, &interactive,
674         N_("Interactive control via keyboard"), NULL},
675     {"volume", 0, 0, G_OPTION_ARG_DOUBLE, &volume,
676         N_("Volume"), NULL},
677     {"playlist", 0, 0, G_OPTION_ARG_FILENAME, &playlist_file,
678         N_("Playlist file containing input media files"), NULL},
679     {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL},
680     {NULL}
681   };
682
683   setlocale (LC_ALL, "");
684
685 #ifdef ENABLE_NLS
686   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
687   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
688   textdomain (GETTEXT_PACKAGE);
689 #endif
690
691   g_set_prgname ("gst-play-" GST_API_VERSION);
692
693   ctx = g_option_context_new ("FILE1|URI1 [FILE2|URI2] [FILE3|URI3] ...");
694   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
695   g_option_context_add_group (ctx, gst_init_get_option_group ());
696   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
697     g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
698     return 1;
699   }
700   g_option_context_free (ctx);
701
702   GST_DEBUG_CATEGORY_INIT (play_debug, "play", 0, "gst-play");
703
704   if (print_version) {
705     gchar *version_str;
706
707     version_str = gst_version_string ();
708     g_print ("%s version %s\n", g_get_prgname (), PACKAGE_VERSION);
709     g_print ("%s\n", version_str);
710     g_print ("%s\n", GST_PACKAGE_ORIGIN);
711     g_free (version_str);
712
713     g_free (audio_sink);
714     g_free (video_sink);
715     g_free (playlist_file);
716
717     return 0;
718   }
719
720   playlist = g_ptr_array_new ();
721
722   if (playlist_file != NULL) {
723     gchar *playlist_contents = NULL;
724     gchar **lines = NULL;
725
726     if (g_file_get_contents (playlist_file, &playlist_contents, NULL, &err)) {
727       lines = g_strsplit (playlist_contents, "\n", 0);
728       num = g_strv_length (lines);
729
730       for (i = 0; i < num; i++) {
731         if (lines[i][0] != '\0') {
732           GST_LOG ("Playlist[%d]: %s", i + 1, lines[i]);
733           add_to_playlist (playlist, lines[i]);
734         }
735       }
736       g_strfreev (lines);
737       g_free (playlist_contents);
738     } else {
739       g_printerr ("Could not read playlist: %s\n", err->message);
740       g_clear_error (&err);
741     }
742     g_free (playlist_file);
743     playlist_file = NULL;
744   }
745
746   if (playlist->len == 0 && (filenames == NULL || *filenames == NULL)) {
747     g_printerr (_("Usage: %s FILE1|URI1 [FILE2|URI2] [FILE3|URI3] ..."),
748         "gst-play-" GST_API_VERSION);
749     g_printerr ("\n\n"),
750         g_printerr ("%s\n\n",
751         _("You must provide at least one filename or URI to play."));
752     /* No input provided. Free array */
753     g_ptr_array_free (playlist, TRUE);
754
755     g_free (audio_sink);
756     g_free (video_sink);
757
758     return 1;
759   }
760
761   /* fill playlist */
762   if (filenames != NULL && *filenames != NULL) {
763     num = g_strv_length (filenames);
764     for (i = 0; i < num; ++i) {
765       GST_LOG ("command line argument: %s", filenames[i]);
766       add_to_playlist (playlist, filenames[i]);
767     }
768     g_strfreev (filenames);
769   }
770
771   num = playlist->len;
772   g_ptr_array_add (playlist, NULL);
773
774   uris = (gchar **) g_ptr_array_free (playlist, FALSE);
775
776   if (shuffle)
777     shuffle_uris (uris, num);
778
779   /* prepare */
780   play = play_new (uris, audio_sink, video_sink, gapless, volume);
781
782   if (interactive) {
783     if (gst_play_kb_set_key_handler (keyboard_cb, play)) {
784       atexit (restore_terminal);
785     } else {
786       g_print ("Interactive keyboard handling in terminal not available.\n");
787     }
788   }
789
790   /* play */
791   do_play (play);
792
793   /* clean up */
794   play_free (play);
795
796   g_free (audio_sink);
797   g_free (video_sink);
798
799   g_print ("\n");
800   return 0;
801 }