Skip to content
Snippets Groups Projects
Commit 659c3692 authored by Alex Beregszaszi's avatar Alex Beregszaszi
Browse files

macromedia flavour adpcm decoding (used in flv and swf)

Originally committed as revision 3969 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 923bd441
No related branches found
No related tags found
No related merge requests found
......@@ -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
......@@ -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
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment