aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2005-02-21 19:27:32 +0000
committerAlex Beregszaszi <alex@rtfs.hu>2005-02-21 19:27:32 +0000
commit659c36925665462a5dec13490359702e48b56160 (patch)
treec368e77f6ef73542cfdb62c35854e1884f20c8fd
parent923bd441fed9d87a3dd2af5f100f99b392cfaff3 (diff)
downloadffmpeg-659c36925665462a5dec13490359702e48b56160.tar.gz
macromedia flavour adpcm decoding (used in flv and swf)
Originally committed as revision 3969 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r--libavcodec/adpcm.c84
-rw-r--r--libavcodec/allcodecs.c1
-rw-r--r--libavcodec/avcodec.h2
3 files changed, 87 insertions, 0 deletions
diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c
index 40c2d430ff..043c4d4b25 100644
--- a/libavcodec/adpcm.c
+++ b/libavcodec/adpcm.c
@@ -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
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 25d9fbd040..b7a05bd26d 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -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
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 6aeb926f1f..1ff8363774 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -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