mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-04 13:32:29 +00:00
gst/gstbus.c: Small documentation clarification about the signal watch.
Original commit message from CVS: * gst/gstbus.c: Small documentation clarification about the signal watch. * libs/gst/base/gstbasesink.c: (gst_base_sink_get_sync_times), (gst_base_sink_wait_clock), (gst_base_sink_do_sync), (gst_base_sink_perform_qos), (gst_base_sink_reset_qos), (gst_base_sink_do_render_stats), (gst_base_sink_render_object), (gst_base_sink_get_position_last), (gst_base_sink_get_position_paused), (gst_base_sink_change_state): Convert and store timestamps in stream time and running time, the raw timestamps are not usefull, also document this better. Use different window sizes for good and bad QoS observations so we react to badness a little quicker. Keep track of the amount of rendered and dropped buffers. Send QoS timestamps in running time. * libs/gst/base/gstbasetransform.c: (gst_base_transform_sink_eventfunc), (gst_base_transform_handle_buffer): Compare QoS timestamps against running time.
This commit is contained in:
parent
19b6a791f2
commit
9a897acec0
4 changed files with 162 additions and 133 deletions
23
ChangeLog
23
ChangeLog
|
@ -1,3 +1,26 @@
|
||||||
|
2006-04-07 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
* gst/gstbus.c:
|
||||||
|
Small documentation clarification about the signal watch.
|
||||||
|
|
||||||
|
* libs/gst/base/gstbasesink.c: (gst_base_sink_get_sync_times),
|
||||||
|
(gst_base_sink_wait_clock), (gst_base_sink_do_sync),
|
||||||
|
(gst_base_sink_perform_qos), (gst_base_sink_reset_qos),
|
||||||
|
(gst_base_sink_do_render_stats), (gst_base_sink_render_object),
|
||||||
|
(gst_base_sink_get_position_last),
|
||||||
|
(gst_base_sink_get_position_paused), (gst_base_sink_change_state):
|
||||||
|
Convert and store timestamps in stream time and running time, the
|
||||||
|
raw timestamps are not usefull, also document this better.
|
||||||
|
Use different window sizes for good and bad QoS observations so
|
||||||
|
we react to badness a little quicker.
|
||||||
|
Keep track of the amount of rendered and dropped buffers.
|
||||||
|
Send QoS timestamps in running time.
|
||||||
|
|
||||||
|
* libs/gst/base/gstbasetransform.c:
|
||||||
|
(gst_base_transform_sink_eventfunc),
|
||||||
|
(gst_base_transform_handle_buffer):
|
||||||
|
Compare QoS timestamps against running time.
|
||||||
|
|
||||||
2006-04-06 Tim-Philipp Müller <tim at centricular dot net>
|
2006-04-06 Tim-Philipp Müller <tim at centricular dot net>
|
||||||
|
|
||||||
* gst/gstpad.c:
|
* gst/gstpad.c:
|
||||||
|
|
|
@ -688,6 +688,7 @@ gst_bus_create_watch (GstBus * bus)
|
||||||
* @notify: the function to call when the source is removed.
|
* @notify: the function to call when the source is removed.
|
||||||
*
|
*
|
||||||
* Adds a bus watch to the default main context with the given @priority.
|
* Adds a bus watch to the default main context with the given @priority.
|
||||||
|
* This function is used to receive asynchronous messages in the main loop.
|
||||||
*
|
*
|
||||||
* When @func is called, the message belongs to the caller; if you want to
|
* When @func is called, the message belongs to the caller; if you want to
|
||||||
* keep a copy of it, call gst_message_ref() before leaving @func.
|
* keep a copy of it, call gst_message_ref() before leaving @func.
|
||||||
|
@ -729,6 +730,7 @@ gst_bus_add_watch_full (GstBus * bus, gint priority,
|
||||||
* @user_data: user data passed to @func.
|
* @user_data: user data passed to @func.
|
||||||
*
|
*
|
||||||
* Adds a bus watch to the default main context with the default priority.
|
* Adds a bus watch to the default main context with the default priority.
|
||||||
|
* This function is used to receive asynchronous messages in the main loop.
|
||||||
*
|
*
|
||||||
* The watch can be removed using g_source_remove() or by returning FALSE
|
* The watch can be removed using g_source_remove() or by returning FALSE
|
||||||
* from @func.
|
* from @func.
|
||||||
|
|
|
@ -152,21 +152,21 @@ struct _GstBaseSinkPrivate
|
||||||
{
|
{
|
||||||
gint qos_enabled; /* ATOMIC */
|
gint qos_enabled; /* ATOMIC */
|
||||||
|
|
||||||
/* last position */
|
/* start, stop of current buffer, stream time, used to report position */
|
||||||
GstClockTime last_cstart;
|
GstClockTime current_sstart;
|
||||||
GstClockTime last_cstop;
|
GstClockTime current_sstop;
|
||||||
|
|
||||||
/* start, stop and jitter of current buffer, stream time */
|
/* start, stop and jitter of current buffer, running time */
|
||||||
GstClockTime current_start;
|
GstClockTime current_rstart;
|
||||||
GstClockTime current_stop;
|
GstClockTime current_rstop;
|
||||||
GstClockTimeDiff current_jitter;
|
GstClockTimeDiff current_jitter;
|
||||||
|
|
||||||
/* last buffer that arrived in time, stream time */
|
/* last buffer that arrived in time, running time */
|
||||||
GstClockTime last_in_time;
|
GstClockTime last_in_time;
|
||||||
/* when the last buffer left the sink, stream time */
|
/* when the last buffer left the sink, running time */
|
||||||
GstClockTime last_left;
|
GstClockTime last_left;
|
||||||
|
|
||||||
/* running averages go here these are done on stream time */
|
/* running averages go here these are done on running time */
|
||||||
GstClockTime avg_pt;
|
GstClockTime avg_pt;
|
||||||
GstClockTime avg_duration;
|
GstClockTime avg_duration;
|
||||||
gdouble avg_rate;
|
gdouble avg_rate;
|
||||||
|
@ -177,11 +177,20 @@ struct _GstBaseSinkPrivate
|
||||||
* buffers. */
|
* buffers. */
|
||||||
GstClockTime last_left_systime;
|
GstClockTime last_left_systime;
|
||||||
GstClockTime avg_jitter;
|
GstClockTime avg_jitter;
|
||||||
|
GTimeVal start, stop;
|
||||||
GstClockTime avg_render;
|
GstClockTime avg_render;
|
||||||
|
|
||||||
|
/* number of rendered and dropped frames */
|
||||||
|
guint64 rendered;
|
||||||
|
guint64 dropped;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RUNNING_AVG_WINDOW 8
|
#define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
|
||||||
#define UPDATE_RUNNING_AVG(avg,val) ((val) + (RUNNING_AVG_WINDOW-1) * (avg)) / RUNNING_AVG_WINDOW
|
|
||||||
|
#define UPDATE_RUNNING_AVG(avg,val) DO_RUNNING_AVG(avg,val,8)
|
||||||
|
|
||||||
|
#define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16)
|
||||||
|
#define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4)
|
||||||
|
|
||||||
/* BaseSink signals and properties */
|
/* BaseSink signals and properties */
|
||||||
enum
|
enum
|
||||||
|
@ -273,10 +282,6 @@ static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
|
||||||
GstMiniObject * obj, GstClockTime start, GstClockTime stop,
|
GstMiniObject * obj, GstClockTime start, GstClockTime stop,
|
||||||
GstClockReturn status, GstClockTimeDiff jitter);
|
GstClockReturn status, GstClockTimeDiff jitter);
|
||||||
|
|
||||||
/* QoS */
|
|
||||||
static void gst_base_sink_record_qos_observation (GstBaseSink * sink,
|
|
||||||
GstClockTime start, GstClockTime stop, GstClockTimeDiff jitter);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_base_sink_base_init (gpointer g_class)
|
gst_base_sink_base_init (gpointer g_class)
|
||||||
{
|
{
|
||||||
|
@ -726,7 +731,6 @@ gst_base_sink_configure_segment (GstBaseSink * basesink, GstPad * pad,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* with PREROLL_LOCK, STREAM_LOCK */
|
/* with PREROLL_LOCK, STREAM_LOCK */
|
||||||
/* FIXME, call change_state function, see #326311 */
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_sink_commit_state (GstBaseSink * basesink)
|
gst_base_sink_commit_state (GstBaseSink * basesink)
|
||||||
{
|
{
|
||||||
|
@ -837,20 +841,23 @@ async_failed:
|
||||||
* Returns TRUE if the object needs synchronisation and takes therefore
|
* Returns TRUE if the object needs synchronisation and takes therefore
|
||||||
* part in prerolling.
|
* part in prerolling.
|
||||||
*
|
*
|
||||||
* rstart/rstop contain the raw timestamp start/stop times of the object.
|
* rsstart/rsstop contain the start/stop in stream time.
|
||||||
* rcstart/rcstop contain the times usefull for synchronising to the clock.
|
* rrstart/rrstop contain the start/stop in running time.
|
||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
|
gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
|
||||||
GstClockTime * rstart, GstClockTime * rstop,
|
GstClockTime * rsstart, GstClockTime * rsstop,
|
||||||
GstClockTime * rcstart, GstClockTime * rcstop, gboolean * do_sync)
|
GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync)
|
||||||
{
|
{
|
||||||
GstBaseSinkClass *bclass;
|
GstBaseSinkClass *bclass;
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
gint64 cstart, cstop;
|
GstClockTime start, stop; /* raw start/stop timestamps */
|
||||||
GstClockTime start, stop;
|
gint64 cstart, cstop; /* clipped raw timestamps */
|
||||||
|
gint64 rstart, rstop; /* clipped timestamps converted to running time */
|
||||||
|
GstClockTime sstart, sstop; /* clipped timestamps converted to stream time */
|
||||||
|
|
||||||
start = stop = cstart = cstop = -1;
|
/* start with nothing */
|
||||||
|
sstart = sstop = rstart = rstop = -1;
|
||||||
|
|
||||||
if (G_UNLIKELY (GST_IS_EVENT (obj))) {
|
if (G_UNLIKELY (GST_IS_EVENT (obj))) {
|
||||||
GstEvent *event = GST_EVENT_CAST (obj);
|
GstEvent *event = GST_EVENT_CAST (obj);
|
||||||
|
@ -858,7 +865,8 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
/* EOS event needs syncing */
|
/* EOS event needs syncing */
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
start = stop = cstart = cstop = basesink->priv->last_cstop;
|
sstart = sstop = basesink->priv->current_sstop;
|
||||||
|
rstart = rstop = basesink->priv->current_rstop;
|
||||||
goto done;
|
goto done;
|
||||||
/* other events do not need syncing */
|
/* other events do not need syncing */
|
||||||
/* FIXME, maybe NEWSEGMENT might need synchronisation
|
/* FIXME, maybe NEWSEGMENT might need synchronisation
|
||||||
|
@ -871,6 +879,10 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* no sync if we did not get a TIME segment format */
|
||||||
|
if (G_UNLIKELY (basesink->segment.format != GST_FORMAT_TIME))
|
||||||
|
goto done;
|
||||||
|
|
||||||
/* else do buffer sync code */
|
/* else do buffer sync code */
|
||||||
buffer = GST_BUFFER_CAST (obj);
|
buffer = GST_BUFFER_CAST (obj);
|
||||||
|
|
||||||
|
@ -890,13 +902,6 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
|
||||||
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
|
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
|
||||||
", stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
|
", stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (stop));
|
||||||
|
|
||||||
/* only clip for TIME format */
|
|
||||||
if (G_UNLIKELY (basesink->segment.format != GST_FORMAT_TIME)) {
|
|
||||||
cstart = start;
|
|
||||||
cstop = stop;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clip */
|
/* clip */
|
||||||
if (G_UNLIKELY (!gst_segment_clip (&basesink->segment, GST_FORMAT_TIME,
|
if (G_UNLIKELY (!gst_segment_clip (&basesink->segment, GST_FORMAT_TIME,
|
||||||
(gint64) start, (gint64) stop, &cstart, &cstop)))
|
(gint64) start, (gint64) stop, &cstart, &cstop)))
|
||||||
|
@ -908,12 +913,21 @@ gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
|
||||||
GST_TIME_ARGS (cstop));
|
GST_TIME_ARGS (cstop));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sstart =
|
||||||
|
gst_segment_to_stream_time (&basesink->segment, GST_FORMAT_TIME, cstart);
|
||||||
|
sstop =
|
||||||
|
gst_segment_to_stream_time (&basesink->segment, GST_FORMAT_TIME, cstop);
|
||||||
|
rstart =
|
||||||
|
gst_segment_to_running_time (&basesink->segment, GST_FORMAT_TIME, cstart);
|
||||||
|
rstop =
|
||||||
|
gst_segment_to_running_time (&basesink->segment, GST_FORMAT_TIME, cstop);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* save times */
|
/* save times */
|
||||||
*rstart = start;
|
*rsstart = sstart;
|
||||||
*rstop = stop;
|
*rsstop = sstop;
|
||||||
*rcstart = cstart;
|
*rrstart = rstart;
|
||||||
*rcstop = cstop;
|
*rrstop = rstop;
|
||||||
|
|
||||||
/* buffers and EOS always need syncing and preroll */
|
/* buffers and EOS always need syncing and preroll */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -940,6 +954,8 @@ out_of_segment:
|
||||||
* Else a blocking wait is performed on the clock. We save the ClockID
|
* Else a blocking wait is performed on the clock. We save the ClockID
|
||||||
* so we can unlock the entry at any time. While we are blocking, we
|
* so we can unlock the entry at any time. While we are blocking, we
|
||||||
* release the PREROLL_LOCK so that other threads can interrupt the entry.
|
* release the PREROLL_LOCK so that other threads can interrupt the entry.
|
||||||
|
*
|
||||||
|
* @time is expressed in running time.
|
||||||
*/
|
*/
|
||||||
static GstClockReturn
|
static GstClockReturn
|
||||||
gst_base_sink_wait_clock (GstBaseSink * basesink, GstClockTime time,
|
gst_base_sink_wait_clock (GstBaseSink * basesink, GstClockTime time,
|
||||||
|
@ -960,12 +976,6 @@ gst_base_sink_wait_clock (GstBaseSink * basesink, GstClockTime time,
|
||||||
if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
|
if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
|
||||||
goto no_clock;
|
goto no_clock;
|
||||||
|
|
||||||
time = gst_segment_to_running_time (&basesink->segment,
|
|
||||||
basesink->segment.format, time);
|
|
||||||
|
|
||||||
if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time)))
|
|
||||||
goto invalid_running_time;
|
|
||||||
|
|
||||||
base_time = GST_ELEMENT_CAST (basesink)->base_time;
|
base_time = GST_ELEMENT_CAST (basesink)->base_time;
|
||||||
id = gst_clock_new_single_shot_id (clock, base_time + time);
|
id = gst_clock_new_single_shot_id (clock, base_time + time);
|
||||||
GST_OBJECT_UNLOCK (basesink);
|
GST_OBJECT_UNLOCK (basesink);
|
||||||
|
@ -988,12 +998,6 @@ invalid_time:
|
||||||
GST_DEBUG_OBJECT (basesink, "time not valid, no sync needed");
|
GST_DEBUG_OBJECT (basesink, "time not valid, no sync needed");
|
||||||
return GST_CLOCK_BADTIME;
|
return GST_CLOCK_BADTIME;
|
||||||
}
|
}
|
||||||
invalid_running_time:
|
|
||||||
{
|
|
||||||
GST_DEBUG_OBJECT (basesink, "sync time not valid, can't sync");
|
|
||||||
GST_OBJECT_UNLOCK (basesink);
|
|
||||||
return GST_CLOCK_BADTIME;
|
|
||||||
}
|
|
||||||
no_sync:
|
no_sync:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (basesink, "sync disabled");
|
GST_DEBUG_OBJECT (basesink, "sync disabled");
|
||||||
|
@ -1037,31 +1041,31 @@ gst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad,
|
||||||
GstClockTimeDiff jitter;
|
GstClockTimeDiff jitter;
|
||||||
gboolean syncable;
|
gboolean syncable;
|
||||||
GstClockReturn status = GST_CLOCK_OK;
|
GstClockReturn status = GST_CLOCK_OK;
|
||||||
GstClockTime start, stop, cstart, cstop;
|
GstClockTime sstart, sstop, rstart, rstop;
|
||||||
gboolean do_sync = TRUE;
|
gboolean do_sync;
|
||||||
|
|
||||||
start = stop = cstart = cstop = -1;
|
sstart = sstop = rstart = rstop = -1;
|
||||||
|
do_sync = TRUE;
|
||||||
|
|
||||||
basesink->priv->current_start = -1;
|
basesink->priv->current_rstart = -1;
|
||||||
|
|
||||||
/* update timing information for this object */
|
/* update timing information for this object */
|
||||||
syncable = gst_base_sink_get_sync_times (basesink, obj,
|
syncable = gst_base_sink_get_sync_times (basesink, obj,
|
||||||
&start, &stop, &cstart, &cstop, &do_sync);
|
&sstart, &sstop, &rstart, &rstop, &do_sync);
|
||||||
|
|
||||||
/* a syncable object needs to participate in preroll and
|
/* a syncable object needs to participate in preroll and
|
||||||
* clocking. All buffers and EOS are syncable. */
|
* clocking. All buffers and EOS are syncable. */
|
||||||
if (G_UNLIKELY (!syncable))
|
if (G_UNLIKELY (!syncable))
|
||||||
goto not_syncable;
|
goto not_syncable;
|
||||||
|
|
||||||
|
/* store timing info for current object */
|
||||||
|
basesink->priv->current_rstart = rstart;
|
||||||
|
basesink->priv->current_rstop = (rstop != -1 ? rstop : rstart);
|
||||||
/* lock because we read this when answering the POSITION
|
/* lock because we read this when answering the POSITION
|
||||||
* query. */
|
* query. */
|
||||||
GST_OBJECT_LOCK (basesink);
|
GST_OBJECT_LOCK (basesink);
|
||||||
if (stop != -1)
|
basesink->priv->current_sstart = sstart;
|
||||||
basesink->priv->last_cstop = cstop;
|
basesink->priv->current_sstop = (sstop != -1 ? sstop : sstart);
|
||||||
else
|
|
||||||
basesink->priv->last_cstop = cstart;
|
|
||||||
|
|
||||||
basesink->priv->last_cstart = cstart;
|
|
||||||
GST_OBJECT_UNLOCK (basesink);
|
GST_OBJECT_UNLOCK (basesink);
|
||||||
|
|
||||||
again:
|
again:
|
||||||
|
@ -1098,11 +1102,11 @@ again:
|
||||||
|
|
||||||
/* preroll done, we can sync since we are in PLAYING now. */
|
/* preroll done, we can sync since we are in PLAYING now. */
|
||||||
GST_DEBUG_OBJECT (basesink, "waiting for clock to reach %" GST_TIME_FORMAT,
|
GST_DEBUG_OBJECT (basesink, "waiting for clock to reach %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (cstart));
|
GST_TIME_ARGS (rstart));
|
||||||
|
|
||||||
/* this function will return immediatly if start == -1, no clock
|
/* this function will return immediatly if start == -1, no clock
|
||||||
* or sync is disabled with GST_CLOCK_BADTIME. */
|
* or sync is disabled with GST_CLOCK_BADTIME. */
|
||||||
status = gst_base_sink_wait_clock (basesink, cstart, &jitter);
|
status = gst_base_sink_wait_clock (basesink, rstart, &jitter);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (basesink, "clock returned %d", status);
|
GST_DEBUG_OBJECT (basesink, "clock returned %d", status);
|
||||||
|
|
||||||
|
@ -1122,10 +1126,10 @@ again:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* successful syncing done, record observation */
|
/* successful syncing done, record observation */
|
||||||
gst_base_sink_record_qos_observation (basesink, cstart, cstop, jitter);
|
basesink->priv->current_jitter = jitter;
|
||||||
|
|
||||||
/* check if the object should be dropped */
|
/* check if the object should be dropped */
|
||||||
*late = gst_base_sink_is_too_late (basesink, obj, start, stop,
|
*late = gst_base_sink_is_too_late (basesink, obj, rstart, rstop,
|
||||||
status, jitter);
|
status, jitter);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -1149,28 +1153,6 @@ stopping:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* record a qos observation for later processing */
|
|
||||||
static void
|
|
||||||
gst_base_sink_record_qos_observation (GstBaseSink * sink, GstClockTime start,
|
|
||||||
GstClockTime stop, GstClockTimeDiff jitter)
|
|
||||||
{
|
|
||||||
GstBaseSinkPrivate *priv;
|
|
||||||
|
|
||||||
priv = sink->priv;
|
|
||||||
|
|
||||||
if (!g_atomic_int_get (&priv->qos_enabled))
|
|
||||||
return;
|
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, sink,
|
|
||||||
"recording QoS observation start: %" GST_TIME_FORMAT ", stop %"
|
|
||||||
GST_TIME_FORMAT ", jitter %" G_GINT64_FORMAT,
|
|
||||||
GST_TIME_ARGS (start), GST_TIME_ARGS (stop), jitter);
|
|
||||||
|
|
||||||
priv->current_start = start;
|
|
||||||
priv->current_stop = stop;
|
|
||||||
priv->current_jitter = jitter;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_sink_send_qos (GstBaseSink * basesink,
|
gst_base_sink_send_qos (GstBaseSink * basesink,
|
||||||
gdouble proportion, GstClockTime time, GstClockTimeDiff diff)
|
gdouble proportion, GstClockTime time, GstClockTimeDiff diff)
|
||||||
|
@ -1203,13 +1185,13 @@ gst_base_sink_perform_qos (GstBaseSink * sink, gboolean dropped)
|
||||||
|
|
||||||
priv = sink->priv;
|
priv = sink->priv;
|
||||||
|
|
||||||
start = priv->current_start;
|
start = priv->current_rstart;
|
||||||
|
|
||||||
/* if QoS disabled, do nothing */
|
/* if QoS disabled, do nothing */
|
||||||
if (!g_atomic_int_get (&priv->qos_enabled) || start == -1)
|
if (!g_atomic_int_get (&priv->qos_enabled) || start == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
stop = priv->current_stop;
|
stop = priv->current_rstop;
|
||||||
jitter = priv->current_jitter;
|
jitter = priv->current_jitter;
|
||||||
|
|
||||||
/* this is the time the buffer entered the sink */
|
/* this is the time the buffer entered the sink */
|
||||||
|
@ -1263,7 +1245,10 @@ gst_base_sink_perform_qos (GstBaseSink * sink, gboolean dropped)
|
||||||
else
|
else
|
||||||
rate = 1.0;
|
rate = 1.0;
|
||||||
|
|
||||||
priv->avg_rate = UPDATE_RUNNING_AVG (priv->avg_rate, rate);
|
if (rate > 1.0)
|
||||||
|
priv->avg_rate = UPDATE_RUNNING_AVG_N (priv->avg_rate, rate);
|
||||||
|
else
|
||||||
|
priv->avg_rate = UPDATE_RUNNING_AVG_P (priv->avg_rate, rate);
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, sink,
|
GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, sink,
|
||||||
"updated: avg_duration: %" GST_TIME_FORMAT ", avg_pt: %" GST_TIME_FORMAT
|
"updated: avg_duration: %" GST_TIME_FORMAT ", avg_pt: %" GST_TIME_FORMAT
|
||||||
|
@ -1271,12 +1256,12 @@ gst_base_sink_perform_qos (GstBaseSink * sink, gboolean dropped)
|
||||||
GST_TIME_ARGS (priv->avg_pt), priv->avg_rate);
|
GST_TIME_ARGS (priv->avg_pt), priv->avg_rate);
|
||||||
|
|
||||||
|
|
||||||
/* last observation did not cause a drop, no need to send
|
if (dropped) {
|
||||||
* a QoS event */
|
priv->avg_rate = 2.0;
|
||||||
if (G_LIKELY (!dropped))
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
gst_base_sink_send_qos (sink, priv->avg_rate, priv->current_start,
|
/* always send QoS events */
|
||||||
|
gst_base_sink_send_qos (sink, priv->avg_rate, priv->current_rstart,
|
||||||
priv->current_jitter);
|
priv->current_jitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1294,6 +1279,8 @@ gst_base_sink_reset_qos (GstBaseSink * sink)
|
||||||
priv->avg_pt = -1;
|
priv->avg_pt = -1;
|
||||||
priv->avg_rate = 1.0;
|
priv->avg_rate = 1.0;
|
||||||
priv->avg_render = -1;
|
priv->avg_render = -1;
|
||||||
|
priv->rendered = 0;
|
||||||
|
priv->dropped = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Checks if the object was scheduled too late.
|
/* Checks if the object was scheduled too late.
|
||||||
|
@ -1374,6 +1361,35 @@ no_timestamp:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start)
|
||||||
|
{
|
||||||
|
GstBaseSinkPrivate *priv;
|
||||||
|
|
||||||
|
priv = basesink->priv;
|
||||||
|
|
||||||
|
if (start) {
|
||||||
|
g_get_current_time (&priv->start);
|
||||||
|
} else {
|
||||||
|
GstClockTime elapsed;
|
||||||
|
|
||||||
|
g_get_current_time (&priv->stop);
|
||||||
|
|
||||||
|
elapsed =
|
||||||
|
GST_TIMEVAL_TO_TIME (priv->stop) - GST_TIMEVAL_TO_TIME (priv->start);
|
||||||
|
|
||||||
|
if (priv->avg_render == -1)
|
||||||
|
priv->avg_render = elapsed;
|
||||||
|
else
|
||||||
|
priv->avg_render = UPDATE_RUNNING_AVG (priv->avg_render, elapsed);
|
||||||
|
|
||||||
|
priv->rendered++;
|
||||||
|
|
||||||
|
GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
|
||||||
|
"avg_render: %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->avg_render));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* with STREAM_LOCK, PREROLL_LOCK,
|
/* with STREAM_LOCK, PREROLL_LOCK,
|
||||||
*
|
*
|
||||||
* Synchronize the object on the clock and then render it.
|
* Synchronize the object on the clock and then render it.
|
||||||
|
@ -1387,6 +1403,9 @@ gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
GstBaseSinkClass *bclass;
|
GstBaseSinkClass *bclass;
|
||||||
gboolean late = FALSE;
|
gboolean late = FALSE;
|
||||||
|
GstBaseSinkPrivate *priv;
|
||||||
|
|
||||||
|
priv = basesink->priv;
|
||||||
|
|
||||||
/* synchronize this object, non syncable objects return OK
|
/* synchronize this object, non syncable objects return OK
|
||||||
* immediatly. */
|
* immediatly. */
|
||||||
|
@ -1396,8 +1415,6 @@ gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
|
||||||
|
|
||||||
/* and now render, event or buffer. */
|
/* and now render, event or buffer. */
|
||||||
if (G_LIKELY (GST_IS_BUFFER (obj))) {
|
if (G_LIKELY (GST_IS_BUFFER (obj))) {
|
||||||
GTimeVal start, stop;
|
|
||||||
|
|
||||||
/* drop late buffers unconditionally, let's hope it's unlikely */
|
/* drop late buffers unconditionally, let's hope it's unlikely */
|
||||||
if (G_UNLIKELY (late))
|
if (G_UNLIKELY (late))
|
||||||
goto dropped;
|
goto dropped;
|
||||||
|
@ -1406,9 +1423,6 @@ gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
|
||||||
|
|
||||||
if (G_LIKELY (bclass->render)) {
|
if (G_LIKELY (bclass->render)) {
|
||||||
gint do_qos;
|
gint do_qos;
|
||||||
GstBaseSinkPrivate *priv;
|
|
||||||
|
|
||||||
priv = basesink->priv;
|
|
||||||
|
|
||||||
/* read once, to get same value before and after */
|
/* read once, to get same value before and after */
|
||||||
do_qos = g_atomic_int_get (&priv->qos_enabled);
|
do_qos = g_atomic_int_get (&priv->qos_enabled);
|
||||||
|
@ -1417,27 +1431,13 @@ gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
|
||||||
|
|
||||||
/* record rendering time for QoS and stats */
|
/* record rendering time for QoS and stats */
|
||||||
if (do_qos)
|
if (do_qos)
|
||||||
g_get_current_time (&start);
|
gst_base_sink_do_render_stats (basesink, TRUE);
|
||||||
|
|
||||||
ret = bclass->render (basesink, GST_BUFFER_CAST (obj));
|
ret = bclass->render (basesink, GST_BUFFER_CAST (obj));
|
||||||
|
|
||||||
if (do_qos) {
|
if (do_qos)
|
||||||
GstClockTime elapsed;
|
gst_base_sink_do_render_stats (basesink, FALSE);
|
||||||
|
|
||||||
g_get_current_time (&stop);
|
|
||||||
|
|
||||||
elapsed = GST_TIMEVAL_TO_TIME (stop) - GST_TIMEVAL_TO_TIME (start);
|
|
||||||
|
|
||||||
if (priv->avg_render == -1)
|
|
||||||
priv->avg_render = elapsed;
|
|
||||||
else
|
|
||||||
priv->avg_render = UPDATE_RUNNING_AVG (priv->avg_render, elapsed);
|
|
||||||
|
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
|
|
||||||
"avg_render: %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->avg_render));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
GstEvent *event = GST_EVENT_CAST (obj);
|
GstEvent *event = GST_EVENT_CAST (obj);
|
||||||
gboolean event_res = TRUE;
|
gboolean event_res = TRUE;
|
||||||
|
@ -1494,6 +1494,7 @@ sync_failed:
|
||||||
}
|
}
|
||||||
dropped:
|
dropped:
|
||||||
{
|
{
|
||||||
|
priv->dropped++;
|
||||||
GST_DEBUG_OBJECT (basesink, "buffer late, dropping");
|
GST_DEBUG_OBJECT (basesink, "buffer late, dropping");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -2177,15 +2178,12 @@ gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the position of the last seen object against the last seen
|
/* get the position of the last seen object */
|
||||||
* segment. */
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_sink_get_position_last (GstBaseSink * basesink, gint64 * cur)
|
gst_base_sink_get_position_last (GstBaseSink * basesink, gint64 * cur)
|
||||||
{
|
{
|
||||||
/* convert last observed stop to stream time */
|
/* return last observed stream time */
|
||||||
*cur =
|
*cur = basesink->priv->current_sstop;
|
||||||
gst_segment_to_stream_time (&basesink->segment, basesink->segment.format,
|
|
||||||
basesink->priv->last_cstop);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2196,9 +2194,7 @@ gst_base_sink_get_position_last (GstBaseSink * basesink, gint64 * cur)
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_base_sink_get_position_paused (GstBaseSink * basesink, gint64 * cur)
|
gst_base_sink_get_position_paused (GstBaseSink * basesink, gint64 * cur)
|
||||||
{
|
{
|
||||||
*cur =
|
*cur = basesink->priv->current_sstart;
|
||||||
gst_segment_to_stream_time (&basesink->segment, basesink->segment.format,
|
|
||||||
basesink->priv->last_cstart);
|
|
||||||
|
|
||||||
if (*cur != -1)
|
if (*cur != -1)
|
||||||
*cur = MAX (*cur, basesink->abidata.ABI.clip_segment->time);
|
*cur = MAX (*cur, basesink->abidata.ABI.clip_segment->time);
|
||||||
|
@ -2395,8 +2391,8 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
|
||||||
basesink->have_preroll = FALSE;
|
basesink->have_preroll = FALSE;
|
||||||
basesink->need_preroll = TRUE;
|
basesink->need_preroll = TRUE;
|
||||||
basesink->playing_async = TRUE;
|
basesink->playing_async = TRUE;
|
||||||
basesink->priv->last_cstart = 0;
|
basesink->priv->current_sstart = 0;
|
||||||
basesink->priv->last_cstop = 0;
|
basesink->priv->current_sstop = 0;
|
||||||
basesink->eos = FALSE;
|
basesink->eos = FALSE;
|
||||||
gst_base_sink_reset_qos (basesink);
|
gst_base_sink_reset_qos (basesink);
|
||||||
ret = GST_STATE_CHANGE_ASYNC;
|
ret = GST_STATE_CHANGE_ASYNC;
|
||||||
|
@ -2462,8 +2458,8 @@ gst_base_sink_change_state (GstElement * element, GstStateChange transition)
|
||||||
GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
|
GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||||
basesink->priv->last_cstart = 0;
|
basesink->priv->current_sstart = 0;
|
||||||
basesink->priv->last_cstop = 0;
|
basesink->priv->current_sstop = 0;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
if (bclass->stop)
|
if (bclass->stop)
|
||||||
|
|
|
@ -1176,7 +1176,7 @@ gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
|
||||||
trans->have_newsegment = TRUE;
|
trans->have_newsegment = TRUE;
|
||||||
|
|
||||||
if (format == GST_FORMAT_TIME) {
|
if (format == GST_FORMAT_TIME) {
|
||||||
GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" GST_TIME_FORMAT
|
GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
|
||||||
" -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
|
" -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
|
||||||
", accum %" GST_TIME_FORMAT,
|
", accum %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (trans->segment.start),
|
GST_TIME_ARGS (trans->segment.start),
|
||||||
|
@ -1254,7 +1254,7 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
guint out_size;
|
guint out_size;
|
||||||
gboolean want_in_place;
|
gboolean want_in_place;
|
||||||
GstClockTime outtime;
|
GstClockTime qostime;
|
||||||
|
|
||||||
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
|
||||||
|
|
||||||
|
@ -1273,7 +1273,14 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
|
||||||
if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
|
if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
|
||||||
goto not_negotiated;
|
goto not_negotiated;
|
||||||
|
|
||||||
if ((outtime = GST_BUFFER_TIMESTAMP (inbuf)) != -1) {
|
/* can only do QoS if the segment is in TIME */
|
||||||
|
if (trans->segment.format != GST_FORMAT_TIME)
|
||||||
|
goto no_qos;
|
||||||
|
|
||||||
|
qostime = gst_segment_to_running_time (&trans->segment, GST_FORMAT_TIME,
|
||||||
|
GST_BUFFER_TIMESTAMP (inbuf));
|
||||||
|
|
||||||
|
if (qostime != -1) {
|
||||||
gboolean need_skip;
|
gboolean need_skip;
|
||||||
GstClockTime earliest_time;
|
GstClockTime earliest_time;
|
||||||
|
|
||||||
|
@ -1282,17 +1289,18 @@ gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
|
||||||
/* check for QoS, don't perform conversion for buffers
|
/* check for QoS, don't perform conversion for buffers
|
||||||
* that are known to be late. */
|
* that are known to be late. */
|
||||||
need_skip = trans->priv->qos_enabled &&
|
need_skip = trans->priv->qos_enabled &&
|
||||||
earliest_time != -1 && outtime <= earliest_time;
|
earliest_time != -1 && qostime != -1 && qostime <= earliest_time;
|
||||||
GST_OBJECT_UNLOCK (trans);
|
GST_OBJECT_UNLOCK (trans);
|
||||||
|
|
||||||
if (need_skip) {
|
if (need_skip) {
|
||||||
GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: outtime %"
|
GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, trans, "skipping transform: qostime %"
|
||||||
GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
|
GST_TIME_FORMAT " <= %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (outtime), GST_TIME_ARGS (earliest_time));
|
GST_TIME_ARGS (qostime), GST_TIME_ARGS (earliest_time));
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
no_qos:
|
||||||
if (trans->passthrough) {
|
if (trans->passthrough) {
|
||||||
/* In passthrough mode, give transform_ip a look at the
|
/* In passthrough mode, give transform_ip a look at the
|
||||||
* buffer, without making it writable, or just push the
|
* buffer, without making it writable, or just push the
|
||||||
|
|
Loading…
Reference in a new issue