一.初始化音频重采样器

  在音频重采样时,用到的核心结构是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]排序算法>选择排序>【简单选择排序】(O(n*n)/不稳定/)

    1 选择排序 1.1 算法思想 每一趟从待排序的记录中选出关键字最小的记录,按顺序放在已排序的记录序列的最后(or最前面),直到全部排完位置. 1.2 算法特征 属于[选择排序] 简单选择排序 堆排序 ...

  2. 浅谈对属性描述符__get__、__set__、__delete__的理解

    1.属性描述符的基础介绍 1.1 何为属性描述符? 属性描述符是一种Python语言中的特殊对象,用于定义和控制类属性的行为.属性描述符可以通过定义__get__.__set__.__delete__ ...

  3. React Native组件(二)

    一.创建一个项目 1.1.找到目标目录cmd命令,请尽量不要有中文路径 npx react-native init reactnative03 进入文件 cd reactnative03 启动 npx ...

  4. Django相关配置信息

    Django相关配置信息 1.配置数据库mysql 1.1 setting.py中配置信息 DATABASES = { 'default': { 'ENGINE': 'django.db.backen ...

  5. pdf 转 word

    目录 pdf 转 word 一.思路 二.软件安装下载 1. windows安装 2 certos7版本安装 3. Debian 版本安装 4. 安装字体 三.实现PDF转word文档 四.制作自己的 ...

  6. Centos7.x jmeter + ant + jenkins接口自动化框架部署

    一.基础环境准备 1.jmeter安装(之前文章有介绍过) 2.ant安装 · 官网下载:https://ant.apache.org/bindownload.cgi · 上传服务器,执行 tar - ...

  7. vCenter报错:Log Disk Exhaustion on 10

    vCenter报错:Log Disk Exhaustion on 10 1.问题现象: 巡检时发现 vCenter Server 中,错误显示为:Log Disk Exhaustion on 10(字 ...

  8. 2022-07-12:以下go语言代码输出什么?A:1 1;B:1.0 1.0;C:编译不通过;D:1.0 1。 package main import “fmt“ func main() {

    2022-07-12:以下go语言代码输出什么?A:1 1:B:1.0 1.0:C:编译不通过:D:1.0 1. package main import "fmt" func ma ...

  9. django时区问题的解决

    django时区问题的解决  更新时间:2021年05月18日 09:37:58   作者:Silent丿丶黑羽     我们都知道时区,标准时区是UTC时区,django默认使用的就是UTC时区,我 ...

  10. Anaconda网址

    Anaconda: python全家桶,之前还有32位,现在需要64位. 官方网址:https://www.anaconda.com/ 国内源:https://mirrors.tuna.tsinghu ...