EA ADPCM R1, R2 and R3 decoder
authorPeter Ross <pross@xvid.org>
Wed, 24 Oct 2007 20:49:42 +0000 (20:49 +0000)
committerAurelien Jacobs <aurel@gnuage.org>
Wed, 24 Oct 2007 20:49:42 +0000 (20:49 +0000)
original patch by Peter Ross

Originally committed as revision 10856 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavcodec/Makefile
libavcodec/adpcm.c
libavcodec/allcodecs.c
libavcodec/avcodec.h
libavformat/electronicarts.c

index 64d4620..6cd7f6e 100644 (file)
@@ -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
index 4b734bd..8a8384f 100644 (file)
@@ -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);
index aeb376b..e405620 100644 (file)
@@ -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);
index 02d0920..1e8179d 100644 (file)
@@ -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,
index b4c14e0..08c2840 100644 (file)
@@ -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;