avcodec/mpegvideo: Allocate ac_val jointly

They are currently allocated separately per slice; allocating them
jointly allows to avoid saving them in ff_update_duplicate_context().

The way it is done also avoids allocating ac_val for encoders that
don't need it (e.g. H.263 or H.263+ with AIC).

This entailed moving setting nb_slices to ff_mpv_init_context_frame()
which is called from ff_mpv_common_frame_size_change(). The resultant
nb_slices will always be one when called from a decoder using
ff_mpv_common_frame_size_change().

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
Andreas Rheinhardt
2025-06-13 06:10:27 +02:00
parent dba1061ba4
commit c4ebe55f94
2 changed files with 52 additions and 44 deletions

View File

@ -120,18 +120,6 @@ static av_cold int init_duplicate_context(MpegEncContext *s)
return AVERROR(ENOMEM);
s->block = s->blocks[0];
if (s->out_format == FMT_H263) {
int mb_height = s->msmpeg4_version == MSMP4_VC1 ?
FFALIGN(s->mb_height, 2) : s->mb_height;
int y_size = s->b8_stride * (2 * mb_height + 1);
int c_size = s->mb_stride * (mb_height + 1);
int yc_size = y_size + 2 * c_size;
/* ac values */
if (!FF_ALLOCZ_TYPED_ARRAY(s->ac_val_base, yc_size))
return AVERROR(ENOMEM);
s->ac_val = s->ac_val_base + s->b8_stride + 1;
}
return 0;
}
@ -171,7 +159,6 @@ static av_cold void free_duplicate_context(MpegEncContext *s)
s->sc.linesize = 0;
av_freep(&s->blocks);
av_freep(&s->ac_val_base);
s->block = NULL;
}
@ -192,7 +179,6 @@ static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src)
COPY(block);
COPY(start_mb_y);
COPY(end_mb_y);
COPY(ac_val_base);
COPY(ac_val);
#undef COPY
}
@ -245,15 +231,34 @@ static av_cold void free_buffer_pools(BufferPoolContext *pools)
av_cold int ff_mpv_init_context_frame(MpegEncContext *s)
{
int nb_slices = (HAVE_THREADS &&
s->avctx->active_thread_type & FF_THREAD_SLICE) ?
s->avctx->thread_count : 1;
BufferPoolContext *const pools = &s->buffer_pools;
int y_size, c_size, yc_size, i, mb_array_size, mv_table_size, x, y;
int mb_height;
if (s->encoding && s->avctx->slices)
nb_slices = s->avctx->slices;
if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && !s->progressive_sequence)
s->mb_height = (s->height + 31) / 32 * 2;
else
s->mb_height = (s->height + 15) / 16;
if (nb_slices > MAX_THREADS || (nb_slices > s->mb_height && s->mb_height)) {
int max_slices;
if (s->mb_height)
max_slices = FFMIN(MAX_THREADS, s->mb_height);
else
max_slices = MAX_THREADS;
av_log(s->avctx, AV_LOG_WARNING, "too many threads/slices (%d),"
" reducing to %d\n", nb_slices, max_slices);
nb_slices = max_slices;
}
s->slice_context_count = nb_slices;
/* VC-1 can change from being progressive to interlaced on a per-frame
* basis. We therefore allocate certain buffers so big that they work
* in both instances. */
@ -332,6 +337,14 @@ av_cold int ff_mpv_init_context_frame(MpegEncContext *s)
}
if (s->h263_pred || s->h263_aic || !s->encoding) {
size_t allslice_yc_size = yc_size * (s->encoding ? nb_slices : 1);
if (s->out_format == FMT_H263) {
/* ac values */
if (!FF_ALLOCZ_TYPED_ARRAY(s->ac_val_base, allslice_yc_size))
return AVERROR(ENOMEM);
s->ac_val = s->ac_val_base + s->b8_stride + 1;
}
/* dc values */
// MN: we need these for error resilience of intra-frames
// Allocating them unconditionally for decoders also means
@ -381,14 +394,8 @@ av_cold int ff_mpv_init_context_frame(MpegEncContext *s)
*/
av_cold int ff_mpv_common_init(MpegEncContext *s)
{
int nb_slices = (HAVE_THREADS &&
s->avctx->active_thread_type & FF_THREAD_SLICE) ?
s->avctx->thread_count : 1;
int ret;
if (s->encoding && s->avctx->slices)
nb_slices = s->avctx->slices;
if (s->avctx->pix_fmt == AV_PIX_FMT_NONE) {
av_log(s->avctx, AV_LOG_ERROR,
"decoding to AV_PIX_FMT_NONE is not supported.\n");
@ -411,20 +418,8 @@ av_cold int ff_mpv_common_init(MpegEncContext *s)
if ((ret = ff_mpv_init_context_frame(s)))
goto fail;
if (nb_slices > MAX_THREADS || (nb_slices > s->mb_height && s->mb_height)) {
int max_slices;
if (s->mb_height)
max_slices = FFMIN(MAX_THREADS, s->mb_height);
else
max_slices = MAX_THREADS;
av_log(s->avctx, AV_LOG_WARNING, "too many threads/slices (%d),"
" reducing to %d\n", nb_slices, max_slices);
nb_slices = max_slices;
}
s->context_initialized = 1;
s->thread_context[0] = s;
s->slice_context_count = nb_slices;
// if (s->width && s->height) {
if (!s->encoding) {
@ -450,6 +445,7 @@ av_cold void ff_mpv_free_context_frame(MpegEncContext *s)
for (int j = 0; j < 2; j++)
s->p_field_mv_table[i][j] = NULL;
av_freep(&s->ac_val_base);
av_freep(&s->dc_val_base);
av_freep(&s->coded_block_base);
av_freep(&s->mbintra_table);

View File

@ -518,24 +518,36 @@ static av_cold int init_slice_buffers(MPVMainEncContext *const m)
static_assert(DCT_ERROR_SIZE * MAX_THREADS + ALIGN - 1 <= SIZE_MAX,
"Need checks for potential overflow.");
unsigned nb_slices = s->c.slice_context_count;
char *dct_error = NULL;
if (!m->noise_reduction)
return 0;
if (m->noise_reduction) {
if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_offset, 2))
return AVERROR(ENOMEM);
dct_error = av_mallocz(ALIGN - 1 + nb_slices * DCT_ERROR_SIZE);
if (!dct_error)
return AVERROR(ENOMEM);
m->dct_error_sum_base = dct_error;
dct_error += FFALIGN((uintptr_t)dct_error, ALIGN) - (uintptr_t)dct_error;
}
if (!FF_ALLOCZ_TYPED_ARRAY(s->dct_offset, 2))
return AVERROR(ENOMEM);
char *dct_error = av_mallocz(ALIGN - 1 + nb_slices * DCT_ERROR_SIZE);
if (!dct_error)
return AVERROR(ENOMEM);
m->dct_error_sum_base = dct_error;
dct_error += FFALIGN((uintptr_t)dct_error, ALIGN) - (uintptr_t)dct_error;
const int y_size = s->c.b8_stride * (2 * s->c.mb_height + 1);
const int c_size = s->c.mb_stride * (s->c.mb_height + 1);
const int yc_size = y_size + 2 * c_size;
ptrdiff_t offset = 0;
for (unsigned i = 0; i < nb_slices; ++i) {
MPVEncContext *const s2 = s->c.enc_contexts[i];
s2->dct_offset = s->dct_offset;
s2->dct_error_sum = (void*)dct_error;
dct_error += DCT_ERROR_SIZE;
if (dct_error) {
s2->dct_offset = s->dct_offset;
s2->dct_error_sum = (void*)dct_error;
dct_error += DCT_ERROR_SIZE;
}
if (s2->c.ac_val) {
s2->c.ac_val += offset;
offset += yc_size;
}
}
return 0;
}