一.初始化音频重采样器

  在音频重采样时,用到的核心结构是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库实现音频重采样的更多相关文章

  1. 【改】利用ALSA库进行音频重采样

    转自:http://www.voidcn.com/article/p-snamarwr-p.html 一.ALSA介绍: 1.简介: 高级Linux声音体系(英语:Advanced LinuxSoun ...

  2. FFmpeg(11)-基于FFmpeg进行音频重采样(swr_init(), swr_convert())

    一.包含头文件和库文件 修改CMakeLists # swresample add_library(swresample SHARED IMPORTED) set_target_properties( ...

  3. 7.SwrContext音频重采样使用

    头文件位于#include <libswresample/swresample.h>   SwrContext常用函数如下所示 SwrContext *swr_alloc(void); / ...

  4. 简洁明了的插值音频重采样算法例子 (附完整C代码)

    近一段时间在图像算法以及音频算法之间来回游走. 经常有一些需求,需要将音频进行采样转码处理. 现有的知名开源库,诸如: webrtc , sox等, 代码阅读起来实在闹心. 而音频重采样其实也就是插值 ...

  5. FFMpeg笔记(三) 音频处理基本概念及音频重采样

    Android放音的采样率固定为44.1KHz,录音的采样率固定为8KHz,因此底层的音频设备驱动需要设置好这两个固定的采样率.如果上层传过来的采样率不符的话,需要进行resample重采样处理. 几 ...

  6. FFmpeg4.0笔记:封装ffmpeg的音频重采样功能类CSwr

    Github https://github.com/gongluck/FFmpeg4.0-study/tree/master/Cff CSwr.h /************************* ...

  7. FFmpeg进行视频帧提取&音频重采样-Process.waitFor()引发的阻塞超时

    由于产品需要对视频做一系列的解析操作,利用FFmpeg命令来完成视频的音频提取.第一帧提取作为封面图片.音频重采样.字幕压缩等功能: 前一篇文章已经记录了FFmpeg在JAVA中的使用-音频提取&am ...

  8. FFMpeg音频重采样和视频格式转

    一.视频像素和尺寸转换函数 1.sws_getContext : 像素格式上下文  --------------->多副图像(多路视频)进行转换同时显示 2.struct SwsContext  ...

  9. 基于傅里叶变换的音频重采样算法 (附完整c代码)

    前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题. 坦白讲, ...

  10. 基于sinc的音频重采样(一):原理

    我在前面的文章<音频开源代码中重采样算法的评估与选择>中说过sinc方法是较好的音频重采样方法,缺点是运算量大.https://ccrma.stanford.edu/~jos/resamp ...

随机推荐

  1. 安全测试前置实践1-白盒&黑盒扫描

    作者:京东物流 陈维 一.引言 G.J.Myers在<软件测试的艺术>中提出:从心理学角度来说,测试是一个为了寻找错误而运行程序的过程. 那么安全测试则是一个寻找系统潜在安全问题的过程,通 ...

  2. DG:windows密码文件

    问题描述:搭建DG,找不到密码文件的位置,就给备库重新生成了一个密码文件,传到了备库,但是拉到了备库以后,恢复过程中,trace日志在报错,后来才知道windows下的密码文件跟linux平台下的面文 ...

  3. Survivor

    Survivor (https://codeforces.com/group/L9GOcnr1dm/contest/422378/problem/F) 血的教训 比较有意思的一个贪心题 简单翻译一下题 ...

  4. RDIFramework.NET敏捷开发框架助力企业BPM业务流程系统的开发与落地

    现如今,很多企事业单位集团都自己有一套独特严密的业务生产经营流程,各个环节紧密相连.前后对应,一旦某个环节疏忽,整个流程就会出现问题.如何保证业务流程的标准化和规范化运营.减少人为差错,这就需要用到B ...

  5. 5221. 【GDOI2018模拟7.10】A

    题目大意: 给你一棵有根树,问你在这棵树上总共有多少棵子树的节点构成了一个完整的整数区间. 考试想法: 考试时就想到了正解,正解就是从下到上遍历整一棵树,每一个节点记录一下它的最小值min.最大值ma ...

  6. mysql+proxysql+replication-manager的主从半同步复制+高可用+读写分离

    环境: AlmaLinux release 9.1 MySQL Community Server Ver 8.0.33 Replication Manager v2.2.40 for MariaDB ...

  7. Grafana 系列-统一展示-2-Prometheus 数据源

    系列文章 Grafana 系列文章 Grafana Prometheus 数据源 Grafana 提供了对 Prometheus 的内置支持.本文会介绍 Grafana Prometheus(也包括 ...

  8. vue核心

    VUE简介 vue--一套用于构建用户界面的渐进式JavaScript框架 vue特点 采用组件化模式--提高代码复用率--让代码更好维护 声明式编程--让编码人员无需直接操作DOM--提高开发效率 ...

  9. 【GiraKoo】Github无法打开,导致无法下载Git安装包

    环境 Windows 11 原因 Git应用的安装程序在Github上,由于Github访问不稳定,导致无法下载. 对策 打开迅雷.将下载链接拷贝进去,利用迅雷的P2P技术,从其他网友处进行下载. 打 ...

  10. EL表达式访问JavaBean

    前景提要 刚才有个朋友问我,赵大哥这个实验怎么做?我说哪个实验,给我发了几张截图.我一看,嗷,原来是今天,有个Java实验啊,他说大哥,能不能教教我,我说可以.我一说 他 啪的就站起来了, 很快啊 , ...