gst/gstelement.c (gst_element_set_base_time): Add debugging.
authorAndy Wingo <wingo@pobox.com>
Tue, 15 Nov 2005 17:57:51 +0000 (17:57 +0000)
committerAndy Wingo <wingo@pobox.com>
Tue, 15 Nov 2005 17:57:51 +0000 (17:57 +0000)
Original commit message from CVS:
2005-11-15  Andy Wingo  <wingo@pobox.com>

* gst/gstelement.c (gst_element_set_base_time): Add debugging.

* gst/gstpipeline.c (gst_pipeline_set_new_stream_time): Document
using GST_CLOCK_TIME_NONE to disable base time management.
(do_pipeline_seek, gst_pipeline_change_state): Don't reset stream
time if it was NONE before.
(gst_pipeline_change_state): Only munge the base time if
stream_time != GST_CLOCK_TIME_NONE.

* check/gst/gstpipeline.c (test_base_time): Punt around the
problem of the probe not being called, because that's not the
issue I'm looking at. Add a check that setting stream_time to NONE
disables base time management.

ChangeLog
check/gst/gstpipeline.c
gst/gstelement.c
gst/gstpipeline.c
tests/check/gst/gstpipeline.c

index 2acbc69..361cb15 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2005-11-15  Andy Wingo  <wingo@pobox.com>
+
+       * gst/gstelement.c (gst_element_set_base_time): Add debugging.
+
+       * gst/gstpipeline.c (gst_pipeline_set_new_stream_time): Document
+       using GST_CLOCK_TIME_NONE to disable base time management.
+       (do_pipeline_seek, gst_pipeline_change_state): Don't reset stream
+       time if it was NONE before.
+       (gst_pipeline_change_state): Only munge the base time if
+       stream_time != GST_CLOCK_TIME_NONE.
+
+       * check/gst/gstpipeline.c (test_base_time): Punt around the
+       problem of the probe not being called, because that's not the
+       issue I'm looking at. Add a check that setting stream_time to NONE
+       disables base time management.
+       
 2005-11-15  Wim Taymans  <wim@fluendo.com>
 
        * gst/base/gstbasesink.c: (gst_base_sink_change_state):
@@ -7,12 +23,6 @@
        (gst_base_transform_change_state):
        Init segment values at start.
 
-2005-11-15  Andy Wingo  <wingo@pobox.com>
-
-       * check/gst/gstpipeline.c (test_base_time): Punt around the
-       problem of the probe not being called, because that's not the
-       issue I'm looking at...
-       
 2005-11-15  Wim Taymans  <wim@fluendo.com>
 
        * gst/base/gstbasesink.c: (gst_base_sink_handle_object):
index 1924280..2a94526 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <gst/check/gstcheck.h>
 
+#define WAIT_TIME (100 * GST_MSECOND)
+
 /* an empty pipeline can go to PLAYING in one go */
 GST_START_TEST (test_async_state_change_empty)
 {
@@ -348,15 +350,16 @@ GST_START_TEST (test_base_time)
     GstClockTime oldbase = base, oldstream = stream;
 
     /* let some time pass */
-    clock_id = gst_clock_new_single_shot_id (clock, upper + GST_SECOND);
+    clock_id = gst_clock_new_single_shot_id (clock, upper + WAIT_TIME);
     fail_unless (gst_clock_id_wait (clock_id, NULL) == GST_CLOCK_OK,
         "unexpected clock_id_wait return");
+    gst_clock_id_unref (clock_id);
 
     lower = gst_clock_get_time (clock);
 
     observed = GST_CLOCK_TIME_NONE;
 
-    fail_unless (lower >= upper + GST_SECOND, "clock did not advance?");
+    fail_unless (lower >= upper + WAIT_TIME, "clock did not advance?");
 
     gst_element_set_state (pipeline, GST_STATE_PLAYING);
     fail_unless (gst_element_get_state (pipeline, NULL, NULL,
@@ -368,7 +371,7 @@ GST_START_TEST (test_base_time)
       g_cond_wait (probe_cond, probe_lock);
     g_mutex_unlock (probe_lock);
 
-    /* now the base time should have advanced by more than GST_SECOND compared
+    /* now the base time should have advanced by more than WAIT_TIME compared
      * to what it was. The buffer will be timestamped between the last stream
      * time and upper minus base.
      */
@@ -389,7 +392,7 @@ GST_START_TEST (test_base_time)
 
     stream = gst_pipeline_get_last_stream_time (GST_PIPELINE (pipeline));
 
-    fail_unless (base >= oldbase + GST_SECOND, "base time not reset");
+    fail_unless (base >= oldbase + WAIT_TIME, "base time not reset");
     fail_unless (upper >= base + stream, "bogus base time: %"
         GST_TIME_FORMAT " > %" GST_TIME_FORMAT, GST_TIME_ARGS (base),
         GST_TIME_ARGS (upper));
@@ -405,6 +408,72 @@ GST_START_TEST (test_base_time)
         GST_TIME_ARGS (observed), GST_TIME_ARGS (upper));
   }
 
+  /* test the third: that if I set CLOCK_TIME_NONE as the stream time, that the
+     base time is not changed */
+  {
+    GstClockID clock_id;
+    GstClockTime oldbase = base, oldobserved = observed;
+
+    /* let some time pass */
+    clock_id = gst_clock_new_single_shot_id (clock, upper + WAIT_TIME);
+    fail_unless (gst_clock_id_wait (clock_id, NULL) == GST_CLOCK_OK,
+        "unexpected clock_id_wait return");
+    gst_clock_id_unref (clock_id);
+
+    lower = gst_clock_get_time (clock);
+
+    observed = GST_CLOCK_TIME_NONE;
+
+    fail_unless (lower >= upper + WAIT_TIME, "clock did not advance?");
+
+    /* bling */
+    gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline),
+        GST_CLOCK_TIME_NONE);
+
+    gst_element_set_state (pipeline, GST_STATE_PLAYING);
+    fail_unless (gst_element_get_state (pipeline, NULL, NULL,
+            GST_CLOCK_TIME_NONE)
+        == GST_STATE_CHANGE_SUCCESS, "failed state change");
+
+    g_mutex_lock (probe_lock);
+    while (observed == GST_CLOCK_TIME_NONE)
+      g_cond_wait (probe_cond, probe_lock);
+    g_mutex_unlock (probe_lock);
+
+    /* now the base time should be the same as it was, and the timestamp should
+     * be more than WAIT_TIME past what it was.
+     */
+
+    base = gst_element_get_base_time (pipeline);
+
+    /* set stream time */
+    gst_element_set_state (pipeline, GST_STATE_PAUSED);
+
+    /* new stream time already set */
+    upper = gst_clock_get_time (clock);
+
+    fail_unless (gst_element_get_state (pipeline, NULL, NULL,
+            GST_CLOCK_TIME_NONE)
+        == GST_STATE_CHANGE_NO_PREROLL, "failed state change");
+
+    fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
+
+    fail_unless (gst_pipeline_get_last_stream_time (GST_PIPELINE (pipeline))
+        == GST_CLOCK_TIME_NONE, "stream time was reset");
+
+    fail_unless (base == oldbase, "base time was reset");
+
+    fail_unless (observed >= lower - base, "early timestamp: %"
+        GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (observed), GST_TIME_ARGS (lower - base));
+    fail_unless (observed <= upper - base, "late timestamp: %"
+        GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (observed), GST_TIME_ARGS (upper - base));
+    fail_unless (observed - oldobserved >= WAIT_TIME,
+        "insufficient tstamp delta: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (observed), GST_TIME_ARGS (oldobserved));
+  }
+
   gst_object_unref (sink);
   gst_object_unref (clock);
   gst_object_unref (pipeline);
index daee12d..fe7fb51 100644 (file)
@@ -450,6 +450,9 @@ gst_element_set_base_time (GstElement * element, GstClockTime time)
   GST_LOCK (element);
   element->base_time = time;
   GST_UNLOCK (element);
+
+  GST_DEBUG_OBJECT (element, "set base_time=%" GST_TIME_FORMAT,
+      GST_TIME_ARGS (time));
 }
 
 /**
index 9f45fca..8d479be 100644 (file)
@@ -243,8 +243,17 @@ do_pipeline_seek (GstElement * element, GstEvent * event)
   res = GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
 
   if (flush && res) {
-    /* need to reset the stream time to 0 after a flushing seek */
-    gst_pipeline_set_new_stream_time (GST_PIPELINE (element), 0);
+    gboolean need_reset;
+
+    GST_LOCK (element);
+    need_reset = GST_PIPELINE (element)->stream_time != GST_CLOCK_TIME_NONE;
+    GST_UNLOCK (element);
+
+    /* need to reset the stream time to 0 after a flushing seek, unless the user
+       explicitly disabled this behavior by setting stream time to NONE */
+    if (need_reset)
+      gst_pipeline_set_new_stream_time (GST_PIPELINE (element), 0);
+
     if (was_playing)
       /* and continue playing */
       gst_element_set_state (element, GST_STATE_PLAYING);
@@ -307,26 +316,26 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+    {
+      GstClockTime new_base_time;
+
       /* when going to playing, select a clock */
-      if ((clock = gst_element_provide_clock (element))) {
-        GstClockTime start_time;
+      clock = gst_element_provide_clock (element);
+
+      if (clock) {
+        GstClockTime start_time, stream_time, delay;
         gboolean new_clock;
 
-        /* get start time */
         start_time = gst_clock_get_time (clock);
 
         GST_LOCK (element);
         new_clock = element->clock != clock;
-        element->base_time = start_time -
-            pipeline->stream_time + pipeline->delay;
-        GST_DEBUG ("stream_time=%" GST_TIME_FORMAT ", start_time=%"
-            GST_TIME_FORMAT ", base time %" GST_TIME_FORMAT,
-            GST_TIME_ARGS (pipeline->stream_time),
-            GST_TIME_ARGS (start_time), GST_TIME_ARGS (element->base_time));
+        stream_time = pipeline->stream_time;
+        delay = pipeline->delay;
         GST_UNLOCK (element);
 
         if (new_clock) {
-          /* now distribute the clock */
+          /* now distribute the clock (which could be NULL I guess) */
           gst_element_set_clock (element, clock);
 
           /* if we selected a new clock, let the app know about it */
@@ -334,11 +343,23 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
               gst_message_new_new_clock (GST_OBJECT_CAST (element), clock));
         }
 
+        if (stream_time != GST_CLOCK_TIME_NONE)
+          new_base_time = start_time - stream_time + delay;
+        else
+          new_base_time = GST_CLOCK_TIME_NONE;
+
         gst_object_unref (clock);
       } else {
         GST_DEBUG ("no clock, using base time of 0");
-        gst_element_set_base_time (element, 0);
+        new_base_time = 0;
       }
+
+      if (new_base_time != GST_CLOCK_TIME_NONE)
+        gst_element_set_base_time (element, new_base_time);
+      else
+        GST_DEBUG_OBJECT (pipeline,
+            "NOT adjusting base time because stream time is NONE");
+    }
       break;
     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
     case GST_STATE_CHANGE_PAUSED_TO_READY:
@@ -352,7 +373,16 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_NULL_TO_READY:
       break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      gst_pipeline_set_new_stream_time (pipeline, 0);
+    {
+      gboolean need_reset;
+
+      GST_LOCK (element);
+      need_reset = pipeline->stream_time != GST_CLOCK_TIME_NONE;
+      GST_UNLOCK (element);
+
+      if (need_reset)
+        gst_pipeline_set_new_stream_time (pipeline, 0);
+    }
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       break;
@@ -370,7 +400,8 @@ gst_pipeline_change_state (GstElement * element, GstStateChange transition)
 
         GST_LOCK (element);
         /* store the current stream time */
-        pipeline->stream_time = now - element->base_time;
+        if (pipeline->stream_time != GST_CLOCK_TIME_NONE)
+          pipeline->stream_time = now - element->base_time;
         GST_DEBUG ("stream_time=%" GST_TIME_FORMAT ", now=%" GST_TIME_FORMAT
             ", base time %" GST_TIME_FORMAT,
             GST_TIME_ARGS (pipeline->stream_time),
@@ -416,6 +447,12 @@ gst_pipeline_get_bus (GstPipeline * pipeline)
  * set the base time on the elements (see @gst_element_set_base_time())
  * in the PAUSED->PLAYING state transition.
  *
+ * Setting @time to #GST_CLOCK_TIME_NONE will disable the pipeline's management
+ * of element base time. The application will then be responsible for
+ * performing base time distribution. This is sometimes useful if you want to
+ * synchronize capture from multiple pipelines, and you can also ensure that the
+ * pipelines have the same clock.
+ *
  * MT safe.
  */
 void
@@ -425,9 +462,13 @@ gst_pipeline_set_new_stream_time (GstPipeline * pipeline, GstClockTime time)
 
   GST_LOCK (pipeline);
   pipeline->stream_time = time;
-  GST_DEBUG ("%s: set new stream_time to %" GST_TIME_FORMAT,
-      GST_ELEMENT_NAME (pipeline), GST_TIME_ARGS (time));
   GST_UNLOCK (pipeline);
+
+  GST_DEBUG_OBJECT (pipeline, "set new stream_time to %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (time));
+
+  if (time == GST_CLOCK_TIME_NONE)
+    GST_DEBUG_OBJECT (pipeline, "told not to adjust base time");
 }
 
 /**
index 1924280..2a94526 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <gst/check/gstcheck.h>
 
+#define WAIT_TIME (100 * GST_MSECOND)
+
 /* an empty pipeline can go to PLAYING in one go */
 GST_START_TEST (test_async_state_change_empty)
 {
@@ -348,15 +350,16 @@ GST_START_TEST (test_base_time)
     GstClockTime oldbase = base, oldstream = stream;
 
     /* let some time pass */
-    clock_id = gst_clock_new_single_shot_id (clock, upper + GST_SECOND);
+    clock_id = gst_clock_new_single_shot_id (clock, upper + WAIT_TIME);
     fail_unless (gst_clock_id_wait (clock_id, NULL) == GST_CLOCK_OK,
         "unexpected clock_id_wait return");
+    gst_clock_id_unref (clock_id);
 
     lower = gst_clock_get_time (clock);
 
     observed = GST_CLOCK_TIME_NONE;
 
-    fail_unless (lower >= upper + GST_SECOND, "clock did not advance?");
+    fail_unless (lower >= upper + WAIT_TIME, "clock did not advance?");
 
     gst_element_set_state (pipeline, GST_STATE_PLAYING);
     fail_unless (gst_element_get_state (pipeline, NULL, NULL,
@@ -368,7 +371,7 @@ GST_START_TEST (test_base_time)
       g_cond_wait (probe_cond, probe_lock);
     g_mutex_unlock (probe_lock);
 
-    /* now the base time should have advanced by more than GST_SECOND compared
+    /* now the base time should have advanced by more than WAIT_TIME compared
      * to what it was. The buffer will be timestamped between the last stream
      * time and upper minus base.
      */
@@ -389,7 +392,7 @@ GST_START_TEST (test_base_time)
 
     stream = gst_pipeline_get_last_stream_time (GST_PIPELINE (pipeline));
 
-    fail_unless (base >= oldbase + GST_SECOND, "base time not reset");
+    fail_unless (base >= oldbase + WAIT_TIME, "base time not reset");
     fail_unless (upper >= base + stream, "bogus base time: %"
         GST_TIME_FORMAT " > %" GST_TIME_FORMAT, GST_TIME_ARGS (base),
         GST_TIME_ARGS (upper));
@@ -405,6 +408,72 @@ GST_START_TEST (test_base_time)
         GST_TIME_ARGS (observed), GST_TIME_ARGS (upper));
   }
 
+  /* test the third: that if I set CLOCK_TIME_NONE as the stream time, that the
+     base time is not changed */
+  {
+    GstClockID clock_id;
+    GstClockTime oldbase = base, oldobserved = observed;
+
+    /* let some time pass */
+    clock_id = gst_clock_new_single_shot_id (clock, upper + WAIT_TIME);
+    fail_unless (gst_clock_id_wait (clock_id, NULL) == GST_CLOCK_OK,
+        "unexpected clock_id_wait return");
+    gst_clock_id_unref (clock_id);
+
+    lower = gst_clock_get_time (clock);
+
+    observed = GST_CLOCK_TIME_NONE;
+
+    fail_unless (lower >= upper + WAIT_TIME, "clock did not advance?");
+
+    /* bling */
+    gst_pipeline_set_new_stream_time (GST_PIPELINE (pipeline),
+        GST_CLOCK_TIME_NONE);
+
+    gst_element_set_state (pipeline, GST_STATE_PLAYING);
+    fail_unless (gst_element_get_state (pipeline, NULL, NULL,
+            GST_CLOCK_TIME_NONE)
+        == GST_STATE_CHANGE_SUCCESS, "failed state change");
+
+    g_mutex_lock (probe_lock);
+    while (observed == GST_CLOCK_TIME_NONE)
+      g_cond_wait (probe_cond, probe_lock);
+    g_mutex_unlock (probe_lock);
+
+    /* now the base time should be the same as it was, and the timestamp should
+     * be more than WAIT_TIME past what it was.
+     */
+
+    base = gst_element_get_base_time (pipeline);
+
+    /* set stream time */
+    gst_element_set_state (pipeline, GST_STATE_PAUSED);
+
+    /* new stream time already set */
+    upper = gst_clock_get_time (clock);
+
+    fail_unless (gst_element_get_state (pipeline, NULL, NULL,
+            GST_CLOCK_TIME_NONE)
+        == GST_STATE_CHANGE_NO_PREROLL, "failed state change");
+
+    fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
+
+    fail_unless (gst_pipeline_get_last_stream_time (GST_PIPELINE (pipeline))
+        == GST_CLOCK_TIME_NONE, "stream time was reset");
+
+    fail_unless (base == oldbase, "base time was reset");
+
+    fail_unless (observed >= lower - base, "early timestamp: %"
+        GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (observed), GST_TIME_ARGS (lower - base));
+    fail_unless (observed <= upper - base, "late timestamp: %"
+        GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (observed), GST_TIME_ARGS (upper - base));
+    fail_unless (observed - oldobserved >= WAIT_TIME,
+        "insufficient tstamp delta: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (observed), GST_TIME_ARGS (oldobserved));
+  }
+
   gst_object_unref (sink);
   gst_object_unref (clock);
   gst_object_unref (pipeline);