changeset 1794:d133b4ad0620 libavcodec

M$ ADPCM encoding & some simplifications
author michael
date Sun, 08 Feb 2004 02:16:48 +0000
parents 11124a5d04f6
children 920e6381e1fe
files adpcm.c
diffstat 1 files changed, 76 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- 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; 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 @@
 
     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;