changeset 2794:ed1ab1566353 libavcodec

Add Yamaha ADPCM encoding/decoding patch by (Vidar Madsen: vidarino, gmail com)
author michael
date Fri, 15 Jul 2005 06:51:36 +0000
parents ae85da6c5c2f
children de03cac6f7c2
files adpcm.c allcodecs.c avcodec.h
diffstat 3 files changed, 85 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/adpcm.c	Thu Jul 14 21:57:22 2005 +0000
+++ b/adpcm.c	Fri Jul 15 06:51:36 2005 +0000
@@ -117,6 +117,16 @@
     /*5*/ { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 }
 };
 
+static const int yamaha_indexscale[] = {
+    230, 230, 230, 230, 307, 409, 512, 614,
+    230, 230, 230, 230, 307, 409, 512, 614
+};
+
+static const int yamaha_difflookup[] = {
+    1, 3, 5, 7, 9, 11, 13, 15,
+    -1, -3, -5, -7, -9, -11, -13, -15
+};
+
 /* end of tables */
 
 typedef struct ADPCMChannelStatus {
@@ -168,6 +178,10 @@
                                                              /* and we have 7 bytes per channel overhead */
         avctx->block_align = BLKSIZE;
         break;
+    case CODEC_ID_ADPCM_YAMAHA:
+        avctx->frame_size = BLKSIZE * avctx->channels;
+        avctx->block_align = BLKSIZE;
+        break;
     default:
         return -1;
         break;
@@ -260,6 +274,31 @@
     return nibble;
 }
 
+static inline unsigned char adpcm_yamaha_compress_sample(ADPCMChannelStatus *c, short sample)
+{
+    int i1 = 0, j1;
+
+    if(!c->step) {
+        c->predictor = 0;
+        c->step = 127;
+    }
+    j1 = sample - c->predictor;
+
+    j1 = (j1 * 8) / c->step;
+    i1 = abs(j1) / 2;
+    if (i1 > 7)
+        i1 = 7;
+    if (j1 < 0)
+        i1 += 8;
+
+    c->predictor = c->predictor + ((c->step * yamaha_difflookup[i1]) / 8);
+    CLAMP_TO_SHORT(c->predictor);
+    c->step = (c->step * yamaha_indexscale[i1]) >> 8;
+    c->step = clip(c->step, 127, 24567);
+
+    return i1;
+}
+
 static int adpcm_encode_frame(AVCodecContext *avctx,
 			    unsigned char *frame, int buf_size, void *data)
 {
@@ -362,6 +401,18 @@
             *dst++ = nibble;
         }
         break;
+    case CODEC_ID_ADPCM_YAMAHA:
+        n = avctx->frame_size / 2;
+        for (; n>0; n--) {
+            for(i = 0; i < avctx->channels; i++) {
+                int nibble;
+                nibble  = adpcm_yamaha_compress_sample(&c->status[i], samples[i]) << 4;
+                nibble |= adpcm_yamaha_compress_sample(&c->status[i], samples[i+avctx->channels]);
+                *dst++ = nibble;
+            }
+            samples += 2 * avctx->channels;
+        }
+        break;
     default:
         return -1;
     }
@@ -463,6 +514,20 @@
     return (short)predictor;
 }
 
+static inline short adpcm_yamaha_expand_nibble(ADPCMChannelStatus *c, unsigned char nibble)
+{
+    if(!c->step) {
+        c->predictor = 0;
+        c->step = 127;
+    }
+
+    c->predictor += (c->step * yamaha_difflookup[nibble]) / 8;
+    CLAMP_TO_SHORT(c->predictor);
+    c->step = (c->step * yamaha_indexscale[nibble]) >> 8;
+    c->step = clip(c->step, 127, 24567);
+    return c->predictor;
+}
+
 static void xa_decode(short *out, const unsigned char *in, 
     ADPCMChannelStatus *left, ADPCMChannelStatus *right, int inc)
 {
@@ -978,6 +1043,22 @@
 	
 	break;
     }
+    case CODEC_ID_ADPCM_YAMAHA:
+        while (src < buf + buf_size) {
+            if (st) {
+                *samples++ = adpcm_yamaha_expand_nibble(&c->status[0],
+                        (src[0] >> 4) & 0x0F);
+                *samples++ = adpcm_yamaha_expand_nibble(&c->status[1],
+                        src[0] & 0x0F);
+            } else {
+                *samples++ = adpcm_yamaha_expand_nibble(&c->status[0],
+                        (src[0] >> 4) & 0x0F);
+                *samples++ = adpcm_yamaha_expand_nibble(&c->status[0],
+                        src[0] & 0x0F);
+            }
+            src++;
+        }
+        break;
     default:
         return -1;
     }
@@ -1035,5 +1116,6 @@
 ADPCM_CODEC(CODEC_ID_ADPCM_EA, adpcm_ea);
 ADPCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
 ADPCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf);
+ADPCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha);
 
 #undef ADPCM_CODEC
--- a/allcodecs.c	Thu Jul 14 21:57:22 2005 +0000
+++ b/allcodecs.c	Fri Jul 15 06:51:36 2005 +0000
@@ -548,6 +548,7 @@
 PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726);
 PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
 PCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf);
+PCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha);
 
 #undef PCM_CODEC
 
--- a/avcodec.h	Thu Jul 14 21:57:22 2005 +0000
+++ b/avcodec.h	Fri Jul 15 06:51:36 2005 +0000
@@ -137,6 +137,7 @@
     CODEC_ID_ADPCM_G726,
     CODEC_ID_ADPCM_CT,
     CODEC_ID_ADPCM_SWF,
+    CODEC_ID_ADPCM_YAMAHA,
 
     /* AMR */
     CODEC_ID_AMR_NB= 0x12000,
@@ -2119,6 +2120,7 @@
 PCM_CODEC(CODEC_ID_ADPCM_G726, adpcm_g726);
 PCM_CODEC(CODEC_ID_ADPCM_CT, adpcm_ct);
 PCM_CODEC(CODEC_ID_ADPCM_SWF, adpcm_swf);
+PCM_CODEC(CODEC_ID_ADPCM_YAMAHA, adpcm_yamaha);
 
 #undef PCM_CODEC