added support for EA ADPCM and SMJPEG IMA ADPCM
authorMike Melanson <mike@multimedia.cx>
Tue, 3 Feb 2004 04:27:17 +0000 (04:27 +0000)
committerMike Melanson <mike@multimedia.cx>
Tue, 3 Feb 2004 04:27:17 +0000 (04:27 +0000)
Originally committed as revision 2744 to svn://svn.ffmpeg.org/ffmpeg/trunk

CREDITS
doc/ffmpeg-doc.texi
libavcodec/adpcm.c
libavcodec/allcodecs.c
libavcodec/avcodec.h

diff --git a/CREDITS b/CREDITS
index 2600105..d5a50df 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -12,6 +12,7 @@ Philip Gladstone
 Vladimir Gneushev
 Falk Hueffner
 Zdenek Kabelac
+Robin Kay
 Nick Kurshev
 Mike Melanson
 Michael Niedermayer
index c25b3f3..046cda0 100644 (file)
@@ -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
index bced66f..7aee84f 100644 (file)
@@ -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:
  *
 
 #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
index b71db05..5023bf4 100644 (file)
@@ -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
 
index 857afa2..b202a00 100644 (file)
@@ -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