mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
Creative ADPCM decoder, format 0x200, courtesy of Konstantin Shishkov
Originally committed as revision 3589 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
8bcb147f54
commit
b3bfb29980
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 },
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user