summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Melanson <mike@multimedia.cx>2004-10-12 12:47:49 +0000
committerMike Melanson <mike@multimedia.cx>2004-10-12 12:47:49 +0000
commitb3bfb29980ba16d8b8553d7f52f00fe477b79251 (patch)
tree61e860fb7f7d8d7d7f3ab923a98f04076cd71486
parent8bcb147f54f25126476587205ee8374bed4e39dc (diff)
Creative ADPCM decoder, format 0x200, courtesy of Konstantin Shishkov
Originally committed as revision 3589 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r--Changelog1
-rw-r--r--doc/ffmpeg-doc.texi1
-rw-r--r--libavcodec/adpcm.c56
-rw-r--r--libavcodec/allcodecs.c1
-rw-r--r--libavcodec/avcodec.h2
-rw-r--r--libavformat/wav.c1
6 files changed, 62 insertions, 0 deletions
diff --git a/Changelog b/Changelog
index 86b467b368..f3c1093ccd 100644
--- a/Changelog
+++ b/Changelog
@@ -3,6 +3,7 @@ version <next>
- IBM Ultimotion (ULTI) video decoder
- Sierra Online audio file demuxer and decoder
- Apple QuickDraw (qdrw) video decoder
+- Creative ADPCM audio decoder
version 0.4.9-pre1:
diff --git a/doc/ffmpeg-doc.texi b/doc/ffmpeg-doc.texi
index d1b80b342c..e3e341256c 100644
--- a/doc/ffmpeg-doc.texi
+++ b/doc/ffmpeg-doc.texi
@@ -805,6 +805,7 @@ solutions.
@tab used in Sega Dreamcast games
@item Electronic Arts ADPCM @tab @tab X
@tab used in various EA titles
+@item Creative ADPCM @tab @tab X
@item RA144 @tab @tab X
@tab Real 14400 bit/s codec
@item RA288 @tab @tab X
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 0755e24fef..40c2d430ff 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -103,6 +103,11 @@ static int ea_adpcm_table[] = {
3, 4, 7, 8, 10, 11, 0, -1, -3, -4
};
+static int ct_adpcm_table[8] = {
+ 0x00E6, 0x00E6, 0x00E6, 0x00E6,
+ 0x0133, 0x0199, 0x0200, 0x0266
+};
+
/* end of tables */
typedef struct ADPCMChannelStatus {
@@ -361,6 +366,9 @@ static int adpcm_decode_init(AVCodecContext * avctx)
c->status[0].step = c->status[1].step = 0;
switch(avctx->codec->id) {
+ case CODEC_ID_ADPCM_CT:
+ c->status[0].step = c->status[1].step = 511;
+ break;
default:
break;
}
@@ -411,6 +419,37 @@ static inline short adpcm_ms_expand_nibble(ADPCMChannelStatus *c, char nibble)
return (short)predictor;
}
+static inline short adpcm_ct_expand_nibble(ADPCMChannelStatus *c, char nibble)
+{
+ int predictor;
+ int sign, delta, diff;
+ int new_step;
+
+ sign = nibble & 8;
+ delta = nibble & 7;
+ /* perform direct multiplication instead of series of jumps proposed by
+ * the reference ADPCM implementation since modern CPUs can do the mults
+ * quickly enough */
+ diff = ((2 * delta + 1) * c->step) >> 3;
+ predictor = c->predictor;
+ /* predictor update is not so trivial: predictor is multiplied on 254/256 before updating */
+ if(sign)
+ predictor = ((predictor * 254) >> 8) - diff;
+ else
+ predictor = ((predictor * 254) >> 8) + diff;
+ /* calculate new step and clamp it to range 511..32767 */
+ new_step = (ct_adpcm_table[nibble & 7] * c->step) >> 8;
+ c->step = new_step;
+ if(c->step < 511)
+ c->step = 511;
+ if(c->step > 32767)
+ c->step = 32767;
+
+ CLAMP_TO_SHORT(predictor);
+ c->predictor = predictor;
+ return (short)predictor;
+}
+
static void xa_decode(short *out, const unsigned char *in,
ADPCMChannelStatus *left, ADPCMChannelStatus *right, int inc)
{
@@ -840,6 +879,22 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
src++;
}
break;
+ case CODEC_ID_ADPCM_CT:
+ while (src < buf + buf_size) {
+ if (st) {
+ *samples++ = adpcm_ct_expand_nibble(&c->status[0],
+ (src[0] >> 4) & 0x0F);
+ *samples++ = adpcm_ct_expand_nibble(&c->status[1],
+ src[0] & 0x0F);
+ } else {
+ *samples++ = adpcm_ct_expand_nibble(&c->status[0],
+ (src[0] >> 4) & 0x0F);
+ *samples++ = adpcm_ct_expand_nibble(&c->status[0],
+ src[0] & 0x0F);
+ }
+ src++;
+ }
+ break;
default:
return -1;
}
@@ -895,5 +950,6 @@ ADPCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm);
ADPCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
ADPCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
ADPCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
+ADPCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
#undef ADPCM_CODEC
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index f6ab7d9e1c..b9228c162f 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -223,6 +223,7 @@ PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726);
+PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
#undef PCM_CODEC
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 6fb667e960..a1888faf2c 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -128,6 +128,7 @@ enum CodecID {
CODEC_ID_ADPCM_ADX,
CODEC_ID_ADPCM_EA,
CODEC_ID_ADPCM_G726,
+ CODEC_ID_ADPCM_CT,
/* AMR */
CODEC_ID_AMR_NB,
@@ -1916,6 +1917,7 @@ PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726);
+PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
#undef PCM_CODEC
diff --git a/libavformat/wav.c b/libavformat/wav.c
index 0bc3c3408b..50d8593ff3 100644
--- a/libavformat/wav.c
+++ b/libavformat/wav.c
@@ -38,6 +38,7 @@ const CodecTag codec_wav_tags[] = {
{ CODEC_ID_VORBIS, ('V'<<8)+'o' }, //HACK/FIXME, does vorbis in WAV/AVI have an (in)official id?
{ CODEC_ID_SONIC, 0x2048 },
{ CODEC_ID_SONIC_LS, 0x2048 },
+ { CODEC_ID_ADPCM_CT, 0x200 },
{ 0, 0 },
};