[FFmpeg-devel] [PATCH] ADPCM AFC decoder
Paul B Mahol
onemda at gmail.com
Mon Nov 19 22:30:42 CET 2012
Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
libavcodec/Makefile | 1 +
libavcodec/adpcm.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
libavcodec/adpcm_data.c | 5 +++++
libavcodec/adpcm_data.h | 1 +
libavcodec/allcodecs.c | 1 +
libavcodec/avcodec.h | 1 +
libavcodec/codec_desc.c | 7 +++++++
libavformat/ast.c | 3 +++
8 files changed, 64 insertions(+)
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 7b3462e..fec7010 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -559,6 +559,7 @@ OBJS-$(CONFIG_PCM_ZORK_DECODER) += pcm.o
OBJS-$(CONFIG_ADPCM_4XM_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o adx.o
OBJS-$(CONFIG_ADPCM_ADX_ENCODER) += adxenc.o adx.o
+OBJS-$(CONFIG_ADPCM_AFC_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_EA_MAXIS_XA_DECODER) += adpcm.o adpcm_data.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 98b65dd..fa4321a 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -145,6 +145,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx)
case AV_CODEC_ID_ADPCM_EA_R3:
case AV_CODEC_ID_ADPCM_EA_XAS:
case AV_CODEC_ID_ADPCM_THP:
+ case AV_CODEC_ID_ADPCM_AFC:
avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
break;
case AV_CODEC_ID_ADPCM_IMA_WS:
@@ -575,6 +576,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb,
*coded_samples -= *coded_samples % 14;
nb_samples = (buf_size - 80) / (8 * ch) * 14;
break;
+ case AV_CODEC_ID_ADPCM_AFC:
+ nb_samples = buf_size / (9 * ch) * 16;
+ break;
case AV_CODEC_ID_ADPCM_XA:
nb_samples = (buf_size / 128) * 224 / ch;
break;
@@ -1232,6 +1236,46 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
*samples++ = adpcm_yamaha_expand_nibble(&c->status[st], v >> 4 );
}
break;
+ case AV_CODEC_ID_ADPCM_AFC:
+ {
+ for (channel = 0; channel < avctx->channels; channel++) {
+ int prev1 = c->status[channel].sample1;
+ int prev2 = c->status[channel].sample2;
+
+ samples = samples_p[channel];
+ /* Read in every sample for this channel. */
+ for (i = 0; i < nb_samples / 16; i++) {
+ int byte = bytestream2_get_byteu(&gb);
+ int scale = 1 << (byte >> 4);
+ int index = byte & 0xf;
+ int factor1 = ff_adpcm_afc_coeffs[0][index];
+ int factor2 = ff_adpcm_afc_coeffs[1][index];
+
+ /* Decode 16 samples. */
+ for (n = 0; n < 16; n++) {
+ int32_t sampledat;
+
+ if (n & 1) {
+ sampledat = sign_extend(byte, 4);
+ } else {
+ byte = bytestream2_get_byteu(&gb);
+ sampledat = sign_extend(byte >> 4, 4);
+ }
+
+ sampledat = ((prev1 * factor1 + prev2 * factor2) +
+ ((sampledat * scale) << 11)) >> 11;
+ *samples = av_clip_int16(sampledat);
+ prev2 = prev1;
+ prev1 = *samples++;
+ }
+ }
+
+ c->status[channel].sample1 = prev1;
+ c->status[channel].sample2 = prev2;
+ }
+ bytestream2_seek(&gb, 0, SEEK_END);
+ break;
+ }
case AV_CODEC_ID_ADPCM_THP:
{
int table[2][16];
@@ -1314,6 +1358,7 @@ AVCodec ff_ ## name_ ## _decoder = { \
/* Note: Do not forget to add new entries to the Makefile as well. */
ADPCM_DECODER(AV_CODEC_ID_ADPCM_4XM, sample_fmts_s16p, adpcm_4xm, "ADPCM 4X Movie");
+ADPCM_DECODER(AV_CODEC_ID_ADPCM_AFC, sample_fmts_s16p, adpcm_afc, "ADPCM Nintendo Gamecube AFC");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_CT, sample_fmts_s16, adpcm_ct, "ADPCM Creative Technology");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA, sample_fmts_s16, adpcm_ea, "ADPCM Electronic Arts");
ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA_MAXIS_XA, sample_fmts_s16, adpcm_ea_maxis_xa, "ADPCM Electronic Arts Maxis CDROM XA");
diff --git a/libavcodec/adpcm_data.c b/libavcodec/adpcm_data.c
index f19d622..fe11644 100644
--- a/libavcodec/adpcm_data.c
+++ b/libavcodec/adpcm_data.c
@@ -76,3 +76,8 @@ const int8_t ff_adpcm_yamaha_difflookup[] = {
1, 3, 5, 7, 9, 11, 13, 15,
-1, -3, -5, -7, -9, -11, -13, -15
};
+
+const int16_t ff_adpcm_afc_coeffs[2][16] = {
+ { 0, 2048, 0, 1024, 4096, 3584, 3072, 4608, 4200, 4800, 5120, 2048, 1024, 64512, 64512, 63488 },
+ { 0, 0, 2048, 1024, 63488, 64000, 64512, 62976, 63288, 63236, 62464, 63488, 64512, 1024, 0, 0 }
+};
diff --git a/libavcodec/adpcm_data.h b/libavcodec/adpcm_data.h
index 97ab66c..24a6909 100644
--- a/libavcodec/adpcm_data.h
+++ b/libavcodec/adpcm_data.h
@@ -35,5 +35,6 @@ extern const uint8_t ff_adpcm_AdaptCoeff1[];
extern const int8_t ff_adpcm_AdaptCoeff2[];
extern const int16_t ff_adpcm_yamaha_indexscale[];
extern const int8_t ff_adpcm_yamaha_difflookup[];
+extern const int16_t ff_adpcm_afc_coeffs[2][16];
#endif /* AVCODEC_ADPCM_DATA_H */
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index e47ff5b..4e7d945 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -386,6 +386,7 @@ void avcodec_register_all(void)
/* ADPCM codecs */
REGISTER_DECODER (ADPCM_4XM, adpcm_4xm);
REGISTER_ENCDEC (ADPCM_ADX, adpcm_adx);
+ REGISTER_DECODER (ADPCM_AFC, adpcm_afc);
REGISTER_DECODER (ADPCM_CT, adpcm_ct);
REGISTER_DECODER (ADPCM_EA, adpcm_ea);
REGISTER_DECODER (ADPCM_EA_MAXIS_XA, adpcm_ea_maxis_xa);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 511cfc6..a458211 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -351,6 +351,7 @@ enum AVCodecID {
AV_CODEC_ID_ADPCM_G722,
AV_CODEC_ID_ADPCM_IMA_APC,
AV_CODEC_ID_VIMA = MKBETAG('V','I','M','A'),
+ AV_CODEC_ID_ADPCM_AFC = MKBETAG('A','F','C',' '),
/* AMR */
AV_CODEC_ID_AMR_NB = 0x12000,
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 2cb2416..0d74cc9 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1750,6 +1750,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA CRYO APC"),
.props = AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_ADPCM_AFC,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_afc",
+ .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo Gamecube AFC"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
/* AMR */
{
diff --git a/libavformat/ast.c b/libavformat/ast.c
index 2027b57..4f83540 100644
--- a/libavformat/ast.c
+++ b/libavformat/ast.c
@@ -43,6 +43,9 @@ static int ast_read_header(AVFormatContext *s)
avio_skip(s->pb, 8);
codec = avio_rb16(s->pb);
switch (codec) {
+ case 0:
+ st->codec->codec_id = AV_CODEC_ID_ADPCM_AFC;
+ break;
case 1:
st->codec->codec_id = AV_CODEC_ID_PCM_S16BE_PLANAR;
break;
--
1.7.11.4
More information about the ffmpeg-devel
mailing list