+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:
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)
{
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;
}
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) {
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) {
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) {
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) {
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)
{
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;
}