aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Melanson <mike@multimedia.cx>2004-02-03 04:27:17 +0000
committerMike Melanson <mike@multimedia.cx>2004-02-03 04:27:17 +0000
commit7d8379f2b78e255b6f8c8bee1a6d41cd8340b0a2 (patch)
treeeb90d88365828e11b1e637884b1032ec7fd6183b
parentdeb7a6cdafa220ff4d0b986c30bf431be0bbcf0b (diff)
downloadffmpeg-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--CREDITS1
-rw-r--r--doc/ffmpeg-doc.texi4
-rw-r--r--libavcodec/adpcm.c87
-rw-r--r--libavcodec/allcodecs.c2
-rw-r--r--libavcodec/avcodec.h4
5 files changed, 98 insertions, 0 deletions
diff --git a/CREDITS b/CREDITS
index 260010559d..d5a50df7aa 100644
--- a/CREDITS
+++ b/CREDITS
@@ -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