summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libavcodec/apedec.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/libavcodec/apedec.c b/libavcodec/apedec.c
index 2d1925018e..65c07d0f7f 100644
--- a/libavcodec/apedec.c
+++ b/libavcodec/apedec.c
@@ -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;