mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 07:47:17 +00:00
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:
parent
df66d00876
commit
bec7f4ad5e
1 changed files with 88 additions and 32 deletions
|
@ -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,20 +1363,38 @@ 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) {
|
||||||
|
if (videorate->to_rate_numerator) {
|
||||||
|
GstClockTime frame_duration = gst_util_uint64_scale (1,
|
||||||
|
videorate->to_rate_denominator * GST_SECOND,
|
||||||
|
videorate->to_rate_numerator);
|
||||||
|
|
||||||
videorate->next_ts =
|
videorate->next_ts =
|
||||||
videorate->segment.stop + videorate->segment.base;
|
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
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* In drop-only mode we can already decide here if we should output the
|
/* In drop-only mode we can already decide here if we should output the
|
||||||
* current frame or drop it because it's coming earlier than our minimum
|
* current frame or drop it because it's coming earlier than our minimum
|
||||||
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue