From 2124c0fded3956b7f132050e3580cd529c48888b Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Tue, 15 Nov 2005 17:57:51 +0000 Subject: [PATCH] gst/gstelement.c (gst_element_set_base_time): Add debugging. Original commit message from CVS: 2005-11-15 Andy Wingo * 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 | 22 +++++++++---- check/gst/gstpipeline.c | 77 ++++++++++++++++++++++++++++++++++++++++--- gst/gstelement.c | 3 ++ gst/gstpipeline.c | 75 +++++++++++++++++++++++++++++++---------- tests/check/gst/gstpipeline.c | 77 ++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 223 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2acbc69..361cb15 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2005-11-15 Andy Wingo + + * 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 * 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 - - * 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 * gst/base/gstbasesink.c: (gst_base_sink_handle_object): diff --git a/check/gst/gstpipeline.c b/check/gst/gstpipeline.c index 1924280..2a94526 100644 --- a/check/gst/gstpipeline.c +++ b/check/gst/gstpipeline.c @@ -21,6 +21,8 @@ #include +#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); diff --git a/gst/gstelement.c b/gst/gstelement.c index daee12d..fe7fb51 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -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)); } /** diff --git a/gst/gstpipeline.c b/gst/gstpipeline.c index 9f45fca..8d479be 100644 --- a/gst/gstpipeline.c +++ b/gst/gstpipeline.c @@ -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"); } /** diff --git a/tests/check/gst/gstpipeline.c b/tests/check/gst/gstpipeline.c index 1924280..2a94526 100644 --- a/tests/check/gst/gstpipeline.c +++ b/tests/check/gst/gstpipeline.c @@ -21,6 +21,8 @@ #include +#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); -- 2.7.4