# HG changeset patch # User michael # Date 1076206608 0 # Node ID d133b4ad0620f567d11f627248b1acb4f3379970 # Parent 11124a5d04f6ab4001cacac925feb8f4cb8e6115 M$ ADPCM encoding & some simplifications diff -r 11124a5d04f6 -r d133b4ad0620 adpcm.c --- a/adpcm.c Sat Feb 07 20:50:26 2004 +0000 +++ b/adpcm.c Sun Feb 08 02:16:48 2004 +0000 @@ -153,8 +153,9 @@ /* 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 @@ 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 @@ samples += 8 * avctx->channels; } break; + case CODEC_ID_ADPCM_MS: + for(i=0; ichannels; i++){ + int predictor=0; + + *dst++ = predictor; + c->status[i].coeff1 = AdaptCoeff1[predictor]; + c->status[i].coeff2 = AdaptCoeff2[predictor]; + } + for(i=0; ichannels; 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; ichannels; i++){ + c->status[i].sample1= *samples++; + + *dst++ = c->status[i].sample1 & 0xFF; + *dst++ = c->status[i].sample1 >> 8; + } + for(i=0; ichannels; i++){ + c->status[i].sample2= *samples++; + + *dst++ = c->status[i].sample2 & 0xFF; + *dst++ = c->status[i].sample2 >> 8; + } + + for(i=7*avctx->channels; iblock_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 @@ 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 @@ 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 @@ 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 @@ 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;