libs/gst/base/gstbasesrc.c: Update docs.

Original commit message from CVS:
* libs/gst/base/gstbasesrc.c: (gst_base_src_query_latency),
(gst_base_src_do_sync), (gst_base_src_change_state):
Update docs.
Clean up the timestamping and syncing code for pseudo live sources.
This commit is contained in:
Wim Taymans 2007-09-13 21:19:08 +00:00
parent 922617a0e0
commit 2a94dbb663
2 changed files with 101 additions and 56 deletions

View file

@ -1,3 +1,10 @@
2007-09-13 Wim Taymans <wim.taymans@gmail.com>
* libs/gst/base/gstbasesrc.c: (gst_base_src_query_latency),
(gst_base_src_do_sync), (gst_base_src_change_state):
Update docs.
Clean up the timestamping and syncing code for pseudo live sources.
2007-09-13 Tim-Philipp Müller <tim at centricular dot net> 2007-09-13 Tim-Philipp Müller <tim at centricular dot net>
Patch by: Steve Fink <sphink gmail com> Patch by: Steve Fink <sphink gmail com>

View file

@ -81,10 +81,10 @@
* to the #GstBaseSrc::create function. * to the #GstBaseSrc::create function.
* </para> * </para>
* <para> * <para>
* #GstBaseSrc has support for live sources. Live sources are sources that * #GstBaseSrc has support for live sources. Live sources are sources that when
* produce data at a fixed rate, such as audio or video capture devices. A * paused discard data, such as audio or video capture devices. A typical live
* typical live source also provides a clock to publish the rate at which * source also produces data at a fixed rate and thus provides a clock to publish
* they produce data. * this rate.
* Use gst_base_src_set_live() to activate the live source mode. * Use gst_base_src_set_live() to activate the live source mode.
* </para> * </para>
* <para> * <para>
@ -95,9 +95,9 @@
* </para> * </para>
* <para> * <para>
* A typical live source will timestamp the buffers it creates with the * A typical live source will timestamp the buffers it creates with the
* current stream time of the pipeline. This is one reason why a live source * current running time of the pipeline. This is one reason why a live source
* can only produce data in the PLAYING state, when the clock is actually * can only produce data in the PLAYING state, when the clock is actually
* distributed and running. * distributed and running.
* </para> * </para>
* <para> * <para>
* Live sources that synchronize and block on the clock (an audio source, for * Live sources that synchronize and block on the clock (an audio source, for
@ -106,16 +106,21 @@
* </para> * </para>
* <para> * <para>
* The #GstBaseSrc::get_times method can be used to implement pseudo-live * The #GstBaseSrc::get_times method can be used to implement pseudo-live
* sources. The base source will wait for the specified stream time returned in * sources.
* #GstBaseSrc::get_times before pushing out the buffer.
* It only makes sense to implement the ::get_times function if the source is * It only makes sense to implement the ::get_times function if the source is
* a live source. * a live source. The ::get_times function should return timestamps starting
* from 0, as if it were a non-live source. The base class will make sure that
* the timestamps are transformed into the current running_time.
* The base source will then wait for the calculated running_time before pushing
* out the buffer.
* </para> * </para>
* <para> * <para>
* For live sources, the base class will by default measure the time it takes to * For live sources, the base class will by default report a latency of 0.
* create the first buffer in the PLAYING state and will report this value as * For pseudo live sources, the base class will by default measure the difference
* the latency. Subclasses should override the query function when this * between the first buffer timestamp and the start time of get_times and will
* behaviour is not acceptable. * report this value as the latency.
* Subclasses should override the query function when this behaviour is not
* acceptable.
* </para> * </para>
* <para> * <para>
* There is only support in #GstBaseSrc for exactly one source pad, which * There is only support in #GstBaseSrc for exactly one source pad, which
@ -178,7 +183,7 @@
* thread might be blocked in PREROLL. * thread might be blocked in PREROLL.
* </para> * </para>
* <para> * <para>
* Last reviewed on 2006-09-27 (0.10.11) * Last reviewed on 2007-09-13 (0.10.15)
* </para> * </para>
* </refsect2> * </refsect2>
*/ */
@ -246,7 +251,10 @@ struct _GstBaseSrcPrivate
/* startup latency is the time it takes between going to PLAYING and producing /* startup latency is the time it takes between going to PLAYING and producing
* the first BUFFER with running_time 0. This value is included in the latency * the first BUFFER with running_time 0. This value is included in the latency
* reporting. */ * reporting. */
GstClockTime startup_latency; GstClockTime latency;
/* timestamp offset, this is the offset add to the values of gst_times for
* pseudo live sources */
GstClockTimeDiff ts_offset;
gboolean do_timestamp; gboolean do_timestamp;
}; };
@ -597,8 +605,8 @@ gst_base_src_query_latency (GstBaseSrc * src, gboolean * live,
/* if we have a startup latency, report this one, else report 0. Subclasses /* if we have a startup latency, report this one, else report 0. Subclasses
* are supposed to override the query function if they want something * are supposed to override the query function if they want something
* else. */ * else. */
if (src->priv->startup_latency != -1) if (src->priv->latency != -1)
min = src->priv->startup_latency; min = src->priv->latency;
else else
min = 0; min = 0;
@ -1482,7 +1490,7 @@ gst_base_src_do_sync (GstBaseSrc * basesrc, GstBuffer * buffer)
GstClockTime base_time; GstClockTime base_time;
GstClock *clock; GstClock *clock;
GstClockTime now = -1, timestamp; GstClockTime now = -1, timestamp;
gboolean do_timestamp; gboolean do_timestamp, first, pseudo_live;
bclass = GST_BASE_SRC_GET_CLASS (basesrc); bclass = GST_BASE_SRC_GET_CLASS (basesrc);
@ -1490,39 +1498,82 @@ gst_base_src_do_sync (GstBaseSrc * basesrc, GstBuffer * buffer)
if (bclass->get_times) if (bclass->get_times)
bclass->get_times (basesrc, buffer, &start, &end); bclass->get_times (basesrc, buffer, &start, &end);
/* get buffer timestamp */
timestamp = GST_BUFFER_TIMESTAMP (buffer);
/* grab the lock to prepare for clocking and calculate the startup /* grab the lock to prepare for clocking and calculate the startup
* latency. */ * latency. */
GST_OBJECT_LOCK (basesrc); GST_OBJECT_LOCK (basesrc);
/* get clock, if no clock, we can't sync or get the latency */ /* if we are asked to sync against the clock we are a pseudo live element */
pseudo_live = (start != -1 && basesrc->is_live);
/* check for the first buffer */
first = (basesrc->priv->latency == -1);
if (timestamp != -1 && pseudo_live) {
GstClockTime latency;
/* we have a timestamp and a sync time, latency is the diff */
if (timestamp <= start)
latency = start - timestamp;
else
latency = 0;
if (first) {
GST_DEBUG_OBJECT (basesrc, "pseudo_live with latency %" GST_TIME_FORMAT,
GST_TIME_ARGS (latency));
/* first time we calculate latency, just configure */
basesrc->priv->latency = latency;
} else {
if (basesrc->priv->latency != latency) {
/* we have a new latency, FIXME post latency message */
basesrc->priv->latency = latency;
GST_DEBUG_OBJECT (basesrc, "latency changed to %" GST_TIME_FORMAT,
GST_TIME_ARGS (latency));
}
}
} else if (first) {
GST_DEBUG_OBJECT (basesrc, "no latency needed, live %d, sync %d",
basesrc->is_live, start != -1);
basesrc->priv->latency = 0;
}
/* get clock, if no clock, we can't sync or do timestamps */
if ((clock = GST_ELEMENT_CLOCK (basesrc)) == NULL) if ((clock = GST_ELEMENT_CLOCK (basesrc)) == NULL)
goto no_clock; goto no_clock;
base_time = GST_ELEMENT_CAST (basesrc)->base_time; base_time = GST_ELEMENT_CAST (basesrc)->base_time;
do_timestamp = basesrc->priv->do_timestamp; do_timestamp = basesrc->priv->do_timestamp;
timestamp = GST_BUFFER_TIMESTAMP (buffer);
/* first buffer, calculate the startup latency */ /* first buffer, calculate the timestamp offset */
if (basesrc->priv->startup_latency == -1) { if (first) {
GstClockTime running_time;
now = gst_clock_get_time (clock); now = gst_clock_get_time (clock);
running_time = now - base_time;
GST_LOG_OBJECT (basesrc, "startup timestamp: %" GST_TIME_FORMAT, GST_LOG_OBJECT (basesrc,
GST_TIME_ARGS (timestamp)); "startup timestamp: %" GST_TIME_FORMAT ", running_time %"
GST_TIME_FORMAT, GST_TIME_ARGS (timestamp),
GST_TIME_ARGS (running_time));
/* startup latency is the diff between when we went to PLAYING (base_time) if (pseudo_live && timestamp != -1) {
* and the current clock time */ /* live source and we need to sync, add startup latency to all timestamps
if (now > base_time) * to get the real running_time. Live sources should always timestamp
basesrc->priv->startup_latency = now - base_time; * according to the current running time. */
else basesrc->priv->ts_offset = GST_CLOCK_DIFF (timestamp, running_time);
basesrc->priv->startup_latency = 0;
GST_LOG_OBJECT (basesrc, "startup running_time: %" GST_TIME_FORMAT, GST_LOG_OBJECT (basesrc, "live with sync, ts_offset %" GST_TIME_FORMAT,
GST_TIME_ARGS (basesrc->priv->startup_latency)); GST_TIME_ARGS (basesrc->priv->ts_offset));
} else {
basesrc->priv->ts_offset = 0;
GST_LOG_OBJECT (basesrc, "no timestamp offset needed");
}
if (!GST_CLOCK_TIME_IS_VALID (timestamp)) { if (!GST_CLOCK_TIME_IS_VALID (timestamp)) {
if (do_timestamp) if (do_timestamp)
timestamp = now - base_time; timestamp = running_time;
else else
timestamp = 0; timestamp = 0;
@ -1532,17 +1583,8 @@ gst_base_src_do_sync (GstBaseSrc * basesrc, GstBuffer * buffer)
GST_TIME_ARGS (timestamp)); GST_TIME_ARGS (timestamp));
} }
/* we have a timestamp, we can subtract it from the startup_latency when it is /* add the timestamp offset we need for sync */
* smaller. If the timestamp is bigger, there is no startup latency. */ timestamp += basesrc->priv->ts_offset;
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
if (timestamp < basesrc->priv->startup_latency)
basesrc->priv->startup_latency -= timestamp;
else
basesrc->priv->startup_latency = 0;
}
GST_LOG_OBJECT (basesrc, "startup latency: %" GST_TIME_FORMAT,
GST_TIME_ARGS (basesrc->priv->startup_latency));
} else { } else {
/* not the first buffer, the timestamp is the diff between the clock and /* not the first buffer, the timestamp is the diff between the clock and
* base_time */ * base_time */
@ -1555,16 +1597,12 @@ gst_base_src_do_sync (GstBaseSrc * basesrc, GstBuffer * buffer)
/* if we don't have a buffer timestamp, we don't sync */ /* if we don't have a buffer timestamp, we don't sync */
if (!GST_CLOCK_TIME_IS_VALID (start)) if (!GST_CLOCK_TIME_IS_VALID (start))
goto invalid_start; goto no_sync;
if (basesrc->is_live) { if (basesrc->is_live && GST_CLOCK_TIME_IS_VALID (timestamp)) {
/* live source and we need to sync, add startup latency to timestamp to /* for pseudo live sources, add our ts_offset to the timestamp */
* get the real running_time */ GST_BUFFER_TIMESTAMP (buffer) += basesrc->priv->ts_offset;
if (timestamp != -1) { start += basesrc->priv->ts_offset;
start += basesrc->priv->startup_latency;
GST_BUFFER_TIMESTAMP (buffer) =
timestamp + basesrc->priv->startup_latency;
}
} }
GST_LOG_OBJECT (basesrc, GST_LOG_OBJECT (basesrc,
@ -1586,9 +1624,9 @@ no_clock:
GST_OBJECT_UNLOCK (basesrc); GST_OBJECT_UNLOCK (basesrc);
return GST_CLOCK_OK; return GST_CLOCK_OK;
} }
invalid_start: no_sync:
{ {
GST_DEBUG_OBJECT (basesrc, "get_times returned invalid start"); GST_DEBUG_OBJECT (basesrc, "no sync needed");
GST_OBJECT_UNLOCK (basesrc); GST_OBJECT_UNLOCK (basesrc);
return GST_CLOCK_OK; return GST_CLOCK_OK;
} }
@ -2420,11 +2458,11 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition)
} }
basesrc->priv->last_sent_eos = FALSE; basesrc->priv->last_sent_eos = FALSE;
basesrc->priv->discont = TRUE; basesrc->priv->discont = TRUE;
basesrc->priv->startup_latency = -1;
GST_LIVE_UNLOCK (element); GST_LIVE_UNLOCK (element);
break; break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING: case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
GST_LIVE_LOCK (element); GST_LIVE_LOCK (element);
basesrc->priv->latency = -1;
if (basesrc->is_live) { if (basesrc->is_live) {
basesrc->live_running = TRUE; basesrc->live_running = TRUE;
GST_LIVE_SIGNAL (element); GST_LIVE_SIGNAL (element);