videorate: handle invalid timestamps better

Handle buffers with -1 timestamps better by keeping track of the en time of the
previous buffer and assuming the -1 timestamp buffer goes right after the
previous one.

when we have two buffers that are equally good, output the oldest buffer once to
minimize latency.

don't try to calculate latency when the input framerate is unknown.
This commit is contained in:
Wim Taymans 2009-04-30 16:37:38 +02:00
parent 6cee823237
commit 956c9f32a3
2 changed files with 31 additions and 10 deletions

View file

@ -268,6 +268,7 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
videorate->from_rate_denominator = rate_denominator; videorate->from_rate_denominator = rate_denominator;
otherpad = videorate->srcpad; otherpad = videorate->srcpad;
} }
/* now try to find something for the peer */ /* now try to find something for the peer */
opeer = gst_pad_get_peer (otherpad); opeer = gst_pad_get_peer (otherpad);
if (opeer) { if (opeer) {
@ -358,6 +359,7 @@ gst_video_rate_reset (GstVideoRate * videorate)
videorate->drop = 0; videorate->drop = 0;
videorate->dup = 0; videorate->dup = 0;
videorate->next_ts = GST_CLOCK_TIME_NONE; videorate->next_ts = GST_CLOCK_TIME_NONE;
videorate->last_ts = GST_CLOCK_TIME_NONE;
videorate->discont = TRUE; videorate->discont = TRUE;
gst_video_rate_swap_prev (videorate, NULL, 0); gst_video_rate_swap_prev (videorate, NULL, 0);
@ -584,11 +586,17 @@ gst_video_rate_query (GstPad * pad, GstQuery * query)
GST_TIME_FORMAT " max %" GST_TIME_FORMAT, GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
GST_TIME_ARGS (min), GST_TIME_ARGS (max)); GST_TIME_ARGS (min), GST_TIME_ARGS (max));
/* add latency. We don't really know since we hold on to the frames if (videorate->from_rate_numerator != 0) {
* until we get a next frame, which can be anything. We assume /* add latency. We don't really know since we hold on to the frames
* however that this will take from_rate time. */ * until we get a next frame, which can be anything. We assume
latency = gst_util_uint64_scale (GST_SECOND, * however that this will take from_rate time. */
videorate->from_rate_denominator, videorate->from_rate_numerator); latency = gst_util_uint64_scale (GST_SECOND,
videorate->from_rate_denominator,
videorate->from_rate_numerator);
} else {
/* no input framerate, we don't know */
latency = 0;
}
GST_DEBUG_OBJECT (videorate, "Our latency: %" GST_DEBUG_OBJECT (videorate, "Our latency: %"
GST_TIME_FORMAT, GST_TIME_ARGS (latency)); GST_TIME_FORMAT, GST_TIME_ARGS (latency));
@ -621,7 +629,7 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
{ {
GstVideoRate *videorate; GstVideoRate *videorate;
GstFlowReturn res = GST_FLOW_OK; GstFlowReturn res = GST_FLOW_OK;
GstClockTime intime, in_ts; GstClockTime intime, in_ts, in_dur;
videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad)); videorate = GST_VIDEO_RATE (GST_PAD_PARENT (pad));
@ -631,9 +639,19 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
goto not_negotiated; goto not_negotiated;
in_ts = GST_BUFFER_TIMESTAMP (buffer); in_ts = GST_BUFFER_TIMESTAMP (buffer);
in_dur = GST_BUFFER_DURATION (buffer);
if (G_UNLIKELY (in_ts == GST_CLOCK_TIME_NONE)) if (G_UNLIKELY (in_ts == GST_CLOCK_TIME_NONE)) {
goto invalid_buffer; in_ts = videorate->last_ts;
if (G_UNLIKELY (in_ts == GST_CLOCK_TIME_NONE))
goto invalid_buffer;
}
/* get the time of the next expected buffer timestamp, we use this when the
* next buffer has -1 as a timestamp */
videorate->last_ts = in_ts;
if (in_dur != GST_CLOCK_TIME_NONE)
videorate->last_ts += in_dur;
GST_DEBUG_OBJECT (videorate, "got buffer with timestamp %" GST_TIME_FORMAT, GST_DEBUG_OBJECT (videorate, "got buffer with timestamp %" GST_TIME_FORMAT,
GST_TIME_ARGS (in_ts)); GST_TIME_ARGS (in_ts));
@ -698,7 +716,7 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
GST_TIME_ARGS (videorate->next_ts)); GST_TIME_ARGS (videorate->next_ts));
/* output first one when its the best */ /* output first one when its the best */
if (diff1 < diff2) { if (diff1 <= diff2) {
count++; count++;
/* on error the _flush function posted a warning already */ /* on error the _flush function posted a warning already */
@ -707,7 +725,8 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
goto done; goto done;
} }
} }
/* continue while the first one was the best */ /* continue while the first one was the best, if they were equal avoid
* going into an infinite loop */
} }
while (diff1 < diff2); while (diff1 < diff2);
@ -820,6 +839,7 @@ gst_video_rate_change_state (GstElement * element, GstStateChange transition)
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_READY_TO_PAUSED:
videorate->discont = TRUE; videorate->discont = TRUE;
videorate->last_ts = -1;
break; break;
default: default:
break; break;

View file

@ -57,6 +57,7 @@ struct _GstVideoRate
guint64 prev_ts; /* Previous buffer timestamp */ guint64 prev_ts; /* Previous buffer timestamp */
guint64 segment_out; /* in-segment counting */ guint64 segment_out; /* in-segment counting */
gboolean discont; gboolean discont;
guint64 last_ts; /* Timestamp of last input buffer */
/* segment handling */ /* segment handling */
GstSegment segment; GstSegment segment;