diff options
author | Mike Melanson <mike@multimedia.cx> | 2004-02-03 04:27:17 +0000 |
---|---|---|
committer | Mike Melanson <mike@multimedia.cx> | 2004-02-03 04:27:17 +0000 |
commit | 7d8379f2b78e255b6f8c8bee1a6d41cd8340b0a2 (patch) | |
tree | eb90d88365828e11b1e637884b1032ec7fd6183b | |
parent | deb7a6cdafa220ff4d0b986c30bf431be0bbcf0b (diff) | |
download | ffmpeg-7d8379f2b78e255b6f8c8bee1a6d41cd8340b0a2.tar.gz |
added support for EA ADPCM and SMJPEG IMA ADPCM
Originally committed as revision 2744 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | CREDITS | 1 | ||||
-rw-r--r-- | doc/ffmpeg-doc.texi | 4 | ||||
-rw-r--r-- | libavcodec/adpcm.c | 87 | ||||
-rw-r--r-- | libavcodec/allcodecs.c | 2 | ||||
-rw-r--r-- | libavcodec/avcodec.h | 4 |
5 files changed, 98 insertions, 0 deletions
@@ -12,6 +12,7 @@ Philip Gladstone Vladimir Gneushev Falk Hueffner Zdenek Kabelac +Robin Kay Nick Kurshev Mike Melanson Michael Niedermayer diff --git a/doc/ffmpeg-doc.texi b/doc/ffmpeg-doc.texi index c25b3f3cd1..046cda0d49 100644 --- a/doc/ffmpeg-doc.texi +++ b/doc/ffmpeg-doc.texi @@ -758,9 +758,13 @@ solutions. @tab used in some Sega Saturn console games @item Westwood Studios IMA ADPCM @tab @tab X @tab used in Westwood Studios games like Command and Conquer +@item SMJPEG IMA ADPCM @tab @tab X +@tab used in certain Loki game ports @item CD-ROM XA ADPCM @tab @tab X @item CRI ADX ADPCM @tab X @tab X @tab used in Sega Dreamcast games +@item Electronic Arts ADPCM @tab @tab X +@tab used in various EA titles @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 bced66f198..7aee84f654 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -25,6 +25,7 @@ * Fringe ADPCM codecs (e.g., DK3, DK4, Westwood) * by Mike Melanson (melanson@pcisys.net) * CD-ROM XA ADPCM codec by BERO + * EA ADPCM decoder by Robin Kay (komadori@myrealbox.com) * * Features and limitations: * @@ -44,6 +45,13 @@ #define BLKSIZE 1024 +#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) +#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) +#define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ + (((uint8_t*)(x))[2] << 16) | \ + (((uint8_t*)(x))[1] << 8) | \ + ((uint8_t*)(x))[0]) + #define CLAMP_TO_SHORT(value) \ if (value > 32767) \ value = 32767; \ @@ -97,6 +105,11 @@ static const int xa_adpcm_table[5][2] = { { 122, -60 } }; +static int ea_adpcm_table[] = { + 0, 240, 460, 392, 0, 0, -208, -220, 0, 1, + 3, 4, 7, 8, 10, 11, 0, -1, -3, -4 +}; + /* end of tables */ typedef struct ADPCMChannelStatus { @@ -444,6 +457,15 @@ static int adpcm_decode_frame(AVCodecContext *avctx, int decode_top_nibble_next = 0; int diff_channel; + /* EA ADPCM state variables */ + uint32_t samples_in_chunk; + int32_t previous_left_sample, previous_right_sample; + int32_t current_left_sample, current_right_sample; + int32_t next_left_sample, next_right_sample; + int32_t coeff1l, coeff2l, coeff1r, coeff2r; + uint8_t shift_left, shift_right; + int count1, count2; + if (!buf_size) return 0; @@ -715,6 +737,69 @@ static int adpcm_decode_frame(AVCodecContext *avctx, buf_size -= 128; } break; + case CODEC_ID_ADPCM_EA: + samples_in_chunk = LE_32(src); + if (samples_in_chunk >= ((buf_size - 12) * 2)) { + src += buf_size; + break; + } + src += 4; + current_left_sample = (int16_t)LE_16(src); + src += 2; + previous_left_sample = (int16_t)LE_16(src); + src += 2; + current_right_sample = (int16_t)LE_16(src); + src += 2; + previous_right_sample = (int16_t)LE_16(src); + src += 2; + + for (count1 = 0; count1 < samples_in_chunk/28;count1++) { + coeff1l = ea_adpcm_table[(*src >> 4) & 0x0F]; + coeff2l = ea_adpcm_table[((*src >> 4) & 0x0F) + 4]; + coeff1r = ea_adpcm_table[*src & 0x0F]; + coeff2r = ea_adpcm_table[(*src & 0x0F) + 4]; + src++; + + shift_left = ((*src >> 4) & 0x0F) + 8; + shift_right = (*src & 0x0F) + 8; + src++; + + for (count2 = 0; count2 < 28; count2++) { + next_left_sample = (((*src & 0xF0) << 24) >> shift_left); + next_right_sample = (((*src & 0x0F) << 28) >> shift_right); + src++; + + next_left_sample = (next_left_sample + + (current_left_sample * coeff1l) + + (previous_left_sample * coeff2l) + 0x80) >> 8; + next_right_sample = (next_right_sample + + (current_right_sample * coeff1r) + + (previous_right_sample * coeff2r) + 0x80) >> 8; + CLAMP_TO_SHORT(next_left_sample); + CLAMP_TO_SHORT(next_right_sample); + + previous_left_sample = current_left_sample; + current_left_sample = next_left_sample; + previous_right_sample = current_right_sample; + current_right_sample = next_right_sample; + *samples++ = (unsigned short)current_left_sample; + *samples++ = (unsigned short)current_right_sample; + } + } + break; + case CODEC_ID_ADPCM_IMA_SMJPEG: + c->status[0].predictor = *src; + src += 2; + c->status[0].step_index = *src++; + src++; /* skip another byte before getting to the meat */ + while (src < buf + buf_size) { + *samples++ = adpcm_ima_expand_nibble(&c->status[0], + *src & 0x0F, 3); + *samples++ = adpcm_ima_expand_nibble(&c->status[0], + (*src >> 4) & 0x0F, 3); + src++; + } + break; default: *data_size = 0; return -1; @@ -765,9 +850,11 @@ ADPCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); ADPCM_CODEC(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3); ADPCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4); ADPCM_CODEC(CODEC_ID_ADPCM_IMA_WS, adpcm_ima_ws); +ADPCM_CODEC(CODEC_ID_ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg); ADPCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); 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); #undef ADPCM_CODEC diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index b71db05308..5023bf4d92 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -196,10 +196,12 @@ PCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); PCM_CODEC(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3); PCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4); PCM_CODEC(CODEC_ID_ADPCM_IMA_WS, adpcm_ima_ws); +PCM_CODEC(CODEC_ID_ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg); PCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa); PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx); +PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea); #undef PCM_CODEC diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 857afa2b26..b202a009a4 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -110,10 +110,12 @@ enum CodecID { CODEC_ID_ADPCM_IMA_DK3, CODEC_ID_ADPCM_IMA_DK4, CODEC_ID_ADPCM_IMA_WS, + CODEC_ID_ADPCM_IMA_SMJPEG, CODEC_ID_ADPCM_MS, CODEC_ID_ADPCM_4XM, CODEC_ID_ADPCM_XA, CODEC_ID_ADPCM_ADX, + CODEC_ID_ADPCM_EA, /* AMR */ CODEC_ID_AMR_NB, @@ -1726,10 +1728,12 @@ PCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); PCM_CODEC(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3); PCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4); PCM_CODEC(CODEC_ID_ADPCM_IMA_WS, adpcm_ima_ws); +PCM_CODEC(CODEC_ID_ADPCM_SMJPEG, adpcm_ima_smjpeg); PCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa); PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx); +PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea); #undef PCM_CODEC |