使用libswresample库实现音频重采样
一.初始化音频重采样器
在音频重采样时,用到的核心结构是SwrContext,我们可以通过swr_alloc()获取swr_ctx实例,然后通过av_opt_set_int()函数和av_opt_set_sample_fmt()函数来设置音频重采样的参数,最后通过swr_init()函数初始化SwrContext实例即可。下面给出代码:
//audio_resampler_core.cpp
#define SRC_NB_SAMPLES 1152
static SwrContext *swr_ctx;
static AVFrame *input_frame= nullptr;
int32_t dst_nb_samples,max_dst_nb_samples,dst_nb_channels,dst_rate,src_rate;
enum AVSampleFormat src_sample_fmt=AV_SAMPLE_FMT_NONE,dst_sample_fmt=AV_SAMPLE_FMT_NONE;
uint8_t **dst_data= nullptr;
int32_t dst_linesize=0;
static int32_t init_frame(int sample_rate,int sample_format,uint64_t channel_layout){
int32_t result=0;
input_frame->sample_rate=sample_rate;
input_frame->nb_samples=SRC_NB_SAMPLES;
input_frame->format=sample_format;
input_frame->channel_layout=channel_layout;
result= av_frame_get_buffer(input_frame,0);
if(result<0){
cerr<<"Error:av_frame_get_buffer failed."<<endl;
return -1;
}
return 0;
}
int32_t init_audio_resampler(int32_t in_sample_rate,const char *in_sample_fmt,const char *in_ch_layout,int32_t out_sample_rate,const char *out_sample_fmt,const char *out_ch_layout){
int32_t result=0;
swr_ctx=swr_alloc();
if(!swr_ctx){
cerr<<"Error:swr_alloc failed."<<endl;
return -1;
}
int64_t src_ch_layout=-1,dst_ch_layout=-1;
if(!strcasecmp(in_ch_layout,"MONO")){
src_ch_layout=AV_CH_LAYOUT_MONO;
}
else if(!strcasecmp(in_ch_layout,"STEREO")){
src_ch_layout=AV_CH_LAYOUT_STEREO;
}
else if(!strcasecmp(in_ch_layout,"SURROUND")){
src_ch_layout=AV_CH_LAYOUT_SURROUND;
}
else{
cerr<<"ERROR:unsupported input channel layout."<<endl;
return -1;
}
if(!strcasecmp(out_ch_layout,"MONO")){
dst_ch_layout=AV_CH_LAYOUT_MONO;
}
else if(!strcasecmp(out_ch_layout,"STEREO")){
dst_ch_layout=AV_CH_LAYOUT_STEREO;
}
else if(!strcasecmp(out_ch_layout,"SURROUND")){
dst_ch_layout=AV_CH_LAYOUT_SURROUND;
}
else{
cerr<<"ERROR:unsupported output channel layout."<<endl;
return -1;
}
if(!strcasecmp(in_sample_fmt,"fltp")){
src_sample_fmt=AV_SAMPLE_FMT_FLTP;
}
else if(!strcasecmp(in_sample_fmt,"s16")){
src_sample_fmt=AV_SAMPLE_FMT_S16P;
}
else{
cerr<<"Error:unsupported input sample format."<<endl;
return -1;
}
if(!strcasecmp(out_sample_fmt,"fltp")){
dst_sample_fmt=AV_SAMPLE_FMT_FLTP;
}
else if(!strcasecmp(out_sample_fmt,"s16")){
dst_sample_fmt=AV_SAMPLE_FMT_S16P;
}
else{
cerr<<"Error:unsupported output sample format."<<endl;
return -1;
}
src_rate=in_sample_rate;
dst_rate=out_sample_rate;
av_opt_set_int(swr_ctx,"in_channel_layout",src_ch_layout,0);
av_opt_set_int(swr_ctx,"in_sample_rate",src_rate,0);
av_opt_set_sample_fmt(swr_ctx,"in_sample_fmt",src_sample_fmt,0);
av_opt_set_int(swr_ctx,"out_channel_layout",dst_ch_layout,0);
av_opt_set_int(swr_ctx,"out_sample_rate",dst_rate,0);
av_opt_set_sample_fmt(swr_ctx,"out_sample_fmt",dst_sample_fmt,0);
result=swr_init(swr_ctx);
if(result<0){
cerr<<"Error:failed to initialize SwrContext."<<endl;
return -1;
}
input_frame=av_frame_alloc();
if(!input_frame){
cerr<<"Error:av_frame_alloc failed."<<endl;
return -1;
}
result= init_frame(in_sample_rate,src_sample_fmt,src_ch_layout);
if(result<0){
cerr<<"Error:init_frame failed."<<endl;
return -1;
}
max_dst_nb_samples=dst_nb_samples=av_rescale_rnd(SRC_NB_SAMPLES,out_sample_rate,in_sample_rate,AV_ROUND_UP);
dst_nb_channels= av_get_channel_layout_nb_channels(dst_ch_layout);
cout<<"max_dst_nb_samples:"<<max_dst_nb_samples<<",dst_nb_channels:"<<dst_nb_channels<<endl;
return 0;
}
二.循环对音频帧进行重采样
音频重采样用到的核心函数是swr_convert(),不过在进行重采样的时候,需要注意每次要去判断目标采样点个数是否大于最大目标采样点个数,如果大于,需要重新给输出缓冲区分配内存空间。下面给出代码:
audio_resampler_core.cpp
static int32_t resampling_frame(){
int32_t result=0;
int32_t dst_bufsize=0;
dst_nb_samples=av_rescale_rnd(swr_get_delay(swr_ctx,src_rate)+SRC_NB_SAMPLES,dst_rate,src_rate,AV_ROUND_UP);
if(dst_nb_samples>max_dst_nb_samples){
av_freep(&dst_data[0]);
result=av_samples_alloc(dst_data,&dst_linesize,dst_nb_channels,dst_nb_samples,dst_sample_fmt,1);
if(result<0){
cerr<<"Error:failed to reallocate dst_data."<<endl;
return -1;
}
cout<<"nb_samples exceeds max_dst_nb_samples,buffer reallocated."<<endl;
max_dst_nb_samples=dst_nb_samples;
}
result=swr_convert(swr_ctx,dst_data,dst_nb_samples,(const uint8_t **)input_frame->data,SRC_NB_SAMPLES);
if(result<0){
cerr<<"Error:swr_convert failed."<<endl;
return -1;
}
dst_bufsize= av_samples_get_buffer_size(&dst_linesize,dst_nb_channels,result,dst_sample_fmt,1);
if(dst_bufsize<0){
cerr<<"Error:Could not get sample buffer size."<<endl;
return -1;
}
write_packed_data_to_file(dst_data[0],dst_bufsize);
return 0;
}
int32_t audio_resampling(){
int32_t result= av_samples_alloc_array_and_samples(&dst_data,&dst_linesize,dst_nb_channels,dst_nb_samples,dst_sample_fmt,0);
if(result<0){
cerr<<"Error:av_samples_alloc_array_and_samples failed."<<endl;
return -1;
}
cout<<"dst_linesize:"<<dst_linesize<<endl;
while(!end_of_input_file()){
result= read_pcm_to_frame2(input_frame,src_sample_fmt,2);//这个函数的代码请看我上篇博客
if(result<0){
cerr<<"Error:read_pcm_to_frame2 failed."<<endl;
return -1;
}
result=resampling_frame();
if(result<0){
cerr<<"Error:resampling_frame failed."<<endl;
return -1;
}
}
return 0;
}
三.将重采样后的数据写入输出文件
在初始化重采样器的时候,我们设置了目标采样格式为s16p,声道数量为1,所以只需要将dst_data[0]的数据写入输出文件即可,下面给出代码:
//io_data.cpp
int32_t write_packed_data_to_file(uint8_t *data,int32_t size){
fwrite(data,1,size,output_file);
}
四.销毁音频重采样器
//audio_resampler_core.cpp
void destroy_audio_resampler(){
av_frame_free(&input_frame);
if(dst_data){
av_freep(&dst_data[0]);
}
av_freep(&dst_data);
swr_free(&swr_ctx);
}
五.main函数实现
int main(){
const char *input_file_name="../input.pcm";
int32_t in_sample_rate=44100;
const char *in_sample_fmt="fltp";
const char *in_sample_layout="STEREO";
const char *output_file_name="../output.pcm";
int32_t out_sample_rate=22050;
const char *out_sample_fmt="s16";
const char *out_sample_layout="MONO";
int32_t result=open_input_output_files(input_file_name,output_file_name);
if(result<0){
return -1;
}
result=init_audio_resampler(in_sample_rate,in_sample_fmt,in_sample_layout,out_sample_rate,out_sample_fmt,out_sample_layout);
if(result<0){
return -1;
}
result=audio_resampling();
if(result<0){
return -1;
}
destroy_audio_resampler();
close_input_output_files();
return 0;
}
最后,使用以下指令可以测试输出的output.pcm文件:
ffplay -f s16le -ac 1 -ar 22050 -i output.pcm
没有给出的函数代码请看我上篇博客
使用libswresample库实现音频重采样的更多相关文章
- 【改】利用ALSA库进行音频重采样
转自:http://www.voidcn.com/article/p-snamarwr-p.html 一.ALSA介绍: 1.简介: 高级Linux声音体系(英语:Advanced LinuxSoun ...
- FFmpeg(11)-基于FFmpeg进行音频重采样(swr_init(), swr_convert())
一.包含头文件和库文件 修改CMakeLists # swresample add_library(swresample SHARED IMPORTED) set_target_properties( ...
- 7.SwrContext音频重采样使用
头文件位于#include <libswresample/swresample.h> SwrContext常用函数如下所示 SwrContext *swr_alloc(void); / ...
- 简洁明了的插值音频重采样算法例子 (附完整C代码)
近一段时间在图像算法以及音频算法之间来回游走. 经常有一些需求,需要将音频进行采样转码处理. 现有的知名开源库,诸如: webrtc , sox等, 代码阅读起来实在闹心. 而音频重采样其实也就是插值 ...
- FFMpeg笔记(三) 音频处理基本概念及音频重采样
Android放音的采样率固定为44.1KHz,录音的采样率固定为8KHz,因此底层的音频设备驱动需要设置好这两个固定的采样率.如果上层传过来的采样率不符的话,需要进行resample重采样处理. 几 ...
- FFmpeg4.0笔记:封装ffmpeg的音频重采样功能类CSwr
Github https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff CSwr.h /************************* ...
- FFmpeg进行视频帧提取&音频重采样-Process.waitFor()引发的阻塞超时
由于产品需要对视频做一系列的解析操作,利用FFmpeg命令来完成视频的音频提取.第一帧提取作为封面图片.音频重采样.字幕压缩等功能: 前一篇文章已经记录了FFmpeg在JAVA中的使用-音频提取&am ...
- FFMpeg音频重采样和视频格式转
一.视频像素和尺寸转换函数 1.sws_getContext : 像素格式上下文 --------------->多副图像(多路视频)进行转换同时显示 2.struct SwsContext ...
- 基于傅里叶变换的音频重采样算法 (附完整c代码)
前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题. 坦白讲, ...
- 基于sinc的音频重采样(一):原理
我在前面的文章<音频开源代码中重采样算法的评估与选择>中说过sinc方法是较好的音频重采样方法,缺点是运算量大.https://ccrma.stanford.edu/~jos/resamp ...
随机推荐
- 四月十六号java基础知识
1.如果没有一个机制来限制对类中成员的访问,则很可能会造成错误的输入如果在类的成员声明前面加上修饰符private,则无法从类的外部访问到该类内部的成员,而只能被该类自身访问和修改,而不能被任何其他类 ...
- 多态 polymorphic
多态是同一个行为具有多个不同表现形式,多态实现需要以下条件 继承父类并重写方法 父类引用指向子类对象:Animal a = new Cat(); 多态实例: //测试类 public class Te ...
- VMware另一个程序锁定文件的一部分,进程无法访问
问题描述:搭建RAC11g,在做共享磁盘的时候,节点2要共享节点1的磁盘,但是有一个问题,节点2关机之后,再打开,是有一个访问节点1的磁盘的过程,如果访问失败,就会开不了机器 rac1加的三个磁盘: ...
- CentOS7.6静默安装19C实例脚本 ORA-27125 [FATAL] [DBT-10322]
脚本: dbca -silent -createDatabase -templateName General_Purpose.dbc -gdbname test -sid test -characte ...
- 【Spring5】IOC
1 Spring概念 Spring是轻量级的开源JavaEE框架.可以解决企业开发的复杂性. Spring有两个核心部分:IOC和Aop ①IOC控制反转:把创建对象过程交给Spring管理 ②Aop ...
- day03-Redis的客户端
Redis的Java客户端 在Redis官网中提供了各种语言的客户端,地址:Get started using Redis clients | Redis Redis的Java客户端: 1.Jedis ...
- docker未授权攻击利用复现
环境配置 受害机:CentOS 攻击者:kali 配置docker配置文件,使得测试机存在未授权访问 vim /usr/lib/systemd/system/docker.service 原本[Ser ...
- Java全栈开发/API
2023/4/16 记录我学习的网站 前端 vuejs axios异步请求 微信开发者文档 uniapp开发文档 快速参考备忘清单 免费前端接口 读取json vant4UI cubeUI mintU ...
- C#自行实现安装卸载程序(不使用官方组件)
正规软件建议还是使用官方的标准安装程序组件,因为官方的标准安装/卸载组件能更好的与操作系统衔接,安装和卸载流程更加规范. 今天提供一种野路子,全用代码实现安装卸载器. 需要写一个程序,包含安装器.卸载 ...
- Axure 手机页面拖动效果
1.设置好上下固定们,中间放一个动态面板,如下图所示,(刚开始创建是没有图片的) 2.再状态1下再创建一个动态面板 命名为D2,如下图所示 3.在D2的状态1下新建一个宽370(大概手机宽)高1100 ...