PR #22287 opened by michaelni URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22287 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22287.patch
47720380 decicycles -> 34335598 decicycles >From b14a62a84da87062bf9a1c63e06773b819cbf7b4 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Wed, 25 Feb 2026 16:57:01 +0100 Subject: [PATCH 1/2] avcodec/notchlc: Avoid clearing history in lz4_decompress() instead of clearing history before "byte 0", we error out clearing 64kb takes time, which this commit avoids Benchmark with big_buck_bunny\ NotchLC\ Optimal\ Encoding\ 1920.mov shows no meassurable difference though Signed-off-by: Michael Niedermayer <[email protected]> --- libavcodec/notchlc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libavcodec/notchlc.c b/libavcodec/notchlc.c index c28fddcea0..278499f450 100644 --- a/libavcodec/notchlc.c +++ b/libavcodec/notchlc.c @@ -79,8 +79,9 @@ static int lz4_decompress(AVCodecContext *avctx, PutByteContext *pb) { unsigned reference_pos, delta, pos = 0; - uint8_t history[HISTORY_SIZE] = { 0 }; + uint8_t history[HISTORY_SIZE]; int match_length; + int wraped = 0; while (bytestream2_get_bytes_left(gb) > 0) { uint8_t token = bytestream2_get_byte(gb); @@ -106,6 +107,7 @@ static int lz4_decompress(AVCodecContext *avctx, if (pos == HISTORY_SIZE) { bytestream2_put_buffer(pb, history, HISTORY_SIZE); pos = 0; + wraped = 1; } } } @@ -125,7 +127,13 @@ static int lz4_decompress(AVCodecContext *avctx, match_length += current; } while (current == 255); } - reference_pos = (pos >= delta) ? (pos - delta) : (HISTORY_SIZE + pos - delta); + reference_pos = pos - delta; + if (pos < delta) { + if (!wraped) + return AVERROR_INVALIDDATA; + reference_pos += HISTORY_SIZE; + } + if (pos + match_length < HISTORY_SIZE && reference_pos + match_length < HISTORY_SIZE) { if (pos >= reference_pos + match_length || reference_pos >= pos + match_length) { memcpy(history + pos, history + reference_pos, match_length); @@ -140,6 +148,7 @@ static int lz4_decompress(AVCodecContext *avctx, if (pos == HISTORY_SIZE) { bytestream2_put_buffer(pb, history, HISTORY_SIZE); pos = 0; + wraped = 1; } reference_pos %= HISTORY_SIZE; } -- 2.52.0 >From b889dbc8dc1451b75e4db67c3c3bd7d4eef7e067 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer <[email protected]> Date: Wed, 25 Feb 2026 17:47:11 +0100 Subject: [PATCH 2/2] avcodec/notchlc: lz4_decompress() avoid byte loops, try to work in blocks 47720380 decicycles -> 34335598 decicycles --- libavcodec/notchlc.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/libavcodec/notchlc.c b/libavcodec/notchlc.c index 278499f450..079e821d6c 100644 --- a/libavcodec/notchlc.c +++ b/libavcodec/notchlc.c @@ -98,18 +98,16 @@ static int lz4_decompress(AVCodecContext *avctx, if (bytestream2_get_bytes_left(gb) < num_literals) return AVERROR_INVALIDDATA; - if (pos + num_literals < HISTORY_SIZE) { - bytestream2_get_buffer(gb, history + pos, num_literals); - pos += num_literals; - } else { - while (num_literals-- > 0) { - history[pos++] = bytestream2_get_byte(gb); - if (pos == HISTORY_SIZE) { - bytestream2_put_buffer(pb, history, HISTORY_SIZE); - pos = 0; - wraped = 1; - } + while (num_literals) { + int max_literals = FFMIN(num_literals, HISTORY_SIZE - pos); + bytestream2_get_buffer(gb, history + pos, max_literals); + pos += max_literals; + if (pos == HISTORY_SIZE) { + bytestream2_put_buffer(pb, history, HISTORY_SIZE); + pos = 0; + wraped = 1; } + num_literals -= max_literals; } if (bytestream2_get_bytes_left(gb) <= 0) @@ -134,24 +132,26 @@ static int lz4_decompress(AVCodecContext *avctx, reference_pos += HISTORY_SIZE; } - if (pos + match_length < HISTORY_SIZE && reference_pos + match_length < HISTORY_SIZE) { - if (pos >= reference_pos + match_length || reference_pos >= pos + match_length) { - memcpy(history + pos, history + reference_pos, match_length); - pos += match_length; + while (match_length) { + int max_match; + if (reference_pos > pos) { + max_match = FFMIN(match_length, HISTORY_SIZE - reference_pos); + memmove(history + pos, history + reference_pos, max_match); + pos += max_match; + reference_pos += max_match; + if (reference_pos == HISTORY_SIZE) reference_pos = 0; } else { - while (match_length-- > 0) - history[pos++] = history[reference_pos++]; - } - } else { - while (match_length-- > 0) { - history[pos++] = history[reference_pos++]; + max_match = FFMIN(match_length, HISTORY_SIZE - pos); + av_memcpy_backptr(history + pos, pos - reference_pos, max_match); + pos += max_match; + reference_pos += max_match; if (pos == HISTORY_SIZE) { bytestream2_put_buffer(pb, history, HISTORY_SIZE); pos = 0; wraped = 1; } - reference_pos %= HISTORY_SIZE; } + match_length -= max_match; } } -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
