X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=tools%2Fgst-launch.c;h=f19b0dc50a862e15d317e55dee991d6eb311c11a;hb=ffc85bf7f6e72f3758f833e552677afb568c8ec4;hp=b616c8aa19465a50d6f67859c93f1813f087eea2;hpb=71422a9a7089864d3a6eb46a5064909a43865b34;p=platform%2Fupstream%2Fgstreamer.git diff --git a/tools/gst-launch.c b/tools/gst-launch.c index b616c8a..f19b0dc 100644 --- a/tools/gst-launch.c +++ b/tools/gst-launch.c @@ -35,6 +35,9 @@ #ifdef G_OS_UNIX #include #include +#elif defined (G_OS_WIN32) +#define WIN32_LEAN_AND_MEAN +#include #endif #include /* for LC_ALL */ #include "tools.h" @@ -62,9 +65,7 @@ static gboolean toc = FALSE; static gboolean messages = FALSE; static gboolean is_live = FALSE; static gboolean waiting_eos = FALSE; - -G_LOCK_DEFINE_STATIC (context); -static GstContext *context = NULL; +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 @@ -325,7 +326,7 @@ print_error_message (GstMessage * msg) 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); } @@ -338,11 +339,13 @@ print_tag (const GstTagList * list, const gchar * tag, gpointer unused) 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; @@ -365,7 +368,11 @@ print_tag (const GstTagList * list, const gchar * tag, gpointer unused) } 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; @@ -395,13 +402,10 @@ print_tag (const GstTagList * list, const gchar * tag, gpointer unused) 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); } } @@ -413,7 +417,8 @@ print_tag_foreach (const GstTagList * tags, const gchar * tag, 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); @@ -462,6 +467,16 @@ print_toc_entry (gpointer data, gpointer user_data) } #ifdef G_OS_UNIX +static guint signal_watch_hup_id; +#endif +#if defined(G_OS_UNIX) || defined(G_OS_WIN32) +static guint signal_watch_intr_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 @@ -478,22 +493,41 @@ intr_handler (gpointer user_data) "message", G_TYPE_STRING, "Pipeline interrupted", NULL))); /* remove signal handler */ - return FALSE; + signal_watch_intr_id = 0; + return G_SOURCE_REMOVE; } -#endif /* G_OS_UNIX */ - +#ifdef G_OS_UNIX static gboolean -merge_structures (GQuark field_id, const GValue * value, gpointer user_data) +hup_handler (gpointer user_data) { - GstStructure *s2 = user_data; + GstElement *pipeline = (GstElement *) user_data; + + if (g_getenv ("GST_DEBUG_DUMP_DOT_DIR") != NULL) { + PRINT ("SIGHUP: dumping dot file snapshot ...\n"); + } else { + PRINT ("SIGHUP: not dumping dot file snapshot, GST_DEBUG_DUMP_DOT_DIR " + "environment variable not set.\n"); + } - /* Copy all fields that are not set yet */ - if (!gst_structure_id_has_field (s2, field_id)) - gst_structure_id_set_value (s2, field_id, value); + /* dump graph on hup */ + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (pipeline), + GST_DEBUG_GRAPH_SHOW_ALL, "gst-launch.snapshot"); + return G_SOURCE_CONTINUE; +} +#endif + +#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 @@ -502,9 +536,6 @@ static EventLoopResult 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; @@ -514,8 +545,14 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress, bus = gst_element_get_bus (GST_ELEMENT (pipeline)); #ifdef G_OS_UNIX - signal_watch_id = + signal_watch_intr_id = g_unix_signal_add (SIGINT, (GSourceFunc) intr_handler, pipeline); + signal_watch_hup_id = + g_unix_signal_add (SIGHUP, (GSourceFunc) hup_handler, pipeline); +#elif defined(G_OS_WIN32) + intr_pipeline = NULL; + if (SetConsoleCtrlHandler (w32_intr_handler, TRUE)) + intr_pipeline = pipeline; #endif while (TRUE) { @@ -640,7 +677,7 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress, if (debug) { PRINT (_("INFO:\n%s\n"), debug); } - g_error_free (gerror); + g_clear_error (&gerror); g_free (debug); g_free (name); break; @@ -659,7 +696,7 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress, 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; @@ -723,7 +760,7 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_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); @@ -808,26 +845,63 @@ event_loop (GstElement * pipeline, gboolean blocking, gboolean do_progress, break; } case GST_MESSAGE_HAVE_CONTEXT:{ - GstContext *context_new; + GstContext *context; + const gchar *context_type; gchar *context_str; - gst_message_parse_have_context (message, &context_new); + 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_new)); - PRINT (_("Got context from element '%s': %s\n"), - GST_ELEMENT_NAME (GST_MESSAGE_SRC (message)), 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_new); - - /* The contexts were merged in the sync handler already, here - * now just print them and propagate the merged context to the - * complete pipeline */ - G_LOCK (context); - context_new = gst_context_ref (context_new); - G_UNLOCK (context); - gst_element_set_context (pipeline, context_new); - gst_context_unref (context_new); + 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 if (G_VALUE_TYPE (val) == GST_TYPE_STRUCTURE) + val_str = gst_structure_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: @@ -845,7 +919,13 @@ exit: gst_message_unref (message); gst_object_unref (bus); #ifdef G_OS_UNIX - g_source_remove (signal_watch_id); + if (signal_watch_intr_id > 0) + g_source_remove (signal_watch_intr_id); + if (signal_watch_hup_id > 0) + g_source_remove (signal_watch_hup_id); +#elif defined(G_OS_WIN32) + intr_pipeline = NULL; + SetConsoleCtrlHandler (w32_intr_handler, FALSE); #endif return res; } @@ -887,49 +967,7 @@ bus_sync_handler (GstBus * bus, GstMessage * message, gpointer data) g_free (state_transition_name); } - case GST_MESSAGE_NEED_CONTEXT:{ - G_LOCK (context); - /* We could filter something here, but instead we can also just pass the complete - * context knowledge we have to the element. If we have what it needs, it will be - * happy, otherwise we can't do anything else anyway */ - if (context) - gst_element_set_context (GST_ELEMENT_CAST (GST_MESSAGE_SRC (message)), - context); - G_UNLOCK (context); - - break; - } - case GST_MESSAGE_HAVE_CONTEXT:{ - GstContext *context_new; - - gst_message_parse_have_context (message, &context_new); - - /* Merge the contexts here as soon as possible and not - * in the async bus handler, in case something asks for - * a specific context before the async bus handler is run. - * - * Don't set the context on the complete pipeline here as it - * might deadlock, but do that from the async bus handler - * instead. - */ - G_LOCK (context); - if (context) { - const GstStructure *s1; - GstStructure *s2; - - /* Merge structures */ - context = gst_context_make_writable (context); - s1 = gst_context_get_structure (context_new); - s2 = gst_context_writable_structure (context); - gst_structure_foreach (s1, merge_structures, s2); - } else { - /* Copy over the context */ - gst_context_replace (&context, context_new); - } - gst_context_unref (context_new); - G_UNLOCK (context); break; - } default: break; } @@ -947,7 +985,6 @@ main (int argc, char *argv[]) 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, @@ -960,8 +997,10 @@ main (int argc, char *argv[]) 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, @@ -987,6 +1026,8 @@ main (int argc, char *argv[]) free (malloc (8)); /* -lefence */ + setlocale (LC_ALL, ""); + #ifdef ENABLE_NLS bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); @@ -994,6 +1035,8 @@ main (int argc, char *argv[]) #endif g_set_prgname ("gst-launch-" GST_API_VERSION); + /* Ensure XInitThreads() is called if/when needed */ + g_setenv ("GST_GL_XINITTHREADS", "1", TRUE); #ifndef GST_DISABLE_OPTION_PARSING ctx = g_option_context_new ("PIPELINE-DESCRIPTION"); @@ -1004,6 +1047,8 @@ main (int argc, char *argv[]) g_printerr ("Error initializing: %s\n", GST_STR_NULL (err->message)); else g_printerr ("Error initializing: Unknown error!\n"); + g_clear_error (&err); + g_option_context_free (ctx); exit (1); } g_option_context_free (ctx); @@ -1031,7 +1076,7 @@ main (int argc, char *argv[]) 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")); } @@ -1039,17 +1084,10 @@ main (int argc, char *argv[]) } 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; - deep_notify_id = g_signal_connect (pipeline, "deep-notify", - G_CALLBACK (gst_object_default_deep_notify), exclude_list); - } - if (!savefile) { GstState state, pending; GstStateChangeReturn ret; @@ -1066,6 +1104,10 @@ main (int argc, char *argv[]) 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 @@ -1105,6 +1147,7 @@ main (int argc, char *argv[]) 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; @@ -1118,6 +1161,7 @@ main (int argc, char *argv[]) if (caught_error) { g_printerr (_("ERROR: pipeline doesn't want to preroll.\n")); + res = caught_error; } else { GstClockTime tfthen, tfnow; GstClockTimeDiff diff; @@ -1142,6 +1186,7 @@ main (int argc, char *argv[]) tfthen = gst_util_get_timestamp (); 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; @@ -1166,10 +1211,12 @@ main (int argc, char *argv[]) } 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; } } @@ -1213,7 +1260,6 @@ main (int argc, char *argv[]) PRINT (_("Freeing pipeline ...\n")); gst_object_unref (pipeline); - gst_context_replace (&context, NULL); gst_deinit ();