一.初始化音频重采样器

  在音频重采样时,用到的核心结构是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)/稳定/N较小/有序/顺序存储+链式存储)

    1 直接插入排序 1.1 算法思想 插入排序的基本思想是:每一趟将1个待排序的记录,按其关键字的大小插入到已经排好序的一组记录的适当位置上,直到所有待排序记录全部插入为止. 1.2 算法特征 属于[插 ...

  2. 升级:In-Place Upgrade升级MySQL5.6.26

    升级需谨慎,事前先备份 MySQL升级的实质是对数据字典的升级,数据字典有:sys.mysql.information_schema.performance_schema . MySQL升级的两种方式 ...

  3. 生成df的几种方法

    法一: pd.DataFrame( [ (第一行),(第二行),(第三行)] ) df = pd.DataFrame([('bird', 389.0), ('bird', 24.0), ('mamma ...

  4. Sitecore10 Demo演示环境Azure一键部署(Step By Step Guide to installing Sitecore10 in Azure Paas)

    本文演示Sitecore XP Single(XP0)在Azure上的一键部署,即"30分钟生成Sitecore演示环境"的一环. 关于XP(即Sitecore Experienc ...

  5. 当我第一次通过Kotlin和Compose来实现一个Canvas时, 我收获了什么?

    当我第一次通过Kotlin和Compose来实现一个Canvas时, 我收获了什么? 自从2019年Google推荐Kotlin为Android开发的首选语言以来已经经历了将近四年的时间, Compo ...

  6. win系统安装wordcloud报错解决方案

    问题: ① 在命令行下执行pip install wordcloud出现报错如图: ②下载了错误的whl文件, 出现wordcloud-1.4.1-cp27-cp27m-win_amd64.whl i ...

  7. Locust 运行方式

      命令参数方式运行 # -*- coding: utf-8 -*- from locust import TaskSet, task, User ''' 命令行参数运行示例代码 ''' class ...

  8. 文心一言 VS chatgpt (16)-- 算法导论4.1 1~2题

    一.当A的所有元素均为负数时,FIND-MAXIMUM-SUBARRAY返回什么? 文心一言: 当A的所有元素均为负数时,FIND-MAXIMUM-SUBARRAY返回-1. 这是因为在二进制中,当所 ...

  9. 2020-10-10:OOM都有哪些,说出几种?

    福哥答案2020-10-10:#福大大架构师每日一题# [答案参考了此链接:](https://cloud.tencent.com/developer/article/1480668) 本地方法栈:1 ...

  10. 2022-02-01:粉刷房子 II。 假如有一排房子,共 n 个,每个房子可以被粉刷成 k 种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同。 当然,因为市场上不同颜色油漆的价

    2022-02-01:粉刷房子 II. 假如有一排房子,共 n 个,每个房子可以被粉刷成 k 种颜色中的一种,你需要粉刷所有的房子并且使其相邻的两个房子颜色不能相同. 当然,因为市场上不同颜色油漆的价 ...