mirror of https://git.ffmpeg.org/ffmpeg.git
added support for EA ADPCM and SMJPEG IMA ADPCM
Originally committed as revision 2744 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
parent
deb7a6cdaf
commit
7d8379f2b7
1
CREDITS
1
CREDITS
|
@ -12,6 +12,7 @@ Philip Gladstone
|
||||||
Vladimir Gneushev
|
Vladimir Gneushev
|
||||||
Falk Hueffner
|
Falk Hueffner
|
||||||
Zdenek Kabelac
|
Zdenek Kabelac
|
||||||
|
Robin Kay
|
||||||
Nick Kurshev
|
Nick Kurshev
|
||||||
Mike Melanson
|
Mike Melanson
|
||||||
Michael Niedermayer
|
Michael Niedermayer
|
||||||
|
|
|
@ -758,9 +758,13 @@ solutions.
|
||||||
@tab used in some Sega Saturn console games
|
@tab used in some Sega Saturn console games
|
||||||
@item Westwood Studios IMA ADPCM @tab @tab X
|
@item Westwood Studios IMA ADPCM @tab @tab X
|
||||||
@tab used in Westwood Studios games like Command and Conquer
|
@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 CD-ROM XA ADPCM @tab @tab X
|
||||||
@item CRI ADX ADPCM @tab X @tab X
|
@item CRI ADX ADPCM @tab X @tab X
|
||||||
@tab used in Sega Dreamcast games
|
@tab used in Sega Dreamcast games
|
||||||
|
@item Electronic Arts ADPCM @tab @tab X
|
||||||
|
@tab used in various EA titles
|
||||||
@item RA144 @tab @tab X
|
@item RA144 @tab @tab X
|
||||||
@tab Real 14400 bit/s codec
|
@tab Real 14400 bit/s codec
|
||||||
@item RA288 @tab @tab X
|
@item RA288 @tab @tab X
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
* Fringe ADPCM codecs (e.g., DK3, DK4, Westwood)
|
* Fringe ADPCM codecs (e.g., DK3, DK4, Westwood)
|
||||||
* by Mike Melanson (melanson@pcisys.net)
|
* by Mike Melanson (melanson@pcisys.net)
|
||||||
* CD-ROM XA ADPCM codec by BERO
|
* CD-ROM XA ADPCM codec by BERO
|
||||||
|
* EA ADPCM decoder by Robin Kay (komadori@myrealbox.com)
|
||||||
*
|
*
|
||||||
* Features and limitations:
|
* Features and limitations:
|
||||||
*
|
*
|
||||||
|
@ -44,6 +45,13 @@
|
||||||
|
|
||||||
#define BLKSIZE 1024
|
#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) \
|
#define CLAMP_TO_SHORT(value) \
|
||||||
if (value > 32767) \
|
if (value > 32767) \
|
||||||
value = 32767; \
|
value = 32767; \
|
||||||
|
@ -97,6 +105,11 @@ static const int xa_adpcm_table[5][2] = {
|
||||||
{ 122, -60 }
|
{ 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 */
|
/* end of tables */
|
||||||
|
|
||||||
typedef struct ADPCMChannelStatus {
|
typedef struct ADPCMChannelStatus {
|
||||||
|
@ -444,6 +457,15 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
|
||||||
int decode_top_nibble_next = 0;
|
int decode_top_nibble_next = 0;
|
||||||
int diff_channel;
|
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)
|
if (!buf_size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -715,6 +737,69 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
|
||||||
buf_size -= 128;
|
buf_size -= 128;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
*data_size = 0;
|
*data_size = 0;
|
||||||
return -1;
|
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_DK3, adpcm_ima_dk3);
|
||||||
ADPCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4);
|
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_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_MS, adpcm_ms);
|
||||||
ADPCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm);
|
ADPCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm);
|
||||||
ADPCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
|
ADPCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
|
||||||
ADPCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
|
ADPCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
|
||||||
|
ADPCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
|
||||||
|
|
||||||
#undef ADPCM_CODEC
|
#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_DK3, adpcm_ima_dk3);
|
||||||
PCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4);
|
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_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_MS, adpcm_ms);
|
||||||
PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm);
|
PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm);
|
||||||
PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
|
PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
|
||||||
PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
|
PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
|
||||||
|
PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
|
||||||
|
|
||||||
#undef PCM_CODEC
|
#undef PCM_CODEC
|
||||||
|
|
||||||
|
|
|
@ -110,10 +110,12 @@ enum CodecID {
|
||||||
CODEC_ID_ADPCM_IMA_DK3,
|
CODEC_ID_ADPCM_IMA_DK3,
|
||||||
CODEC_ID_ADPCM_IMA_DK4,
|
CODEC_ID_ADPCM_IMA_DK4,
|
||||||
CODEC_ID_ADPCM_IMA_WS,
|
CODEC_ID_ADPCM_IMA_WS,
|
||||||
|
CODEC_ID_ADPCM_IMA_SMJPEG,
|
||||||
CODEC_ID_ADPCM_MS,
|
CODEC_ID_ADPCM_MS,
|
||||||
CODEC_ID_ADPCM_4XM,
|
CODEC_ID_ADPCM_4XM,
|
||||||
CODEC_ID_ADPCM_XA,
|
CODEC_ID_ADPCM_XA,
|
||||||
CODEC_ID_ADPCM_ADX,
|
CODEC_ID_ADPCM_ADX,
|
||||||
|
CODEC_ID_ADPCM_EA,
|
||||||
|
|
||||||
/* AMR */
|
/* AMR */
|
||||||
CODEC_ID_AMR_NB,
|
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_DK3, adpcm_ima_dk3);
|
||||||
PCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4);
|
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_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_MS, adpcm_ms);
|
||||||
PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm);
|
PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm);
|
||||||
PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
|
PCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
|
||||||
PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
|
PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
|
||||||
|
PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
|
||||||
|
|
||||||
#undef PCM_CODEC
|
#undef PCM_CODEC
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue