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