logo资料库

ADPCM编码与解码原理.docx

第1页 / 共10页
第2页 / 共10页
第3页 / 共10页
第4页 / 共10页
第5页 / 共10页
第6页 / 共10页
第7页 / 共10页
第8页 / 共10页
资料共10页,剩余部分请下载后查看
ADPCM 编码与解码原理 一、前言 之前许多次说过,有空的时候写写博客,可是一直没有好好落实。由于工作的原因,经常会 接触到一些音视频的编解码技术,而 ADPCM 就是我第一接触的音频编码技术。所以,本人 的第一篇博客就是对 ADPCM 的编码与解码进行详解。本文对 ADPCM 编码与解码的描述, 分为两章进行。 二、IMA-ADPCM 的编码原理 ADPCM(Adaptive Differential Pulse Code Modulation 差分脉冲编码调制)主要是针对连续的波 形数据的, 保存的是相临波形的变化情况, 以达到描述整个波形的目的。本文的以 IMA 的 ADPCM 编码标准为例进行描述,IMA-ADPCM 是 Intel 公司首先开发的是一种主要针对 16bit 采样波形数据的有损压缩算法,压缩比为 4:1.它与通常的 DVI-ADPCM 是同一算法。 (对 8bit 数据压缩时是 3.2:1,也有非标准的 IMA-ADPCM 压缩算法,可以达到 5:1 甚至更高的压缩比)4:1 的压缩是目前使用最多的压缩方式。结尾附 adpcm 编解码的源代码 adpcm.h 与 adpcm.c。 ADPCM 编码本质是一种预测编码,那么它是怎么样进行预测的呢?预测编码利用相邻的音 频数据在时间上的相关性,相邻采样点的音频数据具有相似的特点。因此,进过压缩后的数 据并不是音频数据本身,而是该数据的预测值与实际值之差。偏差需要量化器进行量化,假 如我们对于 16bit 的音频数据采用 16bit 的量化,那么偏差与实际的数据值占据的位数一样 则无法达到压缩数据的目的,如果采用 4bit 的量化位数,其最大的量化步数只能是 16,显 然是不能满足使用要求,因此 ADPCM 应运而生,ADPCM 是一种采用变步长的量化器的预测 编码算法,它的本质是根据预测值与实际的偏差范围,在量化表格中选择出合适的量化值, 使预测变化的幅度保持在 4bit 的范围内。ADPCM 的核心公式如下,其中代表为量化后的值, 为量化步长,代表经过量化后有效的偏差值,加上本次的预测值做为下一次的运算的预测值: 整个 ADPCM 的编码过程分三步进行: 第一步为计算出当前实际值与预测值的偏差,代表了当前数据的实际值,为当前数的预测值。 为量化后的带符号的有效数据为 4bit 的数据,其最高位代表的数据的方向,bit3 为 1 代表负 数,代表-7~7 的整型数据。 当小于 0, bit3 被值 1。 第二步为对进行量化,简易实现不考虑计算效率的情况下完全可以直接参考上面的公式,因 为是在计算机平台进行了除法运算与小数运算,该作者很巧妙的把这些运算使用与或非来实 现了,提高了运算的效率,有兴趣的读者可以看看代码,学习一下这种思路。我们细看一下 公式,,可以发现公式可以拆分为两部分实现,小数部分的量化被转换为了固定的,因此节
约了计算的成本。vpdiff 就是对应这部分的值。 vpdiff = (step >> 3); static int indexTable[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8, }; static int stepsizeTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; 未完。。。。。。 adpcm.h /* ** adpcm.h - include file for adpcm coder. ** ** Version 1.0, 7-Jul-92. */ #ifndef ADPCM_H #define ADPCM_H #ifdef __cplusplus extern "C" { #endif struct adpcm_state { valprev; short char index; /* Previous output value */ /* Index into stepsize table */ }; int adpcm_coder(short *indata, unsigned char *outdata, int len, struct adpcm_state *state);
int adpcm_decoder(unsigned char *indata, short *outdata, int len, struct adpcm_state *state); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ADPCM_H*/ adpcm.c /*********************************************************** Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ /* * Cleaned up by Phil Frisbie for use in HawkVoice */ /* ** Intel/DVI ADPCM coder/decoder. ** ** The algorithm for this coder was taken from the IMA Compatability Project ** proceedings, Vol 2, Number 2; May 1992. ** ** Version 1.2, 18-Dec-92. ** ** Change log: ** - Fixed a stupid bug, where the delta was computed as ** stepsize*code/4 in stead of stepsize*(code+0.5)/4.
an incorrect delta once in a blue moon. ** - There was an off-by-one error causing it to pick ** ** - The NODIVMUL define has been removed. Computations are now always done ** ** ** ** ** ** - Changed some of the variable names to be more meaningful. */ using shifts, adds and subtracts. It turned out that, because the standard is defined using shift/add/subtract, you needed bits of fixup code (because the div/mul simulation using shift/add/sub made some rounding errors that real div/mul don't make) and all together the resultant code ran slower than just using the shifts all the time. #include "adpcm.h" /* Intel ADPCM step variation table */ static int indexTable[16] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8, }; static int stepsizeTable[89] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; int adpcm_coder(short *indata, unsigned char *outdata, int len, struct adpcm_state *state) { int val; /* Current input sample value */ unsigned int delta; /* Current adpcm output value */ int diff; int step; int valpred; int vpdiff; int index; unsigned int outputbuffer = 0;/* place to keep previous 4-bit value */ int count = 0; /* Difference between val and valprev */ /* Stepsize */ /* Predicted output value */ /* Current change to valpred */ /* Current step change index */ /* the number of bytes encoded */ valpred = state->valprev;
index = (int)state->index; step = stepsizeTable[index]; while (len > 0 ) { /* Step 1 - compute difference with previous value */ val = *indata++; diff = val - valpred; if(diff < 0) { delta = 8; diff = (-diff); delta = 0; } else { } delta = diff*4/step; vpdiff = (delta+0.5)*step/4; /* Step 2 - Divide and clamp */ /* Note: ** This code *approximately* computes: ** ** ** but in shift step bits are dropped. The net result of this is ** that even if you have fast mul/div hardware you cannot put it to ** good use since the fixup would be too expensive. */ vpdiff = (step >> 3); if ( diff >= step ) { delta |= 4; diff -= step; vpdiff += step; } step >>= 1; if ( diff >= step ) { delta |= 2; diff -= step; vpdiff += step; } step >>= 1; if ( diff >= step ) { delta |= 1; vpdiff += step; }
/* Phil Frisbie combined steps 3 and 4 */ /* Step 3 - Update previous value */ /* Step 4 - Clamp previous value to 16 bits */ if ( (delta&8) != 0 ) { valpred -= vpdiff; if ( valpred < -32768 ) valpred = -32768; } else { } valpred += vpdiff; if ( valpred > 32767 ) valpred = 32767; /* Step 5 - Assemble value, update index and step values */ index += indexTable[delta]; if ( index < 0 ) index = 0; else if ( index > 88 ) index = 88; step = stepsizeTable[index]; /* Step 6 - Output value */ outputbuffer = (delta << 4); /* Step 1 - compute difference with previous value */ val = *indata++; diff = val - valpred; if(diff < 0) { delta = 8; diff = (-diff); delta = 0; } else { } /* Step 2 - Divide and clamp */ /* Note: ** This code *approximately* computes: ** ** delta = diff*4/step; vpdiff = (delta+0.5)*step/4;
** but in shift step bits are dropped. The net result of this is ** that even if you have fast mul/div hardware you cannot put it to ** good use since the fixup would be too expensive. */ vpdiff = (step >> 3); if ( diff >= step ) { delta |= 4; diff -= step; vpdiff += step; } step >>= 1; if ( diff >= step ) { delta |= 2; diff -= step; vpdiff += step; } step >>= 1; if ( diff >= step ) { delta |= 1; vpdiff += step; } /* Phil Frisbie combined steps 3 and 4 */ /* Step 3 - Update previous value */ /* Step 4 - Clamp previous value to 16 bits */ if ( (delta&8) != 0 ) { valpred -= vpdiff; if ( valpred < -32768 ) valpred = -32768; } else { } valpred += vpdiff; if ( valpred > 32767 ) valpred = 32767; /* Step 5 - Assemble value, update index and step values */ index += indexTable[delta]; if ( index < 0 ) index = 0; else if ( index > 88 ) index = 88; step = stepsizeTable[index];
/* Step 6 - Output value */ *outdata++ = (unsigned char)(delta | outputbuffer); count++; len -= 2; } state->valprev = (short)valpred; state->index = (char)index; return count; } int adpcm_decoder(unsigned char *indata, short *outdata, int len, struct adpcm_state *state) { unsigned int delta; /* Current adpcm output value */ int step; int valpred; int vpdiff; int index; unsigned int inputbuffer = 0;/* place to keep next 4-bit value */ int count = 0; /* Stepsize */ /* Predicted value */ /* Current change to valpred */ /* Current step change index */ valpred = state->valprev; index = (int)state->index; step = stepsizeTable[index]; /* Loop unrolling by Phil Frisbie */ /* This assumes there are ALWAYS an even number of samples */ while ( len-- > 0 ) { /* Step 1 - get the delta value */ inputbuffer = (unsigned int)*indata++; delta = (inputbuffer >> 4); /* Step 2 - Find new index value (for later) */ index += indexTable[delta]; if ( index < 0 ) index = 0; else if ( index > 88 ) index = 88; /* Phil Frisbie combined steps 3, 4, and 5 */ /* Step 3 - Separate sign and magnitude */ /* Step 4 - Compute difference and new predicted value */
分享到:
收藏