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]

Reply via email to