M$ ADPCM encoding & some simplifications

Originally committed as revision 2765 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Michael Niedermayer 2004-02-08 02:16:48 +00:00
parent fc374fe299
commit 6cf9d5ebd3
1 changed files with 76 additions and 28 deletions

View File

@ -153,8 +153,9 @@ static int adpcm_encode_init(AVCodecContext *avctx)
/* seems frame_size isn't taken into account... have to buffer the samples :-( */
break;
case CODEC_ID_ADPCM_MS:
av_log(avctx, AV_LOG_ERROR, "ADPCM: codec adpcm_ms unsupported for encoding !\n");
return -1;
avctx->frame_size = (BLKSIZE - 7 * avctx->channels) * 2 / avctx->channels + 2; /* each 16 bits sample gives one nibble */
/* and we have 7 bytes per channel overhead */
avctx->block_align = BLKSIZE;
break;
default:
return -1;
@ -223,16 +224,42 @@ static inline unsigned char adpcm_ima_compress_sample(ADPCMChannelStatus *c, sho
return nibble;
}
static inline unsigned char adpcm_ms_compress_sample(ADPCMChannelStatus *c, short sample)
{
int predictor, nibble, bias;
predictor = (((c->sample1) * (c->coeff1)) + ((c->sample2) * (c->coeff2))) / 256;
nibble= sample - predictor;
if(nibble>=0) bias= c->idelta/2;
else bias=-c->idelta/2;
nibble= (nibble + bias) / c->idelta;
nibble= clip(nibble, -8, 7)&0x0F;
predictor += (signed)((nibble & 0x08)?(nibble - 0x10):(nibble)) * c->idelta;
CLAMP_TO_SHORT(predictor);
c->sample2 = c->sample1;
c->sample1 = predictor;
c->idelta = (AdaptationTable[(int)nibble] * c->idelta) >> 8;
if (c->idelta < 16) c->idelta = 16;
return nibble;
}
static int adpcm_encode_frame(AVCodecContext *avctx,
unsigned char *frame, int buf_size, void *data)
{
int n;
int n, i, st;
short *samples;
unsigned char *dst;
ADPCMContext *c = avctx->priv_data;
dst = frame;
samples = (short *)data;
st= avctx->channels == 2;
/* n = (BLKSIZE - 4 * avctx->channels) / (2 * 8 * avctx->channels); */
switch(avctx->codec->id) {
@ -289,6 +316,41 @@ static int adpcm_encode_frame(AVCodecContext *avctx,
samples += 8 * avctx->channels;
}
break;
case CODEC_ID_ADPCM_MS:
for(i=0; i<avctx->channels; i++){
int predictor=0;
*dst++ = predictor;
c->status[i].coeff1 = AdaptCoeff1[predictor];
c->status[i].coeff2 = AdaptCoeff2[predictor];
}
for(i=0; i<avctx->channels; i++){
if (c->status[i].idelta < 16)
c->status[i].idelta = 16;
*dst++ = c->status[i].idelta & 0xFF;
*dst++ = c->status[i].idelta >> 8;
}
for(i=0; i<avctx->channels; i++){
c->status[i].sample1= *samples++;
*dst++ = c->status[i].sample1 & 0xFF;
*dst++ = c->status[i].sample1 >> 8;
}
for(i=0; i<avctx->channels; i++){
c->status[i].sample2= *samples++;
*dst++ = c->status[i].sample2 & 0xFF;
*dst++ = c->status[i].sample2 >> 8;
}
for(i=7*avctx->channels; i<avctx->block_align; i++) {
int nibble;
nibble = adpcm_ms_compress_sample(&c->status[ 0], *samples++)<<4;
nibble|= adpcm_ms_compress_sample(&c->status[st], *samples++);
*dst++ = nibble;
}
break;
default:
return -1;
}
@ -350,7 +412,7 @@ static inline short adpcm_ms_expand_nibble(ADPCMChannelStatus *c, char nibble)
c->sample2 = c->sample1;
c->sample1 = predictor;
c->idelta = (AdaptationTable[(int)nibble] * c->idelta) / 256;
c->idelta = (AdaptationTable[(int)nibble] * c->idelta) >> 8;
if (c->idelta < 16) c->idelta = 16;
return (short)predictor;
@ -585,22 +647,16 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
n = buf_size - 7 * avctx->channels;
if (n < 0)
return -1;
block_predictor[0] = (*src++); /* should be bound */
block_predictor[0] = (block_predictor[0] < 0)?(0):((block_predictor[0] > 7)?(7):(block_predictor[0]));
block_predictor[0] = clip(*src++, 0, 7);
block_predictor[1] = 0;
if (st)
block_predictor[1] = (*src++);
block_predictor[1] = (block_predictor[1] < 0)?(0):((block_predictor[1] > 7)?(7):(block_predictor[1]));
c->status[0].idelta = ((*src & 0xFF) | ((src[1] << 8) & 0xFF00));
if (c->status[0].idelta & 0x08000)
c->status[0].idelta -= 0x10000;
block_predictor[1] = clip(*src++, 0, 7);
c->status[0].idelta = (int16_t)((*src & 0xFF) | ((src[1] << 8) & 0xFF00));
src+=2;
if (st)
c->status[1].idelta = ((*src & 0xFF) | ((src[1] << 8) & 0xFF00));
if (st && c->status[1].idelta & 0x08000)
c->status[1].idelta |= 0xFFFF0000;
if (st)
if (st){
c->status[1].idelta = (int16_t)((*src & 0xFF) | ((src[1] << 8) & 0xFF00));
src+=2;
}
c->status[0].coeff1 = AdaptCoeff1[block_predictor[0]];
c->status[0].coeff2 = AdaptCoeff2[block_predictor[0]];
c->status[1].coeff1 = AdaptCoeff1[block_predictor[1]];
@ -629,18 +685,14 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
if (avctx->block_align != 0 && buf_size > avctx->block_align)
buf_size = avctx->block_align;
c->status[0].predictor = (src[0] | (src[1] << 8));
c->status[0].predictor = (int16_t)(src[0] | (src[1] << 8));
c->status[0].step_index = src[2];
src += 4;
if(c->status[0].predictor & 0x8000)
c->status[0].predictor -= 0x10000;
*samples++ = c->status[0].predictor;
if (st) {
c->status[1].predictor = (src[0] | (src[1] << 8));
c->status[1].predictor = (int16_t)(src[0] | (src[1] << 8));
c->status[1].step_index = src[2];
src += 4;
if(c->status[1].predictor & 0x8000)
c->status[1].predictor -= 0x10000;
*samples++ = c->status[1].predictor;
}
while (src < buf + buf_size) {
@ -665,15 +717,11 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
if (avctx->block_align != 0 && buf_size > avctx->block_align)
buf_size = avctx->block_align;
c->status[0].predictor = (src[10] | (src[11] << 8));
c->status[1].predictor = (src[12] | (src[13] << 8));
c->status[0].predictor = (int16_t)(src[10] | (src[11] << 8));
c->status[1].predictor = (int16_t)(src[12] | (src[13] << 8));
c->status[0].step_index = src[14];
c->status[1].step_index = src[15];
/* sign extend the predictors */
if(c->status[0].predictor & 0x8000)
c->status[0].predictor -= 0x10000;
if(c->status[1].predictor & 0x8000)
c->status[1].predictor -= 0x10000;
src += 16;
diff_channel = c->status[1].predictor;