diff options
author | Mike Melanson <mike@multimedia.cx> | 2004-10-12 12:47:49 +0000 |
---|---|---|
committer | Mike Melanson <mike@multimedia.cx> | 2004-10-12 12:47:49 +0000 |
commit | b3bfb29980ba16d8b8553d7f52f00fe477b79251 (patch) | |
tree | 61e860fb7f7d8d7d7f3ab923a98f04076cd71486 /libavcodec | |
parent | 8bcb147f54f25126476587205ee8374bed4e39dc (diff) | |
download | ffmpeg-b3bfb29980ba16d8b8553d7f52f00fe477b79251.tar.gz |
Creative ADPCM decoder, format 0x200, courtesy of Konstantin Shishkov
Originally committed as revision 3589 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/adpcm.c | 56 | ||||
-rw-r--r-- | libavcodec/allcodecs.c | 1 | ||||
-rw-r--r-- | libavcodec/avcodec.h | 2 |
3 files changed, 59 insertions, 0 deletions
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 |