Android音视频开发,详说PCM音频重采样、PCM编码

 

 直播伴音,两种数据能否合在一起?不能叠加在一起 会有噪音 合并以后 再去编码推流 直播的例子

客户端播放器,可以开启多个播放器

对于我们重采样 很多时候就是为了统一格式,就是为了要合并这个流,去推送,他最终要转成同样pcm格式,

合并码流可以通过ffmpeg amix 做混音,支持多音源合并 做混音,再做二次编码

振幅越大声音越大, 观察喇叭 开车音乐 比较大 手比较振 振幅

 波形 模拟时间  一秒钟我采集多少数据  可以1秒钟采集100万次,对于这个硬件成本能不能搞定

硬件采样速度越快  就需要他硬件资源就越多,那需要的成本就越多  采集这么频繁的频率有没有用?对于我们现实世界可以采集回来的一个频率 除以2 2倍去采集的话,

现实世界 500khz这个频率,我通过1000khz 我就可以采集回来 人的耳朵能否听到500khz的声音呢?高频率的 人的耳朵大概能听到20khz 超过就听不到了,

计算机采集大于40khz 就可以采集 就可以还原出现实世界的声音,这就是我们常见的采样率 44.1khz  48khz 怎么来的,就是根据人的耳朵的极限,有一点冗余 后面就开始定义44.1khz  48khz最经典的,看到无损这一些格式,96khz 192khz 这些采样率 这些是不是我的采样率越高 他越能还原出现实世界,就是有些人可以听的频率高一点,这个采样率越高 音质就会更好一些,

 每个采样点 用多少个字节去表示?

2通道

4通道 

5.1通道 

某个通道 某个样本,并不是多个通道的占多少个字节 等等,

为什么16bit对这个现实世界还原度比较高呢?我们这个声音 刚才这个幅值 也是无线的,这个声音

大 到小,大有多大,这个有多小?这个模拟世界他就是一个无限,模拟无限

用2bit去表示样本点,

用2bit组合成  0  1  2  3  这4个值,我去描述一个声音,比如机顶盒声音调到最小,静音和最小的时候,他这个力度就非常的大,往下调就静音了,往上调 声音听起来有点大,就是因为他能表示的音的阶次不够多,如果你的声音只有 只有4个值,你肯定没办法表示这个音量,大小,经过使用得出来,大概是16bit能够对现实世界 这种声音能够做到比较好的采集还原, 表示某个声音 他当前幅值用16bit 他是比较好还原的,还有一些比较差的音质,比如8bit 对于这个8bit 他这个声音 音质是比较一般的,可能我们不一定能听得出来,我可以先去提取pcm数据

通过ffmpeg去提取的, 

48k产生处理 2通道,先用16bit这种格式,这边我们先提取出来,

 这边就提取出来huiguniang.MP3 pcm数据

 

用8bit 提取出来pcm数据可能会小一点,

 通过u8 u8提不出来了

这边我们播放16le

f32通过这个大家讲浮点数的

f32和s16 同一个文件提取出来,这个浮点数 他是比我们s16大了一倍,

浮点数这个f32的一个样本,他是有4个字节,所以大家一定要注意一下,

这个是我们讲的采样率 为什么我们经常看到44.1khz 还有48khz 就是因为这个人的耳朵,大概是20khz左右吧,是一个上线 我们根据产生定理我们大于2倍的一个频率去做采集,才能去再次还原,所以我们20khz*2就是40khz 那这边我们就采用的是44.1khz 还有48khz这两种比较多

肯定很多朋友问为什么是44.1khz 还有48khz 而不是40 早期这个频率就已经定好的 就是为了冗余 就是给大家讲 就是一般人他是大于20khz但是有些人他会上一点点,

 整数和浮点数他是不一样的,与我们格式搞混了,让你会播放,或者你再去做编码他是有噪音的,打比方我们去试一把,像刚才我们播放这个声音,是不是我刚才提取的f32 还有s16 那么这边我去播放 就是我们以s16这种格式,去播放f32的 就是播放浮点数的,那么我们可以看看,

 声音很辣耳朵,以后如果你编码的时候出现,那就是你这个格式,你输入的给你的编码要求不一样,

 还有码率 还有比特率 不是特别关键的,

这个pcm排列格式的问题

 对于我们提取8bit这个采样点,也有,

 8bit 已经称为s8了,并不是s8l1了,因为单个字节没有所谓的大小端,你只有这一个字节,

pcm数据排列格式的问题

音频的帧没有视频中那么清晰,视频他就是一张图像,但是对于我们这个音频来说这个概念,什么才是一帧数据呢?不同的编码格式他是有区别的, 比如说我们最常见的编码格式,acc

多少个样本数 作为 一帧数据做编码呢?  他通常是1024个样本,作为一帧数据,不同编码格式是不一样的,

比如对于mp3来讲, 他是1152个样本

不同的格式他是不同的

acc编码 支持 我是用  默认是 ffmpeg自带的acc编码

 给大家强调了这一块里面,这个acc编码168 跟libfdk_aac编码167他们有什么区别?

就是说ffmpeg自带aac 需要的格式 是采样格式  

设置要给参数,比如说我把这个pcm读进来,这个编码层通过aac.aac

aac这个后缀是什么意思? 我是使用了ffmpeg自带的aac编码器,

我们可以debug一下,  

通过avcodec find encoder by_name方式去查找编码器,

 

这就是我们对应我们的编码 编成什么样的格式,这边都有一些讲解,

 找一下我们怎么去打开我们的编码器,

 264 avcodecopen2 把我们编码器找出打开它,要编码成什么样的格式, 

我们通过AVCodec 发一个avcodec_find_encodel by name 212  我再强调一下 对于这个ffmpeg来讲,我还是回到刚才的问题,对于aac 编码器,那么我们到底有多少个aac编码器?能否有不同的aac编码器?他是可以有的,

 把源码打开看看,多扩展一些知识,对ffmpeg有多深的理解,并不是说我单独的讲某个知识点,

查fdk aac

对aac封装,为什么知道他是 aac编码器呢?他主要是这个id 比如说我们不同的aac编码器,他的id 是一样的,不一样 主要是他的名字不一样, 这个name他是唯一的,

ffmpeg自带的aac 

这一块的id  ac 名字 aac 这里还有一个问题这边有一个sample fmts 我们对这个aac编码器他需要什么样的格式,那这个时候呢,那你需要跟我们fdk aac去对比一下,两者是有区别的,就是我们在使用的时候 我们用不同的格式,比如说你是用浮点数,

还是整数,这边支持他是不太一样的,蓝线部分

就是 我们最终要用什么样的编码 用什么样的pcm格式,那你要根据不同的编码器去选择,

 这个id的acc是一样的 这个name是不一样的,我们样本数用浮点数的方式还是整数的方式,整数方式和浮点数方式有什么区别呢?比如给大家讲这个s16 他是有负 有正,s16他这个范围有多少,这边我们给出来了

 s16 -32768~32767

flt -1~1

这个浮点数并不是无限大,成一个-1~1这样的一个逻辑,这样我们可以引申一下,比如

工具可以把我们pcm数据导进来, 看看这个格式,

 把一个数值导进来看看,先导入s16的吧?我们在导数据到我们这个工具里,刚才我们选的是s16个格式,

这边就可以看到这个波形就可以  转成-1 到1.0实际上是一个整数来的,样本 对于我们在计算机表示的时候,

我把间隔拉大后,我们每个样本之间他是有一个时间间隔的, 但是我们把他放小一点,我们这样子看的时候,看起来有一点像是连续的,但实际上它是离散的,这边我们可以把这边浮点数 把他导进来,

浮点数导进来的时候要选对了,这边选32位float 

这边做规划统一,-1~1

我们s16跟浮点的规划统一后,这些值

这边是左通道的了,左通道要跟左通道做对比,右通道要跟右通道波形做对比,基本上是对起来的

 到时候你可以把他导进来去播一播 听听它的声音,都是可以看一下的,可以对比一下

 格式里面这个帧 样本数是多少的?就是作为一帧数据做编码,那你一定要看具体这个编码器

 

 在调用if (avcodec_open2的时候,这里有codec_ctx上下文,那codec_ctx上下文里面有一个frame_size这样一个参数,这个参数是非常重要的,这里给出来到底有多少样本数,作为一帧数据做编码,现在他这个值是空值,刚才这个值是空值,现在这个值变成1024 这个时候我们每次要送多少数据  送多少个样本给编码器,那么我们就知道了,就是我们每个通道都是送1024个样本数给到对应的编码器作为一帧数据进行编码,
268逻辑稍微改一改,

这是给到的48000hz frame_size:1024 

这边我再来看看 这边改成8k

再来看看

 对应的采样率,

目前也是1024  

你一定是要根据codec_ctx的frame_size为基准

 这里还有个值 这个是采样格式 

(codec_ctx->sample tmt)

 

刚才我是不是给大家讲过,我们 FMT_FLTP对应到刚才讲的avc里面,他需要的正常格式是不是

AV_SAMPLE_FMT_FLTP是什么意思呢?看一下源码,

这个 AVSampleFormat他是有多种格式,AV SAMPLE FMT U8表示一个版本,

AV SAMPLE FMT S16就是16个bit表示样本,这里AV SAMPLE FMT S32就是我们32bit表示样本,他是整数的

AV SAMPLE FMT_FLT,32位浮点数,

AV SAMPLE_FMT_DBL 64位表示

这边上面和下面有什么区别呢?他的表现格式是不一样的,下面这种他是带了一个p 每一行都带了一个p 这边只的是planar 这个是什么意思呢?

两种格式 一种叫交错模式  一种叫非交错模式

非交错模式对应刚才我们这个图里面,这边我把他画出来,这是我们交错模式的

还有非交错模式

这两个有什么区别,这边我是以一帧为例去讲解,打个比方,比如1024为一帧数据,如果是两通道对于s16 或者s32 我就不用去理他, 我们主要是讲planar是什么意思 

大家需要注意就是这边就是我们两个通道,就是对于我们一帧数据来讲 我们这个时候我们排列格式 你看到这个逻辑你理解了没有?我们1024和左右轴 1024个LR这样去排列的

接下来我们给大家讲非交错模式,

这个模式有什么区别呢?这边还是一帧数据  1024个包括这个左右通道是一帧数据 主要往下面看,对于我们来讲的非交错  我这边存数据  你要注意了  这边存的时候,我这边我就存1024个左, 再存 1024个右,这样一个模式

这两种模式如果你搞混了,那么你播放 或者你编码,打个比方就是如果你是本地是s16格式,但你丢给这个编码器需要planar这种格式,那肯定就会有问题,这一点就特别需要注意到

 这个以f32le的方式我们去播另一个 48k通过s16这种格式

为什么强调老是讲这个命令呢?我要给大家讲一下 因为我们这个通道  就有些朋友就是 举个例子,

他本身他解出来这个数据 比如ffmpeg 他自带的aac 他解码解出来的数据是什么格式?解码解出来他是浮点数的,

然后有个朋友他需要转成s16格式 在上面他解出的是fltp 浮点数planar  解出来的是整数 packed

我转出来我转成浮点数后他做了个重采样转成s16 他转成s16后 他把这个数据通过fwrite 写到我们本地 然后写到本地 他怎么测试的呢? 他现在已经 在s16 这个本地 这个重采样采集成s16后,然后他一直找张老师说,张老师我用这个重采样器为什么重采样这个数据有问题?我说怎么有问题?

然后他就给我截了一条命令 他去播这个数据

他采集的数据他应该使用这个f32le去播

明明重采样转成s16了 他干嘛不用s16去播呢?

我们转到f32的时候,我们不能用planar这种格式,我再强调一下,存到本地的数据不能用planar这种格式 那你要转成f32le这种格式,

就对应到就是我们这一个 刚才这个图里面 转到我们AV SAMPLE FMT FLT

有些朋友去验证这个ac解码的时候,直接把这个f32这个planar格式存到本地,直接去播,

这种工具导入数据 他也只能够导这种非交错模式 而且只能导交错模式,不能导planar模式,

 涉及内容有点多,

 decode编码 手动把他转成 左右左 这种格式,

把对应的数据传进来,读一个mp3的文件,还是huiguniang.mp3文件, 

这边我们就debug看一看, 

 mp3 一般是1152 

 

这边对应的是mp3的 是1152 

但具体的要根据编码器 解码器 解出来的为准,这边我们看有一个frame->nb_samples ;对应的参数,

 format 是8的,我们去对一下 刚刚这个表,AVFrame这个参数 ,这个0  1 2  3  4  5  6 就是对应的 planar这种格式,所以大家理解就可以了,

对于这个重采样器 官方有范例

ffmpeg源码 有个example 

 去参考一下resampling audio.c 这个范例做重采样是可以的,只是对于我们课上 有些细节,会讲到 ,有一些参数 他的返回值 没有做判断,568

他这些返回值本身要做一些判断才对的, 但是范例里面并没有做判断,这就是讲的重采样相关的原理,特别是planar这种格式对应的整数和浮点数,还有对应的采样率 为什么是44.1khz比较多,

 流媒体服务器提升编程,对于

 掌握网络知识是非常有帮助的,有个学员面面腾讯 没有学到音视频网络相关的知识,我们音视频里面最专注的就是音视频的知识,当时就挂到网络原理这一块了,大公司大厂怎么不懂网络这块呢?

Android音视频开发,详说PCM音频重采样、PCM编码

猜你喜欢

转载自blog.csdn.net/chezabo6116/article/details/129753354