28254980268fdd7bf5c645f5f82fae589d07c6a0
[platform/upstream/gstreamer.git] / tools / gst-launch.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *               2000 Wim Taymans <wtay@chello.be>
4  *               2004 Thomas Vander Stichele <thomas@apestaart.org>
5  *
6  * gst-launch.c: tool to launch GStreamer pipelines from the command line
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 /* FIXME: hack alert */
29 #ifdef HAVE_WIN32
30 #define DISABLE_FAULT_HANDLER
31 #endif
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <signal.h>
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 #ifndef DISABLE_FAULT_HANDLER
40 #include <sys/wait.h>
41 #endif
42 #include <locale.h>             /* for LC_ALL */
43 #include "tools.h"
44
45 /* FIXME: This is just a temporary hack.  We should have a better
46  * check for siginfo handling. */
47 #ifdef SA_SIGINFO
48 #define USE_SIGINFO
49 #endif
50
51 extern volatile gboolean glib_on_error_halt;
52
53 #ifndef DISABLE_FAULT_HANDLER
54 static void fault_restore (void);
55 static void fault_spin (void);
56 static void sigint_restore (void);
57 static gboolean caught_intr = FALSE;
58 #endif
59
60 /* event_loop return codes */
61 typedef enum _EventLoopResult
62 {
63   ELR_NO_ERROR = 0,
64   ELR_ERROR,
65   ELR_INTERRUPT
66 } EventLoopResult;
67
68 static GstElement *pipeline;
69 static EventLoopResult caught_error = ELR_NO_ERROR;
70 static gboolean quiet = FALSE;
71 static gboolean tags = FALSE;
72 static gboolean toc = FALSE;
73 static gboolean messages = FALSE;
74 static gboolean is_live = FALSE;
75 static gboolean waiting_eos = FALSE;
76
77 /* convenience macro so we don't have to litter the code with if(!quiet) */
78 #define PRINT if(!quiet)g_print
79
80 #ifndef DISABLE_FAULT_HANDLER
81 #ifndef USE_SIGINFO
82 static void
83 fault_handler_sighandler (int signum)
84 {
85   fault_restore ();
86
87   /* printf is used instead of g_print(), since it's less likely to
88    * deadlock */
89   switch (signum) {
90     case SIGSEGV:
91       fprintf (stderr, "Caught SIGSEGV\n");
92       break;
93     case SIGQUIT:
94       if (!quiet)
95         printf ("Caught SIGQUIT\n");
96       break;
97     default:
98       fprintf (stderr, "signo:  %d\n", signum);
99       break;
100   }
101
102   fault_spin ();
103 }
104
105 #else /* USE_SIGINFO */
106
107 static void
108 fault_handler_sigaction (int signum, siginfo_t * si, void *misc)
109 {
110   fault_restore ();
111
112   /* printf is used instead of g_print(), since it's less likely to
113    * deadlock */
114   switch (si->si_signo) {
115     case SIGSEGV:
116       fprintf (stderr, "Caught SIGSEGV accessing address %p\n", si->si_addr);
117       break;
118     case SIGQUIT:
119       if (!quiet)
120         printf ("Caught SIGQUIT\n");
121       break;
122     default:
123       fprintf (stderr, "signo:  %d\n", si->si_signo);
124       fprintf (stderr, "errno:  %d\n", si->si_errno);
125       fprintf (stderr, "code:   %d\n", si->si_code);
126       break;
127   }
128
129   fault_spin ();
130 }
131 #endif /* USE_SIGINFO */
132
133 static void
134 fault_spin (void)
135 {
136   int spinning = TRUE;
137
138   glib_on_error_halt = FALSE;
139   g_on_error_stack_trace ("gst-launch-" GST_API_VERSION);
140
141   wait (NULL);
142
143   /* FIXME how do we know if we were run by libtool? */
144   fprintf (stderr,
145       "Spinning.  Please run 'gdb gst-launch- " GST_API_VERSION " %d' to "
146       "continue debugging, Ctrl-C to quit, or Ctrl-\\ to dump core.\n",
147       (gint) getpid ());
148   while (spinning)
149     g_usleep (1000000);
150 }
151
152 static void
153 fault_restore (void)
154 {
155   struct sigaction action;
156
157   memset (&action, 0, sizeof (action));
158   action.sa_handler = SIG_DFL;
159
160   sigaction (SIGSEGV, &action, NULL);
161   sigaction (SIGQUIT, &action, NULL);
162 }
163
164 static void
165 fault_setup (void)
166 {
167   struct sigaction action;
168
169   memset (&action, 0, sizeof (action));
170 #ifdef USE_SIGINFO
171   action.sa_sigaction = fault_handler_sigaction;
172   action.sa_flags = SA_SIGINFO;
173 #else
174   action.sa_handler = fault_handler_sighandler;
175 #endif
176
177   sigaction (SIGSEGV, &action, NULL);
178   sigaction (SIGQUIT, &action, NULL);
179 }
180 #endif /* DISABLE_FAULT_HANDLER */
181
182 #if 0
183 typedef struct _GstIndexStats
184 {
185   gint id;
186   gchar *desc;
187
188   guint num_frames;
189   guint num_keyframes;
190   guint num_dltframes;
191   GstClockTime last_keyframe;
192   GstClockTime last_dltframe;
193   GstClockTime min_keyframe_gap;
194   GstClockTime max_keyframe_gap;
195   GstClockTime avg_keyframe_gap;
196 } GstIndexStats;
197
198 static void
199 entry_added (GstIndex * index, GstIndexEntry * entry, gpointer user_data)
200 {
201   GPtrArray *index_stats = (GPtrArray *) user_data;
202   GstIndexStats *s;
203
204   switch (entry->type) {
205     case GST_INDEX_ENTRY_ID:
206       /* we have a new writer */
207       GST_DEBUG_OBJECT (index, "id %d: describes writer %s", entry->id,
208           GST_INDEX_ID_DESCRIPTION (entry));
209       if (entry->id >= index_stats->len) {
210         g_ptr_array_set_size (index_stats, entry->id + 1);
211       }
212       s = g_new (GstIndexStats, 1);
213       s->id = entry->id;
214       s->desc = g_strdup (GST_INDEX_ID_DESCRIPTION (entry));
215       s->num_frames = s->num_keyframes = s->num_dltframes = 0;
216       s->last_keyframe = s->last_dltframe = GST_CLOCK_TIME_NONE;
217       s->min_keyframe_gap = s->max_keyframe_gap = s->avg_keyframe_gap =
218           GST_CLOCK_TIME_NONE;
219       g_ptr_array_index (index_stats, entry->id) = s;
220       break;
221     case GST_INDEX_ENTRY_FORMAT:
222       /* have not found any code calling this */
223       GST_DEBUG_OBJECT (index, "id %d: registered format %d for %s\n",
224           entry->id, GST_INDEX_FORMAT_FORMAT (entry),
225           GST_INDEX_FORMAT_KEY (entry));
226       break;
227     case GST_INDEX_ENTRY_ASSOCIATION:
228     {
229       gint64 ts;
230       GstAssocFlags flags = GST_INDEX_ASSOC_FLAGS (entry);
231
232       s = g_ptr_array_index (index_stats, entry->id);
233       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &ts);
234
235       if (flags & GST_ASSOCIATION_FLAG_KEY_UNIT) {
236         s->num_keyframes++;
237
238         if (GST_CLOCK_TIME_IS_VALID (ts)) {
239           if (GST_CLOCK_TIME_IS_VALID (s->last_keyframe)) {
240             GstClockTimeDiff d = GST_CLOCK_DIFF (s->last_keyframe, ts);
241
242             if (G_UNLIKELY (d < 0)) {
243               GST_WARNING ("received out-of-order keyframe at %"
244                   GST_TIME_FORMAT, GST_TIME_ARGS (ts));
245               /* FIXME: does it still make sense to use that for the statistics */
246               d = GST_CLOCK_DIFF (ts, s->last_keyframe);
247             }
248
249             if (GST_CLOCK_TIME_IS_VALID (s->min_keyframe_gap)) {
250               if (d < s->min_keyframe_gap)
251                 s->min_keyframe_gap = d;
252             } else {
253               s->min_keyframe_gap = d;
254             }
255             if (GST_CLOCK_TIME_IS_VALID (s->max_keyframe_gap)) {
256               if (d > s->max_keyframe_gap)
257                 s->max_keyframe_gap = d;
258             } else {
259               s->max_keyframe_gap = d;
260             }
261             if (GST_CLOCK_TIME_IS_VALID (s->avg_keyframe_gap)) {
262               s->avg_keyframe_gap = (d + s->num_frames * s->avg_keyframe_gap) /
263                   (s->num_frames + 1);
264             } else {
265               s->avg_keyframe_gap = d;
266             }
267           }
268           s->last_keyframe = ts;
269         }
270       }
271       if (flags & GST_ASSOCIATION_FLAG_DELTA_UNIT) {
272         s->num_dltframes++;
273         if (GST_CLOCK_TIME_IS_VALID (ts)) {
274           s->last_dltframe = ts;
275         }
276       }
277       s->num_frames++;
278
279       break;
280     }
281     default:
282       break;
283   }
284 }
285
286 /* print statistics from the entry_added callback, free the entries */
287 static void
288 print_index_stats (GPtrArray * index_stats)
289 {
290   gint i;
291
292   if (index_stats->len) {
293     g_print ("%s:\n", _("Index statistics"));
294   }
295
296   for (i = 0; i < index_stats->len; i++) {
297     GstIndexStats *s = g_ptr_array_index (index_stats, i);
298     if (s) {
299       g_print ("id %d, %s\n", s->id, s->desc);
300       if (s->num_frames) {
301         GstClockTime last_frame = s->last_keyframe;
302
303         if (GST_CLOCK_TIME_IS_VALID (s->last_dltframe)) {
304           if (!GST_CLOCK_TIME_IS_VALID (last_frame) ||
305               (s->last_dltframe > last_frame))
306             last_frame = s->last_dltframe;
307         }
308
309         if (GST_CLOCK_TIME_IS_VALID (last_frame)) {
310           g_print ("  total time               = %" GST_TIME_FORMAT "\n",
311               GST_TIME_ARGS (last_frame));
312         }
313         g_print ("  frame/keyframe rate      = %u / %u = ", s->num_frames,
314             s->num_keyframes);
315         if (s->num_keyframes)
316           g_print ("%lf\n", s->num_frames / (gdouble) s->num_keyframes);
317         else
318           g_print ("-\n");
319         if (s->num_keyframes) {
320           g_print ("  min/avg/max keyframe gap = %" GST_TIME_FORMAT ", %"
321               GST_TIME_FORMAT ", %" GST_TIME_FORMAT "\n",
322               GST_TIME_ARGS (s->min_keyframe_gap),
323               GST_TIME_ARGS (s->avg_keyframe_gap),
324               GST_TIME_ARGS (s->max_keyframe_gap));
325         }
326       } else {
327         g_print ("  no stats\n");
328       }
329
330       g_free (s->desc);
331       g_free (s);
332     }
333   }
334 }
335 #endif
336
337 /* Kids, use the functions from libgstpbutils in gst-plugins-base in your
338  * own code (we can't do that here because it would introduce a circular
339  * dependency) */
340 static gboolean
341 gst_is_missing_plugin_message (GstMessage * msg)
342 {
343   if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT
344       || gst_message_get_structure (msg) == NULL)
345     return FALSE;
346
347   return gst_structure_has_name (gst_message_get_structure (msg),
348       "missing-plugin");
349 }
350
351 static const gchar *
352 gst_missing_plugin_message_get_description (GstMessage * msg)
353 {
354   return gst_structure_get_string (gst_message_get_structure (msg), "name");
355 }
356
357 static void
358 print_error_message (GstMessage * msg)
359 {
360   GError *err = NULL;
361   gchar *name, *debug = NULL;
362
363   name = gst_object_get_path_string (msg->src);
364   gst_message_parse_error (msg, &err, &debug);
365
366   g_printerr (_("ERROR: from element %s: %s\n"), name, err->message);
367   if (debug != NULL)
368     g_printerr (_("Additional debug info:\n%s\n"), debug);
369
370   g_error_free (err);
371   g_free (debug);
372   g_free (name);
373 }
374
375 static void
376 print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
377 {
378   gint i, count;
379
380   count = gst_tag_list_get_tag_size (list, tag);
381
382   for (i = 0; i < count; i++) {
383     gchar *str;
384
385     if (gst_tag_get_type (tag) == G_TYPE_STRING) {
386       if (!gst_tag_list_get_string_index (list, tag, i, &str))
387         g_assert_not_reached ();
388     } else if (gst_tag_get_type (tag) == GST_TYPE_BUFFER) {
389       GstBuffer *img;
390
391       img = gst_value_get_buffer (gst_tag_list_get_value_index (list, tag, i));
392       if (img) {
393         gchar *caps_str;
394
395         caps_str = g_strdup ("unknown");
396         str = g_strdup_printf ("buffer of %" G_GSIZE_FORMAT " bytes, type: %s",
397             gst_buffer_get_size (img), caps_str);
398         g_free (caps_str);
399       } else {
400         str = g_strdup ("NULL buffer");
401       }
402     } else if (gst_tag_get_type (tag) == GST_TYPE_DATE_TIME) {
403       GstDateTime *dt = NULL;
404
405       gst_tag_list_get_date_time_index (list, tag, i, &dt);
406       if (gst_date_time_get_hour (dt) < 0) {
407         str = g_strdup_printf ("%02u-%02u-%04u", gst_date_time_get_day (dt),
408             gst_date_time_get_month (dt), gst_date_time_get_year (dt));
409       } else {
410         gdouble tz_offset = gst_date_time_get_time_zone_offset (dt);
411         gchar tz_str[32];
412
413         if (tz_offset != 0.0) {
414           g_snprintf (tz_str, sizeof (tz_str), "(UTC %s%gh)",
415               (tz_offset > 0.0) ? "+" : "", tz_offset);
416         } else {
417           g_snprintf (tz_str, sizeof (tz_str), "(UTC)");
418         }
419
420         str = g_strdup_printf ("%04u-%02u-%02u %02u:%02u:%02u %s",
421             gst_date_time_get_year (dt), gst_date_time_get_month (dt),
422             gst_date_time_get_day (dt), gst_date_time_get_hour (dt),
423             gst_date_time_get_minute (dt), gst_date_time_get_second (dt),
424             tz_str);
425       }
426       gst_date_time_unref (dt);
427     } else {
428       str =
429           g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
430     }
431
432     if (i == 0) {
433       PRINT ("%16s: %s\n", gst_tag_get_nick (tag), str);
434     } else {
435       PRINT ("%16s: %s\n", "", str);
436     }
437
438     g_free (str);
439   }
440 }
441
442 static void
443 print_tag_foreach (const GstTagList * tags, const gchar * tag,
444     gpointer user_data)
445 {
446   GValue val = { 0, };
447   gchar *str;
448   gint depth = GPOINTER_TO_INT (user_data);
449
450   gst_tag_list_copy_value (&val, tags, tag);
451
452   if (G_VALUE_HOLDS_STRING (&val))
453     str = g_value_dup_string (&val);
454   else
455     str = gst_value_serialize (&val);
456
457   g_print ("%*s%s: %s\n", 2 * depth, " ", gst_tag_get_nick (tag), str);
458   g_free (str);
459
460   g_value_unset (&val);
461 }
462
463 #define MAX_INDENT 40
464
465 static void
466 print_toc_entry (gpointer data, gpointer user_data)
467 {
468   GstTocEntry *entry = (GstTocEntry *) data;
469   const gchar spc[MAX_INDENT + 1] = "                                        ";
470   guint indent = MIN (GPOINTER_TO_UINT (user_data), MAX_INDENT);
471   gint64 start, stop;
472
473   gst_toc_entry_get_start_stop (entry, &start, &stop);
474
475   PRINT ("%s%s:", &spc[MAX_INDENT - indent],
476       gst_toc_entry_type_get_nick (entry->type));
477   if (GST_CLOCK_TIME_IS_VALID (start)) {
478     PRINT (" start: %" GST_TIME_FORMAT, GST_TIME_ARGS (start));
479   }
480   if (GST_CLOCK_TIME_IS_VALID (stop)) {
481     PRINT (" stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (stop));
482   }
483   PRINT ("\n");
484   indent += 2;
485
486   /* print tags */
487   gst_tag_list_foreach (entry->tags, print_tag_foreach,
488       GUINT_TO_POINTER (indent));
489
490   /* loop over sub-toc entries */
491   g_list_foreach (entry->subentries, print_toc_entry,
492       GUINT_TO_POINTER (indent));
493 }
494
495 #ifndef DISABLE_FAULT_HANDLER
496 /* we only use sighandler here because the registers are not important */
497 static void
498 sigint_handler_sighandler (int signum)
499 {
500   PRINT ("Caught interrupt -- ");
501
502   /* If we were waiting for an EOS, we still want to catch
503    * the next signal to shutdown properly (and the following one
504    * will quit the program). */
505   if (waiting_eos) {
506     waiting_eos = FALSE;
507   } else {
508     sigint_restore ();
509   }
510   /* we set a flag that is checked by the mainloop, we cannot do much in the
511    * interrupt handler (no mutex or other blocking stuff) */
512   caught_intr = TRUE;
513 }
514
515 /* is called every 250 milliseconds (4 times a second), the interrupt handler
516  * will set a flag for us. We react to this by posting a message. */
517 static gboolean
518 check_intr (GstElement * pipeline)
519 {
520   if (!caught_intr) {
521     return TRUE;
522   } else {
523     caught_intr = FALSE;
524     PRINT ("handling interrupt.\n");
525
526     /* post an application specific message */
527     gst_element_post_message (GST_ELEMENT (pipeline),
528         gst_message_new_application (GST_OBJECT (pipeline),
529             gst_structure_new ("GstLaunchInterrupt",
530                 "message", G_TYPE_STRING, "Pipeline interrupted", NULL)));
531
532     /* remove timeout handler */
533     return FALSE;
534   }
535 }
536
537 static void
538 sigint_setup (void)
539 {
540   struct sigaction action;
541
542   memset (&action, 0, sizeof (action));
543   action.sa_handler = sigint_handler_sighandler;
544
545   sigaction (SIGINT, &action, NULL);
546 }
547
548 static void
549 sigint_restore (void)
550 {
551   struct sigaction action;
552
553   memset (&action, 0, sizeof (action));
554   action.sa_handler = SIG_DFL;
555
556   sigaction (SIGINT, &action, NULL);
557 }
558 #endif /* DISABLE_FAULT_HANDLER */
559
560 /* returns ELR_ERROR if there was an error
561  * or ELR_INTERRUPT if we caught a keyboard interrupt
562  * or ELR_NO_ERROR otherwise. */
563 static EventLoopResult
564 event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
565 {
566 #ifndef DISABLE_FAULT_HANDLER
567   gulong timeout_id;
568 #endif
569   GstBus *bus;
570   GstMessage *message = NULL;
571   EventLoopResult res = ELR_NO_ERROR;
572   gboolean buffering = FALSE;
573
574   bus = gst_element_get_bus (GST_ELEMENT (pipeline));
575
576 #ifndef DISABLE_FAULT_HANDLER
577   timeout_id = g_timeout_add (250, (GSourceFunc) check_intr, pipeline);
578 #endif
579
580   while (TRUE) {
581     message = gst_bus_poll (bus, GST_MESSAGE_ANY, blocking ? -1 : 0);
582
583     /* if the poll timed out, only when !blocking */
584     if (message == NULL)
585       goto exit;
586
587     /* check if we need to dump messages to the console */
588     if (messages) {
589       GstObject *src_obj;
590       const GstStructure *s;
591       guint32 seqnum;
592
593       seqnum = gst_message_get_seqnum (message);
594
595       s = gst_message_get_structure (message);
596
597       src_obj = GST_MESSAGE_SRC (message);
598
599       if (GST_IS_ELEMENT (src_obj)) {
600         PRINT (_("Got message #%u from element \"%s\" (%s): "),
601             (guint) seqnum, GST_ELEMENT_NAME (src_obj),
602             GST_MESSAGE_TYPE_NAME (message));
603       } else if (GST_IS_PAD (src_obj)) {
604         PRINT (_("Got message #%u from pad \"%s:%s\" (%s): "),
605             (guint) seqnum, GST_DEBUG_PAD_NAME (src_obj),
606             GST_MESSAGE_TYPE_NAME (message));
607       } else if (GST_IS_OBJECT (src_obj)) {
608         PRINT (_("Got message #%u from object \"%s\" (%s): "),
609             (guint) seqnum, GST_OBJECT_NAME (src_obj),
610             GST_MESSAGE_TYPE_NAME (message));
611       } else {
612         PRINT (_("Got message #%u (%s): "), (guint) seqnum,
613             GST_MESSAGE_TYPE_NAME (message));
614       }
615
616       if (s) {
617         gchar *sstr;
618
619         sstr = gst_structure_to_string (s);
620         PRINT ("%s\n", sstr);
621         g_free (sstr);
622       } else {
623         PRINT ("no message details\n");
624       }
625     }
626
627     switch (GST_MESSAGE_TYPE (message)) {
628       case GST_MESSAGE_NEW_CLOCK:
629       {
630         GstClock *clock;
631
632         gst_message_parse_new_clock (message, &clock);
633
634         PRINT ("New clock: %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
635         break;
636       }
637       case GST_MESSAGE_CLOCK_LOST:
638         PRINT ("Clock lost, selecting a new one\n");
639         gst_element_set_state (pipeline, GST_STATE_PAUSED);
640         gst_element_set_state (pipeline, GST_STATE_PLAYING);
641         break;
642       case GST_MESSAGE_EOS:{
643         waiting_eos = FALSE;
644         PRINT (_("Got EOS from element \"%s\".\n"),
645             GST_MESSAGE_SRC_NAME (message));
646         goto exit;
647       }
648       case GST_MESSAGE_TAG:
649         if (tags) {
650           GstTagList *tag_list;
651
652           if (GST_IS_ELEMENT (GST_MESSAGE_SRC (message))) {
653             PRINT (_("FOUND TAG      : found by element \"%s\".\n"),
654                 GST_MESSAGE_SRC_NAME (message));
655           } else if (GST_IS_PAD (GST_MESSAGE_SRC (message))) {
656             PRINT (_("FOUND TAG      : found by pad \"%s:%s\".\n"),
657                 GST_DEBUG_PAD_NAME (GST_MESSAGE_SRC (message)));
658           } else if (GST_IS_OBJECT (GST_MESSAGE_SRC (message))) {
659             PRINT (_("FOUND TAG      : found by object \"%s\".\n"),
660                 GST_MESSAGE_SRC_NAME (message));
661           } else {
662             PRINT (_("FOUND TAG\n"));
663           }
664
665           gst_message_parse_tag (message, &tag_list);
666           gst_tag_list_foreach (tag_list, print_tag, NULL);
667           gst_tag_list_unref (tag_list);
668         }
669         break;
670       case GST_MESSAGE_TOC:
671         if (toc) {
672           GstToc *toc_msg;
673           gboolean updated;
674
675           if (GST_IS_ELEMENT (GST_MESSAGE_SRC (message))) {
676             PRINT (_("FOUND TOC      : found by element \"%s\".\n"),
677                 GST_MESSAGE_SRC_NAME (message));
678           } else if (GST_IS_OBJECT (GST_MESSAGE_SRC (message))) {
679             PRINT (_("FOUND TOC      : found by object \"%s\".\n"),
680                 GST_MESSAGE_SRC_NAME (message));
681           } else {
682             PRINT (_("FOUND TOC\n"));
683           }
684
685           gst_message_parse_toc (message, &toc_msg, &updated);
686           /* recursively loop over toc entries */
687           g_list_foreach (toc_msg->entries, print_toc_entry,
688               GUINT_TO_POINTER (0));
689           gst_toc_unref (toc_msg);
690         }
691         break;
692       case GST_MESSAGE_INFO:{
693         GError *gerror;
694         gchar *debug;
695         gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
696
697         gst_message_parse_info (message, &gerror, &debug);
698         if (debug) {
699           PRINT (_("INFO:\n%s\n"), debug);
700         }
701         g_error_free (gerror);
702         g_free (debug);
703         g_free (name);
704         break;
705       }
706       case GST_MESSAGE_WARNING:{
707         GError *gerror;
708         gchar *debug;
709         gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
710
711         /* dump graph on warning */
712         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
713             GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.warning");
714
715         gst_message_parse_warning (message, &gerror, &debug);
716         PRINT (_("WARNING: from element %s: %s\n"), name, gerror->message);
717         if (debug) {
718           PRINT (_("Additional debug info:\n%s\n"), debug);
719         }
720         g_error_free (gerror);
721         g_free (debug);
722         g_free (name);
723         break;
724       }
725       case GST_MESSAGE_ERROR:{
726         /* dump graph on error */
727         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
728             GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.error");
729
730         print_error_message (message);
731
732         /* we have an error */
733         res = ELR_ERROR;
734         goto exit;
735       }
736       case GST_MESSAGE_STATE_CHANGED:{
737         GstState old, new, pending;
738
739         /* we only care about pipeline state change messages */
740         if (GST_MESSAGE_SRC (message) != GST_OBJECT_CAST (pipeline))
741           break;
742
743         /* ignore when we are buffering since then we mess with the states
744          * ourselves. */
745         if (buffering) {
746           PRINT (_("Prerolled, waiting for buffering to finish...\n"));
747           break;
748         }
749
750         gst_message_parse_state_changed (message, &old, &new, &pending);
751
752         /* if we reached the final target state, exit */
753         if (target_state == GST_STATE_PAUSED && new == target_state)
754           goto exit;
755
756         /* else not an interesting message */
757         break;
758       }
759       case GST_MESSAGE_BUFFERING:{
760         gint percent;
761
762         gst_message_parse_buffering (message, &percent);
763         PRINT ("%s %d%%  \r", _("buffering..."), percent);
764
765         /* no state management needed for live pipelines */
766         if (is_live)
767           break;
768
769         if (percent == 100) {
770           /* a 100% message means buffering is done */
771           buffering = FALSE;
772           /* if the desired state is playing, go back */
773           if (target_state == GST_STATE_PLAYING) {
774             PRINT (_("Done buffering, setting pipeline to PLAYING ...\n"));
775             gst_element_set_state (pipeline, GST_STATE_PLAYING);
776           } else
777             goto exit;
778         } else {
779           /* buffering busy */
780           if (buffering == FALSE && target_state == GST_STATE_PLAYING) {
781             /* we were not buffering but PLAYING, PAUSE  the pipeline. */
782             PRINT (_("Buffering, setting pipeline to PAUSED ...\n"));
783             gst_element_set_state (pipeline, GST_STATE_PAUSED);
784           }
785           buffering = TRUE;
786         }
787         break;
788       }
789       case GST_MESSAGE_LATENCY:
790       {
791         PRINT (_("Redistribute latency...\n"));
792         gst_bin_recalculate_latency (GST_BIN (pipeline));
793         break;
794       }
795       case GST_MESSAGE_REQUEST_STATE:
796       {
797         GstState state;
798         gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
799
800         gst_message_parse_request_state (message, &state);
801
802         PRINT (_("Setting state to %s as requested by %s...\n"),
803             gst_element_state_get_name (state), name);
804
805         gst_element_set_state (pipeline, state);
806
807         g_free (name);
808         break;
809       }
810       case GST_MESSAGE_APPLICATION:{
811         const GstStructure *s;
812
813         s = gst_message_get_structure (message);
814
815         if (gst_structure_has_name (s, "GstLaunchInterrupt")) {
816           /* this application message is posted when we caught an interrupt and
817            * we need to stop the pipeline. */
818           PRINT (_("Interrupt: Stopping pipeline ...\n"));
819           res = ELR_INTERRUPT;
820           goto exit;
821         }
822         break;
823       }
824       case GST_MESSAGE_ELEMENT:{
825         if (gst_is_missing_plugin_message (message)) {
826           const gchar *desc;
827
828           desc = gst_missing_plugin_message_get_description (message);
829           PRINT (_("Missing element: %s\n"), desc ? desc : "(no description)");
830         }
831         break;
832       }
833       default:
834         /* just be quiet by default */
835         break;
836     }
837     if (message)
838       gst_message_unref (message);
839   }
840   g_assert_not_reached ();
841
842 exit:
843   {
844     if (message)
845       gst_message_unref (message);
846     gst_object_unref (bus);
847 #ifndef DISABLE_FAULT_HANDLER
848     g_source_remove (timeout_id);
849 #endif
850     return res;
851   }
852 }
853
854 static GstBusSyncReply
855 bus_sync_handler (GstBus * bus, GstMessage * message, gpointer data)
856 {
857   GstElement *pipeline = (GstElement *) data;
858
859   switch (GST_MESSAGE_TYPE (message)) {
860     case GST_MESSAGE_STATE_CHANGED:
861       /* we only care about pipeline state change messages */
862       if (GST_MESSAGE_SRC (message) == GST_OBJECT_CAST (pipeline)) {
863         GstState old, new, pending;
864         gchar *state_transition_name;
865
866         gst_message_parse_state_changed (message, &old, &new, &pending);
867
868         state_transition_name = g_strdup_printf ("%s_%s",
869             gst_element_state_get_name (old), gst_element_state_get_name (new));
870
871         /* dump graph for (some) pipeline state changes */
872         {
873           gchar *dump_name = g_strconcat ("gst-launch.", state_transition_name,
874               NULL);
875           GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
876               GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
877           g_free (dump_name);
878         }
879
880         /* place a marker into e.g. strace logs */
881         {
882           gchar *access_name = g_strconcat (g_get_tmp_dir (), G_DIR_SEPARATOR_S,
883               "gst-launch", G_DIR_SEPARATOR_S, state_transition_name, NULL);
884           g_file_test (access_name, G_FILE_TEST_EXISTS);
885           g_free (access_name);
886         }
887
888         g_free (state_transition_name);
889       }
890     default:
891       break;
892   }
893   return GST_BUS_PASS;
894 }
895
896 int
897 main (int argc, char *argv[])
898 {
899   /* options */
900   gboolean verbose = FALSE;
901   gboolean no_fault = FALSE;
902   gboolean eos_on_shutdown = FALSE;
903 #if 0
904   gboolean check_index = FALSE;
905 #endif
906   gchar *savefile = NULL;
907   gchar *exclude_args = NULL;
908 #ifndef GST_DISABLE_OPTION_PARSING
909   GOptionEntry options[] = {
910     {"tags", 't', 0, G_OPTION_ARG_NONE, &tags,
911         N_("Output tags (also known as metadata)"), NULL},
912     {"toc", 'c', 0, G_OPTION_ARG_NONE, &toc,
913         N_("Output TOC (chapters and editions)"), NULL},
914     {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
915         N_("Output status information and property notifications"), NULL},
916     {"quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet,
917         N_("Do not print any progress information"), NULL},
918     {"messages", 'm', 0, G_OPTION_ARG_NONE, &messages,
919         N_("Output messages"), NULL},
920     {"exclude", 'X', 0, G_OPTION_ARG_NONE, &exclude_args,
921         N_("Do not output status information of TYPE"), N_("TYPE1,TYPE2,...")},
922     {"no-fault", 'f', 0, G_OPTION_ARG_NONE, &no_fault,
923         N_("Do not install a fault handler"), NULL},
924     {"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown,
925         N_("Force EOS on sources before shutting the pipeline down"), NULL},
926 #if 0
927     {"index", 'i', 0, G_OPTION_ARG_NONE, &check_index,
928         N_("Gather and print index statistics"), NULL},
929 #endif
930     GST_TOOLS_GOPTION_VERSION,
931     {NULL}
932   };
933   GOptionContext *ctx;
934   GError *err = NULL;
935 #endif
936 #if 0
937   GstIndex *index;
938   GPtrArray *index_stats = NULL;
939 #endif
940   gchar **argvn;
941   GError *error = NULL;
942   gint res = 0;
943
944   free (malloc (8));            /* -lefence */
945
946 #ifdef ENABLE_NLS
947   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
948   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
949   textdomain (GETTEXT_PACKAGE);
950 #endif
951
952   gst_tools_set_prgname ("gst-launch");
953
954 #ifndef GST_DISABLE_OPTION_PARSING
955   ctx = g_option_context_new ("PIPELINE-DESCRIPTION");
956   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
957   g_option_context_add_group (ctx, gst_init_get_option_group ());
958   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
959     if (err)
960       g_printerr ("Error initializing: %s\n", GST_STR_NULL (err->message));
961     else
962       g_printerr ("Error initializing: Unknown error!\n");
963     exit (1);
964   }
965   g_option_context_free (ctx);
966 #else
967   gst_init (&argc, &argv);
968 #endif
969
970   gst_tools_print_version ("gst-launch");
971
972 #ifndef DISABLE_FAULT_HANDLER
973   if (!no_fault)
974     fault_setup ();
975
976   sigint_setup ();
977 #endif
978
979   /* make a null-terminated version of argv */
980   argvn = g_new0 (char *, argc);
981   memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1));
982   {
983     pipeline =
984         (GstElement *) gst_parse_launchv ((const gchar **) argvn, &error);
985   }
986   g_free (argvn);
987
988   if (!pipeline) {
989     if (error) {
990       g_printerr (_("ERROR: pipeline could not be constructed: %s.\n"),
991           GST_STR_NULL (error->message));
992       g_error_free (error);
993     } else {
994       g_printerr (_("ERROR: pipeline could not be constructed.\n"));
995     }
996     return 1;
997   } else if (error) {
998     g_printerr (_("WARNING: erroneous pipeline: %s\n"),
999         GST_STR_NULL (error->message));
1000     g_error_free (error);
1001     return 1;
1002   }
1003
1004   if (verbose) {
1005     gchar **exclude_list =
1006         exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL;
1007     g_signal_connect (pipeline, "deep-notify",
1008         G_CALLBACK (gst_object_default_deep_notify), exclude_list);
1009   }
1010
1011   if (!savefile) {
1012     GstState state, pending;
1013     GstStateChangeReturn ret;
1014     GstBus *bus;
1015
1016     /* If the top-level object is not a pipeline, place it in a pipeline. */
1017     if (!GST_IS_PIPELINE (pipeline)) {
1018       GstElement *real_pipeline = gst_element_factory_make ("pipeline", NULL);
1019
1020       if (real_pipeline == NULL) {
1021         g_printerr (_("ERROR: the 'pipeline' element wasn't found.\n"));
1022         return 1;
1023       }
1024       gst_bin_add (GST_BIN (real_pipeline), pipeline);
1025       pipeline = real_pipeline;
1026     }
1027 #if 0
1028     if (check_index) {
1029       /* gst_index_new() creates a null-index, it does not store anything, but
1030        * the entry-added signal works and this is what we use to build the
1031        * statistics */
1032       index = gst_index_new ();
1033       if (index) {
1034         index_stats = g_ptr_array_new ();
1035         g_signal_connect (G_OBJECT (index), "entry-added",
1036             G_CALLBACK (entry_added), index_stats);
1037         g_object_set (G_OBJECT (index), "resolver", GST_INDEX_RESOLVER_GTYPE,
1038             NULL);
1039         gst_element_set_index (pipeline, index);
1040       }
1041     }
1042 #endif
1043
1044     bus = gst_element_get_bus (pipeline);
1045     gst_bus_set_sync_handler (bus, bus_sync_handler, (gpointer) pipeline, NULL);
1046     gst_object_unref (bus);
1047
1048     PRINT (_("Setting pipeline to PAUSED ...\n"));
1049     ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
1050
1051     switch (ret) {
1052       case GST_STATE_CHANGE_FAILURE:
1053         g_printerr (_("ERROR: Pipeline doesn't want to pause.\n"));
1054         res = -1;
1055         event_loop (pipeline, FALSE, GST_STATE_VOID_PENDING);
1056         goto end;
1057       case GST_STATE_CHANGE_NO_PREROLL:
1058         PRINT (_("Pipeline is live and does not need PREROLL ...\n"));
1059         is_live = TRUE;
1060         break;
1061       case GST_STATE_CHANGE_ASYNC:
1062         PRINT (_("Pipeline is PREROLLING ...\n"));
1063         caught_error = event_loop (pipeline, TRUE, GST_STATE_PAUSED);
1064         if (caught_error) {
1065           g_printerr (_("ERROR: pipeline doesn't want to preroll.\n"));
1066           goto end;
1067         }
1068         state = GST_STATE_PAUSED;
1069         /* fallthrough */
1070       case GST_STATE_CHANGE_SUCCESS:
1071         PRINT (_("Pipeline is PREROLLED ...\n"));
1072         break;
1073     }
1074
1075     caught_error = event_loop (pipeline, FALSE, GST_STATE_PLAYING);
1076
1077     if (caught_error) {
1078       g_printerr (_("ERROR: pipeline doesn't want to preroll.\n"));
1079     } else {
1080       GstClockTime tfthen, tfnow;
1081       GstClockTimeDiff diff;
1082
1083       PRINT (_("Setting pipeline to PLAYING ...\n"));
1084
1085       if (gst_element_set_state (pipeline,
1086               GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
1087         GstMessage *err_msg;
1088         GstBus *bus;
1089
1090         g_printerr (_("ERROR: pipeline doesn't want to play.\n"));
1091         bus = gst_element_get_bus (pipeline);
1092         if ((err_msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0))) {
1093           print_error_message (err_msg);
1094           gst_message_unref (err_msg);
1095         }
1096         gst_object_unref (bus);
1097         res = -1;
1098         goto end;
1099       }
1100
1101       tfthen = gst_util_get_timestamp ();
1102       caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING);
1103       if (eos_on_shutdown && caught_error != ELR_NO_ERROR) {
1104         gboolean ignore_errors;
1105
1106         waiting_eos = TRUE;
1107         if (caught_error == ELR_INTERRUPT) {
1108           PRINT (_("EOS on shutdown enabled -- Forcing EOS on the pipeline\n"));
1109           gst_element_send_event (pipeline, gst_event_new_eos ());
1110           ignore_errors = FALSE;
1111         } else {
1112           PRINT (_("EOS on shutdown enabled -- waiting for EOS after Error\n"));
1113           ignore_errors = TRUE;
1114         }
1115         PRINT (_("Waiting for EOS...\n"));
1116
1117         while (TRUE) {
1118           caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING);
1119
1120           if (caught_error == ELR_NO_ERROR) {
1121             /* we got EOS */
1122             PRINT (_("EOS received - stopping pipeline...\n"));
1123             break;
1124           } else if (caught_error == ELR_INTERRUPT) {
1125             PRINT (_
1126                 ("Interrupt while waiting for EOS - stopping pipeline...\n"));
1127             break;
1128           } else if (caught_error == ELR_ERROR) {
1129             if (!ignore_errors) {
1130               PRINT (_("An error happened while waiting for EOS\n"));
1131               break;
1132             }
1133           }
1134         }
1135       }
1136       tfnow = gst_util_get_timestamp ();
1137
1138       diff = GST_CLOCK_DIFF (tfthen, tfnow);
1139
1140       PRINT (_("Execution ended after %" G_GUINT64_FORMAT " ns.\n"), diff);
1141     }
1142
1143     PRINT (_("Setting pipeline to PAUSED ...\n"));
1144     gst_element_set_state (pipeline, GST_STATE_PAUSED);
1145     if (caught_error == ELR_NO_ERROR)
1146       gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
1147
1148     /* iterate mainloop to process pending stuff */
1149     while (g_main_context_iteration (NULL, FALSE));
1150
1151     PRINT (_("Setting pipeline to READY ...\n"));
1152     gst_element_set_state (pipeline, GST_STATE_READY);
1153     gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
1154
1155 #if 0
1156     if (check_index) {
1157       print_index_stats (index_stats);
1158       g_ptr_array_free (index_stats, TRUE);
1159     }
1160 #endif
1161
1162   end:
1163     PRINT (_("Setting pipeline to NULL ...\n"));
1164     gst_element_set_state (pipeline, GST_STATE_NULL);
1165   }
1166
1167   PRINT (_("Freeing pipeline ...\n"));
1168   gst_object_unref (pipeline);
1169
1170   gst_deinit ();
1171
1172   return res;
1173 }