mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 08:46:40 +00:00
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:
parent
922617a0e0
commit
2a94dbb663
2 changed files with 101 additions and 56 deletions
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue