videorate: Fix behaviour for frame rate cap changes

The outgoing buffer timestamp is calculated by scaling an output buffer
count by the src pad frame rate caps. If these caps change, we need to
reset the count and work from a new base timestamp. The new output
buffer timestamp is then the count scaled by the new caps values added
onto the base timestamp.
This commit is contained in:
Robert Swain 2011-01-06 13:08:53 +01:00
parent fce99dc0be
commit 2c1bf82d55
2 changed files with 24 additions and 7 deletions

View file

@ -290,6 +290,16 @@ gst_video_rate_setcaps (GstPad * pad, GstCaps * caps)
goto no_framerate;
if (pad == videorate->srcpad) {
/* out_frame_count is scaled by the frame rate caps when calculating next_ts.
* when the frame rate caps change, we must update base_ts and reset
* out_frame_count */
if (videorate->to_rate_numerator) {
videorate->base_ts +=
gst_util_uint64_scale (videorate->out_frame_count,
videorate->to_rate_denominator * GST_SECOND,
videorate->to_rate_numerator);
}
videorate->out_frame_count = 0;
videorate->to_rate_numerator = rate_numerator;
videorate->to_rate_denominator = rate_denominator;
otherpad = videorate->sinkpad;
@ -394,7 +404,8 @@ gst_video_rate_reset (GstVideoRate * videorate)
videorate->in = 0;
videorate->out = 0;
videorate->segment_out = 0;
videorate->base_ts = 0;
videorate->out_frame_count = 0;
videorate->drop = 0;
videorate->dup = 0;
videorate->next_ts = GST_CLOCK_TIME_NONE;
@ -473,11 +484,12 @@ gst_video_rate_flush_prev (GstVideoRate * videorate, gboolean duplicate)
push_ts = videorate->next_ts;
videorate->out++;
videorate->segment_out++;
videorate->out_frame_count++;
if (videorate->to_rate_numerator) {
/* interpolate next expected timestamp in the segment */
videorate->next_ts = videorate->segment.accum + videorate->segment.start +
gst_util_uint64_scale (videorate->segment_out,
videorate->next_ts =
videorate->segment.accum + videorate->segment.start +
videorate->base_ts + gst_util_uint64_scale (videorate->out_frame_count,
videorate->to_rate_denominator * GST_SECOND,
videorate->to_rate_numerator);
GST_BUFFER_DURATION (outbuf) = videorate->next_ts - push_ts;
@ -587,7 +599,8 @@ gst_video_rate_event (GstPad * pad, GstEvent * event)
gst_video_rate_notify_drop (videorate);
}
/* clean up for the new one; _chain will resume from the new start */
videorate->segment_out = 0;
videorate->base_ts = 0;
videorate->out_frame_count = 0;
gst_video_rate_swap_prev (videorate, NULL, 0);
videorate->next_ts = GST_CLOCK_TIME_NONE;
}
@ -783,7 +796,7 @@ gst_video_rate_chain (GstPad * pad, GstBuffer * buffer)
* timestamp in the segment */
if (videorate->skip_to_first) {
videorate->next_ts = in_ts;
videorate->segment_out = gst_util_uint64_scale (in_ts,
videorate->out_frame_count = gst_util_uint64_scale (in_ts,
videorate->to_rate_numerator,
videorate->to_rate_denominator * GST_SECOND) -
(videorate->segment.accum + videorate->segment.start);

View file

@ -55,7 +55,11 @@ struct _GstVideoRate
guint64 next_ts; /* Timestamp of next buffer to output */
GstBuffer *prevbuf;
guint64 prev_ts; /* Previous buffer timestamp */
guint64 segment_out; /* in-segment counting */
guint64 out_frame_count; /* number of frames output since the beginning
* of the segment or the last frame rate caps
* change, whichever was later */
guint64 base_ts; /* used in next_ts calculation after a
* frame rate caps change */
gboolean discont;
guint64 last_ts; /* Timestamp of last input buffer */