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