+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):
(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):
#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)
{
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,
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.
*/
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));
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);
GST_LOCK (element);
element->base_time = time;
GST_UNLOCK (element);
+
+ GST_DEBUG_OBJECT (element, "set base_time=%" GST_TIME_FORMAT,
+ GST_TIME_ARGS (time));
}
/**
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);
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 */
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:
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;
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),
* 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
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");
}
/**
#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)
{
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,
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.
*/
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));
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);