--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gstreamer_core/tools/gst-launch.c Thu Dec 17 08:53:32 2009 +0200
@@ -0,0 +1,806 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ * 2004 Thomas Vander Stichele <thomas@apestaart.org>
+ *
+ * gst-launch.c: tool to launch GStreamer pipelines from the command line
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* FIXME: hack alert */
+#ifdef WIN32
+#define DISABLE_FAULT_HANDLER
+#endif
+
+#include <string.h>
+#include <signal.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef DISABLE_FAULT_HANDLER
+#include <sys/wait.h>
+#endif
+#include <locale.h> /* for LC_ALL */
+#include "tools.h"
+
+/* FIXME: This is just a temporary hack. We should have a better
+ * check for siginfo handling. */
+#ifdef SA_SIGINFO
+#define USE_SIGINFO
+#endif
+
+extern volatile gboolean glib_on_error_halt;
+
+#ifndef DISABLE_FAULT_HANDLER
+static void fault_restore (void);
+static void fault_spin (void);
+static void sigint_restore (void);
+static gboolean caught_intr = FALSE;
+#endif
+
+static GstElement *pipeline;
+static gboolean caught_error = FALSE;
+static gboolean tags = FALSE;
+static gboolean messages = FALSE;
+static gboolean is_live = FALSE;
+
+
+#ifndef GST_DISABLE_LOADSAVE
+static GstElement *
+xmllaunch_parse_cmdline (const gchar ** argv)
+{
+ GstElement *pipeline = NULL, *e;
+ GstXML *xml;
+ gboolean err;
+ const gchar *arg;
+ gchar *element, *property, *value;
+ GList *l;
+ gint i = 0;
+
+ if (!(arg = argv[0])) {
+ g_print (_
+ ("Usage: gst-xmllaunch <file.xml> [ element.property=value ... ]\n"));
+ exit (1);
+ }
+
+ xml = gst_xml_new ();
+ /* FIXME guchar from gstxml.c */
+ err = gst_xml_parse_file (xml, (guchar *) arg, NULL);
+
+ if (err != TRUE) {
+ fprintf (stderr, _("ERROR: parse of xml file '%s' failed.\n"), arg);
+ exit (1);
+ }
+
+ l = gst_xml_get_topelements (xml);
+ if (!l) {
+ fprintf (stderr, _("ERROR: no toplevel pipeline element in file '%s'.\n"),
+ arg);
+ exit (1);
+ }
+
+ if (l->next)
+ fprintf (stderr,
+ _("WARNING: only one toplevel element is supported at this time."));
+
+ pipeline = GST_ELEMENT (l->data);
+
+ while ((arg = argv[++i])) {
+ element = g_strdup (arg);
+ property = strchr (element, '.');
+ value = strchr (element, '=');
+
+ if (!(element < property && property < value)) {
+ fprintf (stderr,
+ _("ERROR: could not parse command line argument %d: %s.\n"), i,
+ element);
+ g_free (element);
+ exit (1);
+ }
+
+ *property++ = '\0';
+ *value++ = '\0';
+
+ e = gst_bin_get_by_name (GST_BIN (pipeline), element);
+ if (!e) {
+ fprintf (stderr, _("WARNING: element named '%s' not found.\n"), element);
+ } else {
+ gst_util_set_object_arg (G_OBJECT (e), property, value);
+ }
+ g_free (element);
+ }
+
+ if (!l)
+ return NULL;
+
+ gst_object_ref (pipeline);
+ gst_object_unref (xml);
+ return pipeline;
+}
+#endif
+
+#ifndef DISABLE_FAULT_HANDLER
+#ifndef USE_SIGINFO
+static void
+fault_handler_sighandler (int signum)
+{
+ fault_restore ();
+
+ /* printf is used instead of g_print(), since it's less likely to
+ * deadlock */
+ switch (signum) {
+ case SIGSEGV:
+ printf ("Caught SIGSEGV\n");
+ break;
+ case SIGQUIT:
+ printf ("Caught SIGQUIT\n");
+ break;
+ default:
+ printf ("signo: %d\n", signum);
+ break;
+ }
+
+ fault_spin ();
+}
+
+#else /* USE_SIGINFO */
+
+static void
+fault_handler_sigaction (int signum, siginfo_t * si, void *misc)
+{
+ fault_restore ();
+
+ /* printf is used instead of g_print(), since it's less likely to
+ * deadlock */
+ switch (si->si_signo) {
+ case SIGSEGV:
+ printf ("Caught SIGSEGV accessing address %p\n", si->si_addr);
+ break;
+ case SIGQUIT:
+ printf ("Caught SIGQUIT\n");
+ break;
+ default:
+ printf ("signo: %d\n", si->si_signo);
+ printf ("errno: %d\n", si->si_errno);
+ printf ("code: %d\n", si->si_code);
+ break;
+ }
+
+ fault_spin ();
+}
+#endif /* USE_SIGINFO */
+
+static void
+fault_spin (void)
+{
+ int spinning = TRUE;
+
+ glib_on_error_halt = FALSE;
+ g_on_error_stack_trace ("gst-launch");
+
+ wait (NULL);
+
+ /* FIXME how do we know if we were run by libtool? */
+ printf ("Spinning. Please run 'gdb gst-launch %d' to continue debugging, "
+ "Ctrl-C to quit, or Ctrl-\\ to dump core.\n", (gint) getpid ());
+ while (spinning)
+ g_usleep (1000000);
+}
+
+static void
+fault_restore (void)
+{
+ struct sigaction action;
+
+ memset (&action, 0, sizeof (action));
+ action.sa_handler = SIG_DFL;
+
+ sigaction (SIGSEGV, &action, NULL);
+ sigaction (SIGQUIT, &action, NULL);
+}
+
+static void
+fault_setup (void)
+{
+ struct sigaction action;
+
+ memset (&action, 0, sizeof (action));
+#ifdef USE_SIGINFO
+ action.sa_sigaction = fault_handler_sigaction;
+ action.sa_flags = SA_SIGINFO;
+#else
+ action.sa_handler = fault_handler_sighandler;
+#endif
+
+ sigaction (SIGSEGV, &action, NULL);
+ sigaction (SIGQUIT, &action, NULL);
+}
+#endif /* DISABLE_FAULT_HANDLER */
+
+static void
+print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
+{
+ gint i, count;
+
+ count = gst_tag_list_get_tag_size (list, tag);
+
+ for (i = 0; i < count; i++) {
+ gchar *str;
+
+ if (gst_tag_get_type (tag) == G_TYPE_STRING) {
+ if (!gst_tag_list_get_string_index (list, tag, i, &str))
+ g_assert_not_reached ();
+ } else if (gst_tag_get_type (tag) == GST_TYPE_BUFFER) {
+ GstBuffer *img;
+
+ img = gst_value_get_buffer (gst_tag_list_get_value_index (list, tag, i));
+ if (img) {
+ gchar *caps_str;
+
+ caps_str = GST_BUFFER_CAPS (img) ?
+ gst_caps_to_string (GST_BUFFER_CAPS (img)) : g_strdup ("unknown");
+ str = g_strdup_printf ("buffer of %u bytes, type: %s",
+ GST_BUFFER_SIZE (img), caps_str);
+ g_free (caps_str);
+ } else {
+ str = g_strdup ("NULL buffer");
+ }
+ } else {
+ str =
+ g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
+ }
+
+ if (i == 0) {
+ g_print ("%16s: %s\n", gst_tag_get_nick (tag), str);
+ } else {
+ g_print ("%16s: %s\n", "", str);
+ }
+
+ g_free (str);
+ }
+}
+
+#ifndef DISABLE_FAULT_HANDLER
+/* we only use sighandler here because the registers are not important */
+static void
+sigint_handler_sighandler (int signum)
+{
+ g_print ("Caught interrupt -- ");
+
+ sigint_restore ();
+
+ /* we set a flag that is checked by the mainloop, we cannot do much in the
+ * interrupt handler (no mutex or other blocking stuff) */
+ caught_intr = TRUE;
+}
+
+/* is called every 50 milliseconds (20 times a second), the interrupt handler
+ * will set a flag for us. We react to this by posting a message. */
+static gboolean
+check_intr (GstElement * pipeline)
+{
+ if (!caught_intr) {
+ return TRUE;
+ } else {
+ caught_intr = FALSE;
+ g_print ("handling interrupt.\n");
+
+ /* post an application specific message */
+ gst_element_post_message (GST_ELEMENT (pipeline),
+ gst_message_new_application (GST_OBJECT (pipeline),
+ gst_structure_new ("GstLaunchInterrupt",
+ "message", G_TYPE_STRING, "Pipeline interrupted", NULL)));
+
+ /* remove timeout handler */
+ return FALSE;
+ }
+}
+
+static void
+sigint_setup (void)
+{
+ struct sigaction action;
+
+ memset (&action, 0, sizeof (action));
+ action.sa_handler = sigint_handler_sighandler;
+
+ sigaction (SIGINT, &action, NULL);
+}
+
+static void
+sigint_restore (void)
+{
+ struct sigaction action;
+
+ memset (&action, 0, sizeof (action));
+ action.sa_handler = SIG_DFL;
+
+ sigaction (SIGINT, &action, NULL);
+}
+
+static void
+play_handler (int signum)
+{
+ switch (signum) {
+ case SIGUSR1:
+ g_print ("Caught SIGUSR1 - Play request.\n");
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+ break;
+ case SIGUSR2:
+ g_print ("Caught SIGUSR2 - Stop request.\n");
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ break;
+ }
+}
+
+static void
+play_signal_setup (void)
+{
+ struct sigaction action;
+
+ memset (&action, 0, sizeof (action));
+ action.sa_handler = play_handler;
+ sigaction (SIGUSR1, &action, NULL);
+ sigaction (SIGUSR2, &action, NULL);
+}
+#endif /* DISABLE_FAULT_HANDLER */
+
+/* returns TRUE if there was an error or we caught a keyboard interrupt. */
+static gboolean
+event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
+{
+ GstBus *bus;
+ GstMessage *message = NULL;
+ gboolean res = FALSE;
+ gboolean buffering = FALSE;
+
+ bus = gst_element_get_bus (GST_ELEMENT (pipeline));
+
+#ifndef DISABLE_FAULT_HANDLER
+ g_timeout_add (50, (GSourceFunc) check_intr, pipeline);
+#endif
+
+ while (TRUE) {
+ message = gst_bus_poll (bus, GST_MESSAGE_ANY, blocking ? -1 : 0);
+
+ /* if the poll timed out, only when !blocking */
+ if (message == NULL)
+ goto exit;
+
+ /* check if we need to dump messages to the console */
+ if (messages) {
+ const GstStructure *s;
+
+ s = gst_message_get_structure (message);
+
+ g_print (_("Got Message from element \"%s\" (%s): "),
+ GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))),
+ gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
+ if (s) {
+ gchar *sstr;
+
+ sstr = gst_structure_to_string (s);
+ g_print ("%s\n", sstr);
+ g_free (sstr);
+ } else {
+ g_print ("no message details\n");
+ }
+ }
+
+ switch (GST_MESSAGE_TYPE (message)) {
+ case GST_MESSAGE_NEW_CLOCK:
+ {
+ GstClock *clock;
+
+ gst_message_parse_new_clock (message, &clock);
+
+ g_print ("New clock: %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
+ break;
+ }
+ case GST_MESSAGE_EOS:
+ g_print (_
+ ("Got EOS from element \"%s\".\n"),
+ GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
+ goto exit;
+ case GST_MESSAGE_TAG:
+ if (tags) {
+ GstTagList *tags;
+
+ gst_message_parse_tag (message, &tags);
+ g_print (_("FOUND TAG : found by element \"%s\".\n"),
+ GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
+ gst_tag_list_foreach (tags, print_tag, NULL);
+ gst_tag_list_free (tags);
+ }
+ break;
+ case GST_MESSAGE_INFO:{
+ GError *gerror;
+ gchar *debug;
+ gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
+
+ gst_message_parse_info (message, &gerror, &debug);
+ if (debug) {
+ g_print (_("INFO:\n%s\n"), debug);
+ }
+ g_error_free (gerror);
+ g_free (debug);
+ g_free (name);
+ break;
+ }
+ case GST_MESSAGE_WARNING:{
+ GError *gerror;
+ gchar *debug;
+ gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
+
+ /* dump graph on warning */
+ GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
+ GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.warning");
+
+ gst_message_parse_warning (message, &gerror, &debug);
+ g_print (_("WARNING: from element %s: %s\n"), name, gerror->message);
+ if (debug) {
+ g_print (_("Additional debug info:\n%s\n"), debug);
+ }
+ g_error_free (gerror);
+ g_free (debug);
+ g_free (name);
+ break;
+ }
+ case GST_MESSAGE_ERROR:{
+ GError *gerror;
+ gchar *debug;
+
+ /* dump graph on error */
+ GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
+ GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.error");
+
+ gst_message_parse_error (message, &gerror, &debug);
+ gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+ g_error_free (gerror);
+ g_free (debug);
+ /* we have an error */
+ res = TRUE;
+ goto exit;
+ }
+ case GST_MESSAGE_STATE_CHANGED:{
+ GstState old, new, pending;
+
+ gst_message_parse_state_changed (message, &old, &new, &pending);
+
+ /* we only care about pipeline state change messages */
+ if (GST_MESSAGE_SRC (message) != GST_OBJECT_CAST (pipeline))
+ break;
+
+ /* dump graph for pipeline state changes */
+ {
+ gchar *dump_name = g_strdup_printf ("gst-launch.%s_%s",
+ gst_element_state_get_name (old),
+ gst_element_state_get_name (new));
+ GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline),
+ GST_DEBUG_GRAPH_SHOW_ALL, dump_name);
+ g_free (dump_name);
+ }
+
+ /* ignore when we are buffering since then we mess with the states
+ * ourselves. */
+ if (buffering) {
+ fprintf (stderr,
+ _("Prerolled, waiting for buffering to finish...\n"));
+ break;
+ }
+
+ /* if we reached the final target state, exit */
+ if (target_state == GST_STATE_PAUSED && new == target_state)
+ goto exit;
+
+ /* else not an interesting message */
+ break;
+ }
+ case GST_MESSAGE_BUFFERING:{
+ gint percent;
+
+ gst_message_parse_buffering (message, &percent);
+ fprintf (stderr, _("buffering... %d \r"), percent);
+
+ /* no state management needed for live pipelines */
+ if (is_live)
+ break;
+
+ if (percent == 100) {
+ /* a 100% message means buffering is done */
+ buffering = FALSE;
+ /* if the desired state is playing, go back */
+ if (target_state == GST_STATE_PLAYING) {
+ fprintf (stderr,
+ _("Done buffering, setting pipeline to PLAYING ...\n"));
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+ } else
+ goto exit;
+ } else {
+ /* buffering busy */
+ if (buffering == FALSE && target_state == GST_STATE_PLAYING) {
+ /* we were not buffering but PLAYING, PAUSE the pipeline. */
+ fprintf (stderr, _("Buffering, setting pipeline to PAUSED ...\n"));
+ gst_element_set_state (pipeline, GST_STATE_PAUSED);
+ }
+ buffering = TRUE;
+ }
+ break;
+ }
+ case GST_MESSAGE_APPLICATION:{
+ const GstStructure *s;
+
+ s = gst_message_get_structure (message);
+
+ if (gst_structure_has_name (s, "GstLaunchInterrupt")) {
+ /* this application message is posted when we caught an interrupt and
+ * we need to stop the pipeline. */
+ fprintf (stderr, _("Interrupt: Stopping pipeline ...\n"));
+ /* return TRUE when we caught an interrupt */
+ res = TRUE;
+ goto exit;
+ }
+ }
+ default:
+ /* just be quiet by default */
+ break;
+ }
+ if (message)
+ gst_message_unref (message);
+ }
+ g_assert_not_reached ();
+
+exit:
+ {
+ if (message)
+ gst_message_unref (message);
+ gst_object_unref (bus);
+ return res;
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ /* options */
+ gboolean verbose = FALSE;
+ gboolean no_fault = FALSE;
+ gboolean trace = FALSE;
+ gchar *savefile = NULL;
+ gchar *exclude_args = NULL;
+ GOptionEntry options[] = {
+ {"tags", 't', 0, G_OPTION_ARG_NONE, &tags,
+ N_("Output tags (also known as metadata)"), NULL},
+ {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
+ N_("Output status information and property notifications"), NULL},
+ {"messages", 'm', 0, G_OPTION_ARG_NONE, &messages,
+ N_("Output messages"), NULL},
+ {"exclude", 'X', 0, G_OPTION_ARG_NONE, &exclude_args,
+ N_("Do not output status information of TYPE"), N_("TYPE1,TYPE2,...")},
+#ifndef GST_DISABLE_LOADSAVE
+ {"output", 'o', 0, G_OPTION_ARG_STRING, &savefile,
+ N_("Save xml representation of pipeline to FILE and exit"), N_("FILE")},
+#endif
+ {"no-fault", 'f', 0, G_OPTION_ARG_NONE, &no_fault,
+ N_("Do not install a fault handler"), NULL},
+ {"trace", 'T', 0, G_OPTION_ARG_NONE, &trace,
+ N_("Print alloc trace (if enabled at compile time)"), NULL},
+ GST_TOOLS_GOPTION_VERSION,
+ {NULL}
+ };
+ GOptionContext *ctx;
+ GError *err = NULL;
+ gchar **argvn;
+ GError *error = NULL;
+ gint res = 0;
+
+ free (malloc (8)); /* -lefence */
+
+#ifdef ENABLE_NLS
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+#endif
+
+ if (!g_thread_supported ())
+ g_thread_init (NULL);
+
+ gst_alloc_trace_set_flags_all (GST_ALLOC_TRACE_LIVE);
+
+ ctx = g_option_context_new ("PIPELINE-DESCRIPTION");
+ g_option_context_add_main_entries (ctx, options, GETTEXT_PACKAGE);
+ g_option_context_add_group (ctx, gst_init_get_option_group ());
+ if (!g_option_context_parse (ctx, &argc, &argv, &err)) {
+ if (err)
+ g_print ("Error initializing: %s\n", GST_STR_NULL (err->message));
+ else
+ g_print ("Error initializing: Unknown error!\n");
+ exit (1);
+ }
+ g_option_context_free (ctx);
+
+ gst_tools_print_version ("gst-launch");
+
+#ifndef DISABLE_FAULT_HANDLER
+ if (!no_fault)
+ fault_setup ();
+
+ sigint_setup ();
+ play_signal_setup ();
+#endif
+
+ if (trace) {
+ if (!gst_alloc_trace_available ()) {
+ g_warning ("Trace not available (recompile with trace enabled).");
+ }
+ gst_alloc_trace_print_live ();
+ }
+
+ /* make a null-terminated version of argv */
+ argvn = g_new0 (char *, argc);
+ memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1));
+#ifndef GST_DISABLE_LOADSAVE
+ if (strstr (argv[0], "gst-xmllaunch")) {
+ pipeline = xmllaunch_parse_cmdline ((const gchar **) argvn);
+ } else
+#endif
+ {
+ pipeline =
+ (GstElement *) gst_parse_launchv ((const gchar **) argvn, &error);
+ }
+ g_free (argvn);
+
+ if (!pipeline) {
+ if (error) {
+ fprintf (stderr, _("ERROR: pipeline could not be constructed: %s.\n"),
+ GST_STR_NULL (error->message));
+ g_error_free (error);
+ } else {
+ fprintf (stderr, _("ERROR: pipeline could not be constructed.\n"));
+ }
+ return 1;
+ } else if (error) {
+ fprintf (stderr, _("WARNING: erroneous pipeline: %s\n"),
+ GST_STR_NULL (error->message));
+ g_error_free (error);
+ return 1;
+ }
+
+ if (verbose) {
+ gchar **exclude_list =
+ exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL;
+ g_signal_connect (pipeline, "deep_notify",
+ G_CALLBACK (gst_object_default_deep_notify), exclude_list);
+ }
+#ifndef GST_DISABLE_LOADSAVE
+ if (savefile) {
+ gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w"));
+ }
+#endif
+
+ if (!savefile) {
+ GstState state, pending;
+ GstStateChangeReturn ret;
+
+ /* If the top-level object is not a pipeline, place it in a pipeline. */
+ if (!GST_IS_PIPELINE (pipeline)) {
+ GstElement *real_pipeline = gst_element_factory_make ("pipeline", NULL);
+
+ if (real_pipeline == NULL) {
+ fprintf (stderr, _("ERROR: the 'pipeline' element wasn't found.\n"));
+ return 1;
+ }
+ gst_bin_add (GST_BIN (real_pipeline), pipeline);
+ pipeline = real_pipeline;
+ }
+ fprintf (stderr, _("Setting pipeline to PAUSED ...\n"));
+ ret = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+
+ switch (ret) {
+ case GST_STATE_CHANGE_FAILURE:
+ fprintf (stderr, _("ERROR: Pipeline doesn't want to pause.\n"));
+ res = -1;
+ event_loop (pipeline, FALSE, GST_STATE_VOID_PENDING);
+ goto end;
+ case GST_STATE_CHANGE_NO_PREROLL:
+ fprintf (stderr, _("Pipeline is live and does not need PREROLL ...\n"));
+ is_live = TRUE;
+ break;
+ case GST_STATE_CHANGE_ASYNC:
+ fprintf (stderr, _("Pipeline is PREROLLING ...\n"));
+ caught_error = event_loop (pipeline, TRUE, GST_STATE_PAUSED);
+ if (caught_error) {
+ fprintf (stderr, _("ERROR: pipeline doesn't want to preroll.\n"));
+ goto end;
+ }
+ state = GST_STATE_PAUSED;
+ /* fallthrough */
+ case GST_STATE_CHANGE_SUCCESS:
+ fprintf (stderr, _("Pipeline is PREROLLED ...\n"));
+ break;
+ }
+
+ caught_error = event_loop (pipeline, FALSE, GST_STATE_PLAYING);
+
+ if (caught_error) {
+ fprintf (stderr, _("ERROR: pipeline doesn't want to preroll.\n"));
+ } else {
+ GstClockTime tfthen, tfnow;
+ GstClockTimeDiff diff;
+
+ fprintf (stderr, _("Setting pipeline to PLAYING ...\n"));
+ if (gst_element_set_state (pipeline,
+ GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+ GstMessage *err_msg;
+ GstBus *bus;
+
+ fprintf (stderr, _("ERROR: pipeline doesn't want to play.\n"));
+ bus = gst_element_get_bus (pipeline);
+ if ((err_msg = gst_bus_poll (bus, GST_MESSAGE_ERROR, 0))) {
+ GError *gerror;
+ gchar *debug;
+
+ gst_message_parse_error (err_msg, &gerror, &debug);
+ gst_object_default_error (GST_MESSAGE_SRC (err_msg), gerror, debug);
+ gst_message_unref (err_msg);
+ g_error_free (gerror);
+ g_free (debug);
+ }
+ gst_object_unref (bus);
+ res = -1;
+ goto end;
+ }
+
+ tfthen = gst_util_get_timestamp ();
+ caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING);
+ tfnow = gst_util_get_timestamp ();
+
+ diff = GST_CLOCK_DIFF (tfthen, tfnow);
+
+ g_print (_("Execution ended after %" G_GUINT64_FORMAT " ns.\n"), diff);
+ }
+
+ /* iterate mainloop to process pending stuff */
+ while (g_main_context_iteration (NULL, FALSE));
+
+ fprintf (stderr, _("Setting pipeline to PAUSED ...\n"));
+ gst_element_set_state (pipeline, GST_STATE_PAUSED);
+ if (!caught_error)
+ gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
+ fprintf (stderr, _("Setting pipeline to READY ...\n"));
+ gst_element_set_state (pipeline, GST_STATE_READY);
+ gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
+
+ end:
+ fprintf (stderr, _("Setting pipeline to NULL ...\n"));
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
+ }
+
+ fprintf (stderr, _("FREEING pipeline ...\n"));
+ gst_object_unref (pipeline);
+
+ gst_deinit ();
+ if (trace)
+ gst_alloc_trace_print_live ();
+
+ return res;
+}