一.初始化音频重采样器

  在音频重采样时,用到的核心结构是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. 四月六号java基础学习

    四月六号 1.今天学习了JAVA语言特点,有以下几个特点: 1)简单易学:相对于C/c++语言,java语言省去了指针(pointer).联合体(Unions)以及结构体(struct) 2)面向对象 ...

  2. 随手记:lnmp 安装完 redis 后无法全局操作

     说明redis-server不是全局命令,那么假如到全局即可 假设redis安装目录是:/usr/local/redis/bin/redis-cli ln -s /usr/local/redis/b ...

  3. JUC(四)多线程锁

    目录 多线程锁 Synchronized锁的八种情况 公平锁和非公平锁 可重入锁 synchronized Lock 死锁 检查死锁 多线程锁 Synchronized锁的八种情况 以一个手机类为例, ...

  4. ROS2的安装与使用(超详细图文教程)

    ROS2的安装与使用(超详细图文教程) 如果前面的虚拟机以及Ubuntu22.04镜像都安装好了,根据目录直接跳到ROS2的安装. 资料参考于:古月居 VMware虚拟机的安装 安装地址: 对于不了解 ...

  5. Centos7.x 安装配置Web性能压力测试工具Siege

    一.简介 Siege是一款开源的压力测试工具,设计用于评估WEB应用在压力下的承受能力.可以根据配置对一个WEB站点进行多用户的并发访问,记录每个用户所有请求过程的相应时间,并在一定数量的并发访问下重 ...

  6. 网络编程之java简易聊天室实现

    最近浅学习了一些关于网络编程方面的知识,视频是跟着狂神学习的,可能学习的不是很深 说到网络,相信大家都对TCP.UDP和HTTP协议这些都不是很陌生,学习这部分应该先对端口.Ip地址这些基础知识有一定 ...

  7. [MAUI]模仿iOS多任务切换卡片滑动的交互实现

    @ 目录 原理 创建布局 创建分布函数 创建动效 创建绑定数据 细节调整 首张卡片的处理 为卡片添加裁剪 跳转到最后一张卡片 项目地址 看了上一篇博文的评论,大家对MAUI还是比较感兴趣的,非常感谢大 ...

  8. Spring AOP 分享

    初级篇 AOP是什么? Aspect-oriented Programming (AOP) 即面向切面编程.简单来说,AOP 是一种编程范式,允许我们模块化地定义横跨多个对象的行为.AOP 可以帮助我 ...

  9. 2021-04-18:给定一个二维数组matrix,里面的值不是1就是0,上、下、左、右相邻的1认为是一片岛,返回matrix中岛的数量。

    2021-04-18:给定一个二维数组matrix,里面的值不是1就是0,上.下.左.右相邻的1认为是一片岛,返回matrix中岛的数量. 福大大 答案2021-04-18: 并查集. 代码用gola ...

  10. 2021-05-06:给定一个二维数组matrix, 你可以从任何位置出发,走向上下左右四个方向 。返回能走出来的最长的递增链长度。

    2021-05-06:给定一个二维数组matrix, 你可以从任何位置出发,走向上下左右四个方向 .返回能走出来的最长的递增链长度. 福大大 答案2021-05-06: 自然智慧即可. 动态规划.二维 ...