#ifdef G_OS_UNIX
#include <glib-unix.h>
#include <sys/wait.h>
+#elif defined (G_OS_WIN32)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
#endif
#include <locale.h> /* for LC_ALL */
#include "tools.h"
static gboolean messages = FALSE;
static gboolean is_live = FALSE;
static gboolean waiting_eos = FALSE;
+static gchar **exclude_args = NULL;
/* convenience macro so we don't have to litter the code with if(!quiet) */
#define PRINT if(!quiet)g_print
/* FIXME how do we know if we were run by libtool? */
fprintf (stderr,
- "Spinning. Please run 'gdb gst-launch- " GST_API_VERSION " %d' to "
+ "Spinning. Please run 'gdb gst-launch-" GST_API_VERSION " %d' to "
"continue debugging, Ctrl-C to quit, or Ctrl-\\ to dump core.\n",
(gint) getpid ());
while (spinning)
if (debug != NULL)
g_printerr (_("Additional debug info:\n%s\n"), debug);
- g_error_free (err);
+ g_clear_error (&err);
g_free (debug);
g_free (name);
}
count = gst_tag_list_get_tag_size (list, tag);
for (i = 0; i < count; i++) {
- gchar *str;
+ gchar *str = NULL;
if (gst_tag_get_type (tag) == G_TYPE_STRING) {
- if (!gst_tag_list_get_string_index (list, tag, i, &str))
+ if (!gst_tag_list_get_string_index (list, tag, i, &str)) {
+ g_warning ("Couldn't fetch string for %s tag", tag);
g_assert_not_reached ();
+ }
} else if (gst_tag_get_type (tag) == GST_TYPE_SAMPLE) {
GstSample *sample = NULL;
} else {
str = g_strdup ("NULL buffer");
}
+ } else {
+ g_warning ("Couldn't fetch sample for %s tag", tag);
+ g_assert_not_reached ();
}
+ gst_sample_unref (sample);
} else if (gst_tag_get_type (tag) == GST_TYPE_DATE_TIME) {
GstDateTime *dt = NULL;
g_strdup_value_contents (gst_tag_list_get_value_index (list, tag, i));
}
- if (i == 0) {
- PRINT ("%16s: %s\n", gst_tag_get_nick (tag), str);
- } else {
- PRINT ("%16s: %s\n", "", str);
+ if (str) {
+ PRINT ("%16s: %s\n", i == 0 ? gst_tag_get_nick (tag) : "", str);
+ g_free (str);
}
-
- g_free (str);
}
}
gchar *str;
gint depth = GPOINTER_TO_INT (user_data);
- gst_tag_list_copy_value (&val, tags, tag);
+ if (!gst_tag_list_copy_value (&val, tags, tag))
+ return;
if (G_VALUE_HOLDS_STRING (&val))
str = g_value_dup_string (&val);
g_list_foreach (subentries, print_toc_entry, GUINT_TO_POINTER (indent));
}
-#ifdef G_OS_UNIX
+#if defined(G_OS_UNIX) || defined(G_OS_WIN32)
+static guint signal_watch_id;
+#if defined(G_OS_WIN32)
+static GstElement *intr_pipeline;
+#endif
+#endif
+
+#if defined(G_OS_UNIX) || defined(G_OS_WIN32)
/* As the interrupt handler is dispatched from GMainContext as a GSourceFunc
* handler, we can react to this by posting a message. */
static gboolean
"message", G_TYPE_STRING, "Pipeline interrupted", NULL)));
/* remove signal handler */
+ signal_watch_id = 0;
return FALSE;
}
+#if defined(G_OS_WIN32) /* G_OS_UNIX */
+static BOOL WINAPI
+w32_intr_handler (DWORD dwCtrlType)
+{
+ intr_handler ((gpointer) intr_pipeline);
+ intr_pipeline = NULL;
+ return TRUE;
+}
+#endif /* G_OS_WIN32 */
#endif /* G_OS_UNIX */
/* 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)
+event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress,
+ GstState target_state)
{
-#ifdef G_OS_UNIX
- guint signal_watch_id;
-#endif
GstBus *bus;
GstMessage *message = NULL;
EventLoopResult res = ELR_NO_ERROR;
- gboolean buffering = FALSE;
+ gboolean buffering = FALSE, in_progress = FALSE;
gboolean prerolled = target_state != GST_STATE_PAUSED;
bus = gst_element_get_bus (GST_ELEMENT (pipeline));
#ifdef G_OS_UNIX
signal_watch_id =
g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline);
+#elif defined(G_OS_WIN32)
+ intr_pipeline = NULL;
+ if (SetConsoleCtrlHandler (w32_intr_handler, TRUE))
+ intr_pipeline = pipeline;
#endif
while (TRUE) {
if (debug) {
PRINT (_("INFO:\n%s\n"), debug);
}
- g_error_free (gerror);
+ g_clear_error (&gerror);
g_free (debug);
g_free (name);
break;
if (debug) {
PRINT (_("Additional debug info:\n%s\n"), debug);
}
- g_error_free (gerror);
+ g_clear_error (&gerror);
g_free (debug);
g_free (name);
break;
PRINT (_("Prerolled, waiting for buffering to finish...\n"));
break;
}
+ if (in_progress) {
+ PRINT (_("Prerolled, waiting for progress to finish...\n"));
+ break;
+ }
goto exit;
}
/* else not an interesting message */
if (target_state == GST_STATE_PLAYING) {
PRINT (_("Done buffering, setting pipeline to PLAYING ...\n"));
gst_element_set_state (pipeline, GST_STATE_PLAYING);
- } else if (prerolled)
+ } else if (prerolled && !in_progress)
goto exit;
} else {
/* buffering busy */
- if (buffering == FALSE && target_state == GST_STATE_PLAYING) {
+ if (!buffering && 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);
}
break;
}
+ case GST_MESSAGE_PROGRESS:
+ {
+ GstProgressType type;
+ gchar *code, *text;
+
+ gst_message_parse_progress (message, &type, &code, &text);
+
+ switch (type) {
+ case GST_PROGRESS_TYPE_START:
+ case GST_PROGRESS_TYPE_CONTINUE:
+ if (do_progress) {
+ in_progress = TRUE;
+ blocking = TRUE;
+ }
+ break;
+ case GST_PROGRESS_TYPE_COMPLETE:
+ case GST_PROGRESS_TYPE_CANCELED:
+ case GST_PROGRESS_TYPE_ERROR:
+ in_progress = FALSE;
+ break;
+ default:
+ break;
+ }
+ PRINT (_("Progress: (%s) %s\n"), code, text);
+ g_free (code);
+ g_free (text);
+
+ if (do_progress && !in_progress && !buffering && prerolled)
+ goto exit;
+ break;
+ }
case GST_MESSAGE_ELEMENT:{
if (gst_is_missing_plugin_message (message)) {
const gchar *desc;
}
break;
}
+ case GST_MESSAGE_HAVE_CONTEXT:{
+ GstContext *context;
+ const gchar *context_type;
+ gchar *context_str;
+
+ gst_message_parse_have_context (message, &context);
+
+ context_type = gst_context_get_context_type (context);
+ context_str =
+ gst_structure_to_string (gst_context_get_structure (context));
+ PRINT (_("Got context from element '%s': %s=%s\n"),
+ GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)), context_type,
+ context_str);
+ g_free (context_str);
+ gst_context_unref (context);
+ break;
+ }
+ case GST_MESSAGE_PROPERTY_NOTIFY:{
+ const GValue *val;
+ const gchar *name;
+ GstObject *obj;
+ gchar *val_str = NULL;
+ gchar **ex_prop, *obj_name;
+
+ if (quiet)
+ break;
+
+ gst_message_parse_property_notify (message, &obj, &name, &val);
+
+ /* Let's not print anything for excluded properties... */
+ ex_prop = exclude_args;
+ while (ex_prop != NULL && *ex_prop != NULL) {
+ if (strcmp (name, *ex_prop) == 0)
+ break;
+ ex_prop++;
+ }
+ if (ex_prop != NULL && *ex_prop != NULL)
+ break;
+
+ obj_name = gst_object_get_path_string (GST_OBJECT (obj));
+ if (val != NULL) {
+ if (G_VALUE_HOLDS_STRING (val))
+ val_str = g_value_dup_string (val);
+ else if (G_VALUE_TYPE (val) == GST_TYPE_CAPS)
+ val_str = gst_caps_to_string (g_value_get_boxed (val));
+ else if (G_VALUE_TYPE (val) == GST_TYPE_TAG_LIST)
+ val_str = gst_tag_list_to_string (g_value_get_boxed (val));
+ else
+ val_str = gst_value_serialize (val);
+ } else {
+ val_str = g_strdup ("(no value)");
+ }
+
+ g_print ("%s: %s = %s\n", obj_name, name, val_str);
+ g_free (obj_name);
+ g_free (val_str);
+ break;
+ }
default:
/* just be quiet by default */
break;
gst_message_unref (message);
gst_object_unref (bus);
#ifdef G_OS_UNIX
- g_source_remove (signal_watch_id);
+ if (signal_watch_id > 0)
+ g_source_remove (signal_watch_id);
+#elif defined(G_OS_WIN32)
+ intr_pipeline = NULL;
+ SetConsoleCtrlHandler (w32_intr_handler, FALSE);
#endif
return res;
}
g_free (state_transition_name);
}
+ break;
default:
break;
}
gboolean check_index = FALSE;
#endif
gchar *savefile = NULL;
- gchar *exclude_args = NULL;
#ifndef GST_DISABLE_OPTION_PARSING
GOptionEntry options[] = {
{"tags", 't', 0, G_OPTION_ARG_NONE, &tags,
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,...")},
+ {"exclude", 'X', 0, G_OPTION_ARG_STRING_ARRAY, &exclude_args,
+ N_("Do not output status information for the specified property "
+ "if verbose output is enabled (can be used multiple times)"),
+ N_("PROPERTY-NAME")},
{"no-fault", 'f', 0, G_OPTION_ARG_NONE, &no_fault,
N_("Do not install a fault handler"), NULL},
{"eos-on-shutdown", 'e', 0, G_OPTION_ARG_NONE, &eos_on_shutdown,
#endif
gchar **argvn;
GError *error = NULL;
+ gulong deep_notify_id = 0;
gint res = 0;
free (malloc (8)); /* -lefence */
+ setlocale (LC_ALL, "");
+
#ifdef ENABLE_NLS
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
g_printerr ("Error initializing: %s\n", GST_STR_NULL (err->message));
else
g_printerr ("Error initializing: Unknown error!\n");
+ g_clear_error (&error);
+ g_option_context_free (ctx);
exit (1);
}
g_option_context_free (ctx);
if (error) {
g_printerr (_("ERROR: pipeline could not be constructed: %s.\n"),
GST_STR_NULL (error->message));
- g_error_free (error);
+ g_clear_error (&error);
} else {
g_printerr (_("ERROR: pipeline could not be constructed.\n"));
}
} else if (error) {
g_printerr (_("WARNING: erroneous pipeline: %s\n"),
GST_STR_NULL (error->message));
- g_error_free (error);
+ g_clear_error (&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);
- }
-
if (!savefile) {
GstState state, pending;
GstStateChangeReturn ret;
gst_bin_add (GST_BIN (real_pipeline), pipeline);
pipeline = real_pipeline;
}
+ if (verbose) {
+ deep_notify_id =
+ gst_element_add_property_deep_notify_watch (pipeline, NULL, TRUE);
+ }
#if 0
if (check_index) {
/* gst_index_new() creates a null-index, it does not store anything, but
case GST_STATE_CHANGE_FAILURE:
g_printerr (_("ERROR: Pipeline doesn't want to pause.\n"));
res = -1;
- event_loop (pipeline, FALSE, GST_STATE_VOID_PENDING);
+ event_loop (pipeline, FALSE, FALSE, GST_STATE_VOID_PENDING);
goto end;
case GST_STATE_CHANGE_NO_PREROLL:
PRINT (_("Pipeline is live and does not need PREROLL ...\n"));
break;
case GST_STATE_CHANGE_ASYNC:
PRINT (_("Pipeline is PREROLLING ...\n"));
- caught_error = event_loop (pipeline, TRUE, GST_STATE_PAUSED);
+ caught_error = event_loop (pipeline, TRUE, TRUE, GST_STATE_PAUSED);
if (caught_error) {
g_printerr (_("ERROR: pipeline doesn't want to preroll.\n"));
+ res = caught_error;
goto end;
}
state = GST_STATE_PAUSED;
break;
}
- caught_error = event_loop (pipeline, FALSE, GST_STATE_PLAYING);
+ caught_error = event_loop (pipeline, FALSE, TRUE, GST_STATE_PLAYING);
if (caught_error) {
g_printerr (_("ERROR: pipeline doesn't want to preroll.\n"));
+ res = caught_error;
} else {
GstClockTime tfthen, tfnow;
GstClockTimeDiff diff;
}
tfthen = gst_util_get_timestamp ();
- caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING);
+ caught_error = event_loop (pipeline, TRUE, FALSE, GST_STATE_PLAYING);
+ res = caught_error;
if (eos_on_shutdown && caught_error != ELR_NO_ERROR) {
gboolean ignore_errors;
PRINT (_("Waiting for EOS...\n"));
while (TRUE) {
- caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING);
+ caught_error = event_loop (pipeline, TRUE, FALSE, GST_STATE_PLAYING);
if (caught_error == ELR_NO_ERROR) {
/* we got EOS */
} else if (caught_error == ELR_INTERRUPT) {
PRINT (_
("Interrupt while waiting for EOS - stopping pipeline...\n"));
+ res = caught_error;
break;
} else if (caught_error == ELR_ERROR) {
if (!ignore_errors) {
PRINT (_("An error happened while waiting for EOS\n"));
+ res = caught_error;
break;
}
}
/* iterate mainloop to process pending stuff */
while (g_main_context_iteration (NULL, FALSE));
+ /* No need to see all those pad caps going to NULL etc., it's just noise */
+ if (deep_notify_id != 0)
+ g_signal_handler_disconnect (pipeline, deep_notify_id);
+
PRINT (_("Setting pipeline to READY ...\n"));
gst_element_set_state (pipeline, GST_STATE_READY);
gst_element_get_state (pipeline, &state, &pending, GST_CLOCK_TIME_NONE);