这是编码子程序,大概思路是这样的,还需要自己微调。
#include<stdioh>
#include<mathh>
int main()
{int dataleft=0X0000;
scanf("%d",&dataleft);
int b=0 ,lj=0,dl=0,dn=0,pcm=0 ;
if(dataleft<=0)
{dataleft=abs(dataleft);
b=1;
};
dataleft>>4;
if(dataleft<=15&&dataleft>=0)
{ lj=1;
dl=000;
dn=(dataleft-0)/lj;}
if(dataleft<=31&dataleft>=16)
{ lj=1;
dl=001;
dn=(dataleft-16)/lj;}
if(dataleft<=63&dataleft>=32)
{lj=2;
dl=010;
dn=(dataleft-32)/lj;}
if(dataleft<=127&dataleft>=64)
{ lj=4;
dl=011;
dn=(dataleft-64)/lj;}
if(dataleft<=255&dataleft>=128)
{ lj=8;
dl=100;
dn=(dataleft-128)/lj;}
if(dataleft<=511&dataleft>=256)
{ lj=16;
dl=101;
dn=(dataleft-256)/lj;}
if(dataleft<=1023&dataleft>=512)
{ lj=32;
dl=110;
dn=(dataleft-512)/lj;}
if(dataleft<=2047&dataleft>=1024)
{lj=64;
dl=111;
dn=(dataleft-1024)/lj;}
b=b<<7;
dl=dl<<3;
pcm=b+dl+dn;
printf("%d",pcm);
}
本文分为四个部分:音频基本概念,PCM编码格式介绍,PCM A-law编码格式介绍,制作测试样本。
我们听到的声音是由频率(是什么)和强度(有多响)决定的。上图是一个正弦函数生成的音频,频率是441Hz,采样率是441kHz,采样(sample)的最大值是4095。声音的频率就是一个完整的波形没秒钟重复的次数,采样率(sample_rate)是每秒钟收集多少次声音的强度数据,这样每个完整的波形包含100个采样。
上面这个图是个单声道(channel)的音频,实际的音频很多都是多声道的。当有多个声道时,需要定义每个声道中的采样用什么方式进行排列,例如:双声道的时,可以 LRLR ,也可以 LL,RR 。(这个问题会在后续讲容器的文章中在详细说明)
每个采样(sample)代表了声音的强度,但它这并不是个绝对的声音大小,只是相对的。因为,同样的声音文件通过不同的设备播放,声音的大小显然不同,这个和播放设备提供的能量有关。声音的绝对大小用分贝(dB)度量,采样只是和分贝的相对关系。
PCM(Pulse Code Modulation,脉冲编码调制)是对声音的振幅(音量的大小)进行编码,位深度为14bit,20bit,24bit等(用多少个二进制位表示)。通过每秒钟记录若干次振幅的值(采样率,8k,441k,48k等),把声音的波形记录下来(频率)。
计算机系统中8个二进制位对应1个字节,所以实际表示一个采样时,需要用1个,2个或4个字节进行表示;每个字节又可采用有符号或无符号的方式。当用多个字节表示一个采样时,又存在字节序的问题,就是前面的字节表示的高位还是低位,分为大字节序(big-endian,将高序字节存储在起始地址)和小字节序(little-endian,将低序字节存储在起始地址)。这样就会产生 很多编码的组合,下面是 ffmpeg 支持的 pcm 采样格式(也可以通过命令行 ffmpeg -formats | grep PCM 查看)。
PCM本身是一种无损(lossless)编码格式(我理解无损的含义是收集到什么就记录什么,不同格式间的差别在于记录的精度,并不因为方式产生的损失)。但是在电话系统中为了更有效地传递数据,提出了 PCM A-alaw 和 PCM mu-law 两种编码格式,其思路是将原始的PCM编码, 压缩成8位的编码(具体的算法不展开了,可以参考 g711原理pcm转alaw,pcm转ulaw,alaw转pcm,ulaw转pcm )。
alaw 是将13位的有符号数压缩为8位的有符号数,是有损编码(压缩),编码后的数据通过解码无法恢复到原状,数值越大的采样损失的数据就越多。(这里有个疑问,在系统中是用16位保存一个样本的,那是否又有3位数据丢掉了?)
alaw 只定义了采样的编解码方法,但是实际使用中还要注意采样率的问题,通常mp3,mp4这些音视频文件中的采样率为441k或48k,而电话系统中的采样率为8k,那么从高采样率到低采样率,必然又会产生损失。
上图是实现Asterisk播放mp4文件的简要流程,中间涉及到音频的编解码过程,其中任何一个环节(出现错误或者因为编解码带来损失)都可能导致最终听到的声音有问题(失真,噪音等)。我们必须找到一种方法验证在各个环节是否运行正确,例如;采样率,采样位深度等等。我采用的方法是通过 ffmpeg 这个工具生成测试数据,并按照各个环节产生的编码格式生成对应的参照数据,然后比较在各个环节实际产生的数据是否正确。
通常mp4文件中的音频解码出的裸流是 pcm_s16le (有符号,2字节,小字节序),那么我们先生成一个该格式的10秒钟的裸流。
ffmpeg 告诉我们生成的文件的编码格式 pcm_s16le ,采样率是 44100 ,单声道 mono 。通过查看源码(libavfilter/asrc_sinec)可以知道:1、正弦波的频率是441Hz,那么 每周期包含100个采样(44100/441) ,这个有助于我们理解生成的数据的变化规律;2、 采样的最大值等于4095(0xfff) ,并不是有符号16位数的最大值32767(0x8000),这个最大值正好是12bit,加上1位符号位是13,正好和 alaw 将13位有符号数转为8位对应上了。
生成文件的大小是 882000 字节,44100个采样/秒 10秒 2字节/采样。
读取生成文件的前200个采样(400个字节)生成图形如下:
按16进制格式打开文件(vi sine-10ss16le,打开后 :%!xxd ),查看数据:
可以看到在第26个采样达到最大值 ff0f ,第76个采样达到最小值 01f0 。因为是小字节序,要调换字节顺序,所以最大值对应的是 0x0fff(4095) ,最小值对应的是 0xf001(-4095) 。
用上面的 ffmpeg 命令生成一段10秒钟的 pcm_s16le 格式音频文件(裸流,没有进行封装)。我们既可以用耳朵听,也可以用眼睛看这个音频。
下面我们把同样的声音做 alaw 编码。
生成文件的大小 441000 ,44100个采样/秒 10秒 2字节/采样。
读取生成文件的前200个采样(200个)字节,生成图形:
alaw 采样的符号位和原始pcm数据符号位是相反的,所以波峰和波谷和 s16le 是相反的;因为数据进行了编码压缩,所以编码后的数据并不能体现出原始波形,但是频率并没有发生改变。
直接打开文件查看数据:
可以看到在波峰波谷位置数据的差异变小了。
如果需要设置采样率(默认是441k),例如:8k,可以通过 ar 参数实现。
alaw 是一种压缩格式,需要解压缩才能播放,按 alaw 算法解码出来的采样时13位有符号数,对应的存储格式就是 pcm_s16le ,所以我们看看alaw转s16le会是什么样?
这次是用之前生成好的 alaw 文件作为输入。
取前200个样本生成图形。
从图形上可以看到整体波形并没有发生改变,但是在波峰波谷的位置存在失真,这表明 alaw 的编解码过程带来了损失。
查看原始数据我们也可以看到已经和原始 s16le 数据不同,数据精度下降了。
生成一段空白10秒裸流,采样全是0。
ffmpeg -lavfi anullsrc=r=44100:cl=mono -t 10 -f s16le -c:a pcm_s16le null-10sraw
生成一段指定内容的裸流(并不能设定为特定值,如果指定的是0,输出的是0,否则是最大值)。
ffmpeg -lavfi aevalsrc=1 -t 1 -f s16le -c:a pcm_s16le eval-1sraw
执行如下命令,可以查看音频文件的音量:
获得输出内容:
n_samples: 441000
mean_volume: -211 dB
max_volume: -181 dB
histogram_18db: 128000
看这个数据仍然不太明白音量到底是什么,通过看源码,形成大体上的理解,0dB被当作音量的极大值,对应16位有符号数的最大值就是32767(0x8000),等于91dB的音量。(目前并不确切知道为什么选91分贝这个值,似乎是再高的值人就受不了。)
参考: >
我的电脑前段时间经常出现(初始化pcm解码器失败)。用了多种方法无济于事,最后用下面的方法解决了。
打开计算机,在右上角搜索框内输了bugreportexe,搜索所有bugreportexe文件,选择全部删除,重新打开全民K歌就解决问题了。
以上就是关于PCM编码的DSP实现全部的内容,包括:PCM编码的DSP实现、Asterisk播放mp4(1)——音频和PCM编码、电脑版全民K歌下载伴奏后提示初始化pcm解码器失败咋回事卸载了重新装的也不行,重新打开也不行,求等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)