macromedia flavour adpcm decoding (used in flv and swf)
authorAlex Beregszaszi <alex@rtfs.hu>
Mon, 21 Feb 2005 19:27:32 +0000 (19:27 +0000)
committerAlex Beregszaszi <alex@rtfs.hu>
Mon, 21 Feb 2005 19:27:32 +0000 (19:27 +0000)
Originally committed as revision 3969 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavcodec/adpcm.c
libavcodec/allcodecs.c
libavcodec/avcodec.h

index 40c2d43..043c4d4 100644 (file)
@@ -17,6 +17,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include "avcodec.h"
+#include "bitstream.h"
 
 /**
  * @file adpcm.c
@@ -108,6 +109,14 @@ static int ct_adpcm_table[8] = {
     0x0133, 0x0199, 0x0200, 0x0266
 };
 
+// padded to zero where table size is less then 16
+static int swf_index_tables[4][16] = {
+    /*2*/ { -1, 2 },
+    /*3*/ { -1, -1, 2, 4 },
+    /*4*/ { -1, -1, -1, -1, 2, 4, 6, 8 },
+    /*5*/ { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 }
+};
+
 /* end of tables */
 
 typedef struct ADPCMChannelStatus {
@@ -129,6 +138,10 @@ typedef struct ADPCMContext {
     int channel; /* for stereo MOVs, decode left, then decode right, then tell it's decoded */
     ADPCMChannelStatus status[2];
     short sample_buffer[32]; /* hold left samples while waiting for right samples */
+
+    /* SWF only */
+    int nb_bits;
+    int nb_samples;
 } ADPCMContext;
 
 /* XXX: implement encoding */
@@ -895,6 +908,76 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
            src++;
         }
         break;
+    case CODEC_ID_ADPCM_SWF:
+    {
+       GetBitContext gb;
+       int *table;
+       int k0, signmask;
+       int size = buf_size*8;
+       
+       init_get_bits(&gb, buf, size);
+
+       // first frame, read bits & inital values
+       if (!c->nb_bits)
+       {
+           c->nb_bits = get_bits(&gb, 2)+2;
+//         av_log(NULL,AV_LOG_INFO,"nb_bits: %d\n", c->nb_bits);
+       }
+       
+       table = swf_index_tables[c->nb_bits-2];
+       k0 = 1 << (c->nb_bits-2);
+       signmask = 1 << (c->nb_bits-1);
+       
+       while (get_bits_count(&gb) <= size)
+       {
+           int i;
+
+           c->nb_samples++;
+           // wrap around at every 4096 samples...
+           if ((c->nb_samples & 0xfff) == 1)
+           {
+               for (i = 0; i <= st; i++)
+               {
+                   *samples++ = c->status[i].predictor = get_sbits(&gb, 16);
+                   c->status[i].step_index = get_bits(&gb, 6);
+               }
+           }
+
+           // similar to IMA adpcm
+           for (i = 0; i <= st; i++)
+           {
+               int delta = get_bits(&gb, c->nb_bits);
+               int step = step_table[c->status[i].step_index];
+               long vpdiff = 0; // vpdiff = (delta+0.5)*step/4
+               int k = k0;
+               
+               do {
+                   if (delta & k)
+                       vpdiff += step;
+                   step >>= 1;
+                   k >>= 1;
+               } while(k);
+               vpdiff += step;
+               
+               if (delta & signmask)
+                   c->status[i].predictor -= vpdiff;
+               else
+                   c->status[i].predictor += vpdiff;
+               
+               c->status[i].step_index += table[delta & (~signmask)];
+               
+               c->status[i].step_index = clip(c->status[i].step_index, 0, 88);
+               c->status[i].predictor = clip(c->status[i].predictor, -32768, 32767);
+               
+               *samples++ = c->status[i].predictor;
+           }
+       }
+       
+//     src += get_bits_count(&gb)*8;
+       src += size;
+       
+       break;
+    }
     default:
         return -1;
     }
@@ -951,5 +1034,6 @@ ADPCM_CODEC(CODEC_ID_ADPCM_XA, adpcm_xa);
 ADPCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
 ADPCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
 ADPCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
+ADPCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf);
 
 #undef ADPCM_CODEC
index 25d9fbd..b7a05bd 100644 (file)
@@ -241,6 +241,7 @@ PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
 PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
 PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726);
 PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
+PCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf);
 
 #undef PCM_CODEC
 
index 6aeb926..1ff8363 100644 (file)
@@ -130,6 +130,7 @@ enum CodecID {
     CODEC_ID_ADPCM_EA,
     CODEC_ID_ADPCM_G726,
     CODEC_ID_ADPCM_CT,
+    CODEC_ID_ADPCM_SWF,
 
     /* AMR */
     CODEC_ID_AMR_NB= 0x12000,
@@ -2033,6 +2034,7 @@ PCM_CODEC(CODEC_ID_ADPCM_ADX, adpcm_adx);
 PCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
 PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726);
 PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
+PCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf);
 
 #undef PCM_CODEC