summaryrefslogtreecommitdiff
path: root/libavcodec/adpcm.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2020-02-14 20:37:42 +0100
committerPaul B Mahol <onemda@gmail.com>2020-02-16 12:54:57 +0100
commitdfb0b9370d3621ab1f603e7bb8e142b1f6996562 (patch)
treec67df7eb8327419f95d485647b353318b666f4f3 /libavcodec/adpcm.c
parent7b7b418277fc36a864f7b8b449feacb39f2dbced (diff)
avcodec: fix pcm zork decoder
Fixes #1939
Diffstat (limited to 'libavcodec/adpcm.c')
-rw-r--r--libavcodec/adpcm.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 0cd28431d7..f5d20ddd81 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -83,6 +83,10 @@ static const int8_t swf_index_tables[4][16] = {
/*5*/ { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 }
};
+static const int8_t zork_index_table[8] = {
+ -1, -1, -1, 1, 4, 7, 10, 12,
+};
+
/* end of tables */
typedef struct ADPCMDecodeContext {
@@ -154,6 +158,10 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
if (avctx->bits_per_coded_sample != 4)
return AVERROR_INVALIDDATA;
break;
+ case AV_CODEC_ID_ADPCM_ZORK:
+ if (avctx->bits_per_coded_sample != 8)
+ return AVERROR_INVALIDDATA;
+ break;
default:
break;
}
@@ -416,6 +424,41 @@ static inline int16_t adpcm_mtaf_expand_nibble(ADPCMChannelStatus *c, uint8_t ni
return c->predictor;
}
+static inline int16_t adpcm_zork_expand_nibble(ADPCMChannelStatus *c, uint8_t nibble)
+{
+ int16_t index = c->step_index;
+ uint32_t lookup_sample = ff_adpcm_step_table[index];
+ int32_t sample = 0;
+
+ if (nibble & 0x40)
+ sample += lookup_sample;
+ if (nibble & 0x20)
+ sample += lookup_sample >> 1;
+ if (nibble & 0x10)
+ sample += lookup_sample >> 2;
+ if (nibble & 0x08)
+ sample += lookup_sample >> 3;
+ if (nibble & 0x04)
+ sample += lookup_sample >> 4;
+ if (nibble & 0x02)
+ sample += lookup_sample >> 5;
+ if (nibble & 0x01)
+ sample += lookup_sample >> 6;
+ if (nibble & 0x80)
+ sample = -sample;
+
+ sample += c->predictor;
+ sample = av_clip_int16(sample);
+
+ index += zork_index_table[(nibble >> 4) & 7];
+ index = av_clip(index, 0, 88);
+
+ c->predictor = sample;
+ c->step_index = index;
+
+ return sample;
+}
+
static int xa_decode(AVCodecContext *avctx, int16_t *out0, int16_t *out1,
const uint8_t *in, ADPCMChannelStatus *left,
ADPCMChannelStatus *right, int channels, int sample_offset)
@@ -780,6 +823,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
case AV_CODEC_ID_ADPCM_PSX:
nb_samples = buf_size / (16 * ch) * 28;
break;
+ case AV_CODEC_ID_ADPCM_ZORK:
+ nb_samples = buf_size / ch;
+ break;
}
/* validate coded sample count */
@@ -1842,6 +1888,19 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
}
}
break;
+ case AV_CODEC_ID_ADPCM_ZORK:
+ if (!c->has_status) {
+ for (channel = 0; channel < avctx->channels; channel++) {
+ c->status[channel].predictor = 0;
+ c->status[channel].step_index = 0;
+ }
+ c->has_status = 1;
+ }
+ for (n = 0; n < nb_samples * avctx->channels; n++) {
+ int v = bytestream2_get_byteu(&gb);
+ *samples++ = adpcm_zork_expand_nibble(&c->status[n % avctx->channels], v);
+ }
+ break;
default:
av_assert0(0); // unsupported codec_id should not happen
}
@@ -1930,3 +1989,4 @@ ADPCM_DECODER(AV_CODEC_ID_ADPCM_THP_LE, sample_fmts_s16p, adpcm_thp_le,
ADPCM_DECODER(AV_CODEC_ID_ADPCM_THP, sample_fmts_s16p, adpcm_thp, "ADPCM Nintendo THP");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_XA, sample_fmts_s16p, adpcm_xa, "ADPCM CDROM XA");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_YAMAHA, sample_fmts_s16, adpcm_yamaha, "ADPCM Yamaha");
+ADPCM_DECODER(AV_CODEC_ID_ADPCM_ZORK, sample_fmts_s16, adpcm_zork, "ADPCM Zork");