PR #23642 opened by Niklas Haas (haasn)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23642
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23642.patch


>From 193f371efed20d31ccf7d9c4df2db743b0af86c9 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Mon, 29 Jun 2026 17:35:13 +0200
Subject: [PATCH 1/2] avformat/shared: increase CRC size to 32-bits

This increases the amount of corrupted data we can correctly detect
as corrupted from (on average) 2 GiB to 128 TiB, at the default 32 KiB block
size.

Sponsored-by: nxtedition AB
Signed-off-by: Niklas Haas <[email protected]>
---
 libavformat/shared.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/libavformat/shared.c b/libavformat/shared.c
index 7c8b17350c..0c99867796 100644
--- a/libavformat/shared.c
+++ b/libavformat/shared.c
@@ -79,7 +79,7 @@ static int hash_uri(uint8_t hash[HASH_SIZE], const char *uri)
 }
 
 #define HEADER_MAGIC   MKTAG(u'\xFF', 'S', 'h', '$')
-#define HEADER_VERSION 2
+#define HEADER_VERSION 3
 
 enum BlockState {
     /* Reserved block state values */
@@ -93,9 +93,9 @@ enum BlockState {
      */
 };
 
-static uint16_t get_block_crc(const uint8_t *block, size_t block_size)
+static uint32_t get_block_crc(const uint8_t *block, size_t block_size)
 {
-    uint16_t crc = av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, block, 
block_size);
+    uint32_t crc = av_crc(av_crc_get_table(AV_CRC_32_ANSI), 0, block, 
block_size);
     switch (crc) {
     case BLOCK_NONE:
     case BLOCK_FAILED:
@@ -107,7 +107,7 @@ static uint16_t get_block_crc(const uint8_t *block, size_t 
block_size)
 }
 
 typedef struct Block {
-    atomic_ushort state; /* enum BlockState */
+    atomic_uint state; /* enum BlockState */
 } Block;
 
 typedef struct Spacemap {
@@ -601,7 +601,7 @@ static int shared_read(URLContext *h, unsigned char *buf, 
int size)
         return ret;
 
     Block *const block = &s->spacemap->blocks[block_id];
-    unsigned short state = atomic_load_explicit(&block->state, 
memory_order_acquire);
+    unsigned state = atomic_load_explicit(&block->state, memory_order_acquire);
     int64_t pending_since = 0;
     int verify_read = 0, is_race = 0;
 
@@ -622,10 +622,10 @@ retry:
             }
         }
 
-        uint16_t crc = get_block_crc(tmp, block_size);
+        uint32_t crc = get_block_crc(tmp, block_size);
         if (crc != state) {
             av_log(h, AV_LOG_ERROR, "Cache corruption detected for block 
0x%"PRIx64" at "
-                   "offset 0x%"PRIx64": expected CRC: 0x%04X, got: 0x%04X\n",
+                   "offset 0x%"PRIx64": expected CRC: 0x%08X, got: 0x%08X\n",
                    block_id, block_pos, state, crc);
             return AVERROR(EIO);
         }
@@ -786,9 +786,9 @@ retry:
                                                     memory_order_relaxed,
                                                     memory_order_relaxed);
         } else {
-            uint16_t crc = get_block_crc(tmp, bytes_read);
+            uint32_t crc = get_block_crc(tmp, bytes_read);
             av_log(h, AV_LOG_TRACE, "Cached %d bytes to block 0x%"PRIx64" at "
-                   "offset 0x%"PRIx64", CRC 0x%04X\n", bytes_read, block_id,
+                   "offset 0x%"PRIx64", CRC 0x%08X\n", bytes_read, block_id,
                    block_pos, crc);
             atomic_store_explicit(&block->state, crc, memory_order_release);
         }
-- 
2.52.0


>From 46ed278fad7cd527081651a9c9cd39202ae51620 Mon Sep 17 00:00:00 2001
From: Niklas Haas <[email protected]>
Date: Mon, 29 Jun 2026 17:56:24 +0200
Subject: [PATCH 2/2] avformat/shared: add -retry_corrupt option

Similar to -retry_failed, this retries blocks whose only crime is failing
the CRC self-check.

Sponsored-by: nxtedition AB
Signed-off-by: Niklas Haas <[email protected]>
---
 doc/protocols.texi   |  5 +++++
 libavformat/shared.c | 12 +++++++++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/doc/protocols.texi b/doc/protocols.texi
index 5f8cc8094d..d51c12d6f8 100644
--- a/doc/protocols.texi
+++ b/doc/protocols.texi
@@ -1621,6 +1621,11 @@ If true (the default), transient read errors from the 
underlying input stream
 are ignored and retried again. If false, any blocks that previously failed
 being read from will be treated as permanently inaccessible.
 
+@item retry_corrupt
+If true (the default), blocks whose contents fail the CRC integrity check are
+re-fetched from the underlying input stream, overwriting the corrupt cached
+data. If false, cache corruption is treated as a fatal read error.
+
 @end table
 
 URL Syntax is
diff --git a/libavformat/shared.c b/libavformat/shared.c
index 0c99867796..96b0d8080b 100644
--- a/libavformat/shared.c
+++ b/libavformat/shared.c
@@ -152,6 +152,7 @@ typedef struct SharedContext {
     int read_only;
     int64_t timeout;
     int retry_errors;
+    int retry_corrupt;
     int verify;
 
     /* misc state */
@@ -627,6 +628,8 @@ retry:
             av_log(h, AV_LOG_ERROR, "Cache corruption detected for block 
0x%"PRIx64" at "
                    "offset 0x%"PRIx64": expected CRC: 0x%08X, got: 0x%08X\n",
                    block_id, block_pos, state, crc);
+            if (s->retry_corrupt)
+                goto read_block;
             return AVERROR(EIO);
         }
 
@@ -643,9 +646,11 @@ retry:
         return size;
 
     case BLOCK_FAILED:
-        if (!s->retry_errors)
-            return AVERROR(EIO);
-        av_fallthrough;
+        if (s->retry_errors)
+            goto read_block;
+        return AVERROR(EIO);
+
+read_block:
     case BLOCK_NONE:
         if (s->read_only)
             break; /* don't mark block as pending */
@@ -874,6 +879,7 @@ static const AVOption options[] = {
     { "cache_verify",   "Verify correctness of the cache against the source",  
 OFFSET(verify),     AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, .flags = D },
     { "cache_timeout",  "Time in us to wait before re-fetching pending 
blocks", OFFSET(timeout),    AV_OPT_TYPE_INT64, {.i64 = 10000}, 0, INT64_MAX, 
.flags = D },
     { "retry_errors",   "Re-request blocks even if they previously failed", 
OFFSET(retry_errors),   AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, .flags = D },
+    { "retry_corrupt",  "Re-request blocks that fail the CRC check",        
OFFSET(retry_corrupt),  AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, .flags = D },
     {0},
 };
 
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to