#endif
/* FIXME: hack alert */
-#ifdef _MSC_VER
+#ifdef HAVE_WIN32
#define DISABLE_FAULT_HANDLER
#endif
+#include <stdio.h>
#include <string.h>
-#include <stdlib.h>
#include <signal.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include <sys/wait.h>
#endif
#include <locale.h> /* for LC_ALL */
-#include "gst/gst-i18n-app.h"
-
-#include <gst/gst.h>
+#include "tools.h"
/* FIXME: This is just a temporary hack. We should have a better
* check for siginfo handling. */
static void fault_restore (void);
static void fault_spin (void);
static void sigint_restore (void);
+static gboolean caught_intr = FALSE;
#endif
-static gint max_iterations = 0;
+/* event_loop return codes */
+typedef enum _EventLoopResult
+{
+ ELR_NO_ERROR = 0,
+ ELR_ERROR,
+ ELR_INTERRUPT
+} EventLoopResult;
+
static GstElement *pipeline;
-static gboolean caught_intr = FALSE;
-static gboolean caught_error = FALSE;
+static EventLoopResult caught_error = ELR_NO_ERROR;
+static gboolean quiet = FALSE;
static gboolean tags = FALSE;
static gboolean messages = FALSE;
+static gboolean is_live = FALSE;
+static gboolean waiting_eos = FALSE;
+/* convenience macro so we don't have to litter the code with if(!quiet) */
+#define PRINT if(!quiet)g_print
#ifndef GST_DISABLE_LOADSAVE
static GstElement *
err = gst_xml_parse_file (xml, (guchar *) arg, NULL);
if (err != TRUE) {
- fprintf (stderr, _("ERROR: parse of xml file '%s' failed.\n"), arg);
+ g_printerr (_("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);
+ g_printerr (_("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."));
+ if (l->next) {
+ g_printerr ("%s",
+ _("WARNING: only one toplevel element is supported at this time.\n"));
+ }
pipeline = GST_ELEMENT (l->data);
value = strchr (element, '=');
if (!(element < property && property < value)) {
- fprintf (stderr,
- _("ERROR: could not parse command line argument %d: %s.\n"), i,
- element);
+ g_printerr (_("ERROR: could not parse command line argument %d: %s.\n"),
+ i, element);
g_free (element);
exit (1);
}
e = gst_bin_get_by_name (GST_BIN (pipeline), element);
if (!e) {
- fprintf (stderr, _("WARNING: element named '%s' not found.\n"), element);
+ g_printerr (_("WARNING: element named '%s' not found.\n"), element);
} else {
gst_util_set_object_arg (G_OBJECT (e), property, value);
}
if (!l)
return NULL;
- else
- return l->data;
+
+ gst_object_ref (pipeline);
+ gst_object_unref (xml);
+ return pipeline;
}
#endif
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 ("%15s: %s\n", gst_tag_get_nick (tag), str);
+ g_print ("%16s: %s\n", gst_tag_get_nick (tag), str);
} else {
- g_print (" : %s\n", str);
+ g_print ("%16s: %s\n", "", str);
}
g_free (str);
{
g_print ("Caught interrupt -- ");
- sigint_restore ();
-
+ /* If we were waiting for an EOS, we still want to catch
+ * the next signal to shutdown properly (and the following one
+ * will quit the program). */
+ if (waiting_eos) {
+ waiting_eos = FALSE;
+ } else {
+ 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 250 milliseconds (4 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 {
- GstBus *bus;
- GstMessage *message;
-
caught_intr = FALSE;
- g_print ("Pausing pipeline.\n");
-
- bus = gst_element_get_bus (GST_ELEMENT (pipeline));
- message = gst_message_new_warning (GST_OBJECT (pipeline),
- NULL, "pipeline interrupted");
- gst_bus_post (bus, message);
-
- /* pipeline will wait for element to go to PAUSED */
- gst_element_set_state (pipeline, GST_STATE_PAUSED);
- g_print ("Pipeline paused.\n");
+ g_print ("handling interrupt.\n");
- gst_object_unref (bus);
+ /* 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;
}
}
}
#endif /* DISABLE_FAULT_HANDLER */
-static gboolean
-event_loop (GstElement * pipeline, gboolean blocking)
+/* returns ELR_ERROR if there was an error
+ * or ELR_INTERRUPT if we caught a keyboard interrupt
+ * or ELR_NO_ERROR otherwise. */
+static EventLoopResult
+event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
{
+#ifndef DISABLE_FAULT_HANDLER
+ gulong timeout_id;
+#endif
GstBus *bus;
GstMessage *message = NULL;
+ EventLoopResult res = ELR_NO_ERROR;
+ gboolean buffering = FALSE;
bus = gst_element_get_bus (GST_ELEMENT (pipeline));
- g_timeout_add (50, (GSourceFunc) check_intr, pipeline);
+#ifndef DISABLE_FAULT_HANDLER
+ timeout_id = g_timeout_add (250, (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) {
- gst_object_unref (bus);
- return FALSE;
- }
+ if (message == NULL)
+ goto exit;
+ /* check if we need to dump messages to the console */
if (messages) {
+ GstObject *src_obj;
const GstStructure *s;
+ guint32 seqnum;
+
+ seqnum = gst_message_get_seqnum (message);
s = gst_message_get_structure (message);
- g_print (_("Got Message from element \"%s\"\n"),
- GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
+
+ src_obj = GST_MESSAGE_SRC (message);
+
+ if (GST_IS_ELEMENT (src_obj)) {
+ PRINT (_("Got message #%u from element \"%s\" (%s): "),
+ (guint) seqnum, GST_ELEMENT_NAME (src_obj),
+ GST_MESSAGE_TYPE_NAME (message));
+ } else if (GST_IS_PAD (src_obj)) {
+ PRINT (_("Got message #%u from pad \"%s:%s\" (%s): "),
+ (guint) seqnum, GST_DEBUG_PAD_NAME (src_obj),
+ GST_MESSAGE_TYPE_NAME (message));
+ } else if (GST_IS_OBJECT (src_obj)) {
+ PRINT (_("Got message #%u from object \"%s\" (%s): "),
+ (guint) seqnum, GST_OBJECT_NAME (src_obj),
+ GST_MESSAGE_TYPE_NAME (message));
+ } else {
+ PRINT (_("Got message #%u (%s): "), (guint) seqnum,
+ GST_MESSAGE_TYPE_NAME (message));
+ }
+
if (s) {
gchar *sstr;
sstr = gst_structure_to_string (s);
- g_print ("%s\n", sstr);
+ PRINT ("%s\n", sstr);
g_free (sstr);
+ } else {
+ PRINT ("no message details\n");
}
}
switch (GST_MESSAGE_TYPE (message)) {
- case GST_MESSAGE_EOS:
- g_print (_
- ("Got EOS from element \"%s\".\n"),
- GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
- gst_message_unref (message);
- gst_object_unref (bus);
- return FALSE;
+ case GST_MESSAGE_NEW_CLOCK:
+ {
+ GstClock *clock;
+
+ gst_message_parse_new_clock (message, &clock);
+
+ PRINT ("New clock: %s\n", (clock ? GST_OBJECT_NAME (clock) : "NULL"));
+ break;
+ }
+ case GST_MESSAGE_CLOCK_LOST:
+#if 0
+ /* disabled for now as it caused problems with rtspsrc. We need to fix
+ * rtspsrc first, then release -good before we can reenable this again
+ */
+ PRINT ("Clock lost, selecting a new one\n");
+ gst_element_set_state (pipeline, GST_STATE_PAUSED);
+ gst_element_set_state (pipeline, GST_STATE_PLAYING);
+#endif
+ break;
+ case GST_MESSAGE_EOS:{
+ waiting_eos = FALSE;
+ PRINT (_("Got EOS from element \"%s\".\n"),
+ GST_MESSAGE_SRC_NAME (message));
+ goto exit;
+ }
case GST_MESSAGE_TAG:
if (tags) {
GstTagList *tags;
+ if (GST_IS_ELEMENT (GST_MESSAGE_SRC (message))) {
+ PRINT (_("FOUND TAG : found by element \"%s\".\n"),
+ GST_MESSAGE_SRC_NAME (message));
+ } else if (GST_IS_PAD (GST_MESSAGE_SRC (message))) {
+ PRINT (_("FOUND TAG : found by pad \"%s:%s\".\n"),
+ GST_DEBUG_PAD_NAME (GST_MESSAGE_SRC (message)));
+ } else if (GST_IS_OBJECT (GST_MESSAGE_SRC (message))) {
+ PRINT (_("FOUND TAG : found by object \"%s\".\n"),
+ GST_MESSAGE_SRC_NAME (message));
+ } else {
+ PRINT (_("FOUND TAG\n"));
+ }
+
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);
}
- gst_message_unref (message);
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) {
+ 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);
+ PRINT (_("WARNING: from element %s: %s\n"), name, gerror->message);
if (debug) {
- g_print ("WARNING: Element \"%s\" warns: %s\n",
- GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))),
- debug);
+ PRINT (_("Additional debug info:\n%s\n"), debug);
}
- gst_message_unref (message);
- if (gerror)
- g_error_free (gerror);
+ 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);
- gst_message_unref (message);
- if (gerror)
- g_error_free (gerror);
+ g_error_free (gerror);
g_free (debug);
- gst_object_unref (bus);
- return TRUE;
+ /* we have an error */
+ res = ELR_ERROR;
+ goto exit;
}
case GST_MESSAGE_STATE_CHANGED:{
- GstState old, new;
+ GstState old, new, pending;
+
+ gst_message_parse_state_changed (message, &old, &new, &pending);
- gst_message_parse_state_changed (message, &old, &new);
- if (!(old == GST_STATE_PLAYING && new == GST_STATE_PAUSED &&
- GST_MESSAGE_SRC (message) == GST_OBJECT (pipeline))) {
- gst_message_unref (message);
+ /* 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) {
+ PRINT (_("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);
+ PRINT ("%s %d%% \r", _("buffering..."), 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) {
+ PRINT (_("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. */
+ PRINT (_("Buffering, setting pipeline to PAUSED ...\n"));
+ gst_element_set_state (pipeline, GST_STATE_PAUSED);
+ }
+ buffering = TRUE;
+ }
+ break;
+ }
+ case GST_MESSAGE_LATENCY:
+ {
+ PRINT (_("Redistribute latency...\n"));
+ gst_bin_recalculate_latency (GST_BIN (pipeline));
+ break;
+ }
+ case GST_MESSAGE_REQUEST_STATE:
+ {
+ GstState state;
+ gchar *name = gst_object_get_path_string (GST_MESSAGE_SRC (message));
+
+ gst_message_parse_request_state (message, &state);
+
+ PRINT (_("Setting state to %s as requested by %s...\n"),
+ gst_element_state_get_name (state), name);
+
+ gst_element_set_state (pipeline, state);
+
+ g_free (name);
+ 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. */
+ PRINT (_("Interrupt: Stopping pipeline ...\n"));
+ res = ELR_INTERRUPT;
+ goto exit;
}
- g_print (_
- ("Element \"%s\" has gone from PLAYING to PAUSED, quitting.\n"),
- GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
- /* cut out of the event loop if check_intr set us to PAUSED */
- gst_message_unref (message);
- gst_object_unref (bus);
- return FALSE;
}
default:
/* just be quiet by default */
- gst_message_unref (message);
break;
}
+ if (message)
+ gst_message_unref (message);
}
-
g_assert_not_reached ();
- return TRUE;
+
+exit:
+ {
+ if (message)
+ gst_message_unref (message);
+ gst_object_unref (bus);
+#ifndef DISABLE_FAULT_HANDLER
+ g_source_remove (timeout_id);
+#endif
+ return res;
+ }
}
int
main (int argc, char *argv[])
{
- gint i, j;
-
/* options */
gboolean verbose = FALSE;
gboolean no_fault = FALSE;
+ gboolean no_play = FALSE;
gboolean trace = FALSE;
+ gboolean eos_on_shutdown = FALSE;
gchar *savefile = NULL;
gchar *exclude_args = NULL;
- struct poptOption options[] = {
- {"tags", 't', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &tags, 0,
+#ifndef GST_DISABLE_OPTION_PARSING
+ GOptionEntry options[] = {
+ {"tags", 't', 0, G_OPTION_ARG_NONE, &tags,
N_("Output tags (also known as metadata)"), NULL},
- {"messages", 'm', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &messages, 0,
- N_("Output messages"), NULL},
- {"verbose", 'v', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &verbose, 0,
+ {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
N_("Output status information and property notifications"), NULL},
- {"exclude", 'X', POPT_ARG_STRING | POPT_ARGFLAG_STRIP, &exclude_args, 0,
+ {"quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet,
+ N_("Do not print any progress information"), 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', POPT_ARG_STRING | POPT_ARGFLAG_STRIP, &savefile, 0,
+ {"output", 'o', 0, G_OPTION_ARG_STRING, &savefile,
N_("Save xml representation of pipeline to FILE and exit"), N_("FILE")},
#endif
- {"no-fault", 'f', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &no_fault, 0,
+ {"no-fault", 'f', 0, G_OPTION_ARG_NONE, &no_fault,
N_("Do not install a fault handler"), NULL},
- {"trace", 'T', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &trace, 0,
+ {"no-play", 'p', 0, G_OPTION_ARG_NONE, &no_play,
+ N_("Do not install a play handler"), NULL},
+ {"trace", 'T', 0, G_OPTION_ARG_NONE, &trace,
N_("Print alloc trace (if enabled at compile time)"), NULL},
- {"iterations", 'i', POPT_ARG_INT | POPT_ARGFLAG_STRIP, &max_iterations, 0,
- N_("Number of times to iterate pipeline"), NULL},
- POPT_TABLEEND
+ {"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown,
+ N_("Force EOS on sources before shutting the pipeline down"), NULL},
+ GST_TOOLS_GOPTION_VERSION,
+ {NULL}
};
-
+ GOptionContext *ctx;
+ GError *err = NULL;
+#endif
gchar **argvn;
GError *error = NULL;
gint res = 0;
free (malloc (8)); /* -lefence */
-#ifdef GETTEXT_PACKAGE
+#ifdef ENABLE_NLS
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
#endif
- gst_alloc_trace_set_flags_all (GST_ALLOC_TRACE_LIVE);
-
- gst_init_with_popt_table (&argc, &argv, options);
+ g_thread_init (NULL);
- /* FIXpopt: strip short args, too. We do it ourselves for now */
- j = 1;
- for (i = 1; i < argc; i++) {
- if (*(argv[i]) == '-') {
- if (strlen (argv[i]) == 2) {
- gchar *c = argv[i];
+ gst_tools_set_prgname ("gst-launch");
- c++;
- if (*c == 'X' || *c == 'o') {
- i++;
- }
- }
- } else {
- argv[j] = argv[i];
- j++;
- }
+#ifndef GST_DISABLE_OPTION_PARSING
+ 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_printerr ("Error initializing: %s\n", GST_STR_NULL (err->message));
+ else
+ g_printerr ("Error initializing: Unknown error!\n");
+ exit (1);
}
- argc = j;
+ g_option_context_free (ctx);
+#else
+ gst_init (&argc, &argv);
+#endif
+
+ gst_tools_print_version ("gst-launch");
#ifndef DISABLE_FAULT_HANDLER
if (!no_fault)
fault_setup ();
sigint_setup ();
- play_signal_setup ();
+
+ if (!no_play)
+ play_signal_setup ();
#endif
if (trace) {
if (!gst_alloc_trace_available ()) {
g_warning ("Trace not available (recompile with trace enabled).");
}
+ gst_alloc_trace_set_flags_all (GST_ALLOC_TRACE_LIVE |
+ GST_ALLOC_TRACE_MEM_LIVE);
gst_alloc_trace_print_live ();
}
if (!pipeline) {
if (error) {
- fprintf (stderr, _("ERROR: pipeline could not be constructed: %s.\n"),
- error->message);
+ g_printerr (_("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"));
+ g_printerr (_("ERROR: pipeline could not be constructed.\n"));
}
return 1;
} else if (error) {
- fprintf (stderr, _("WARNING: erroneous pipeline: %s\n"), error->message);
+ g_printerr (_("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_signal_connect (pipeline, "deep-notify",
G_CALLBACK (gst_object_default_deep_notify), exclude_list);
}
#ifndef GST_DISABLE_LOADSAVE
GstState state, pending;
GstStateChangeReturn ret;
- if (!GST_IS_BIN (pipeline)) {
+ /* 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"));
+ g_printerr (_("ERROR: the 'pipeline' element wasn't found.\n"));
return 1;
}
gst_bin_add (GST_BIN (real_pipeline), pipeline);
pipeline = real_pipeline;
}
-
- fprintf (stderr, _("PAUSE pipeline ...\n"));
+ PRINT (_("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"));
+ g_printerr (_("ERROR: Pipeline doesn't want to pause.\n"));
res = -1;
- event_loop (pipeline, FALSE);
+ event_loop (pipeline, FALSE, GST_STATE_VOID_PENDING);
goto end;
case GST_STATE_CHANGE_NO_PREROLL:
- fprintf (stderr, _("NO_PREROLL pipeline ...\n"));
+ PRINT (_("Pipeline is live and does not need PREROLL ...\n"));
+ is_live = TRUE;
break;
case GST_STATE_CHANGE_ASYNC:
- fprintf (stderr, _("PREROLL pipeline ...\n"));
- gst_element_get_state (pipeline, &state, &pending, NULL);
+ PRINT (_("Pipeline is PREROLLING ...\n"));
+ caught_error = event_loop (pipeline, TRUE, GST_STATE_PAUSED);
+ if (caught_error) {
+ g_printerr (_("ERROR: pipeline doesn't want to preroll.\n"));
+ goto end;
+ }
+ state = GST_STATE_PAUSED;
/* fallthrough */
case GST_STATE_CHANGE_SUCCESS:
- fprintf (stderr, _("PREROLLED pipeline ...\n"));
+ PRINT (_("Pipeline is PREROLLED ...\n"));
break;
}
- caught_error = event_loop (pipeline, FALSE);
+ caught_error = event_loop (pipeline, FALSE, GST_STATE_PLAYING);
if (caught_error) {
- fprintf (stderr, _("ERROR: pipeline doesn't want to preroll.\n"));
+ g_printerr (_("ERROR: pipeline doesn't want to preroll.\n"));
} else {
- GTimeVal tfthen, tfnow;
+ GstClockTime tfthen, tfnow;
GstClockTimeDiff diff;
- fprintf (stderr, _("RUNNING pipeline ...\n"));
+ PRINT (_("Setting pipeline to PLAYING ...\n"));
+
if (gst_element_set_state (pipeline,
GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
- fprintf (stderr, _("ERROR: pipeline doesn't want to play.\n"));
+ GstMessage *err_msg;
+ GstBus *bus;
+
+ g_printerr (_("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;
}
- g_get_current_time (&tfthen);
- caught_error = event_loop (pipeline, TRUE);
- g_get_current_time (&tfnow);
+ tfthen = gst_util_get_timestamp ();
+ caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING);
+ if (eos_on_shutdown && caught_error == ELR_INTERRUPT) {
+ PRINT (_("EOS on shutdown enabled -- Forcing EOS on the pipeline\n"));
+ waiting_eos = TRUE;
+ gst_element_send_event (pipeline, gst_event_new_eos ());
+ PRINT (_("Waiting for EOS...\n"));
+ caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING);
+
+ if (caught_error == ELR_NO_ERROR) {
+ /* we got EOS */
+ PRINT (_("EOS received - stopping pipeline...\n"));
+ } else if (caught_error == ELR_ERROR) {
+ PRINT (_("An error happened while waiting for EOS\n"));
+ }
+ }
+ tfnow = gst_util_get_timestamp ();
- diff = GST_TIMEVAL_TO_TIME (tfnow) - GST_TIMEVAL_TO_TIME (tfthen);
+ diff = GST_CLOCK_DIFF (tfthen, tfnow);
- g_print (_("Execution ended after %" G_GUINT64_FORMAT " ns.\n"), diff);
+ PRINT (_("Execution ended after %" G_GUINT64_FORMAT " ns.\n"), diff);
}
- while (g_main_context_iteration (NULL, FALSE));
- fprintf (stderr, _("PAUSE pipeline ...\n"));
+ PRINT (_("Setting pipeline to PAUSED ...\n"));
gst_element_set_state (pipeline, GST_STATE_PAUSED);
- gst_element_get_state (pipeline, &state, &pending, NULL);
- fprintf (stderr, _("READY pipeline ...\n"));
+ if (caught_error == ELR_NO_ERROR)
+ gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
+
+ /* iterate mainloop to process pending stuff */
+ while (g_main_context_iteration (NULL, FALSE));
+
+ PRINT (_("Setting pipeline to READY ...\n"));
gst_element_set_state (pipeline, GST_STATE_READY);
- gst_element_get_state (pipeline, &state, &pending, NULL);
+ gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
end:
- fprintf (stderr, _("NULL pipeline ...\n"));
+ PRINT (_("Setting pipeline to NULL ...\n"));
gst_element_set_state (pipeline, GST_STATE_NULL);
- gst_element_get_state (pipeline, &state, &pending, NULL);
+ gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);
}
- fprintf (stderr, _("FREEING pipeline ...\n"));
+ PRINT (_("Freeing pipeline ...\n"));
gst_object_unref (pipeline);
gst_deinit ();