PR #25668 opened by romainhedouin URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25668 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25668.patch
The scratch buffer for the reordered and predicted pixels was allocated for every block and only freed when the encoder is closed, although it is only used inside the iteration of one block. Use one buffer per codec context instead (each frame thread has its own context). Only -compression rle, zip1 and zip16 allocate it. The output is byte-identical: the framemd5 of 2088 test cells (8 sizes from 1x1 to 1921x1081, 3 pixel formats, 4 compression modes, float/half, 1/2/8 threads, smooth/constant/real/random content) is the same before and after with Apple clang and GCC 16, and fate-lavf-*.exr passes. | float, gbrpf32le | RAM before | RAM after | CPU before | CPU after | |---|---|---|---|---| | 1080p zip16, 1 thread | 233 MiB | 208 MiB | 3.39 s | 3.43 s | | 1080p zip1, 1 thread | 376 MiB | 347 MiB | 3.12 s | 2.97 s | | 1080p rle, 1 thread | 435 MiB | 406 MiB | 2.59 s | 2.56 s | | 1080p zip16, 8 threads | 1033 MiB | 833 MiB | 9.28 s | 9.26 s | | 4K zip16, 8 threads | 4082 MiB | 3274 MiB | 30.1 s | 29.9 s | | 1080p none, 1 thread (control) | 340 MiB | 340 MiB | 2.66 s | 2.66 s | Noticed during a review sweep of ffmpeg using an LLM. Signed-off-by: romainhedouin <[email protected]> <!-- If this PR requires new FATE test samples, attach them to the PR and list their target paths below (relative to the fate-suite root). Attached filenames must match the sample's filename: ```fate-samples # e.g. vorbis/new-sample.ogg ``` --> >From 64efd92118e4b65bc5ce370e7ce97bcf72e70da6 Mon Sep 17 00:00:00 2001 From: romainhedouin <[email protected]> Date: Sun, 1 Nov 2026 22:10:26 +0100 Subject: [PATCH] avcodec/exrenc: use one scratch buffer for all blocks The scratch buffer for the reordered and predicted pixels was allocated for every block and kept until the encoder is closed, although it is only used inside the iteration of one block. Use one buffer per context instead. The output is unchanged. Noticed during a review sweep of ffmpeg using an LLM. Signed-off-by: romainhedouin <[email protected]> --- libavcodec/exrenc.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libavcodec/exrenc.c b/libavcodec/exrenc.c index 68eb683aa5a..5f27030b2ae 100644 --- a/libavcodec/exrenc.c +++ b/libavcodec/exrenc.c @@ -66,9 +66,6 @@ typedef struct EXRScanlineData { uint8_t *uncompressed_data; unsigned int uncompressed_size; - uint8_t *tmp; - unsigned int tmp_size; - int64_t actual_size; } EXRScanlineData; @@ -87,6 +84,9 @@ typedef struct EXRContext { EXRScanlineData *scanline; + uint8_t *tmp; + unsigned int tmp_size; + Float2HalfTables f2h_tables; } EXRContext; @@ -145,12 +145,12 @@ static av_cold int encode_close(AVCodecContext *avctx) for (int y = 0; y < s->nb_scanlines && s->scanline; y++) { EXRScanlineData *scanline = &s->scanline[y]; - av_freep(&scanline->tmp); av_freep(&scanline->compressed_data); av_freep(&scanline->uncompressed_data); } av_freep(&s->scanline); + av_freep(&s->tmp); return 0; } @@ -231,8 +231,8 @@ static int encode_scanline_rle(EXRContext *s, const AVFrame *frame) if (!scanline->uncompressed_data) return AVERROR(ENOMEM); - av_fast_padded_malloc(&scanline->tmp, &scanline->tmp_size, tmp_size); - if (!scanline->tmp) + av_fast_padded_malloc(&s->tmp, &s->tmp_size, tmp_size); + if (!s->tmp) return AVERROR(ENOMEM); av_fast_padded_malloc(&scanline->compressed_data, &scanline->compressed_size, max_compressed_size); @@ -260,11 +260,11 @@ static int encode_scanline_rle(EXRContext *s, const AVFrame *frame) break; } - reorder_pixels(scanline->tmp, scanline->uncompressed_data, tmp_size); - predictor(scanline->tmp, tmp_size); + reorder_pixels(s->tmp, scanline->uncompressed_data, tmp_size); + predictor(s->tmp, tmp_size); scanline->actual_size = rle_compress(scanline->compressed_data, max_compressed_size, - scanline->tmp, tmp_size); + s->tmp, tmp_size); if (scanline->actual_size <= 0 || scanline->actual_size >= tmp_size) { FFSWAP(uint8_t *, scanline->uncompressed_data, scanline->compressed_data); @@ -291,8 +291,8 @@ static int encode_scanline_zip(EXRContext *s, const AVFrame *frame) if (!scanline->uncompressed_data) return AVERROR(ENOMEM); - av_fast_padded_malloc(&scanline->tmp, &scanline->tmp_size, tmp_size); - if (!scanline->tmp) + av_fast_padded_malloc(&s->tmp, &s->tmp_size, tmp_size); + if (!s->tmp) return AVERROR(ENOMEM); av_fast_padded_malloc(&scanline->compressed_data, &scanline->compressed_size, max_compressed_size); @@ -329,12 +329,12 @@ static int encode_scanline_zip(EXRContext *s, const AVFrame *frame) break; } - reorder_pixels(scanline->tmp, scanline->uncompressed_data, tmp_size); - predictor(scanline->tmp, tmp_size); + reorder_pixels(s->tmp, scanline->uncompressed_data, tmp_size); + predictor(s->tmp, tmp_size); source_size = tmp_size; actual_size = max_compressed_size; compress(scanline->compressed_data, &actual_size, - scanline->tmp, source_size); + s->tmp, source_size); scanline->actual_size = actual_size; if (scanline->actual_size >= tmp_size) { -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
