basesrc: use segment start if DTS for first buffer is unset
[platform/upstream/gstreamer.git] / tools / gst-launch.c
index 5d4ee46..a8ab1cd 100644 (file)
@@ -102,7 +102,7 @@ fault_spin (void)
 
   /* 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)
@@ -335,11 +335,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;
 
@@ -362,6 +364,9 @@ 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 ();
       }
     } else if (gst_tag_get_type (tag) == GST_TYPE_DATE_TIME) {
       GstDateTime *dt = NULL;
@@ -392,13 +397,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);
   }
 }
 
@@ -410,7 +412,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);
@@ -459,6 +462,10 @@ print_toc_entry (gpointer data, gpointer user_data)
 }
 
 #ifdef G_OS_UNIX
+static guint signal_watch_id;
+#endif
+
+#ifdef G_OS_UNIX
 /* As the interrupt handler is dispatched from GMainContext as a GSourceFunc
  * handler, we can react to this by posting a message. */
 static gboolean
@@ -475,6 +482,7 @@ intr_handler (gpointer user_data)
               "message", G_TYPE_STRING, "Pipeline interrupted", NULL)));
 
   /* remove signal handler */
+  signal_watch_id = 0;
   return FALSE;
 }
 
@@ -484,15 +492,14 @@ intr_handler (gpointer user_data)
  * 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));
 
@@ -665,19 +672,23 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
         if (GST_MESSAGE_SRC (message) != GST_OBJECT_CAST (pipeline))
           break;
 
-        /* ignore when we are buffering since then we mess with the states
-         * ourselves. */
-        if (buffering) {
-          PRINT (_("Prerolled, waiting for buffering to finish...\n"));
-          break;
-        }
-
         gst_message_parse_state_changed (message, &old, &new, &pending);
 
         /* if we reached the final target state, exit */
-        if (target_state == GST_STATE_PAUSED && new == target_state)
+        if (target_state == GST_STATE_PAUSED && new == target_state) {
+          prerolled = TRUE;
+          /* 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 (in_progress) {
+            PRINT (_("Prerolled, waiting for progress to finish...\n"));
+            break;
+          }
           goto exit;
-
+        }
         /* else not an interesting message */
         break;
       }
@@ -698,7 +709,7 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
           if (target_state == GST_STATE_PLAYING) {
             PRINT (_("Done buffering, setting pipeline to PLAYING ...\n"));
             gst_element_set_state (pipeline, GST_STATE_PLAYING);
-          } else
+          } else if (prerolled && !in_progress)
             goto exit;
         } else {
           /* buffering busy */
@@ -746,6 +757,37 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
         }
         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;
@@ -755,6 +797,23 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
         }
         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;
+      }
       default:
         /* just be quiet by default */
         break;
@@ -770,7 +829,8 @@ exit:
       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);
 #endif
     return res;
   }
@@ -812,6 +872,7 @@ bus_sync_handler (GstBus * bus, GstMessage * message, gpointer data)
 
         g_free (state_transition_name);
       }
+      break;
     default:
       break;
   }
@@ -864,6 +925,7 @@ main (int argc, char *argv[])
 #endif
   gchar **argvn;
   GError *error = NULL;
+  gulong deep_notify_id = 0;
   gint res = 0;
 
   free (malloc (8));            /* -lefence */
@@ -927,7 +989,7 @@ main (int argc, char *argv[])
   if (verbose) {
     gchar **exclude_list =
         exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL;
-    g_signal_connect (pipeline, "deep-notify",
+    deep_notify_id = g_signal_connect (pipeline, "deep-notify",
         G_CALLBACK (gst_object_default_deep_notify), exclude_list);
   }
 
@@ -975,7 +1037,7 @@ main (int argc, char *argv[])
       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"));
@@ -983,9 +1045,10 @@ main (int argc, char *argv[])
         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;
@@ -995,10 +1058,11 @@ main (int argc, char *argv[])
         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;
@@ -1022,7 +1086,7 @@ main (int argc, char *argv[])
       }
 
       tfthen = gst_util_get_timestamp ();
-      caught_error = event_loop (pipeline, TRUE, GST_STATE_PLAYING);
+      caught_error = event_loop (pipeline, TRUE, FALSE, GST_STATE_PLAYING);
       if (eos_on_shutdown && caught_error != ELR_NO_ERROR) {
         gboolean ignore_errors;
 
@@ -1038,7 +1102,7 @@ main (int argc, char *argv[])
         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 */
@@ -1047,10 +1111,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;
             }
           }
@@ -1072,6 +1138,10 @@ main (int argc, char *argv[])
     /* 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);