]> git.sesse.net Git - ffmpeg/commitdiff
apedec: add ability to check CRC
authorLynne <dev@lynne.ee>
Wed, 6 Mar 2019 11:01:01 +0000 (11:01 +0000)
committerLynne <dev@lynne.ee>
Tue, 26 May 2020 09:23:06 +0000 (10:23 +0100)
The CRC flag is only signalled once every few minutes but CRC is still
always present so the patch uses the file version instead.
CRC on 24-bit files wants non-padded samples so skip such files.
Some corrupt samples may have been output before the final check
depending on the -max_samples setting.

libavcodec/apedec.c

index 2d1925018eb47bcc1bd5da45a3d3fec8cac0446e..65c07d0f7f723e0fd22cf5254aa3a1e79115d49f 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "libavutil/avassert.h"
 #include "libavutil/channel_layout.h"
+#include "libavutil/crc.h"
 #include "libavutil/opt.h"
 #include "lossless_audiodsp.h"
 #include "avcodec.h"
@@ -147,7 +148,8 @@ typedef struct APEContext {
     int fset;                                ///< which filter set to use (calculated from compression level)
     int flags;                               ///< global decoder flags
 
-    uint32_t CRC;                            ///< frame CRC
+    uint32_t CRC;                            ///< signalled frame CRC
+    uint32_t CRC_state;                      ///< accumulated CRC
     int frameflags;                          ///< frame flags
     APEPredictor predictor;                  ///< predictor used for final reconstruction
 
@@ -750,6 +752,7 @@ static int init_entropy_decoder(APEContext *ctx)
 
     /* Read the frame flags if they exist */
     ctx->frameflags = 0;
+    ctx->CRC_state = UINT32_MAX;
     if ((ctx->fileversion > 3820) && (ctx->CRC & 0x80000000)) {
         ctx->CRC &= ~0x80000000;
 
@@ -1577,6 +1580,27 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data,
 
     s->samples -= blockstodecode;
 
+    if (avctx->err_recognition & AV_EF_CRCCHECK &&
+        s->fileversion >= 3900 && s->bps < 24) {
+        uint32_t crc = s->CRC_state;
+        const AVCRC *crc_tab = av_crc_get_table(AV_CRC_32_IEEE_LE);
+        for (i = 0; i < blockstodecode; i++) {
+            for (ch = 0; ch < s->channels; ch++) {
+                uint8_t *smp = frame->data[ch] + (i*(s->bps >> 3));
+                crc = av_crc(crc_tab, crc, smp, s->bps >> 3);
+            }
+        }
+
+        if (!s->samples && (~crc >> 1) ^ s->CRC) {
+            av_log(avctx, AV_LOG_ERROR, "CRC mismatch! Previously decoded "
+                   "frames may have been affected as well.\n");
+            if (avctx->err_recognition & AV_EF_EXPLODE)
+                return AVERROR_INVALIDDATA;
+        }
+
+        s->CRC_state = crc;
+    }
+
     *got_frame_ptr = 1;
 
     return !s->samples ? avpkt->size : 0;