PR #24552 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24552 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24552.patch
Fixes: division by zero Fixes: 1XvjZP0UGl6O Found-by: Gabe Sherman (Trail of Bits) >From c60b9b59ad86b025f4c32502bafe4170d68539d3 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 17 Sep 2026 16:21:42 +0200 Subject: [PATCH 1/7] avcodec/mpegvideo_enc: assert on the frame distance before it is truncated to 16 bits Fixes: assertion failure Fixes: 1XvjZP0UGl6O Found-by: Gabe Sherman (Trail of Bits) --- libavcodec/mpegvideo_enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 7751de8510..1a6cdbfdfb 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -3665,9 +3665,9 @@ static void set_frame_distances(MPVEncContext *const s) s->c.pb_time = s->c.pp_time - (s->c.last_non_b_time - s->c.time); av_assert1(s->c.pb_time > 0 && s->c.pb_time < s->c.pp_time); }else{ + av_assert1(s->picture_number == 0 || s->c.time > s->c.last_non_b_time); s->c.pp_time = s->c.time - s->c.last_non_b_time; s->c.last_non_b_time = s->c.time; - av_assert1(s->picture_number == 0 || s->c.pp_time > 0); } } -- 2.52.0 >From 63793db62946752c3a769299d24b0232f1f42871 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 17 Sep 2026 18:41:48 +0200 Subject: [PATCH 2/7] avcodec/mpegvideo_enc: keep MPEG-4 B frame chains within the 16 bit frame distance Fixes: division by zero Fixes: 1XvjZP0UGl6O Found-by: Gabe Sherman (Trail of Bits) --- libavcodec/mpegvideo_enc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 1a6cdbfdfb..3d749360f9 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -1722,6 +1722,12 @@ static int set_bframe_chain_length(MPVMainEncContext *const m) } } + if (s->c.codec_id == AV_CODEC_ID_MPEG4) + while (b_frames && + m->input_picture[b_frames]->f->pts * s->c.avctx->time_base.num - + s->c.last_non_b_time > UINT16_MAX) + b_frames--; + for (int i = b_frames - 1; i >= 0; i--) { int type = m->input_picture[i]->f->pict_type; if (type && type != AV_PICTURE_TYPE_B) -- 2.52.0 >From 1643f9aa74986026bd395009b0244db72656f987 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 17 Sep 2026 18:02:03 +0200 Subject: [PATCH 3/7] avcodec/mpegvideo_enc: reject pts outside the range the MPEG-4 time can represent Fixes: signed integer overflow Found during review of the fix for 1XvjZP0UGl6O --- libavcodec/mpegvideo_enc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 3d749360f9..f52e3617d7 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -1301,6 +1301,13 @@ static int load_input_picture(MPVMainEncContext *const m, const AVFrame *pic_arg display_picture_number = m->input_picture_number++; if (pts != AV_NOPTS_VALUE) { + if (s->c.codec_id == AV_CODEC_ID_MPEG4 && + (pts > INT64_MAX / 2 / s->c.avctx->time_base.num || + pts < INT64_MIN / 2 / s->c.avctx->time_base.num)) { + av_log(s->c.avctx, AV_LOG_ERROR, "pts %"PRId64" is out of the supported range\n", pts); + return AVERROR_PATCHWELCOME; + } + if (m->user_specified_pts != AV_NOPTS_VALUE) { int64_t last = m->user_specified_pts; -- 2.52.0 >From ebbb735b5acd34d18eb1d33225e26866c6364ec4 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 17 Sep 2026 17:02:55 +0200 Subject: [PATCH 4/7] avcodec/mpeg4videoenc: compute the GOP header time with av_rescale_rnd() pts * time_base.num can overflow int64_t; av_rescale_rnd() computes the same floor division exactly. --- libavcodec/mpeg4videoenc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c index a10da6af82..f7aa635d2e 100644 --- a/libavcodec/mpeg4videoenc.c +++ b/libavcodec/mpeg4videoenc.c @@ -861,10 +861,9 @@ static void mpeg4_encode_gop_header(MPVMainEncContext *const m) time = s->c.cur_pic.ptr->f->pts; if (m->reordered_input_picture[1]) time = FFMIN(time, m->reordered_input_picture[1]->f->pts); - time = time * s->c.avctx->time_base.num; - s->c.last_time_base = FFUDIV(time, s->c.avctx->time_base.den); + seconds = av_rescale_rnd(time, s->c.avctx->time_base.num, s->c.avctx->time_base.den, AV_ROUND_DOWN); + s->c.last_time_base = seconds; - seconds = FFUDIV(time, s->c.avctx->time_base.den); minutes = FFUDIV(seconds, 60); seconds = FFUMOD(seconds, 60); hours = FFUDIV(minutes, 60); minutes = FFUMOD(minutes, 60); hours = FFUMOD(hours , 24); -- 2.52.0 >From 4b5da16fcec07b111a5584736542bc1e03148e3c Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 17 Sep 2026 18:02:03 +0200 Subject: [PATCH 5/7] avcodec/ituh263enc: compute the temporal reference with av_rescale_rnd() The hand written multiply and divide can overflow int64_t for a large time_base.num; av_rescale_rnd() computes the same truncating division exactly. --- libavcodec/ituh263enc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavcodec/ituh263enc.c b/libavcodec/ituh263enc.c index 56259783b0..e9c5d08a78 100644 --- a/libavcodec/ituh263enc.c +++ b/libavcodec/ituh263enc.c @@ -245,8 +245,8 @@ static int h263_encode_picture_header(MPVMainEncContext *const m) coded_frame_rate_base= (1000+best_clock_code)*best_divisor; put_bits(&s->pb, 22, 0x20); /* PSC */ - temp_ref = s->picture_number * (int64_t)coded_frame_rate * s->c.avctx->time_base.num / //FIXME use timestamp - (coded_frame_rate_base * (int64_t)s->c.avctx->time_base.den); + temp_ref = av_rescale_rnd(s->picture_number, coded_frame_rate * (int64_t)s->c.avctx->time_base.num, //FIXME use timestamp + coded_frame_rate_base * (int64_t)s->c.avctx->time_base.den, AV_ROUND_ZERO); put_sbits(&s->pb, 8, temp_ref); /* TemporalReference */ put_bits(&s->pb, 1, 1); /* marker */ -- 2.52.0 >From e01500e214b3bc2a1f5a9e42a66ba283df5c7c91 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 17 Sep 2026 18:41:48 +0200 Subject: [PATCH 6/7] avcodec/motion_est: scale the B frame vector predictors with the exact frame distances Fixes: division by zero Fixes: 1XvjZP0UGl6O Found-by: Gabe Sherman (Trail of Bits) --- libavcodec/motion_est.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index 894fa85576..492336ca54 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -1149,11 +1149,12 @@ static int estimate_motion_b(MPVEncContext *const s, int mb_x, int mb_y, c->pred_x = P_LEFT[0]; c->pred_y = P_LEFT[1]; - if(mv_table == s->b_forw_mv_table){ - mv_scale= (s->c.pb_time<<16) / (s->c.pp_time<<shift); - }else{ - mv_scale = ((s->c.pb_time - s->c.pp_time) * (1 << 16)) / (s->c.pp_time<<shift); - } + int64_t pp = s->c.next_pic.ptr->f->pts - s->c.last_pic.ptr->f->pts; + int64_t pb = s->c. cur_pic.ptr->f->pts - s->c.last_pic.ptr->f->pts; + if (mv_table == s->b_forw_mv_table) + mv_scale = (pb << (16 - shift)) / pp; + else + mv_scale = (pb - pp) * (1 << (16 - shift)) / pp; dmin = ff_epzs_motion_search(s, &mx, &my, P, 0, ref_index, s->p_mv_table, mv_scale, 0, 16); } -- 2.52.0 >From a70f21a538a193f86ba0443b62c6184f5b497b9b Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Thu, 17 Sep 2026 18:41:48 +0200 Subject: [PATCH 7/7] avcodec/mpegvideo_enc: compute the frame distances only for MPEG-4 time, last_non_b_time, pp_time and pb_time are the MPEG-4 time bookkeeping; the only other reader was the B frame motion estimation of the MPEG-1/2 encoders, which now scales with the timestamps. --- libavcodec/mpegvideo_enc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index f52e3617d7..6ce342dde8 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -3691,12 +3691,10 @@ static int encode_picture(MPVMainEncContext *const m, const AVPacket *pkt) int bits; int context_count = s->c.slice_context_count; - /* we need to initialize some time vars before we can encode B-frames */ - // RAL: Condition added for MPEG1VIDEO - if (s->c.out_format == FMT_MPEG1 || (s->c.h263_pred && s->c.msmpeg4_version == MSMP4_UNUSED)) + if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4) { set_frame_distances(s); - if (CONFIG_MPEG4_ENCODER && s->c.codec_id == AV_CODEC_ID_MPEG4) ff_set_mpeg4_time(s); + } // s->lambda = s->c.cur_pic.ptr->quality; //FIXME qscale / ... stuff for ME rate distortion -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
