changeset 2516:9f17dd9b80c6 libavcodec

macromedia flavour adpcm decoding (used in flv and swf)
author alex
date Mon, 21 Feb 2005 19:27:32 +0000
parents 0a68e8dd1c3b
children 3d8bbb8e7156
files adpcm.c allcodecs.c avcodec.h
diffstat 3 files changed, 87 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/adpcm.c	Mon Feb 21 17:52:23 2005 +0000
+++ b/adpcm.c	Mon Feb 21 19:27:32 2005 +0000
@@ -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 @@
     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 @@
     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 @@
 	    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_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
--- a/allcodecs.c	Mon Feb 21 17:52:23 2005 +0000
+++ b/allcodecs.c	Mon Feb 21 19:27:32 2005 +0000
@@ -241,6 +241,7 @@
 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
 
--- a/avcodec.h	Mon Feb 21 17:52:23 2005 +0000
+++ b/avcodec.h	Mon Feb 21 19:27:32 2005 +0000
@@ -130,6 +130,7 @@
     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_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