PR #21705 opened by mkver URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21705 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21705.patch
>From 2bf4e2773d81cbe518c814f27e9eaad536fe8a43 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Mon, 9 Feb 2026 14:33:01 +0100 Subject: [PATCH 1/9] avcodec/snow: Only allocate emu_edge_buffer for encoder Also allocate it during init and move it to the encoder's context. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/snow.c | 6 +----- libavcodec/snow.h | 1 - libavcodec/snowenc.c | 9 ++++++++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libavcodec/snow.c b/libavcodec/snow.c index 006d84d8ce..094b893c96 100644 --- a/libavcodec/snow.c +++ b/libavcodec/snow.c @@ -540,10 +540,7 @@ int ff_snow_common_init_after_header(AVCodecContext *avctx) { int plane_index, level, orientation; if(!s->scratchbuf) { - int emu_buf_size; - emu_buf_size = FFMAX(s->mconly_picture->linesize[0], 2*avctx->width+256) * (2 * MB_SIZE + HTAPS_MAX - 1); - if (!FF_ALLOCZ_TYPED_ARRAY(s->scratchbuf, FFMAX(s->mconly_picture->linesize[0], 2*avctx->width+256) * 7 * MB_SIZE) || - !FF_ALLOCZ_TYPED_ARRAY(s->emu_edge_buffer, emu_buf_size)) + if (!FF_ALLOCZ_TYPED_ARRAY(s->scratchbuf, FFMAX(s->mconly_picture->linesize[0], 2*avctx->width+256) * 7 * MB_SIZE)) return AVERROR(ENOMEM); } @@ -642,7 +639,6 @@ av_cold void ff_snow_common_end(SnowContext *s) av_freep(&s->block); av_freep(&s->scratchbuf); - av_freep(&s->emu_edge_buffer); for(i=0; i<MAX_REF_FRAMES; i++){ av_frame_free(&s->last_picture[i]); diff --git a/libavcodec/snow.h b/libavcodec/snow.h index 83dc6c1256..82417c3324 100644 --- a/libavcodec/snow.h +++ b/libavcodec/snow.h @@ -168,7 +168,6 @@ typedef struct SnowContext{ slice_buffer sb; uint8_t *scratchbuf; - uint8_t *emu_edge_buffer; AVMotionVector *avmv; unsigned avmv_size; diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 68c2bb2ebc..79bd2763fe 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -68,6 +68,8 @@ typedef struct SnowEncContext { uint64_t encoding_error[SNOW_MAX_PLANES]; + uint8_t *emu_edge_buffer; + IDWTELEM obmc_scratchpad[MB_SIZE * MB_SIZE * 12 * 2]; } SnowEncContext; @@ -286,6 +288,10 @@ static av_cold int encode_init(AVCodecContext *avctx) if ((ret = get_encode_buffer(s, s->input_picture)) < 0) return ret; + enc->emu_edge_buffer = av_calloc(avctx->width + 128, 2 * (2 * MB_SIZE + HTAPS_MAX - 1)); + if (!enc->emu_edge_buffer) + return AVERROR(ENOMEM); + if (enc->motion_est == FF_ME_ITER) { int size= s->b_width * s->b_height << 2*s->block_max_depth; for(i=0; i<s->max_ref_frames; i++){ @@ -770,7 +776,7 @@ static int get_block_rd(SnowEncContext *enc, int mb_x, int mb_y, const uint8_t *src = s->input_picture->data[plane_index]; IDWTELEM *pred = enc->obmc_scratchpad + plane_index * block_size * block_size * 4; uint8_t *cur = s->scratchbuf; - uint8_t *tmp = s->emu_edge_buffer; + uint8_t *tmp = enc->emu_edge_buffer; const int b_stride = s->b_width << s->block_max_depth; const int b_height = s->b_height<< s->block_max_depth; const int w= p->width; @@ -2091,6 +2097,7 @@ static av_cold int encode_end(AVCodecContext *avctx) enc->m.s.me.temp = NULL; av_freep(&enc->m.s.me.scratchpad); + av_freep(&enc->emu_edge_buffer); av_freep(&avctx->stats_out); -- 2.52.0 >From 6514960155bc07417de5041b60828ec4d7299bf5 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Mon, 9 Feb 2026 14:56:57 +0100 Subject: [PATCH 2/9] avcodec/snowenc: Don't pretend spatial_decomposition_count to change It depends only upon the dimensions and the pixel format, neither of which can change for an encoder. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/snowenc.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 79bd2763fe..b4ccf9c0b4 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -281,6 +281,17 @@ static av_cold int encode_init(AVCodecContext *avctx) if (ret) return ret; + s->spatial_decomposition_count = 5; + + while( !(avctx->width >>(s->chroma_h_shift + s->spatial_decomposition_count)) + || !(avctx->height>>(s->chroma_v_shift + s->spatial_decomposition_count))) + s->spatial_decomposition_count--; + + if (s->spatial_decomposition_count <= 0) { + av_log(avctx, AV_LOG_ERROR, "Resolution too low\n"); + return AVERROR(EINVAL); + } + s->input_picture = av_frame_alloc(); if (!s->input_picture) return AVERROR(ENOMEM); @@ -1634,12 +1645,7 @@ static void encode_header(SnowContext *s){ put_symbol(&s->c, s->header_state, FFABS(p->hcoeff[i]), 0); } } - if(s->last_spatial_decomposition_count != s->spatial_decomposition_count){ - put_rac(&s->c, s->header_state, 1); - put_symbol(&s->c, s->header_state, s->spatial_decomposition_count, 0); - encode_qlogs(s); - }else - put_rac(&s->c, s->header_state, 0); + put_rac(&s->c, s->header_state, 0); } put_symbol(&s->c, s->header_state, s->spatial_decomposition_type - s->last_spatial_decomposition_type, 1); @@ -1892,18 +1898,6 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, } redo_frame: - - s->spatial_decomposition_count= 5; - - while( !(width >>(s->chroma_h_shift + s->spatial_decomposition_count)) - || !(height>>(s->chroma_v_shift + s->spatial_decomposition_count))) - s->spatial_decomposition_count--; - - if (s->spatial_decomposition_count <= 0) { - av_log(avctx, AV_LOG_ERROR, "Resolution too low\n"); - return AVERROR(EINVAL); - } - mpv->c.pict_type = pic->pict_type; s->qbias = pic->pict_type == AV_PICTURE_TYPE_P ? 2 : 0; -- 2.52.0 >From 7651d40da6895d09104963e1bfc812f9cbe0ad1b Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Mon, 9 Feb 2026 15:15:01 +0100 Subject: [PATCH 3/9] avcodec/snowenc: Call ff_snow_common_init_after_header() earlier Namely in encode_init(). It only needs the dimensions, pixel format and spatial_decomposition_count, all of which are known during init. Also check the return value. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/snowenc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index b4ccf9c0b4..4bfa8e1bac 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -292,6 +292,10 @@ static av_cold int encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } + ret = ff_snow_common_init_after_header(avctx); + if (ret < 0) + return ret; + s->input_picture = av_frame_alloc(); if (!s->input_picture) return AVERROR(ENOMEM); @@ -1901,8 +1905,6 @@ redo_frame: mpv->c.pict_type = pic->pict_type; s->qbias = pic->pict_type == AV_PICTURE_TYPE_P ? 2 : 0; - ff_snow_common_init_after_header(avctx); - if(s->last_spatial_decomposition_count != s->spatial_decomposition_count){ for(plane_index=0; plane_index < s->nb_planes; plane_index++){ calculate_visual_weight(s, &s->plane[plane_index]); -- 2.52.0 >From 5e69acdea24a7341ad303d763261c5e3352bba94 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Mon, 9 Feb 2026 15:20:25 +0100 Subject: [PATCH 4/9] avcodec/snow: Rename ff_snow_common_init_after_header->secondary_init It needs information found in the header, but for an encoder this information is available before writing the header. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/snow.c | 3 ++- libavcodec/snow.h | 7 ++++++- libavcodec/snowdec.c | 3 ++- libavcodec/snowenc.c | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/libavcodec/snow.c b/libavcodec/snow.c index 094b893c96..501df57dfc 100644 --- a/libavcodec/snow.c +++ b/libavcodec/snow.c @@ -535,7 +535,8 @@ av_cold int ff_snow_common_init(AVCodecContext *avctx){ return 0; } -int ff_snow_common_init_after_header(AVCodecContext *avctx) { +int ff_snow_secondary_init(AVCodecContext *avctx) +{ SnowContext *s = avctx->priv_data; int plane_index, level, orientation; diff --git a/libavcodec/snow.h b/libavcodec/snow.h index 82417c3324..14da1201be 100644 --- a/libavcodec/snow.h +++ b/libavcodec/snow.h @@ -182,7 +182,12 @@ extern int ff_scale_mv_ref[MAX_REF_FRAMES][MAX_REF_FRAMES]; /* common code */ int ff_snow_common_init(AVCodecContext *avctx); -int ff_snow_common_init_after_header(AVCodecContext *avctx); +/** + * Needs the dimensions, pixel format related properties + * and spatial_decomposition_count to be set; i.e. for a decoder, + * it can be called after parsing the header. + */ +int ff_snow_secondary_init(AVCodecContext *avctx); void ff_snow_common_end(SnowContext *s); void ff_snow_reset_contexts(SnowContext *s); int ff_snow_alloc_blocks(SnowContext *s); diff --git a/libavcodec/snowdec.c b/libavcodec/snowdec.c index c16e824c73..2e941d2d61 100644 --- a/libavcodec/snowdec.c +++ b/libavcodec/snowdec.c @@ -615,7 +615,8 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, return AVERROR_INVALIDDATA; } - if ((res=ff_snow_common_init_after_header(avctx)) < 0) + res = ff_snow_secondary_init(avctx); + if (res < 0) return res; // realloc slice buffer for the case that spatial_decomposition_count changed diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 4bfa8e1bac..85fdd6ee06 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -292,7 +292,7 @@ static av_cold int encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ret = ff_snow_common_init_after_header(avctx); + ret = ff_snow_secondary_init(avctx); if (ret < 0) return ret; -- 2.52.0 >From 9a5efd5d4a15bf570ee43940455807243a4f44be Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Mon, 9 Feb 2026 15:30:53 +0100 Subject: [PATCH 5/9] avcodec/snowenc: Move calculate_visual_weight() up Will avoid a forward declaration in the next commit. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/snowenc.c | 60 ++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 85fdd6ee06..ae807436c6 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -73,6 +73,36 @@ typedef struct SnowEncContext { IDWTELEM obmc_scratchpad[MB_SIZE * MB_SIZE * 12 * 2]; } SnowEncContext; +static void calculate_visual_weight(SnowContext *s, Plane *p) +{ + int width = p->width; + int height = p->height; + + for (int level = 0; level < s->spatial_decomposition_count; ++level) { + int64_t error = 0; + for (int orientation = level ? 1 : 0; orientation < 4; ++orientation) { + SubBand *b = &p->band[level][orientation]; + IDWTELEM *ibuf = b->ibuf; + + memset(s->spatial_idwt_buffer, 0, sizeof(*s->spatial_idwt_buffer)*width*height); + ibuf[b->width/2 + b->height/2*b->stride]= 256*16; + ff_spatial_idwt(s->spatial_idwt_buffer, s->temp_idwt_buffer, width, height, width, s->spatial_decomposition_type, s->spatial_decomposition_count); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + int64_t d = s->spatial_idwt_buffer[x + y*width]*16; + error += d*d; + } + } + if (orientation == 2) + error /= 2; + b->qlog = (int)(QROOT * log2(352256.0/sqrt(error)) + 0.5); + if (orientation != 1) + error = 0; + } + p->band[level][1].qlog = p->band[level][2].qlog; + } +} + static void init_ref(MotionEstContext *c, const uint8_t *const src[3], uint8_t *const ref[3], uint8_t *const ref2[3], int x, int y, int ref_index) @@ -1738,36 +1768,6 @@ static int ratecontrol_1pass(SnowEncContext *enc, AVFrame *pict) return delta_qlog; } -static void calculate_visual_weight(SnowContext *s, Plane *p){ - int width = p->width; - int height= p->height; - int level, orientation, x, y; - - for(level=0; level<s->spatial_decomposition_count; level++){ - int64_t error=0; - for(orientation=level ? 1 : 0; orientation<4; orientation++){ - SubBand *b= &p->band[level][orientation]; - IDWTELEM *ibuf= b->ibuf; - - memset(s->spatial_idwt_buffer, 0, sizeof(*s->spatial_idwt_buffer)*width*height); - ibuf[b->width/2 + b->height/2*b->stride]= 256*16; - ff_spatial_idwt(s->spatial_idwt_buffer, s->temp_idwt_buffer, width, height, width, s->spatial_decomposition_type, s->spatial_decomposition_count); - for(y=0; y<height; y++){ - for(x=0; x<width; x++){ - int64_t d= s->spatial_idwt_buffer[x + y*width]*16; - error += d*d; - } - } - if (orientation == 2) - error /= 2; - b->qlog= (int)(QROOT * log2(352256.0/sqrt(error)) + 0.5); - if (orientation != 1) - error = 0; - } - p->band[level][1].qlog = p->band[level][2].qlog; - } -} - static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { -- 2.52.0 >From e5cf5fecafc2efd569a5bf97cc9ef52c0e7a0da5 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Mon, 9 Feb 2026 15:34:02 +0100 Subject: [PATCH 6/9] avcodec/snowenc: Calculate visual weight during init Everything that is needed to do so is already known during init. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/snowenc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index ae807436c6..a1fb531103 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -326,6 +326,9 @@ static av_cold int encode_init(AVCodecContext *avctx) if (ret < 0) return ret; + for (int plane_index = 0; plane_index < s->nb_planes; ++plane_index) + calculate_visual_weight(s, &s->plane[plane_index]); + s->input_picture = av_frame_alloc(); if (!s->input_picture) return AVERROR(ENOMEM); @@ -1905,12 +1908,6 @@ redo_frame: mpv->c.pict_type = pic->pict_type; s->qbias = pic->pict_type == AV_PICTURE_TYPE_P ? 2 : 0; - if(s->last_spatial_decomposition_count != s->spatial_decomposition_count){ - for(plane_index=0; plane_index < s->nb_planes; plane_index++){ - calculate_visual_weight(s, &s->plane[plane_index]); - } - } - encode_header(s); mpv->misc_bits = 8 * (s->c.bytestream - s->c.bytestream_start); encode_blocks(enc, 1); -- 2.52.0 >From 26105f24d67377b89c3b8160e673d885d7a98746 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Mon, 9 Feb 2026 15:35:25 +0100 Subject: [PATCH 7/9] avcodec/snow: Remove last_spatial_decomposition_count Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/snow.h | 1 - libavcodec/snowenc.c | 1 - 2 files changed, 2 deletions(-) diff --git a/libavcodec/snow.h b/libavcodec/snow.h index 14da1201be..dda927966d 100644 --- a/libavcodec/snow.h +++ b/libavcodec/snow.h @@ -136,7 +136,6 @@ typedef struct SnowContext{ int last_spatial_decomposition_type; int temporal_decomposition_type; int spatial_decomposition_count; - int last_spatial_decomposition_count; int temporal_decomposition_count; int max_ref_frames; int ref_frames; diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index a1fb531103..f264997df9 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -1710,7 +1710,6 @@ static void update_last_header_values(SnowContext *s){ s->last_qbias = s->qbias; s->last_mv_scale = s->mv_scale; s->last_block_max_depth = s->block_max_depth; - s->last_spatial_decomposition_count = s->spatial_decomposition_count; } static int qscale2qlog(int qscale){ -- 2.52.0 >From c2bb7c014d6274ac3292502c29a13c7bb0e0db92 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Mon, 10 Oct 2022 02:48:57 +0200 Subject: [PATCH 8/9] avcodec/snowdec: Remove debug code The Snow decoder checks two bits of AVCodecContext.debug via numerical constants, not defines. One of these constants (512) used to be equivalent to FF_DEBUG_PTS which has been removed in 302554835e39b79b977ed60c9afe81b44590dfef (merged in 6e69525e6984d51165de0b17b796bbc29f9dd6e7). It is unlikely that 512 was intended to be FF_DEBUG_PTS, as it has nothing do to with PTS; instead it makes certain parts of the code behave like it does for keyframes even if the current frame is not a keyframe. This behavior started with the very first Snow commit (791e7b83c3ab18f0d00e2ecdb72a3409dfc1ae62) where setting the 512 flag led to skipping of prediction. The two other instances where added in a0d1931c0e6d1a701e1dce791d1955bbaba74ee8 and it appears that this was just a temporary aid for development. Whatever it might have been intended for, it is unused now and potentially dangerous as 512 might be reused in the future. This commit therefore removes said checks. Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/snow.h | 2 +- libavcodec/snowdec.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libavcodec/snow.h b/libavcodec/snow.h index dda927966d..c82414b4fc 100644 --- a/libavcodec/snow.h +++ b/libavcodec/snow.h @@ -363,7 +363,7 @@ static av_always_inline void predict_slice(SnowContext *s, IDWTELEM *buf, int pl int w= p->width; int h= p->height; av_assert2(s->chroma_h_shift == s->chroma_v_shift); // obmc params assume squares - if(s->keyframe || (s->avctx->debug&512)){ + if (s->keyframe) { if(mb_y==mb_h) return; diff --git a/libavcodec/snowdec.c b/libavcodec/snowdec.c index 2e941d2d61..d405acf609 100644 --- a/libavcodec/snowdec.c +++ b/libavcodec/snowdec.c @@ -193,7 +193,7 @@ static av_always_inline void predict_slice_buffered(SnowContext *s, slice_buffer int w= p->width; int h= p->height; - if(s->keyframe || (s->avctx->debug&512)){ + if (s->keyframe) { if(mb_y==mb_h) return; @@ -717,7 +717,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, int slice_starty = block_h*mb_y; int slice_h = block_h*(mb_y+1); - if (!(s->keyframe || s->avctx->debug&512)){ + if (!s->keyframe) { slice_starty = FFMAX(0, slice_starty - (block_h >> 1)); slice_h -= (block_h >> 1); } @@ -732,7 +732,7 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *picture, const int extra= 3; start_y = (mb_y ? ((block_h * our_mb_start) >> (s->spatial_decomposition_count - level)) + s->spatial_decomposition_count - level + extra: 0); end_y = (((block_h * our_mb_end) >> (s->spatial_decomposition_count - level)) + s->spatial_decomposition_count - level + extra); - if (!(s->keyframe || s->avctx->debug&512)){ + if (!s->keyframe) { start_y = FFMAX(0, start_y - (block_h >> (1+s->spatial_decomposition_count - level))); end_y = FFMAX(0, end_y - (block_h >> (1+s->spatial_decomposition_count - level))); } -- 2.52.0 >From 13b91ea036cb9705ebe4290aacc4a5eb2b71b51c Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt <[email protected]> Date: Mon, 9 Feb 2026 17:57:30 +0100 Subject: [PATCH 9/9] avcodec/snow: Reduce sizeof(SnowContext) Each SubBand currently contains an array of 519 uint8_t[32], yet most of these are unused: For both the decoder and the encoder, at most 34 contexts are actually used: The only variable index is context+2, where context is the result of av_log2() and therefore in the 0..31 range. There are also several accesses using compile-time indices, the highest of which is 30. FATE passes with 31 contexts and maybe these are enough, but I don't know. Reducing the number to 34 reduces sizeof(SnowContext) from 2141656B to 155096B here (on x64). Signed-off-by: Andreas Rheinhardt <[email protected]> --- libavcodec/snow.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/snow.h b/libavcodec/snow.h index c82414b4fc..2fd48c1d2c 100644 --- a/libavcodec/snow.h +++ b/libavcodec/snow.h @@ -92,7 +92,7 @@ typedef struct SubBand{ int stride_line; ///< Stride measured in lines, not pixels. x_and_coeff * x_coeff; struct SubBand *parent; - uint8_t state[/*7*2*/ 7 + 512][32]; + uint8_t state[34][32]; }SubBand; typedef struct Plane{ -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
