check/gst/gstpipeline.c (test_base_time): New test for buffer timestamps with live...
authorAndy Wingo <wingo@pobox.com>
Tue, 15 Nov 2005 12:29:07 +0000 (12:29 +0000)
committerAndy Wingo <wingo@pobox.com>
Tue, 15 Nov 2005 12:29:07 +0000 (12:29 +0000)
Original commit message from CVS:
2005-11-15  Andy Wingo  <wingo@pobox.com>

* check/gst/gstpipeline.c (test_base_time): New test for buffer
timestamps with live capture.

* gst/elements/gstfakesrc.c (gst_fake_src_create): If the datarate
is 0 but we are a live source, timestamp the buffers using the
element's clock.

ChangeLog
check/gst/gstpipeline.c
gst/elements/gstfakesrc.c
plugins/elements/gstfakesrc.c
tests/check/gst/gstpipeline.c

index d5b3f2e..612319d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2005-11-15  Andy Wingo  <wingo@pobox.com>
+
+       * check/gst/gstpipeline.c (test_base_time): New test for buffer
+       timestamps with live capture.
+
+       * gst/elements/gstfakesrc.c (gst_fake_src_create): If the datarate
+       is 0 but we are a live source, timestamp the buffers using the
+       element's clock.
+
 2005-11-14  Stefan Kost  <ensonic@users.sf.net>
 
        * docs/gst/gstreamer-sections.txt:
index 514d125..dc54c33 100644 (file)
@@ -226,6 +226,93 @@ GST_START_TEST (test_bus)
 
 GST_END_TEST;
 
+static gboolean
+sink_pad_probe (GstPad * pad, GstBuffer * buffer,
+    GstClockTime * first_timestamp)
+{
+  gint memory_barrier = 1;
+  volatile gint foo;
+
+  fail_if (GST_BUFFER_TIMESTAMP (buffer) == GST_CLOCK_TIME_NONE,
+      "testing if buffer timestamps are right, but got CLOCK_TIME_NONE");
+
+  if (*first_timestamp == GST_CLOCK_TIME_NONE)
+    *first_timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+  /* make sure the other thread sees the update */
+  foo = g_atomic_int_get (&memory_barrier);
+
+  return TRUE;
+}
+
+GST_START_TEST (test_base_time)
+{
+  GstElement *pipeline, *fakesrc, *fakesink;
+  GstPad *sink;
+  GstClockTime observed, lower, upper, base;
+  GstClock *clock;
+
+  pipeline = gst_element_factory_make ("pipeline", "pipeline");
+  fakesrc = gst_element_factory_make ("fakesrc", "fakesrc");
+  fakesink = gst_element_factory_make ("fakesink", "fakesink");
+
+  fail_unless (pipeline && fakesrc && fakesink, "couldn't make elements");
+
+  g_object_set (fakesrc, "is-live", (gboolean) TRUE, NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL);
+  gst_element_link (fakesrc, fakesink);
+
+  sink = gst_element_get_pad (fakesink, "sink");
+  gst_pad_add_buffer_probe (sink, G_CALLBACK (sink_pad_probe), &observed);
+
+  observed = GST_CLOCK_TIME_NONE;
+
+  fail_unless (gst_element_set_state (pipeline, GST_STATE_PAUSED)
+      == GST_STATE_CHANGE_NO_PREROLL, "expected no-preroll from live pipeline");
+
+  clock = gst_system_clock_obtain ();
+  fail_unless (clock && GST_IS_CLOCK (clock), "i want a clock dammit");
+  gst_pipeline_use_clock (GST_PIPELINE (pipeline), clock);
+
+  lower = gst_clock_get_time (clock);
+
+  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");
+
+  /* now something a little more than lower was distributed as the base time,
+   * and the buffer was timestamped at the base time or a little bit afterwards
+   */
+
+  base = gst_element_get_base_time (pipeline);
+
+  upper = gst_clock_get_time (clock);
+
+  /* make sure we don't have other threads running, makes errors nicer */
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
+
+  fail_unless (base >= lower, "early base time: %" GST_TIME_FORMAT " < %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (base), GST_TIME_ARGS (lower));
+  fail_unless (upper >= base, "bogus base time: %" GST_TIME_FORMAT " > %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (base), GST_TIME_ARGS (upper));
+
+  fail_unless (observed + base >= lower,
+      "early timestamp: %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (observed), GST_TIME_ARGS (lower));
+  fail_unless (observed + base <= upper,
+      "late timestamp: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (observed), GST_TIME_ARGS (upper));
+
+  gst_object_unref (sink);
+  gst_object_unref (clock);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
 Suite *
 gst_pipeline_suite (void)
 {
@@ -240,6 +327,7 @@ gst_pipeline_suite (void)
   tcase_add_test (tc_chain, test_async_state_change_fake);
   tcase_add_test (tc_chain, test_get_bus);
   tcase_add_test (tc_chain, test_bus);
+  tcase_add_test (tc_chain, test_base_time);
 
   return s;
 }
index 0b5d806..350fd0a 100644 (file)
@@ -692,8 +692,6 @@ gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
   buf = gst_fake_src_create_buffer (src);
   GST_BUFFER_OFFSET (buf) = src->buffer_count++;
 
-  time = GST_CLOCK_TIME_NONE;
-
   if (src->datarate > 0) {
     time = (src->bytes_sent * GST_SECOND) / src->datarate;
     if (src->sync) {
@@ -702,7 +700,20 @@ gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
 
     GST_BUFFER_DURATION (buf) =
         GST_BUFFER_SIZE (buf) * GST_SECOND / src->datarate;
+  } else if (gst_base_src_is_live (basesrc)) {
+    GstClock *clock;
+
+    clock = gst_element_get_clock (GST_ELEMENT (src));
+    g_return_val_if_fail (clock != NULL, GST_FLOW_ERROR);
+
+    time = gst_clock_get_time (clock);
+    time -= gst_element_get_base_time (GST_ELEMENT (src));
+
+    gst_object_unref (clock);
+  } else {
+    time = GST_CLOCK_TIME_NONE;
   }
+
   GST_BUFFER_TIMESTAMP (buf) = time;
 
   if (!src->silent) {
index 0b5d806..350fd0a 100644 (file)
@@ -692,8 +692,6 @@ gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
   buf = gst_fake_src_create_buffer (src);
   GST_BUFFER_OFFSET (buf) = src->buffer_count++;
 
-  time = GST_CLOCK_TIME_NONE;
-
   if (src->datarate > 0) {
     time = (src->bytes_sent * GST_SECOND) / src->datarate;
     if (src->sync) {
@@ -702,7 +700,20 @@ gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length,
 
     GST_BUFFER_DURATION (buf) =
         GST_BUFFER_SIZE (buf) * GST_SECOND / src->datarate;
+  } else if (gst_base_src_is_live (basesrc)) {
+    GstClock *clock;
+
+    clock = gst_element_get_clock (GST_ELEMENT (src));
+    g_return_val_if_fail (clock != NULL, GST_FLOW_ERROR);
+
+    time = gst_clock_get_time (clock);
+    time -= gst_element_get_base_time (GST_ELEMENT (src));
+
+    gst_object_unref (clock);
+  } else {
+    time = GST_CLOCK_TIME_NONE;
   }
+
   GST_BUFFER_TIMESTAMP (buf) = time;
 
   if (!src->silent) {
index 514d125..dc54c33 100644 (file)
@@ -226,6 +226,93 @@ GST_START_TEST (test_bus)
 
 GST_END_TEST;
 
+static gboolean
+sink_pad_probe (GstPad * pad, GstBuffer * buffer,
+    GstClockTime * first_timestamp)
+{
+  gint memory_barrier = 1;
+  volatile gint foo;
+
+  fail_if (GST_BUFFER_TIMESTAMP (buffer) == GST_CLOCK_TIME_NONE,
+      "testing if buffer timestamps are right, but got CLOCK_TIME_NONE");
+
+  if (*first_timestamp == GST_CLOCK_TIME_NONE)
+    *first_timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+  /* make sure the other thread sees the update */
+  foo = g_atomic_int_get (&memory_barrier);
+
+  return TRUE;
+}
+
+GST_START_TEST (test_base_time)
+{
+  GstElement *pipeline, *fakesrc, *fakesink;
+  GstPad *sink;
+  GstClockTime observed, lower, upper, base;
+  GstClock *clock;
+
+  pipeline = gst_element_factory_make ("pipeline", "pipeline");
+  fakesrc = gst_element_factory_make ("fakesrc", "fakesrc");
+  fakesink = gst_element_factory_make ("fakesink", "fakesink");
+
+  fail_unless (pipeline && fakesrc && fakesink, "couldn't make elements");
+
+  g_object_set (fakesrc, "is-live", (gboolean) TRUE, NULL);
+
+  gst_bin_add_many (GST_BIN (pipeline), fakesrc, fakesink, NULL);
+  gst_element_link (fakesrc, fakesink);
+
+  sink = gst_element_get_pad (fakesink, "sink");
+  gst_pad_add_buffer_probe (sink, G_CALLBACK (sink_pad_probe), &observed);
+
+  observed = GST_CLOCK_TIME_NONE;
+
+  fail_unless (gst_element_set_state (pipeline, GST_STATE_PAUSED)
+      == GST_STATE_CHANGE_NO_PREROLL, "expected no-preroll from live pipeline");
+
+  clock = gst_system_clock_obtain ();
+  fail_unless (clock && GST_IS_CLOCK (clock), "i want a clock dammit");
+  gst_pipeline_use_clock (GST_PIPELINE (pipeline), clock);
+
+  lower = gst_clock_get_time (clock);
+
+  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");
+
+  /* now something a little more than lower was distributed as the base time,
+   * and the buffer was timestamped at the base time or a little bit afterwards
+   */
+
+  base = gst_element_get_base_time (pipeline);
+
+  upper = gst_clock_get_time (clock);
+
+  /* make sure we don't have other threads running, makes errors nicer */
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+
+  fail_if (observed == GST_CLOCK_TIME_NONE, "no timestamp recorded");
+
+  fail_unless (base >= lower, "early base time: %" GST_TIME_FORMAT " < %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (base), GST_TIME_ARGS (lower));
+  fail_unless (upper >= base, "bogus base time: %" GST_TIME_FORMAT " > %"
+      GST_TIME_FORMAT, GST_TIME_ARGS (base), GST_TIME_ARGS (upper));
+
+  fail_unless (observed + base >= lower,
+      "early timestamp: %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (observed), GST_TIME_ARGS (lower));
+  fail_unless (observed + base <= upper,
+      "late timestamp: %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+      GST_TIME_ARGS (observed), GST_TIME_ARGS (upper));
+
+  gst_object_unref (sink);
+  gst_object_unref (clock);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
 Suite *
 gst_pipeline_suite (void)
 {
@@ -240,6 +327,7 @@ gst_pipeline_suite (void)
   tcase_add_test (tc_chain, test_async_state_change_fake);
   tcase_add_test (tc_chain, test_get_bus);
   tcase_add_test (tc_chain, test_bus);
+  tcase_add_test (tc_chain, test_base_time);
 
   return s;
 }