Commit 7d8379f2 authored by Mike Melanson's avatar Mike Melanson

added support for EA ADPCM and SMJPEG IMA ADPCM

Originally committed as revision 2744 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent deb7a6cd
......@@ -12,6 +12,7 @@ Philip Gladstone
Vladimir Gneushev
Falk Hueffner
Zdenek Kabelac
Robin Kay
Nick Kurshev
Mike Melanson
Michael Niedermayer
......
......@@ -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
......
......@@ -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
......@@ -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
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment