videorate: In reverse playback mode, don't output the first buffer with ts=segment.stop

Instead go backwards before segment.stop based on the framerate or the
next buffers end timestamp. Otherwise the first buffer will usually be
dropped because outside the segment.

https://bugzilla.gnome.org/show_bug.cgi?id=781899
This commit is contained in:
Sebastian Dröge 2017-04-28 15:24:43 +03:00
parent df66d00876
commit bec7f4ad5e

View file

@ -550,7 +550,8 @@ gst_video_rate_setcaps (GstBaseTransform * trans, GstCaps * in_caps,
* out_frame_count */ * out_frame_count */
if (videorate->to_rate_numerator) { if (videorate->to_rate_numerator) {
videorate->base_ts += videorate->base_ts +=
gst_util_uint64_scale (videorate->out_frame_count, gst_util_uint64_scale (videorate->out_frame_count +
(videorate->segment.rate < 0.0 ? 1 : 0),
videorate->to_rate_denominator * GST_SECOND, videorate->to_rate_denominator * GST_SECOND,
videorate->to_rate_numerator); videorate->to_rate_numerator);
} }
@ -653,13 +654,13 @@ gst_video_rate_push_buffer (GstVideoRate * videorate, GstBuffer * outbuf,
if (videorate->segment.rate < 0.0) { if (videorate->segment.rate < 0.0) {
if (videorate->to_rate_numerator) { if (videorate->to_rate_numerator) {
/* interpolate next expected timestamp in the segment */ /* interpolate next expected timestamp in the segment */
videorate->next_ts = videorate->next_ts =
videorate->segment.base + videorate->segment.stop - videorate->segment.base + videorate->segment.stop -
videorate->base_ts - videorate->base_ts -
gst_util_uint64_scale (videorate->out_frame_count, gst_util_uint64_scale (videorate->out_frame_count + 1,
videorate->to_rate_denominator * GST_SECOND, videorate->to_rate_denominator * GST_SECOND,
videorate->to_rate_numerator); videorate->to_rate_numerator);
GST_BUFFER_DURATION (outbuf) = push_ts - videorate->next_ts; GST_BUFFER_DURATION (outbuf) = push_ts - videorate->next_ts;
} else if (next_intime != GST_CLOCK_TIME_NONE) { } else if (next_intime != GST_CLOCK_TIME_NONE) {
videorate->next_ts = next_intime; videorate->next_ts = next_intime;
@ -1362,18 +1363,36 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
* timestamp in the segment */ * timestamp in the segment */
if (videorate->skip_to_first || skip) { if (videorate->skip_to_first || skip) {
videorate->next_ts = intime; videorate->next_ts = intime;
if (videorate->segment.rate < 0.0) if (videorate->segment.rate < 0.0) {
videorate->base_ts = videorate->segment.stop - in_ts; videorate->base_ts = videorate->segment.stop - in_ts;
else } else {
videorate->base_ts = in_ts - videorate->segment.start; videorate->base_ts = in_ts - videorate->segment.start;
}
videorate->out_frame_count = 0; videorate->out_frame_count = 0;
} else { } else {
if (videorate->segment.rate < 0.0) if (videorate->segment.rate < 0.0) {
videorate->next_ts = if (videorate->to_rate_numerator) {
videorate->segment.stop + videorate->segment.base; GstClockTime frame_duration = gst_util_uint64_scale (1,
else videorate->to_rate_denominator * GST_SECOND,
videorate->to_rate_numerator);
videorate->next_ts =
videorate->segment.stop + videorate->segment.base;
if (videorate->next_ts > frame_duration)
videorate->next_ts =
MAX (videorate->segment.start,
videorate->next_ts - frame_duration);
else
videorate->next_ts = videorate->segment.start;
} else {
/* What else can we do? */
videorate->next_ts = intime;
}
} else {
videorate->next_ts = videorate->next_ts =
videorate->segment.start + videorate->segment.base; videorate->segment.start + videorate->segment.base;
}
} }
} }
@ -1429,37 +1448,74 @@ gst_video_rate_transform_ip (GstBaseTransform * trans, GstBuffer * buffer)
/* got 2 buffers, see which one is the best */ /* got 2 buffers, see which one is the best */
do { do {
GstClockTime next_ts = videorate->next_ts * videorate->rate; GstClockTime next_ts;
/* take absolute values, beware: abs and ABS don't work for gint64 */
if (prevtime > next_ts)
diff1 = prevtime - next_ts;
else
diff1 = next_ts - prevtime;
if (intime > next_ts)
diff2 = intime - next_ts;
else
diff2 = next_ts - intime;
GST_LOG_OBJECT (videorate,
"diff with prev %" GST_TIME_FORMAT " diff with new %"
GST_TIME_FORMAT " outgoing ts %" GST_TIME_FORMAT,
GST_TIME_ARGS (diff1), GST_TIME_ARGS (diff2),
GST_TIME_ARGS (next_ts));
if (videorate->segment.rate < 0.0) { if (videorate->segment.rate < 0.0) {
/* Make sure that we have a duration for this buffer. The previous /* Make sure that we have a duration for this buffer. The previous
* buffer already has a duration given by either exactly this code, * buffer already has a duration given by either exactly this code,
* or the code above for the very first buffer */ * or the code above for the very first buffer */
g_assert (GST_BUFFER_DURATION_IS_VALID (videorate->prevbuf)); g_assert (GST_BUFFER_DURATION_IS_VALID (videorate->prevbuf));
if (!GST_BUFFER_DURATION_IS_VALID (buffer) && prevtime > intime) if (!GST_BUFFER_DURATION_IS_VALID (buffer))
GST_BUFFER_DURATION (buffer) = prevtime - intime; GST_BUFFER_DURATION (buffer) =
prevtime > intime ? prevtime - intime : 0;
} else { } else {
/* Make sure that we have a duration for previous buffer */ /* Make sure that we have a duration for previous buffer */
if (!GST_BUFFER_DURATION_IS_VALID (videorate->prevbuf) if (!GST_BUFFER_DURATION_IS_VALID (videorate->prevbuf))
&& intime > prevtime) GST_BUFFER_DURATION (videorate->prevbuf) =
GST_BUFFER_DURATION (videorate->prevbuf) = intime - prevtime; intime > prevtime ? intime - prevtime : 0;
}
#ifndef ABSDIFF
#define ABSDIFF(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
#endif
/* take absolute diffs */
if (videorate->segment.rate < 0.0) {
GstClockTime next_end_ts;
GstClockTime prev_endtime;
GstClockTime in_endtime;
next_ts = videorate->next_ts;
prev_endtime =
MAX (prevtime + GST_BUFFER_DURATION (videorate->prevbuf),
videorate->segment.stop);
in_endtime =
MAX (intime + GST_BUFFER_DURATION (buffer),
videorate->segment.stop);
if (videorate->to_rate_numerator) {
GstClockTime frame_duration = gst_util_uint64_scale (1,
videorate->to_rate_denominator * GST_SECOND,
videorate->to_rate_numerator);
next_end_ts = MAX (next_ts + frame_duration, videorate->segment.stop);
} else {
next_end_ts =
MAX (next_ts + GST_BUFFER_DURATION (videorate->prevbuf),
videorate->segment.stop);
}
next_ts *= videorate->rate;
next_end_ts *= videorate->rate;
diff1 = ABSDIFF (prev_endtime, next_end_ts);
diff2 = ABSDIFF (in_endtime, next_end_ts);
GST_LOG_OBJECT (videorate,
"diff with prev %" GST_TIME_FORMAT " diff with new %"
GST_TIME_FORMAT " outgoing ts %" GST_TIME_FORMAT,
GST_TIME_ARGS (diff1), GST_TIME_ARGS (diff2),
GST_TIME_ARGS (next_end_ts));
} else {
next_ts = videorate->next_ts * videorate->rate;
diff1 = ABSDIFF (prevtime, next_ts);
diff2 = ABSDIFF (intime, next_ts);
GST_LOG_OBJECT (videorate,
"diff with prev %" GST_TIME_FORMAT " diff with new %"
GST_TIME_FORMAT " outgoing ts %" GST_TIME_FORMAT,
GST_TIME_ARGS (diff1), GST_TIME_ARGS (diff2),
GST_TIME_ARGS (next_ts));
} }
/* output first one when its the best */ /* output first one when its the best */