aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ross <pross@xvid.org>2007-10-24 20:49:42 +0000
committerAurelien Jacobs <aurel@gnuage.org>2007-10-24 20:49:42 +0000
commite7583962687adf44b4e6b5556a296f37485c7c8b (patch)
tree7eccd7643ae8b71792c9ea9862a84d1d62ec1896
parentd2bbb2f743e253869316db3e45f639d09285f583 (diff)
downloadffmpeg-e7583962687adf44b4e6b5556a296f37485c7c8b.tar.gz
EA ADPCM R1, R2 and R3 decoder
original patch by Peter Ross Originally committed as revision 10856 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r--libavcodec/Makefile3
-rw-r--r--libavcodec/adpcm.c96
-rw-r--r--libavcodec/allcodecs.c3
-rw-r--r--libavcodec/avcodec.h7
-rw-r--r--libavformat/electronicarts.c10
5 files changed, 115 insertions, 4 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 64d462051c..6cd7f6e200 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -266,6 +266,9 @@ OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_CT_ENCODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_EA_ENCODER) += adpcm.o
+OBJS-$(CONFIG_ADPCM_EA_R1_DECODER) += adpcm.o
+OBJS-$(CONFIG_ADPCM_EA_R2_DECODER) += adpcm.o
+OBJS-$(CONFIG_ADPCM_EA_R3_DECODER) += adpcm.o
OBJS-$(CONFIG_ADPCM_G726_DECODER) += g726.o
OBJS-$(CONFIG_ADPCM_G726_ENCODER) += g726.o
OBJS-$(CONFIG_ADPCM_IMA_AMV_DECODER) += adpcm.o
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 4b734bd5f6..8a8384ff65 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -30,6 +30,7 @@
* by Mike Melanson (melanson@pcisys.net)
* CD-ROM XA ADPCM codec by BERO
* EA ADPCM decoder by Robin Kay (komadori@myrealbox.com)
+ * EA ADPCM R1/R2/R3 decoder by Peter Ross (pross@xvid.org)
* THP ADPCM decoder by Marco Gerards (mgerards@xs4all.nl)
*
* Features and limitations:
@@ -144,7 +145,7 @@ typedef struct ADPCMChannelStatus {
typedef struct ADPCMContext {
int channel; /* for stereo MOVs, decode left, then decode right, then tell it's decoded */
- ADPCMChannelStatus status[2];
+ ADPCMChannelStatus status[6];
} ADPCMContext;
/* XXX: implement encoding */
@@ -635,8 +636,16 @@ static int adpcm_encode_frame(AVCodecContext *avctx,
static int adpcm_decode_init(AVCodecContext * avctx)
{
ADPCMContext *c = avctx->priv_data;
+ unsigned int max_channels = 2;
- if(avctx->channels > 2U){
+ switch(avctx->codec->id) {
+ case CODEC_ID_ADPCM_EA_R1:
+ case CODEC_ID_ADPCM_EA_R2:
+ case CODEC_ID_ADPCM_EA_R3:
+ max_channels = 6;
+ break;
+ }
+ if(avctx->channels > max_channels){
return -1;
}
@@ -1176,6 +1185,86 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
}
}
break;
+ case CODEC_ID_ADPCM_EA_R1:
+ case CODEC_ID_ADPCM_EA_R2:
+ case CODEC_ID_ADPCM_EA_R3: {
+ /* channel numbering
+ 2chan: 0=fl, 1=fr
+ 4chan: 0=fl, 1=rl, 2=fr, 3=rr
+ 6chan: 0=fl, 1=c, 2=fr, 3=rl, 4=rr, 5=sub */
+ const int big_endian = avctx->codec->id == CODEC_ID_ADPCM_EA_R3;
+ int32_t previous_sample, current_sample, next_sample;
+ int32_t coeff1, coeff2;
+ uint8_t shift;
+ unsigned int channel;
+ uint16_t *samplesC;
+ uint8_t *srcC;
+
+ samples_in_chunk = (big_endian ? bytestream_get_be32(&src)
+ : bytestream_get_le32(&src)) / 28;
+ if (samples_in_chunk > UINT32_MAX/(28*avctx->channels) ||
+ 28*samples_in_chunk*avctx->channels > samples_end-samples) {
+ src += buf_size - 4;
+ break;
+ }
+
+ for (channel=0; channel<avctx->channels; channel++) {
+ srcC = src + (big_endian ? bytestream_get_be32(&src)
+ : bytestream_get_le32(&src))
+ + (avctx->channels-channel-1) * 4;
+ samplesC = samples + channel;
+
+ if (avctx->codec->id == CODEC_ID_ADPCM_EA_R1) {
+ current_sample = (int16_t)bytestream_get_le16(&srcC);
+ previous_sample = (int16_t)bytestream_get_le16(&srcC);
+ } else {
+ current_sample = c->status[channel].predictor;
+ previous_sample = c->status[channel].prev_sample;
+ }
+
+ for (count1=0; count1<samples_in_chunk; count1++) {
+ if (*srcC == 0xEE) { /* only seen in R2 and R3 */
+ srcC++;
+ current_sample = (int16_t)bytestream_get_be16(&srcC);
+ previous_sample = (int16_t)bytestream_get_be16(&srcC);
+
+ for (count2=0; count2<28; count2++) {
+ *samplesC = (int16_t)bytestream_get_be16(&srcC);
+ samplesC += avctx->channels;
+ }
+ } else {
+ coeff1 = ea_adpcm_table[ (*srcC>>4) & 0x0F ];
+ coeff2 = ea_adpcm_table[((*srcC>>4) & 0x0F) + 4];
+ shift = (*srcC++ & 0x0F) + 8;
+
+ for (count2=0; count2<28; count2++) {
+ if (count2 & 1)
+ next_sample = ((*srcC++ & 0x0F) << 28) >> shift;
+ else
+ next_sample = ((*srcC & 0xF0) << 24) >> shift;
+
+ next_sample += (current_sample * coeff1) +
+ (previous_sample * coeff2);
+ next_sample = av_clip_int16(next_sample >> 8);
+
+ previous_sample = current_sample;
+ current_sample = next_sample;
+ *samplesC = current_sample;
+ samplesC += avctx->channels;
+ }
+ }
+ }
+
+ if (avctx->codec->id != CODEC_ID_ADPCM_EA_R1) {
+ c->status[channel].predictor = current_sample;
+ c->status[channel].prev_sample = previous_sample;
+ }
+ }
+
+ src = src + buf_size - (4 + 4*avctx->channels);
+ samples += 28 * samples_in_chunk * avctx->channels;
+ break;
+ }
case CODEC_ID_ADPCM_IMA_AMV:
case CODEC_ID_ADPCM_IMA_SMJPEG:
c->status[0].predictor = (int16_t)bytestream_get_le16(&src);
@@ -1451,6 +1540,9 @@ ADPCM_CODEC(CODEC_ID_ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg);
ADPCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav);
ADPCM_CODEC(CODEC_ID_ADPCM_IMA_WS, adpcm_ima_ws);
ADPCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms);
+ADPCM_CODEC(CODEC_ID_ADPCM_EA_R1, adpcm_ea_r1);
+ADPCM_CODEC(CODEC_ID_ADPCM_EA_R2, adpcm_ea_r2);
+ADPCM_CODEC(CODEC_ID_ADPCM_EA_R3, adpcm_ea_r3);
ADPCM_CODEC(CODEC_ID_ADPCM_SBPRO_4, adpcm_sbpro_4);
ADPCM_CODEC(CODEC_ID_ADPCM_SBPRO_3, adpcm_sbpro_3);
ADPCM_CODEC(CODEC_ID_ADPCM_SBPRO_2, adpcm_sbpro_2);
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index aeb376b742..e405620915 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -247,6 +247,9 @@ void avcodec_register_all(void)
REGISTER_ENCDEC (ADPCM_ADX, adpcm_adx);
REGISTER_ENCDEC (ADPCM_CT, adpcm_ct);
REGISTER_ENCDEC (ADPCM_EA, adpcm_ea);
+ REGISTER_DECODER (ADPCM_EA_R1, adpcm_ea_r1);
+ REGISTER_DECODER (ADPCM_EA_R2, adpcm_ea_r2);
+ REGISTER_DECODER (ADPCM_EA_R3, adpcm_ea_r3);
REGISTER_ENCDEC (ADPCM_G726, adpcm_g726);
REGISTER_DECODER (ADPCM_IMA_AMV, adpcm_ima_amv);
REGISTER_ENCDEC (ADPCM_IMA_DK3, adpcm_ima_dk3);
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 02d0920135..1e8179d513 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -33,8 +33,8 @@
#define AV_STRINGIFY(s) AV_TOSTRING(s)
#define AV_TOSTRING(s) #s
-#define LIBAVCODEC_VERSION_INT ((51<<16)+(47<<8)+0)
-#define LIBAVCODEC_VERSION 51.47.0
+#define LIBAVCODEC_VERSION_INT ((51<<16)+(47<<8)+1)
+#define LIBAVCODEC_VERSION 51.47.1
#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT
#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION)
@@ -211,6 +211,9 @@ enum CodecID {
CODEC_ID_ADPCM_SBPRO_2,
CODEC_ID_ADPCM_THP,
CODEC_ID_ADPCM_IMA_AMV,
+ CODEC_ID_ADPCM_EA_R1,
+ CODEC_ID_ADPCM_EA_R3,
+ CODEC_ID_ADPCM_EA_R2,
/* AMR */
CODEC_ID_AMR_NB= 0x12000,
diff --git a/libavformat/electronicarts.c b/libavformat/electronicarts.c
index b4c14e0080..08c2840656 100644
--- a/libavformat/electronicarts.c
+++ b/libavformat/electronicarts.c
@@ -149,6 +149,16 @@ static int process_audio_header_elements(AVFormatContext *s)
switch (compression_type) {
case 0: ea->audio_codec = CODEC_ID_PCM_S16LE; break;
case 7: ea->audio_codec = CODEC_ID_ADPCM_EA; break;
+ case -1:
+ switch (revision) {
+ case 1: ea->audio_codec = CODEC_ID_ADPCM_EA_R1; break;
+ case 2: ea->audio_codec = CODEC_ID_ADPCM_EA_R2; break;
+ case 3: ea->audio_codec = CODEC_ID_ADPCM_EA_R3; break;
+ default:
+ av_log(s, AV_LOG_ERROR, "unsupported stream type; revision=%i\n", revision);
+ return 0;
+ }
+ break;
default:
av_log(s, AV_LOG_ERROR, "unsupported stream type; compression_type=%i\n", compression_type);
return 0;