gstreamer_core/tools/gst-launch.c
changeset 11 1373546e05c6
equal deleted inserted replaced
10:6f340f756486 11:1373546e05c6
       
     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 WIN32
       
    30 #define DISABLE_FAULT_HANDLER
       
    31 #endif
       
    32 
       
    33 #include <string.h>
       
    34 #include <signal.h>
       
    35 #ifdef HAVE_UNISTD_H
       
    36 #include <unistd.h>
       
    37 #endif
       
    38 #ifndef DISABLE_FAULT_HANDLER
       
    39 #include <sys/wait.h>
       
    40 #endif
       
    41 #include <locale.h>             /* for LC_ALL */
       
    42 #include "tools.h"
       
    43 #include <glib.h>
       
    44 #include "../gst/gst-i18n-app.h"
       
    45 
       
    46 /* FIXME: This is just a temporary hack.  We should have a better
       
    47  * check for siginfo handling. */
       
    48 #ifdef SA_SIGINFO
       
    49 #define USE_SIGINFO
       
    50 #endif
       
    51 
       
    52 //extern volatile gboolean glib_on_error_halt;
       
    53 
       
    54 #ifndef DISABLE_FAULT_HANDLER
       
    55 static void fault_restore (void);
       
    56 static void fault_spin (void);
       
    57 static void sigint_restore (void);
       
    58 static gboolean caught_intr = FALSE;
       
    59 #endif
       
    60 
       
    61 static GstElement *pipeline;
       
    62 static gboolean caught_error = FALSE;
       
    63 static gboolean tags = FALSE;
       
    64 static gboolean messages = FALSE;
       
    65 static gboolean is_live = FALSE;
       
    66 
       
    67 
       
    68 #ifndef GST_DISABLE_LOADSAVE
       
    69 static GstElement *
       
    70 xmllaunch_parse_cmdline (const gchar ** argv)
       
    71 {
       
    72   GstElement *pipeline = NULL, *e;
       
    73   GstXML *xml;
       
    74   gboolean err;
       
    75   const gchar *arg;
       
    76   gchar *element, *property, *value;
       
    77   GList *l;
       
    78   gint i = 0;
       
    79 
       
    80   if (!(arg = argv[0])) {
       
    81     g_print (_
       
    82         ("Usage: gst-xmllaunch <file.xml> [ element.property=value ... ]\n"));
       
    83     exit (1);
       
    84   }
       
    85 
       
    86   xml = gst_xml_new ();
       
    87   /* FIXME guchar from gstxml.c */
       
    88   err = gst_xml_parse_file (xml, (guchar *) arg, NULL);
       
    89 
       
    90   if (err != TRUE) {
       
    91     fprintf (stderr, _("ERROR: parse of xml file '%s' failed.\n"), arg);
       
    92     exit (1);
       
    93   }
       
    94 
       
    95   l = gst_xml_get_topelements (xml);
       
    96   if (!l) {
       
    97     fprintf (stderr, _("ERROR: no toplevel pipeline element in file '%s'.\n"),
       
    98         arg);
       
    99     exit (1);
       
   100   }
       
   101 
       
   102   if (l->next)
       
   103     fprintf (stderr,
       
   104         _("WARNING: only one toplevel element is supported at this time."));
       
   105 
       
   106   pipeline = GST_ELEMENT (l->data);
       
   107 
       
   108   while ((arg = argv[++i])) {
       
   109     element = g_strdup (arg);
       
   110     property = strchr (element, '.');
       
   111     value = strchr (element, '=');
       
   112 
       
   113     if (!(element < property && property < value)) {
       
   114       fprintf (stderr,
       
   115           _("ERROR: could not parse command line argument %d: %s.\n"), i,
       
   116           element);
       
   117       g_free (element);
       
   118       exit (1);
       
   119     }
       
   120 
       
   121     *property++ = '\0';
       
   122     *value++ = '\0';
       
   123 
       
   124     e = gst_bin_get_by_name (GST_BIN (pipeline), element);
       
   125     if (!e) {
       
   126       fprintf (stderr, _("WARNING: element named '%s' not found.\n"), element);
       
   127     } else {
       
   128       gst_util_set_object_arg (G_OBJECT (e), property, value);
       
   129     }
       
   130     g_free (element);
       
   131   }
       
   132 
       
   133   if (!l)
       
   134     return NULL;
       
   135 
       
   136   gst_object_ref (pipeline);
       
   137   gst_object_unref (xml);
       
   138   return pipeline;
       
   139 }
       
   140 #endif
       
   141 
       
   142 #ifndef DISABLE_FAULT_HANDLER
       
   143 #ifndef USE_SIGINFO
       
   144 static void
       
   145 fault_handler_sighandler (int signum)
       
   146 {
       
   147   fault_restore ();
       
   148 
       
   149   /* printf is used instead of g_print(), since it's less likely to
       
   150    * deadlock */
       
   151   switch (signum) {
       
   152     case SIGSEGV:
       
   153       printf ("Caught SIGSEGV\n");
       
   154       break;
       
   155     case SIGQUIT:
       
   156       printf ("Caught SIGQUIT\n");
       
   157       break;
       
   158     default:
       
   159       printf ("signo:  %d\n", signum);
       
   160       break;
       
   161   }
       
   162 
       
   163   fault_spin ();
       
   164 }
       
   165 
       
   166 #else /* USE_SIGINFO */
       
   167 
       
   168 static void
       
   169 fault_handler_sigaction (int signum, siginfo_t * si, void *misc)
       
   170 {
       
   171   fault_restore ();
       
   172 
       
   173   /* printf is used instead of g_print(), since it's less likely to
       
   174    * deadlock */
       
   175   switch (si->si_signo) {
       
   176     case SIGSEGV:
       
   177       printf ("Caught SIGSEGV accessing address %p\n", si->si_addr);
       
   178       break;
       
   179     case SIGQUIT:
       
   180       printf ("Caught SIGQUIT\n");
       
   181       break;
       
   182     default:
       
   183       printf ("signo:  %d\n", si->si_signo);
       
   184       printf ("errno:  %d\n", si->si_errno);
       
   185       printf ("code:   %d\n", si->si_code);
       
   186       break;
       
   187   }
       
   188 
       
   189   fault_spin ();
       
   190 }
       
   191 #endif /* USE_SIGINFO */
       
   192 
       
   193 static void
       
   194 fault_spin (void)
       
   195 {
       
   196   int spinning = TRUE;
       
   197 
       
   198   glib_on_error_halt = FALSE;
       
   199   g_on_error_stack_trace ("gst-launch");
       
   200 
       
   201   wait (NULL);
       
   202 
       
   203   /* FIXME how do we know if we were run by libtool? */
       
   204   printf ("Spinning.  Please run 'gdb gst-launch %d' to continue debugging, "
       
   205       "Ctrl-C to quit, or Ctrl-\\ to dump core.\n", (gint) getpid ());
       
   206   while (spinning)
       
   207     g_usleep (1000000);
       
   208 }
       
   209 
       
   210 static void
       
   211 fault_restore (void)
       
   212 {
       
   213   struct sigaction action;
       
   214 
       
   215   memset (&action, 0, sizeof (action));
       
   216   action.sa_handler = SIG_DFL;
       
   217 
       
   218   sigaction (SIGSEGV, &action, NULL);
       
   219   sigaction (SIGQUIT, &action, NULL);
       
   220 }
       
   221 
       
   222 static void
       
   223 fault_setup (void)
       
   224 {
       
   225   struct sigaction action;
       
   226 
       
   227   memset (&action, 0, sizeof (action));
       
   228 #ifdef USE_SIGINFO
       
   229   action.sa_sigaction = fault_handler_sigaction;
       
   230   action.sa_flags = SA_SIGINFO;
       
   231 #else
       
   232   action.sa_handler = fault_handler_sighandler;
       
   233 #endif
       
   234 
       
   235   sigaction (SIGSEGV, &action, NULL);
       
   236   sigaction (SIGQUIT, &action, NULL);
       
   237 }
       
   238 #endif /* DISABLE_FAULT_HANDLER */
       
   239 
       
   240 static void
       
   241 print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
       
   242 {
       
   243   gint i, count;
       
   244 
       
   245   count = gst_tag_list_get_tag_size (list, tag);
       
   246 
       
   247   for (i = 0; i < count; i++) {
       
   248     gchar *str;
       
   249 
       
   250     if (gst_tag_get_type (tag) == G_TYPE_STRING) {
       
   251       if (!gst_tag_list_get_string_index (list, tag, i, &str))
       
   252         g_assert_not_reached ();
       
   253     } else if (gst_tag_get_type (tag) == GST_TYPE_BUFFER) {
       
   254       GstBuffer *img;
       
   255 
       
   256       img = gst_value_get_buffer (gst_tag_list_get_value_index (list, tag, i));
       
   257       if (img) {
       
   258         gchar *caps_str;
       
   259 
       
   260         caps_str = GST_BUFFER_CAPS (img) ?
       
   261             gst_caps_to_string (GST_BUFFER_CAPS (img)) : g_strdup ("unknown");
       
   262         str = g_strdup_printf ("buffer of %u bytes, type: %s",
       
   263             GST_BUFFER_SIZE (img), caps_str);
       
   264         g_free (caps_str);
       
   265       } else {
       
   266         str = g_strdup ("NULL buffer");
       
   267       }
       
   268     } else {
       
   269       str =
       
   270           g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
       
   271     }
       
   272 
       
   273     if (i == 0) {
       
   274       g_print ("%16s: %s\n", gst_tag_get_nick (tag), str);
       
   275     } else {
       
   276       g_print ("%16s: %s\n", "", str);
       
   277     }
       
   278 
       
   279     g_free (str);
       
   280   }
       
   281 }
       
   282 
       
   283 #ifndef DISABLE_FAULT_HANDLER
       
   284 /* we only use sighandler here because the registers are not important */
       
   285 static void
       
   286 sigint_handler_sighandler (int signum)
       
   287 {
       
   288   g_print ("Caught interrupt -- ");
       
   289 
       
   290   sigint_restore ();
       
   291 
       
   292   /* we set a flag that is checked by the mainloop, we cannot do much in the
       
   293    * interrupt handler (no mutex or other blocking stuff) */
       
   294   caught_intr = TRUE;
       
   295 }
       
   296 
       
   297 /* is called every 50 milliseconds (20 times a second), the interrupt handler
       
   298  * will set a flag for us. We react to this by posting a message. */
       
   299 static gboolean
       
   300 check_intr (GstElement * pipeline)
       
   301 {
       
   302   if (!caught_intr) {
       
   303     return TRUE;
       
   304   } else {
       
   305     caught_intr = FALSE;
       
   306     g_print ("handling interrupt.\n");
       
   307 
       
   308     /* post an application specific message */
       
   309     gst_element_post_message (GST_ELEMENT (pipeline),
       
   310         gst_message_new_application (GST_OBJECT (pipeline),
       
   311             gst_structure_new ("GstLaunchInterrupt",
       
   312                 "message", G_TYPE_STRING, "Pipeline interrupted", NULL)));
       
   313 
       
   314     /* remove timeout handler */
       
   315     return FALSE;
       
   316   }
       
   317 }
       
   318 
       
   319 static void
       
   320 sigint_setup (void)
       
   321 {
       
   322   struct sigaction action;
       
   323 
       
   324   memset (&action, 0, sizeof (action));
       
   325   action.sa_handler = sigint_handler_sighandler;
       
   326 
       
   327   sigaction (SIGINT, &action, NULL);
       
   328 }
       
   329 
       
   330 static void
       
   331 sigint_restore (void)
       
   332 {
       
   333   struct sigaction action;
       
   334 
       
   335   memset (&action, 0, sizeof (action));
       
   336   action.sa_handler = SIG_DFL;
       
   337 
       
   338   sigaction (SIGINT, &action, NULL);
       
   339 }
       
   340 
       
   341 static void
       
   342 play_handler (int signum)
       
   343 {
       
   344   switch (signum) {
       
   345     case SIGUSR1:
       
   346       g_print ("Caught SIGUSR1 - Play request.\n");
       
   347       gst_element_set_state (pipeline, GST_STATE_PLAYING);
       
   348       break;
       
   349     case SIGUSR2:
       
   350       g_print ("Caught SIGUSR2 - Stop request.\n");
       
   351       gst_element_set_state (pipeline, GST_STATE_NULL);
       
   352       break;
       
   353   }
       
   354 }
       
   355 
       
   356 static void
       
   357 play_signal_setup (void)
       
   358 {
       
   359   struct sigaction action;
       
   360 
       
   361   memset (&action, 0, sizeof (action));
       
   362   action.sa_handler = play_handler;
       
   363   sigaction (SIGUSR1, &action, NULL);
       
   364   sigaction (SIGUSR2, &action, NULL);
       
   365 }
       
   366 #endif /* DISABLE_FAULT_HANDLER */
       
   367 
       
   368 /* returns TRUE if there was an error or we caught a keyboard interrupt. */
       
   369 static gboolean
       
   370 event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
       
   371 {
       
   372   GstBus *bus;
       
   373   GstMessage *message = NULL;
       
   374   gboolean res = FALSE;
       
   375   gboolean buffering = FALSE;
       
   376 
       
   377   bus = gst_element_get_bus (GST_ELEMENT (pipeline));
       
   378 
       
   379 #ifndef DISABLE_FAULT_HANDLER
       
   380   g_timeout_add (50, (GSourceFunc) check_intr, pipeline);
       
   381 #endif
       
   382 
       
   383   while (TRUE) {
       
   384     message = gst_bus_poll (bus, GST_MESSAGE_ANY, blocking ? -1 : 0);
       
   385 
       
   386     /* if the poll timed out, only when !blocking */
       
   387     if (message == NULL)
       
   388       goto exit;
       
   389 
       
   390     /* check if we need to dump messages to the console */
       
   391     if (messages) {
       
   392       const GstStructure *s;
       
   393 
       
   394       s = gst_message_get_structure (message);
       
   395 
       
   396       g_print (_("Got Message from element \"%s\" (%s): "),
       
   397           GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))),
       
   398           gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
       
   399       if (s) {
       
   400         gchar *sstr;
       
   401 
       
   402         sstr = gst_structure_to_string (s);
       
   403         g_print ("%s\n", sstr);
       
   404         g_free (sstr);
       
   405       } else {
       
   406         g_print ("no message details\n");
       
   407       }
       
   408     }
       
   409 
       
   410     switch (GST_MESSAGE_TYPE (message)) {
       
   411       case GST_MESSAGE_NEW_CLOCK:
       
   412       {
       
   413         GstClock *clock;
       
   414 
       
   415         gst_message_parse_new_clock (message, &clock);
       
   416 
       
   417         g_print ("New clock: %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
       
   418         break;
       
   419       }
       
   420       case GST_MESSAGE_EOS:
       
   421         g_print (_
       
   422             ("Got EOS from element \"%s\".\n"),
       
   423             GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
       
   424         goto exit;
       
   425       case GST_MESSAGE_TAG:
       
   426         if (tags) {
       
   427           GstTagList *tags;
       
   428 
       
   429           gst_message_parse_tag (message, &tags);
       
   430           g_print (_("FOUND TAG      : found by element \"%s\".\n"),
       
   431               GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
       
   432           gst_tag_list_foreach (tags, print_tag, NULL);
       
   433           gst_tag_list_free (tags);
       
   434         }
       
   435         break;
       
   436       case GST_MESSAGE_INFO:{
       
   437         GError *gerror;
       
   438         gchar *debug;
       
   439         gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
       
   440 
       
   441         gst_message_parse_info (message, &gerror, &debug);
       
   442         if (debug) {
       
   443           g_print (_("INFO:\n%s\n"), debug);
       
   444         }
       
   445         g_error_free (gerror);
       
   446         g_free (debug);
       
   447         g_free (name);
       
   448         break;
       
   449       }
       
   450       case GST_MESSAGE_WARNING:{
       
   451         GError *gerror;
       
   452         gchar *debug;
       
   453         gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
       
   454 
       
   455         /* dump graph on warning */
       
   456         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
       
   457             GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.warning");
       
   458 
       
   459         gst_message_parse_warning (message, &gerror, &debug);
       
   460         g_print (_("WARNING: from element %s: %s\n"), name, gerror->message);
       
   461         if (debug) {
       
   462           g_print (_("Additional debug info:\n%s\n"), debug);
       
   463         }
       
   464         g_error_free (gerror);
       
   465         g_free (debug);
       
   466         g_free (name);
       
   467         break;
       
   468       }
       
   469       case GST_MESSAGE_ERROR:{
       
   470         GError *gerror;
       
   471         gchar *debug;
       
   472 
       
   473         /* dump graph on error */
       
   474         GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
       
   475             GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.error");
       
   476 
       
   477         gst_message_parse_error (message, &gerror, &debug);
       
   478         gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
       
   479         g_error_free (gerror);
       
   480         g_free (debug);
       
   481         /* we have an error */
       
   482         res = TRUE;
       
   483         goto exit;
       
   484       }
       
   485       case GST_MESSAGE_STATE_CHANGED:{
       
   486         GstState old, new, pending;
       
   487 
       
   488         gst_message_parse_state_changed (message, &old, &new, &pending);
       
   489 
       
   490         /* we only care about pipeline state change messages */
       
   491         if (GST_MESSAGE_SRC (message) != GST_OBJECT_CAST (pipeline))
       
   492           break;
       
   493 
       
   494         /* dump graph for pipeline state changes */
       
   495         {
       
   496           gchar *dump_name = g_strdup_printf ("gst-launch.%s_%s",
       
   497               gst_element_state_get_name (old),
       
   498               gst_element_state_get_name (new));
       
   499           GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
       
   500               GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
       
   501           g_free (dump_name);
       
   502         }
       
   503 
       
   504         /* ignore when we are buffering since then we mess with the states
       
   505          * ourselves. */
       
   506         if (buffering) {
       
   507           fprintf (stderr,
       
   508               _("Prerolled, waiting for buffering to finish...\n"));
       
   509           break;
       
   510         }
       
   511 
       
   512         /* if we reached the final target state, exit */
       
   513         if (target_state == GST_STATE_PAUSED && new == target_state)
       
   514           goto exit;
       
   515 
       
   516         /* else not an interesting message */
       
   517         break;
       
   518       }
       
   519       case GST_MESSAGE_BUFFERING:{
       
   520         gint percent;
       
   521 
       
   522         gst_message_parse_buffering (message, &percent);
       
   523         fprintf (stderr, _("buffering... %d  \r"), percent);
       
   524 
       
   525         /* no state management needed for live pipelines */
       
   526         if (is_live)
       
   527           break;
       
   528 
       
   529         if (percent == 100) {
       
   530           /* a 100% message means buffering is done */
       
   531           buffering = FALSE;
       
   532           /* if the desired state is playing, go back */
       
   533           if (target_state == GST_STATE_PLAYING) {
       
   534             fprintf (stderr,
       
   535                 _("Done buffering, setting pipeline to PLAYING ...\n"));
       
   536             gst_element_set_state (pipeline, GST_STATE_PLAYING);
       
   537           } else
       
   538             goto exit;
       
   539         } else {
       
   540           /* buffering busy */
       
   541           if (buffering == FALSE && target_state == GST_STATE_PLAYING) {
       
   542             /* we were not buffering but PLAYING, PAUSE  the pipeline. */
       
   543             fprintf (stderr, _("Buffering, setting pipeline to PAUSED ...\n"));
       
   544             gst_element_set_state (pipeline, GST_STATE_PAUSED);
       
   545           }
       
   546           buffering = TRUE;
       
   547         }
       
   548         break;
       
   549       }
       
   550       case GST_MESSAGE_APPLICATION:{
       
   551         const GstStructure *s;
       
   552 
       
   553         s = gst_message_get_structure (message);
       
   554 
       
   555         if (gst_structure_has_name (s, "GstLaunchInterrupt")) {
       
   556           /* this application message is posted when we caught an interrupt and
       
   557            * we need to stop the pipeline. */
       
   558           fprintf (stderr, _("Interrupt: Stopping pipeline ...\n"));
       
   559           /* return TRUE when we caught an interrupt */
       
   560           res = TRUE;
       
   561           goto exit;
       
   562         }
       
   563       }
       
   564       default:
       
   565         /* just be quiet by default */
       
   566         break;
       
   567     }
       
   568     if (message)
       
   569       gst_message_unref (message);
       
   570   }
       
   571   g_assert_not_reached ();
       
   572 
       
   573 exit:
       
   574   {
       
   575     if (message)
       
   576       gst_message_unref (message);
       
   577     gst_object_unref (bus);
       
   578     return res;
       
   579   }
       
   580 }
       
   581 
       
   582 int
       
   583 main (int argc, char *argv[])
       
   584 {
       
   585   /* options */
       
   586   static gboolean verbose = FALSE;
       
   587   static gboolean no_fault = FALSE;
       
   588   static gboolean trace = FALSE;
       
   589   gchar *savefile = NULL;
       
   590   static gchar *exclude_args = NULL;
       
   591   GOptionEntry options[] = {
       
   592     {"tags", 't', 0, G_OPTION_ARG_NONE, &tags,
       
   593         N_("Output tags (also known as metadata)"), NULL},
       
   594     {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
       
   595         N_("Output status information and property notifications"), NULL},
       
   596     {"messages", 'm', 0, G_OPTION_ARG_NONE, &messages,
       
   597         N_("Output messages"), NULL},
       
   598     {"exclude", 'X', 0, G_OPTION_ARG_NONE, &exclude_args,
       
   599         N_("Do not output status information of TYPE"), N_("TYPE1,TYPE2,...")},
       
   600 #ifndef GST_DISABLE_LOADSAVE
       
   601     {"output", 'o', 0, G_OPTION_ARG_STRING, &savefile,
       
   602         N_("Save xml representation of pipeline to FILE and exit"), N_("FILE")},
       
   603 #endif
       
   604     {"no-fault", 'f', 0, G_OPTION_ARG_NONE, &no_fault,
       
   605         N_("Do not install a fault handler"), NULL},
       
   606     {"trace", 'T', 0, G_OPTION_ARG_NONE, &trace,
       
   607         N_("Print alloc trace (if enabled at compile time)"), NULL},
       
   608     GST_TOOLS_GOPTION_VERSION,
       
   609     {NULL}
       
   610   };
       
   611   GOptionContext *ctx;
       
   612   GError *err = NULL;
       
   613   gchar **argvn;
       
   614   GError *error = NULL;
       
   615   gint res = 0;
       
   616 
       
   617   free (malloc (8));            /* -lefence */
       
   618 
       
   619 #ifdef ENABLE_NLS
       
   620   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
       
   621   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
       
   622   textdomain (GETTEXT_PACKAGE);
       
   623 #endif
       
   624 
       
   625   if (!g_thread_supported ())
       
   626     g_thread_init (NULL);
       
   627 
       
   628   gst_alloc_trace_set_flags_all (GST_ALLOC_TRACE_LIVE);
       
   629 
       
   630   ctx = g_option_context_new ("PIPELINE-DESCRIPTION");
       
   631   g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
       
   632   g_option_context_add_group (ctx, gst_init_get_option_group ());
       
   633   if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
       
   634     if (err)
       
   635       g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
       
   636     else
       
   637       g_print ("Error initializing: Unknown error!\n");
       
   638     exit (1);
       
   639   }
       
   640   g_option_context_free (ctx);
       
   641 
       
   642   gst_tools_print_version ("gst-launch");
       
   643 
       
   644 #ifndef DISABLE_FAULT_HANDLER
       
   645   if (!no_fault)
       
   646     fault_setup ();
       
   647 
       
   648   sigint_setup ();
       
   649   play_signal_setup ();
       
   650 #endif
       
   651 
       
   652   if (trace) {
       
   653     if (!gst_alloc_trace_available ()) {
       
   654       g_warning ("Trace not available (recompile with trace enabled).");
       
   655     }
       
   656     gst_alloc_trace_print_live ();
       
   657   }
       
   658 
       
   659   /* make a null-terminated version of argv */
       
   660   argvn = g_new0 (char *, argc);
       
   661   memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1));
       
   662 #ifndef GST_DISABLE_LOADSAVE
       
   663   if (strstr (argv[0], "gst-xmllaunch")) {
       
   664     pipeline = xmllaunch_parse_cmdline ((const gchar **) argvn);
       
   665   } else
       
   666 #endif
       
   667   {
       
   668     pipeline =
       
   669         (GstElement *) gst_parse_launchv ((const gchar **) argvn, &error);
       
   670   }
       
   671   g_free (argvn);
       
   672 
       
   673   if (!pipeline) {
       
   674     if (error) {
       
   675       fprintf (stderr, _("ERROR: pipeline could not be constructed: %s.\n"),
       
   676           GST_STR_NULL (error->message));
       
   677       g_error_free (error);
       
   678     } else {
       
   679       fprintf (stderr, _("ERROR: pipeline could not be constructed.\n"));
       
   680     }
       
   681     return 1;
       
   682   } else if (error) {
       
   683     fprintf (stderr, _("WARNING: erroneous pipeline: %s\n"),
       
   684         GST_STR_NULL (error->message));
       
   685     g_error_free (error);
       
   686     return 1;
       
   687   }
       
   688 
       
   689   if (verbose) {
       
   690     gchar **exclude_list =
       
   691         exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL;
       
   692     g_signal_connect (pipeline, "deep_notify",
       
   693         G_CALLBACK (gst_object_default_deep_notify), exclude_list);
       
   694   }
       
   695 #ifndef GST_DISABLE_LOADSAVE
       
   696   if (savefile) {
       
   697     gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w"));
       
   698   }
       
   699 #endif
       
   700 
       
   701   if (!savefile) {
       
   702     GstState state, pending;
       
   703     GstStateChangeReturn ret;
       
   704 
       
   705     /* If the top-level object is not a pipeline, place it in a pipeline. */
       
   706     if (!GST_IS_PIPELINE (pipeline)) {
       
   707       GstElement *real_pipeline = gst_element_factory_make ("pipeline", NULL);
       
   708 
       
   709       if (real_pipeline == NULL) {
       
   710         fprintf (stderr, _("ERROR: the 'pipeline' element wasn't found.\n"));
       
   711         return 1;
       
   712       }
       
   713       gst_bin_add (GST_BIN (real_pipeline), pipeline);
       
   714       pipeline = real_pipeline;
       
   715     }
       
   716     fprintf (stderr, _("Setting pipeline to PAUSED ...\n"));
       
   717     ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
       
   718 
       
   719     switch (ret) {
       
   720       case GST_STATE_CHANGE_FAILURE:
       
   721         fprintf (stderr, _("ERROR: Pipeline doesn't want to pause.\n"));
       
   722         res = -1;
       
   723         event_loop (pipeline, FALSE, GST_STATE_VOID_PENDING);
       
   724         goto end;
       
   725       case GST_STATE_CHANGE_NO_PREROLL:
       
   726         fprintf (stderr, _("Pipeline is live and does not need PREROLL ...\n"));
       
   727         is_live = TRUE;
       
   728         break;
       
   729       case GST_STATE_CHANGE_ASYNC:
       
   730         fprintf (stderr, _("Pipeline is PREROLLING ...\n"));
       
   731         caught_error = event_loop (pipeline, TRUE, GST_STATE_PAUSED);
       
   732         if (caught_error) {
       
   733           fprintf (stderr, _("ERROR: pipeline doesn't want to preroll.\n"));
       
   734           goto end;
       
   735         }
       
   736         state = GST_STATE_PAUSED;
       
   737         /* fallthrough */
       
   738       case GST_STATE_CHANGE_SUCCESS:
       
   739         fprintf (stderr, _("Pipeline is PREROLLED ...\n"));
       
   740         break;
       
   741     }
       
   742 
       
   743     caught_error = event_loop (pipeline, FALSE, GST_STATE_PLAYING);
       
   744 
       
   745     if (caught_error) {
       
   746       fprintf (stderr, _("ERROR: pipeline doesn't want to preroll.\n"));
       
   747     } else {
       
   748       GstClockTime tfthen, tfnow;
       
   749       GstClockTimeDiff diff;
       
   750 
       
   751       fprintf (stderr, _("Setting pipeline to PLAYING ...\n"));
       
   752       if (gst_element_set_state (pipeline,
       
   753               GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
       
   754         GstMessage *err_msg;
       
   755         GstBus *bus;
       
   756 
       
   757         fprintf (stderr, _("ERROR: pipeline doesn't want to play.\n"));
       
   758         bus = gst_element_get_bus (pipeline);
       
   759         if ((err_msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0))) {
       
   760           GError *gerror;
       
   761           gchar *debug;
       
   762 
       
   763           gst_message_parse_error (err_msg, &gerror, &debug);
       
   764           gst_object_default_error (GST_MESSAGE_SRC (err_msg), gerror, debug);
       
   765           gst_message_unref (err_msg);
       
   766           g_error_free (gerror);
       
   767           g_free (debug);
       
   768         }
       
   769         gst_object_unref (bus);
       
   770         res = -1;
       
   771         goto end;
       
   772       }
       
   773 
       
   774       tfthen = gst_util_get_timestamp ();
       
   775       caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING);
       
   776       tfnow = gst_util_get_timestamp ();
       
   777 
       
   778       diff = GST_CLOCK_DIFF (tfthen, tfnow);
       
   779 
       
   780       g_print (_("Execution ended after %" G_GUINT64_FORMAT " ns.\n"), diff);
       
   781     }
       
   782 
       
   783     /* iterate mainloop to process pending stuff */
       
   784     while (g_main_context_iteration (NULL, FALSE));
       
   785 
       
   786     fprintf (stderr, _("Setting pipeline to PAUSED ...\n"));
       
   787     gst_element_set_state (pipeline, GST_STATE_PAUSED);
       
   788     if (!caught_error)
       
   789       gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
       
   790     fprintf (stderr, _("Setting pipeline to READY ...\n"));
       
   791     gst_element_set_state (pipeline, GST_STATE_READY);
       
   792     gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
       
   793 
       
   794   end:
       
   795     fprintf (stderr, _("Setting pipeline to NULL ...\n"));
       
   796     gst_element_set_state (pipeline, GST_STATE_NULL);
       
   797     gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
       
   798   }
       
   799 
       
   800   fprintf (stderr, _("FREEING pipeline ...\n"));
       
   801   gst_object_unref (pipeline);
       
   802 
       
   803   gst_deinit ();
       
   804   if (trace)
       
   805     gst_alloc_trace_print_live ();
       
   806 
       
   807   return res;
       
   808 }