Fix T93328: Movie seeking doesn't work.

Caused by integer overflow in `steps_per_frame` calculation.
This commit is contained in:
Richard Antalik 2022-01-27 23:15:03 +01:00
parent da848b7440
commit f2b24272dd
Notes: blender-bot 2023-02-14 09:38:57 +01:00
Referenced by issue #95606, Crash on clicking in viewport with active GN workspace
Referenced by issue #95611, Regression: Capture Attribute in Face Corner mode produces garbage data
Referenced by issue #95278, 3.1 does not launch
Referenced by issue #95093, VSE: Variable framerate videos cause proxies to mismatch
Referenced by issue #93328, Blender VSE preview showing different result than Render
1 changed files with 11 additions and 21 deletions

View File

@ -993,21 +993,23 @@ static int ffmpeg_seek_by_byte(AVFormatContext *pFormatCtx)
return false;
}
static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search)
static double ffmpeg_steps_per_frame_get(struct anim *anim)
{
AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
AVRational frame_rate = v_st->r_frame_rate;
AVRational time_base = v_st->time_base;
double steps_per_frame = (double)(frame_rate.den * time_base.den) /
(double)(frame_rate.num * time_base.num);
AVRational frame_rate = av_guess_frame_rate(anim->pFormatCtx, v_st, NULL);
return av_q2d(av_inv_q(av_mul_q(frame_rate, time_base)));
;
}
static int64_t ffmpeg_get_seek_pts(struct anim *anim, int64_t pts_to_search)
{
/* Step back half a frame position to make sure that we get the requested
* frame and not the one after it. This is a workaround as ffmpeg will
* sometimes not seek to a frame after the requested pts even if
* AVSEEK_FLAG_BACKWARD is specified.
*/
int64_t pts = pts_to_search - (steps_per_frame / 2);
return pts;
return pts_to_search - (ffmpeg_steps_per_frame_get(anim) / 2);
}
/* This gives us an estimate of which pts our requested frame will have.
@ -1026,13 +1028,8 @@ static int64_t ffmpeg_get_pts_to_search(struct anim *anim,
else {
AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
int64_t start_pts = v_st->start_time;
AVRational frame_rate = v_st->r_frame_rate;
AVRational time_base = v_st->time_base;
double steps_per_frame = (double)(frame_rate.den * time_base.den) /
(double)(frame_rate.num * time_base.num);
pts_to_search = round(position * steps_per_frame);
pts_to_search = round(position * ffmpeg_steps_per_frame_get(anim));
if (start_pts != AV_NOPTS_VALUE) {
pts_to_search += start_pts;
@ -1122,13 +1119,6 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim,
int64_t *requested_pts,
int64_t pts_to_search)
{
AVStream *v_st = anim->pFormatCtx->streams[anim->videoStream];
AVRational frame_rate = v_st->r_frame_rate;
AVRational time_base = v_st->time_base;
double steps_per_frame = (double)(frame_rate.den * time_base.den) /
(double)(frame_rate.num * time_base.num);
int64_t current_pts = *requested_pts;
int64_t offset = 0;
@ -1136,7 +1126,7 @@ static int ffmpeg_generic_seek_workaround(struct anim *anim,
/* Step backward frame by frame until we find the key frame we are looking for. */
while (current_pts != 0) {
current_pts = *requested_pts - (int64_t)round(offset * steps_per_frame);
current_pts = *requested_pts - (int64_t)round(offset * ffmpeg_steps_per_frame_get(anim));
current_pts = MAX2(current_pts, 0);
/* Seek to timestamp. */