From e7583962687adf44b4e6b5556a296f37485c7c8b Mon Sep 17 00:00:00 2001 From: Peter Ross Date: Wed, 24 Oct 2007 20:49:42 +0000 Subject: [PATCH] EA ADPCM R1, R2 and R3 decoder original patch by Peter Ross Originally committed as revision 10856 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/Makefile | 3 ++ libavcodec/adpcm.c | 96 +++++++++++++++++++++++++++++++++++- libavcodec/allcodecs.c | 3 ++ libavcodec/avcodec.h | 7 ++- libavformat/electronicarts.c | 10 ++++ 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; channelchannels; 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; count1channels; + } + } 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;