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