ADPCM 编码解码.详解

上传人:野鹰 文档编号:2878058 上传时间:2017-07-28 格式:DOC 页数:18 大小:68.50KB
返回 下载 相关 举报
ADPCM 编码解码.详解_第1页
第1页 / 共18页
ADPCM 编码解码.详解_第2页
第2页 / 共18页
ADPCM 编码解码.详解_第3页
第3页 / 共18页
ADPCM 编码解码.详解_第4页
第4页 / 共18页
ADPCM 编码解码.详解_第5页
第5页 / 共18页
点击查看更多>>
资源描述

《ADPCM 编码解码.详解》由会员分享,可在线阅读,更多相关《ADPCM 编码解码.详解(18页珍藏版)》请在金锄头文库上搜索。

1、ADPCM 编码解码.详解技术知识 2010-03-24 16:17:09 阅读 126 评论 0 字号:大中小 订阅 http:/ ADPCM 编码解码算法因为种种原因,最近需要把原始的 wav 文件压缩成 ADPCM 格式。但是网上几乎搜不到相关的中文资料。花了相当长的时间,七拼八凑的从一些文章中得到了些信息,终于搞定了它。为了方便遇到跟我一样麻烦的人,我决定把它详细的写下来。1. 关于 DPCMDPCM 是 differential pulse code modulation 的缩写,也就是差分脉冲编码调制的意思。他的主要思想是通过已知的数据预测下一个数据,然后传递预测值与实际值之间的差

2、值。具体的细节可以在很多信号处理相关的书上找到。一般的 DPCM 编码器都是采用的线性预测。假设传递的数据是 X1,X2,.Xn,而下一个数据,Xn+1 还是未知。可以通过前面的 X1,X2,.Xn 的加权和来预测 Xn+1,也就是Xn+1 = (Ai*Xi),其中 i 属于 1.n为了简化计算,大部分编码的实现只取前两项,也就是,Xn+1 = a*Xn + b*Xn-1, 现在,最主要的事情就是如何对 a,b 进行取值,才能使得 Xn+1 的误差最小。如果假设 xi 是预测值, xi 是实际值,那么,(xi-xi)2 最小的时候,a,b 就是最优的。设 F=(Xi-Xi)2,因为 Xi =

3、a*Xi-1 + b*Xi-2,可以得出,F 是关于 a,b 的二元函数 .也就是 F=f(a,b) 。可以分别对 a 和b 求偏导数,求出它的极值点。fa(a,b) = 0 ;fb(a,b) = 0 ;可以得到a * (Xi-1)2 + b * (Xi-1)*(Xi-2) = Xi*Xi-1a * (Xi-1)*(Xi-2) + b * (Xi-2)2 = Xi*Xi-2如果设alpha = (Xi-1)2beta = (Xi-1)*(Xi-2)gama = (Xi-2)2m = Xi*Xi-1n = Xi*Xi-2上面的式子就可以写成a*alpha + b*beta = ma*beta +

4、 b*gama = n算出 alpha,beta,gama,m,n 以后,a 和 b 的值就可以计算出来了,实际上我们只需要一个循环遍历前 n 个数就能把它们都求出来。2. ADPCM 的思想如果直接使用 DPCM 进行编码的话,是得不到什么压缩的效率的。缘故是,需要传输或保存的是预测值后的值与实际值之间的差值,这与原来的数据占用同样的空间。为了满足我们原始的压缩数据的动机,你可以对这些差值进行各种各样的编码。因为,大部分情况下,差值都是像 1,1,1,2,3,5,5,5 之类的数。可以对它们进行通常的游程编码或者 huffman 编码,运气好的话能够得到很大的压缩比。这样做会有一个很大的弊端

5、。因为有些数据可能之间的联系会呈线性或者某种连续函数的性质。但是大部分情况下,数据的分布还是有一定的离散性的。当数据之间出现很大的跳跃的时候,这种方法就显得很苍白无力了。我们可以这么做,每次对得到的差值用一个随着差值大小变化的数来除。这样就可以随着差值的变化,不断调整比例因子。这样出现较大的跳跃时也能把我们要存储的差值限定在一个较小的范围之内。如果你现在有些迷惑,没事,我们换种方式来说明一下。假设差值是 diff,也就是 diff = Xi - Xi,那么,diff 就有可能变动很大,如果引入一个不断变化的因子iDelta,那么, diff = diff / iDelta,而对于 iDelta

6、,每当 diff 变大的时候,他就变大比较大,当 diff 变得比较小的时候,他就相应的减小。这样,我们的 diff就能保持相对的稳定了。通过 iDelta 的引入,可以使得我们的 DPCM 编码自动的适应数据间大幅度的跳跃。这就是自适应脉冲编码调制,ADPCM 的主要思想。你现在可能会想,iDelta 到底怎么变化,才能自动的匹配 diff 的变化? 一种可行的方法就是,把它定义为diff 的一个函数,这个函数根据不同的 diff 的值的大小取不同大小的值。通常我们会做一个 iDelta 值的表,通过 diff 作为索引,这样,就可以根据不同的 diff 值,iDelta 就可以作相应的变化

7、了。3. WAV 文件的格式IMA-ADPCM 压缩的音频文件并没有一个统一的格式。我们现在只考虑微软的自己的 wav 格式。apple 公司的网站上有一篇写得很不错的 technical note, 可以看后面的链接地址。wav 文件是微软定义的一系列资源文件中的一个。这些文件通常是由一系列的 chunk 组成。所有的文件都以 RIFF 标记开头,然后指出文件的大小。接着表明类型,比如 WAVE,MIDI 等. 一个 wav 文件的结构大致如下_| RIFF WAVE Chunk | groupID = RIFF | riffType = WAVE | _ | | Format Chunk

8、| | | ckID = fmt | | |_| | _ | | Sound Data Chunk | | | ckID = data | | |_| |_| 一般每一个 chunk 都有一个 id 和一个 size 来表明 chunk 的类型和大小,这样就可以很容易的将 chunk 读出。id 一般是四个字节,用 ASCII 码的值来标记,比如 data chunk 的 id 就是data,而 format chunk 的 id就是fmt .要注意的是,size 表明的大小是以字节为单位的,而且不包括 id 和 size 字段本身所占的空间。原始的 wave 文件一般只有两个 chunk,也

9、就是 fmt 和 data,原则上,你可以添加任何的其他 chunk,用来添加不同的信息.这也是 wav 文件出现很多变种的原因.windows 下一般有两种格式的 wav 文件,一种是普通未压缩的原始数据,另一种就是采用了 ADPCM 压缩了的。无论哪一种,你都可以使用现存的播放器播放。未压缩的存储格式比较简单,只需要一个 format chunk 来描述格式信息,然后再用一个 data chunk 来存储数据。现在的 wave 文件按规定都必须包括一个 fact chunk,而且在 fmt chunk 里必须包含一个扩展了的 format description,这通过一个 WAVEFOR

10、MATEX 的结构来描述,但是以 WAVE_FORMAT_PCM 为格式的文件并不需要这些额外的信息。下面是 WAVEFORMATEX 的定义typedef struct waveformat_extended_tag WORD wFormatTag; /* format type */WORD nChannels; /* number of channels (i.e. mono, stereo.) */DWORD nSamplesPerSec; /* sample rate */DWORD nAvgBytesPerSec; /* for buffer estimation */WORD n

11、BlockAlign; /* block size of data */WORD wBitsPerSample; /* Number of bits per sample of mono data */WORD cbSize; /* The count in bytes of the extra size */ WAVEFORMATEX;其中 wFormatTag 标明了文件的类型,这样我们就可以判断后面的数据是以什么方式来存储和表示的了,比如,#define WAVE_FORMAT_PCM 0x0001 这样,WAVE_FORMAT_PCM 表示的就是普通的原始wav 文件格式。再比如,#d

12、efine WAVE_FORMAT_ADPCM 0x0002 我们就可以知道,wFormatTag 的值为 WAVE_FORMAT_ADPCM 就是以 ADPCM 压缩的格式了。具体的文件的类型有很多种,详细的定义可以在 mmreg.h 头文件里找到。WAVEFORMATEX 是所有的 format 所共有的一个头部,不同格式会在后面添加自己的相关的数据段,添加的段的字节数可以通过 cbSize 来得到。cbSize 用来描述不同的格式后面添加的多余的字节数。比如 WAVE_FORMAT_ADPCM 格式的 format 的这个值就是 32,表明还有 32 个字节在后面。另外一些字段会在后面解

13、释。fact chunk 是一个值得注意的 chunk,现在的 wav 文件,无论是否压缩,都必须包含一个 fact chunk,用来存储文件文件相关的信息。但是现在它里面只定义了一个字段,用来指出文件里一个有多少个 sample。4. WAVE_FORMAT_ADPCM 的 wav 文件格式再回到我们前面讨论的 DPCM,对于预测后得到的差值 diff,我们应该怎么处理它才能的比较好的压缩比?比如我们的数据是 3,3,4,7,9,2.可以注意到,如果预测做的比较好的话,得到的差值可能会很小,甚至为0,假设我们的原始的音频数据时 16 位的,那么,如果仍然使用 16 位来存储这些数据,肯定是一

14、种浪费。很直观的,你会想到减少每一个 diff 的存储空间,没错,这就是 ADPCM 格式压缩的 wav 文件采用的方法。在压缩过的 wav 文件里,每一个 diff 使用 4 个 bit 来存储的,被称作一个 nibble。这样,我们将一个 16bit的原始数据缩减到 4bit,可以得到一个稳定的 4:1 的压缩比。因为我们采用的是预测编码,这就需要选择预测的系数 a 和 b,我们在前面已经详细的推导过了 a 和 b 的计算方法。现在,我们需要解决的是,一个 wav 文件,我们是对整个文件计算来得出合理的 a 和 b 吗?显然,对整个文件采用相同预测系数并不实际,首先是计算起来麻烦,再一个,

15、一个 wav 文件太长,如果对整个文件采用相同的 a 和 b 起不到什么效果,对于局部的数据,偏差仍然会是很大,这就丧失了我们的初衷。不妨这么考虑,我们将音频数据分成不同的块,分别对每一块求不同的系数,来进行预测编码,一般声音都是连续的,在一个局部的小区域里变化很小,所以 a 和 b 就能很准确的预测出每一个值了。在 apple 下系统下,每一个块称作一个 packet,以 64 个 sample 为固定的大小。而在 windows 下被称作一个 block,他的大小是可变的,所包含的 sample 的个数由 nSamplesPerBlock 来指出,后面我们会看到. 在 WAVEFORMATEX 结构里的 nBlockAlign 描述了每一个 block 所占的字节数.不同的采样率会有不同的大小,下面是 blockAlign 在不同采样率大小下的值nSamplesPerSec x Channels nBlockAlign8k 25611k 25622k 51244k 1024这样,我们可以把压缩后的数据以 block 为单位存储在 data chunk 里.但是,除了压缩的数据以外,我们同样还需要存储当前块的 a 和 b 系数的值 .下面是 A

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号