一.初始化音频滤镜
(相关资料图)
初始化音频滤镜的方法基本上和初始化视频滤镜的方法相同,不懂的可以看上篇博客,这里直接给出代码:
//audio_filter_core.cpp#define INPUT_SAMPLERATE 44100#define INPUT_FORMAT AV_SAMPLE_FMT_FLTP#define INPUT_CHANNEL_LAYOUT AV_CH_LAYOUT_STEREOstatic AVFilterGraph *filter_graph;static AVFilterContext *abuffersrc_ctx;static AVFilterContext *volume_ctx;static AVFilterContext *aformat_ctx;static AVFilterContext *abuffersink_ctx;static AVFrame *input_frame= nullptr,*output_frame= nullptr;int32_t init_audio_filter(const char *volume_factor){ int32_t result=0; char ch_layout[64]; char options_str[1024]; AVDictionary *options_dict= nullptr; //创建滤镜图 filter_graph=avfilter_graph_alloc(); if(!filter_graph){ cerr<<"Error:Unable to create filter graph."<=0){ result=avfilter_link(volume_ctx,0,aformat_ctx,0); } if(result>=0){ result=avfilter_link(aformat_ctx,0,abuffersink_ctx,0); } if(result<0){ fprintf(stderr,"Error connecting filters\n"); return -1; } //配置滤镜图 result=avfilter_graph_config(filter_graph, nullptr); if(result<0){ cerr<<"Error:Error configuring the filter graph."<二.初始化输入音频帧
在这一步需要给输入音频帧设置一些参数,包括采样率,采样点个数,声道布局,音频帧格式等,然后就可以给音频帧分配内存空间了。代码如下:
//audio_filter_core.cppstatic int32_t init_frames(){ int result=0; input_frame->sample_rate=44100; input_frame->format=AV_SAMPLE_FMT_FLTP; input_frame->channel_layout=AV_CH_LAYOUT_STEREO; input_frame->nb_samples=1024; result= av_frame_get_buffer(input_frame,0); if(result<0){ cerr<<"Error:av_frame_get_buffer failed."<三.循环编辑音频帧
在这一步需要注意的是,每次将输入音频帧放入滤镜图前,都要做一次初始化音频帧操作,否则会报错:filter context - fmt: fltp r: 44100 layout: 3 ch: 2, incoming frame - fmt: (null) r: 0 layout: 3 ch: 2 pts_time: NOPTS【Changing audio frame properties on the fly is not supported.】。注意一定是每次,不要只初始化一次,这样只有第一帧初始化了,后面的帧还是会报错,因为输入帧的格式要和滤镜上下文保持一致,如果没有每次都初始化,后面的帧的格式和采样率就识别不到,为null了。下面给出代码:
//audio_filter_core.cppstatic int32_t filter_frame(){ int32_t result= av_buffersrc_add_frame(abuffersrc_ctx,input_frame); if(result<0){ cerr<<"Error:add frame to buffersrc failed."<channels<<",nb_samples:"<nb_samples<<",sample_fmt:"<format<四.将编辑后的数据写入输出文件
在这一步需要注意的是,由于在滤镜图中有一个滤镜实例将音频帧的采样格式设置为了AV_SAMPLE_FMT_S16,这是packed格式的帧,左右声道的数据交错存储在frame->data[0]指向的内存单元中,所以在写入的时候,需要注意这一点。下面给出代码:
//io_data.cppint32_t write_samples_to_pcm2(AVFrame* frame){ int16_t* samples = reinterpret_cast(frame->data[0]); int dataSize = frame->nb_samples * frame->channels * sizeof(int16_t); fwrite(samples, 1, dataSize, output_file); return 0;} 数据读入代码:
//io_data.cpp
static FILE* input_file= nullptr;static FILE* output_file= nullptr;int32_t read_pcm_to_frame2(AVFrame *frame,enum AVSampleFormat sample_fmt,int channels){ int data_size= av_get_bytes_per_sample(sample_fmt); if(data_size<0){ cerr<<"Error:Failed to calculate data size."<data[ch]+i*data_size,1,data_size,input_file); } } return 0;}int32_t open_input_output_files(const char* input_name,const char* output_name){ if(strlen(input_name)==0||strlen(output_name)==0){ cout<<"Error:empty input or output file name."<五.销毁资源
audio_filter_core.cppstatic void free_frames(){ av_frame_free(&input_frame); av_frame_free(&output_frame);}void destroy_audio_filter(){ free_frames(); avfilter_graph_free(&filter_graph);}六.main函数实现
int main(){ const char *input_file_name="../input.pcm"; const char *output_file_name="../output.pcm"; const char *volume_factor="0.9"; int32_t result=0; result= open_input_output_files(input_file_name,output_file_name); if(result<0){ return -1; } result= init_audio_filter(volume_factor); if(result<0){ return -1; } result=audio_filtering(); if(result<0){ return -1; } destroy_audio_filter(); close_input_output_files(); return 0;}最后,可以使用下面的指令测试输出的pcm文件:
ffplay -ac 2 -ar 44100 -f s16le -i output.pcm


















