# HG changeset patch # User alex # Date 1109014052 0 # Node ID 9f17dd9b80c6277b5536e25a72076962fa00bbcd # Parent 0a68e8dd1c3b015e05a8b57d4b1eecb5403f8f16 macromedia flavour adpcm decoding (used in flv and swf) diff -r 0a68e8dd1c3b -r 9f17dd9b80c6 adpcm.c --- 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 diff -r 0a68e8dd1c3b -r 9f17dd9b80c6 allcodecs.c --- 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 diff -r 0a68e8dd1c3b -r 9f17dd9b80c6 avcodec.h --- 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