音频重采样 c++_基于 ffmpeg 实现重采样和混音

本文介绍了音频的采样率和采样精度,并详细阐述了如何在C++中使用ffmpeg进行音频重采样,确保两道音频流具有相同的格式。混音部分采用线性叠加求平均值的方法,适用于8 bit和16 bit的采样位深。文章还讨论了Android环境下字节序问题,并提供了释放重采样上下文资源的方法。
摘要由CSDN通过智能技术生成

fc56992aebc95cc5e87a9414fdf171b5.png

一、音频概念介绍

1.采样率

一秒钟内对声音信号的采样次数称为采样率,单位 Hz。采样率越高所表示的声波越平滑,对声音的还原度就越好,需要的存储空间也会更大。在数字音频领域常见的采样率有:

l 8000Hz 电话所用采样率

l 22050Hz 无线电广播所用采样率

l 32000Hz miniDV 数码视频 camcorder、DAT(LPmode) 所用采样率

l 44100Hz 音频 CD,也常用于 MPEG-1 音频(VCD,SVCD,MP3)所用采样率

l 48000Hz miniDV、数字电视、DVD、DAT、电影和专业音频所用的数字声音所用采样率

l 96000或192000Hz DVD-Audio、一些 LPCMDVD 音轨、BD-ROM(蓝光盘)音轨、和 HD-DVD(高清晰度 DVD)音轨所用采样率

2.采样精度

对声音信号的每一次采样在计算机中都表示为一个数字,数字的取值范围越大所表示的声音振幅的变化范围就越大,在 Android 中支持的采样精度有三种,定义在 AudioFormat 中:

6dbb946402fd5d49dac92a6e1a359596.png

二、混音实现

这里我们采用线性叠加求平均值的方式对两道音频流进行混音,混音前需要保证两道音频流具有相同的采样率、采样位深和声道数。

1.采样位深为 8 bit 时的混音实现

采样位深为 8 bit 时只需要将两端 pcm 数据对应位置的数字相加求平均值即可。

4a8dca09b99249a9fa38b0902f1485df.png

2.采样位深为 16 bit 时的混音实现

采样位深为 16 bit 时,一次采样需要用两个 byte 表示,所以需要先把连续的两个 byte 转换成 short 再相加求平均值。同时还需要考虑字节序问题,字节序分为大端字节序(高位字节在前,低位字节在后)和小端字节序(低位字节在前,高位字节在后),在 Android 中通过 MediaCodec 解码或从 AudioRecord 中录制的音频数据所采用的字节序都可以通过 ByteOrder.nativeOrder() 方法获得,一般都采用的小端字节序。

4e09893abc832b2997964adcbbbf3e43.png

三、使用 ffmpeg 实现重采样

实现混音时需要保证两道音频流的格式(采样率、位深和声道数)完全相同,因此在混音前需要对原始音频数据进行重采样。这里我们使用 ffmpeg 来实现,只需要编译

libswresample、libavformat 和 libavformat 这三个库就可以:

02d8eadf00b0aebdc29f4ec12aa414b9.png

上面的代码中创建了一个重采样需要的上下文环境 SwrContext,并配置了重采样前和重采样后的必备参数,接下来看下如何使用 SwrContext 实现重采样:

d9fa482b26fdd645ca7cc0f8435f6055.png

cfd5e0b2f6589c21ffcc448a9545dee7.png

上面代码实现中出现的 inbuffer_address 和 outbuffer_address 是 Android 层调用 ByteBuffer.allocateDirect() 方法提前创建的输入/输出缓存,因为 Android 调用 cxx 涉及到 JNI 调用,且重采样方法的调用也会比较频繁,创建缓存可以避免频繁的分配和销毁内存产生的消耗。另外还需要注意,实际输出的采样数目并不一定与输入的采样数目相同,在创建输出缓存时需要将缓存大小设置的比预期稍高一些或动态调整缓存大小。

最后在重采样结束后还需要释放上下文占用的资源:

c1f2644056506e2231a2ab6c296e964f.png

四、总结

本文首先采用 ffmpeg 将源音频数据重采样为目标音频格式,再将两道音频格式相同的音频流混成一道音频流,采用的混音方式是将两道音频流对应位置的采样数据相加求平均值,这种混音方式不会引入额外的噪音,但是在音频流数量比较多时会导致总体音量下降的问题。对于混音的方式,感兴趣的可以自行探索。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值