From 9a126503f549cd5f8f39f1c9bf515633489adfc1 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> Date: Tue, 18 Mar 2025 11:47:58 +0100 Subject: [PATCH 38/77] avcodec/mpegvideo: Move MPVPicture arrays to MPVMainEncContext Also avoid allocations while at it. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com> --- libavcodec/mpeg4videoenc.c | 11 ++-- libavcodec/mpegvideo.h | 2 - libavcodec/mpegvideo_enc.c | 124 ++++++++++++++++++------------------- libavcodec/mpegvideoenc.h | 3 + 4 files changed, 68 insertions(+), 72 deletions(-) diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c index d54064cd89..4c31e7e9c8 100644 --- a/libavcodec/mpeg4videoenc.c +++ b/libavcodec/mpeg4videoenc.c @@ -668,7 +668,7 @@ static void mpeg4_encode_mb(MpegEncContext *const s, int16_t block[][64], for (int i = 0; i < m->max_b_frames; i++) { const uint8_t *b_pic; int diff; - const MPVPicture *pic = s->reordered_input_picture[i + 1]; + const MPVPicture *pic = m->reordered_input_picture[i + 1]; if (!pic || pic->f->pict_type != AV_PICTURE_TYPE_B) break; @@ -900,16 +900,17 @@ void ff_set_mpeg4_time(MpegEncContext *s) } } -static void mpeg4_encode_gop_header(MpegEncContext *s) +static void mpeg4_encode_gop_header(MPVMainEncContext *const m) { + MpegEncContext *const s = &m->s; int64_t hours, minutes, seconds; int64_t time; put_bits32(&s->pb, GOP_STARTCODE); time = s->cur_pic.ptr->f->pts; - if (s->reordered_input_picture[1]) - time = FFMIN(time, s->reordered_input_picture[1]->f->pts); + if (m->reordered_input_picture[1]) + time = FFMIN(time, m->reordered_input_picture[1]->f->pts); time = time * s->avctx->time_base.num; s->last_time_base = FFUDIV(time, s->avctx->time_base.den); @@ -1077,7 +1078,7 @@ static int mpeg4_encode_picture_header(MPVMainEncContext *const m) if (s->avctx->strict_std_compliance < FF_COMPLIANCE_VERY_STRICT || s->picture_number == 0) // HACK, the reference sw is buggy mpeg4_encode_vol_header(m4, 0, 0); } - mpeg4_encode_gop_header(s); + mpeg4_encode_gop_header(m); } s->partitioned_frame = s->data_partitioning && s->pict_type != AV_PICTURE_TYPE_B; diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index d25b5cdf3a..12cb8fc3d5 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -123,8 +123,6 @@ typedef struct MpegEncContext { ptrdiff_t linesize; ///< line size, in bytes, may be different from width ptrdiff_t uvlinesize; ///< line size, for chroma in bytes, may be different from width struct AVRefStructPool *picture_pool; ///< Pool for MPVPictures - MPVPicture **input_picture;///< next pictures on display order for encoding - MPVPicture **reordered_input_picture; ///< pointer to the next pictures in coded order for encoding BufferPoolContext buffer_pools; diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index ffa652d02d..8af572a69e 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -915,8 +915,6 @@ av_cold int ff_mpv_encode_init(AVCodecContext *avctx) return ret; if (!(avctx->stats_out = av_mallocz(256)) || - !FF_ALLOCZ_TYPED_ARRAY(s->input_picture, MPVENC_MAX_B_FRAMES + 1) || - !FF_ALLOCZ_TYPED_ARRAY(s->reordered_input_picture, MPVENC_MAX_B_FRAMES + 1) || !(s->new_pic = av_frame_alloc()) || !(s->picture_pool = ff_mpv_alloc_pic_pool(0))) return AVERROR(ENOMEM); @@ -1049,11 +1047,9 @@ av_cold int ff_mpv_encode_end(AVCodecContext *avctx) ff_mpv_common_end(s); av_refstruct_pool_uninit(&s->picture_pool); - if (s->input_picture && s->reordered_input_picture) { - for (int i = 0; i < MPVENC_MAX_B_FRAMES + 1; i++) { - av_refstruct_unref(&s->input_picture[i]); - av_refstruct_unref(&s->reordered_input_picture[i]); - } + for (int i = 0; i < MPVENC_MAX_B_FRAMES + 1; i++) { + av_refstruct_unref(&m->input_picture[i]); + av_refstruct_unref(&m->reordered_input_picture[i]); } for (int i = 0; i < FF_ARRAY_ELEMS(m->tmp_frames); i++) av_frame_free(&m->tmp_frames[i]); @@ -1077,8 +1073,6 @@ av_cold int ff_mpv_encode_end(AVCodecContext *avctx) av_freep(&s->q_intra_matrix); av_freep(&s->q_intra_matrix16); - av_freep(&s->input_picture); - av_freep(&s->reordered_input_picture); av_freep(&s->dct_offset); av_freep(&s->mb_var); av_freep(&s->mc_mb_var); @@ -1260,7 +1254,7 @@ static int load_input_picture(MPVMainEncContext *const m, const AVFrame *pic_arg int flush_offset = 1; int direct = 1; - av_assert1(!s->input_picture[0]); + av_assert1(!m->input_picture[0]); if (pic_arg) { pts = pic_arg->pts; @@ -1363,14 +1357,14 @@ static int load_input_picture(MPVMainEncContext *const m, const AVFrame *pic_arg pic->display_picture_number = display_picture_number; pic->f->pts = pts; // we set this here to avoid modifying pic_arg - } else if (!s->reordered_input_picture[1]) { + } else if (!m->reordered_input_picture[1]) { /* Flushing: When the above check is true, the encoder is about to run * out of frames to encode. Check if there are input_pictures left; - * if so, ensure s->input_picture[0] contains the first picture. + * if so, ensure m->input_picture[0] contains the first picture. * A flush_offset != 1 will only happen if we did not receive enough * input frames. */ for (flush_offset = 0; flush_offset < encoding_delay + 1; flush_offset++) - if (s->input_picture[flush_offset]) + if (m->input_picture[flush_offset]) break; encoding_delay -= flush_offset - 1; @@ -1378,11 +1372,11 @@ static int load_input_picture(MPVMainEncContext *const m, const AVFrame *pic_arg /* shift buffer entries */ for (int i = flush_offset; i <= MPVENC_MAX_B_FRAMES; i++) - s->input_picture[i - flush_offset] = s->input_picture[i]; + m->input_picture[i - flush_offset] = m->input_picture[i]; for (int i = MPVENC_MAX_B_FRAMES + 1 - flush_offset; i <= MPVENC_MAX_B_FRAMES; i++) - s->input_picture[i] = NULL; + m->input_picture[i] = NULL; - s->input_picture[encoding_delay] = pic; + m->input_picture[encoding_delay] = pic; return 0; fail: @@ -1482,7 +1476,7 @@ static int estimate_best_b_count(MPVMainEncContext *const m) FF_LAMBDA_SHIFT; for (int i = 0; i < m->max_b_frames + 2; i++) { - const MPVPicture *pre_input_ptr = i ? s->input_picture[i - 1] : + const MPVPicture *pre_input_ptr = i ? m->input_picture[i - 1] : s->next_pic.ptr; if (pre_input_ptr) { @@ -1517,7 +1511,7 @@ static int estimate_best_b_count(MPVMainEncContext *const m) AVCodecContext *c; int64_t rd = 0; - if (!s->input_picture[j]) + if (!m->input_picture[j]) break; c = avcodec_alloc_context3(NULL); @@ -1612,16 +1606,16 @@ static int set_bframe_chain_length(MPVMainEncContext *const m) MpegEncContext *const s = &m->s; /* Either nothing to do or can't do anything */ - if (s->reordered_input_picture[0] || !s->input_picture[0]) + if (m->reordered_input_picture[0] || !m->input_picture[0]) return 0; /* set next picture type & ordering */ if (m->frame_skip_threshold || m->frame_skip_factor) { if (m->picture_in_gop_number < m->gop_size && s->next_pic.ptr && - skip_check(m, s->input_picture[0], s->next_pic.ptr)) { + skip_check(m, m->input_picture[0], s->next_pic.ptr)) { // FIXME check that the gop check above is +-1 correct - av_refstruct_unref(&s->input_picture[0]); + av_refstruct_unref(&m->input_picture[0]); ff_vbv_update(m, 0); @@ -1631,48 +1625,48 @@ static int set_bframe_chain_length(MPVMainEncContext *const m) if (/* m->picture_in_gop_number >= m->gop_size || */ !s->next_pic.ptr || m->intra_only) { - s->reordered_input_picture[0] = s->input_picture[0]; - s->input_picture[0] = NULL; - s->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_I; - s->reordered_input_picture[0]->coded_picture_number = + m->reordered_input_picture[0] = m->input_picture[0]; + m->input_picture[0] = NULL; + m->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_I; + m->reordered_input_picture[0]->coded_picture_number = m->coded_picture_number++; } else { int b_frames = 0; if (s->avctx->flags & AV_CODEC_FLAG_PASS2) { for (int i = 0; i < m->max_b_frames + 1; i++) { - int pict_num = s->input_picture[0]->display_picture_number + i; + int pict_num = m->input_picture[0]->display_picture_number + i; if (pict_num >= m->rc_context.num_entries) break; - if (!s->input_picture[i]) { + if (!m->input_picture[i]) { m->rc_context.entry[pict_num - 1].new_pict_type = AV_PICTURE_TYPE_P; break; } - s->input_picture[i]->f->pict_type = + m->input_picture[i]->f->pict_type = m->rc_context.entry[pict_num].new_pict_type; } } if (m->b_frame_strategy == 0) { b_frames = m->max_b_frames; - while (b_frames && !s->input_picture[b_frames]) + while (b_frames && !m->input_picture[b_frames]) b_frames--; } else if (m->b_frame_strategy == 1) { for (int i = 1; i < m->max_b_frames + 1; i++) { - if (s->input_picture[i] && - s->input_picture[i]->b_frame_score == 0) { - s->input_picture[i]->b_frame_score = + if (m->input_picture[i] && + m->input_picture[i]->b_frame_score == 0) { + m->input_picture[i]->b_frame_score = get_intra_count(s, - s->input_picture[i ]->f->data[0], - s->input_picture[i - 1]->f->data[0], + m->input_picture[i ]->f->data[0], + m->input_picture[i - 1]->f->data[0], s->linesize) + 1; } } for (int i = 0; i < m->max_b_frames + 1; i++) { - if (!s->input_picture[i] || - s->input_picture[i]->b_frame_score - 1 > + if (!m->input_picture[i] || + m->input_picture[i]->b_frame_score - 1 > s->mb_num / m->b_sensitivity) { b_frames = FFMAX(0, i - 1); break; @@ -1681,11 +1675,11 @@ static int set_bframe_chain_length(MPVMainEncContext *const m) /* reset scores */ for (int i = 0; i < b_frames + 1; i++) - s->input_picture[i]->b_frame_score = 0; + m->input_picture[i]->b_frame_score = 0; } else if (m->b_frame_strategy == 2) { b_frames = estimate_best_b_count(m); if (b_frames < 0) { - av_refstruct_unref(&s->input_picture[0]); + av_refstruct_unref(&m->input_picture[0]); return b_frames; } } @@ -1693,11 +1687,11 @@ static int set_bframe_chain_length(MPVMainEncContext *const m) emms_c(); for (int i = b_frames - 1; i >= 0; i--) { - int type = s->input_picture[i]->f->pict_type; + int type = m->input_picture[i]->f->pict_type; if (type && type != AV_PICTURE_TYPE_B) b_frames = i; } - if (s->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_B && + if (m->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_B && b_frames == m->max_b_frames) { av_log(s->avctx, AV_LOG_ERROR, "warning, too many B-frames in a row\n"); @@ -1710,26 +1704,26 @@ static int set_bframe_chain_length(MPVMainEncContext *const m) } else { if (s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) b_frames = 0; - s->input_picture[b_frames]->f->pict_type = AV_PICTURE_TYPE_I; + m->input_picture[b_frames]->f->pict_type = AV_PICTURE_TYPE_I; } } if ((s->avctx->flags & AV_CODEC_FLAG_CLOSED_GOP) && b_frames && - s->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_I) + m->input_picture[b_frames]->f->pict_type == AV_PICTURE_TYPE_I) b_frames--; - s->reordered_input_picture[0] = s->input_picture[b_frames]; - s->input_picture[b_frames] = NULL; - if (s->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_I) - s->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_P; - s->reordered_input_picture[0]->coded_picture_number = + m->reordered_input_picture[0] = m->input_picture[b_frames]; + m->input_picture[b_frames] = NULL; + if (m->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_I) + m->reordered_input_picture[0]->f->pict_type = AV_PICTURE_TYPE_P; + m->reordered_input_picture[0]->coded_picture_number = m->coded_picture_number++; for (int i = 0; i < b_frames; i++) { - s->reordered_input_picture[i + 1] = s->input_picture[i]; - s->input_picture[i] = NULL; - s->reordered_input_picture[i + 1]->f->pict_type = + m->reordered_input_picture[i + 1] = m->input_picture[i]; + m->input_picture[i] = NULL; + m->reordered_input_picture[i + 1]->f->pict_type = AV_PICTURE_TYPE_B; - s->reordered_input_picture[i + 1]->coded_picture_number = + m->reordered_input_picture[i + 1]->coded_picture_number = m->coded_picture_number++; } } @@ -1742,34 +1736,34 @@ static int select_input_picture(MPVMainEncContext *const m) MpegEncContext *const s = &m->s; int ret; - av_assert1(!s->reordered_input_picture[0]); + av_assert1(!m->reordered_input_picture[0]); for (int i = 1; i <= MPVENC_MAX_B_FRAMES; i++) - s->reordered_input_picture[i - 1] = s->reordered_input_picture[i]; - s->reordered_input_picture[MPVENC_MAX_B_FRAMES] = NULL; + m->reordered_input_picture[i - 1] = m->reordered_input_picture[i]; + m->reordered_input_picture[MPVENC_MAX_B_FRAMES] = NULL; ret = set_bframe_chain_length(m); - av_assert1(!s->input_picture[0]); + av_assert1(!m->input_picture[0]); if (ret < 0) return ret; av_frame_unref(s->new_pic); - if (s->reordered_input_picture[0]) { - s->reordered_input_picture[0]->reference = - s->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_B; + if (m->reordered_input_picture[0]) { + m->reordered_input_picture[0]->reference = + m->reordered_input_picture[0]->f->pict_type != AV_PICTURE_TYPE_B; - if (s->reordered_input_picture[0]->shared || s->avctx->rc_buffer_size) { + if (m->reordered_input_picture[0]->shared || s->avctx->rc_buffer_size) { // input is a shared pix, so we can't modify it -> allocate a new // one & ensure that the shared one is reuseable - av_frame_move_ref(s->new_pic, s->reordered_input_picture[0]->f); + av_frame_move_ref(s->new_pic, m->reordered_input_picture[0]->f); - ret = prepare_picture(s, s->reordered_input_picture[0]->f, s->new_pic); + ret = prepare_picture(s, m->reordered_input_picture[0]->f, s->new_pic); if (ret < 0) goto fail; } else { // input is not a shared pix -> reuse buffer for current_pix - ret = av_frame_ref(s->new_pic, s->reordered_input_picture[0]->f); + ret = av_frame_ref(s->new_pic, m->reordered_input_picture[0]->f); if (ret < 0) goto fail; for (int i = 0; i < MPV_MAX_PLANES; i++) { @@ -1777,8 +1771,8 @@ static int select_input_picture(MPVMainEncContext *const m) s->new_pic->data[i] += INPLACE_OFFSET; } } - s->cur_pic.ptr = s->reordered_input_picture[0]; - s->reordered_input_picture[0] = NULL; + s->cur_pic.ptr = m->reordered_input_picture[0]; + m->reordered_input_picture[0] = NULL; av_assert1(s->mb_width == s->buffer_pools.alloc_mb_width); av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height); av_assert1(s->mb_stride == s->buffer_pools.alloc_mb_stride); @@ -1793,7 +1787,7 @@ static int select_input_picture(MPVMainEncContext *const m) } return 0; fail: - av_refstruct_unref(&s->reordered_input_picture[0]); + av_refstruct_unref(&m->reordered_input_picture[0]); return ret; } diff --git a/libavcodec/mpegvideoenc.h b/libavcodec/mpegvideoenc.h index 27bd099aad..f02708e7ec 100644 --- a/libavcodec/mpegvideoenc.h +++ b/libavcodec/mpegvideoenc.h @@ -49,6 +49,9 @@ typedef struct MPVMainEncContext { int input_picture_number; ///< used to set pic->display_picture_number int coded_picture_number; ///< used to set pic->coded_picture_number + MPVPicture *input_picture[MPVENC_MAX_B_FRAMES + 1]; ///< next pictures in display order + MPVPicture *reordered_input_picture[MPVENC_MAX_B_FRAMES + 1]; ///< next pictures in coded order + int64_t user_specified_pts; ///< last non-zero pts from user-supplied AVFrame /** * pts difference between the first and second input frame, used for -- 2.45.2