ffmpeg进行混音,将两路音频pcm数据合成一路输出
生活随笔
收集整理的這篇文章主要介紹了
ffmpeg进行混音,将两路音频pcm数据合成一路输出
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
ffmpeg進行混音,將兩路音頻pcm數(shù)據(jù)合成一路輸出
audiomixer.h
audiomixer.cpp
#include "audiomixer.h" #include <iostream>AudioMixer::AudioMixer():inited(false),filterGraph(nullptr),audio_output_info_ptr(nullptr) {//初始化重置智能指針audio_mix_info_ptr.reset(new AudioInfo);audio_mix_info_ptr->name = "amix";//混音audio_sink_info_ptr.reset(new AudioInfo);audio_sink_info_ptr->name = "sink";//輸出}AudioMixer::~AudioMixer() {if(inited){exit();} }int AudioMixer::addAudioInput(uint32_t index, uint32_t samplerate, uint32_t channels, uint32_t bitsPerSample, AVSampleFormat format) {std::lock_guard<std::mutex> locker(mutex);if(inited){std::cout<< __PRETTY_FUNCTION__ << "inited return -1!" << std::endl;return -1;}//根據(jù)index保存是否已經(jīng)存在if(audio_input_infos.find(index) != audio_input_infos.end()){return -1;}//auto& filterInfo = audio_input_infos[index];//設(shè)置音頻相關(guān)參數(shù)filterInfo.samplerate = samplerate;filterInfo.channels = channels;filterInfo.bitsPerSample = bitsPerSample;filterInfo.format = format;filterInfo.name = std::string("input") + std::to_string(index);return 0;}int AudioMixer::addAudioOutput(const uint32_t samplerate, const uint32_t channels, const uint32_t bitsPerSample, const AVSampleFormat format) {std::lock_guard<std::mutex> locker(mutex);if(inited){std::cout<< __PRETTY_FUNCTION__ << "inited return -1!" << std::endl;return -1;}//設(shè)置音頻相關(guān)參數(shù)audio_output_info_ptr.reset(new AudioInfo);audio_output_info_ptr->samplerate = samplerate;audio_output_info_ptr->channels = channels;audio_output_info_ptr->bitsPerSample = bitsPerSample;audio_output_info_ptr->format = format;audio_output_info_ptr->name = "output";return 0; }int AudioMixer::init(const char *duration) {std::lock_guard<std::mutex> locker(mutex);if(inited){std::cout<< __PRETTY_FUNCTION__ << "inited return -1!" << std::endl;return -1;}if(!audio_output_info_ptr){std::cout<< __PRETTY_FUNCTION__ << "audio_output_info_ptr return -1!" << std::endl;return -1;}if(audio_input_infos.size() == 0){std::cout<< __PRETTY_FUNCTION__ << "audio_input_infos.size() == 0 return -1!" << std::endl;return -1;}//用于整個過濾流程的一個封裝filterGraph = avfilter_graph_alloc();if(filterGraph == nullptr){return -1;}char args[512] = {0};//混音const AVFilter* amix = avfilter_get_by_name("amix");audio_mix_info_ptr->filterCtx = avfilter_graph_alloc_filter(filterGraph, amix, "amix");//inputs=輸入流數(shù)量//duration=決定流的結(jié)束(longest最長輸入時間,shortest最短,first第一個輸入持續(xù)的時間)//dropout_transition= 輸入流結(jié)束時,音量重整時間snprintf(args, sizeof(args), "inputs=%d:duration=%s:dropout_transition=0",audio_input_infos.size(), duration);if(avfilter_init_str(audio_mix_info_ptr->filterCtx, args) != 0){std::cout<< __PRETTY_FUNCTION__ << "avfilter_init_str audio_mix_info_ptr failed!" << std::endl;return -1;}//輸出const AVFilter* abuffersink = avfilter_get_by_name("abuffersink");audio_sink_info_ptr->filterCtx = avfilter_graph_alloc_filter(filterGraph, abuffersink, "sink");if(avfilter_init_str(audio_sink_info_ptr->filterCtx, nullptr) != 0){std::cout<< __PRETTY_FUNCTION__ << "avfilter_init_str audio_sink_info_ptr failed!" << std::endl;return -1;}//輸入for(auto& iter : audio_input_infos){const AVFilter* abuffer = avfilter_get_by_name("abuffer");snprintf(args, sizeof(args),"sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",iter.second.samplerate,av_get_sample_fmt_name(iter.second.format),av_get_default_channel_layout(iter.second.channels));iter.second.filterCtx = avfilter_graph_alloc_filter(filterGraph, abuffer, audio_output_info_ptr->name.c_str());if(avfilter_init_str(iter.second.filterCtx, args) != 0){std::cout<< __PRETTY_FUNCTION__ << "avfilter_init_str iter.second.filterCtx failed!" << std::endl;return -1;}//audio_input_infos[index] -> audio_min_info_ptr[index]if(avfilter_link(iter.second.filterCtx, 0, audio_mix_info_ptr->filterCtx, iter.first) != 0){std::cout<< __PRETTY_FUNCTION__ << "avfilter_link audio_input_infos[index] -> audio_min_info_ptr[index] failed!" << std::endl;return -1;}}if(audio_output_info_ptr != nullptr){//轉(zhuǎn)換格式const AVFilter* aformat = avfilter_get_by_name("aformat");snprintf(args, sizeof(args),"sample_rates=%d:sample_fmts=%s:channel_layouts=0x%I64x",audio_output_info_ptr->samplerate,av_get_sample_fmt_name(audio_output_info_ptr->format),av_get_default_channel_layout(audio_output_info_ptr->channels));audio_output_info_ptr->filterCtx = avfilter_graph_alloc_filter(filterGraph,aformat,"aformat");if(avfilter_init_str(audio_output_info_ptr->filterCtx, args) != 0){std::cout<< __PRETTY_FUNCTION__ << "avfilter_init_str audio_output_info_ptr failed!" << std::endl;return -1;}//audio_mix_info_ptr -> audio_output_info_ptrif(avfilter_link(audio_mix_info_ptr->filterCtx, 0, audio_output_info_ptr->filterCtx, 0) != 0){std::cout<< __PRETTY_FUNCTION__ << "avfilter_link audio_mix_info_ptr -> audio_output_info_ptr failed!" << std::endl;return -1;}//audio_output_info_ptr -> audio_sink_info_ptrif(avfilter_link(audio_output_info_ptr->filterCtx, 0, audio_sink_info_ptr->filterCtx, 0) != 0){std::cout<< __PRETTY_FUNCTION__ << "avfilter_link audio_output_info_ptr -> audio_sink_info_ptr failed!" << std::endl;return -1;}}if(avfilter_graph_config(filterGraph, NULL) < 0){std::cout<< __PRETTY_FUNCTION__ << "avfilter_graph_config failed!" << std::endl;return -1;}inited = true;return 0; }int AudioMixer::exit() {std::lock_guard<std::mutex> locker(mutex);if(inited){//釋放輸入for(auto iter : audio_input_infos){if(iter.second.filterCtx != nullptr){avfilter_free(iter.second.filterCtx);}}audio_input_infos.clear();//釋放格式轉(zhuǎn)換if(audio_output_info_ptr && audio_output_info_ptr->filterCtx){avfilter_free(audio_output_info_ptr->filterCtx);audio_output_info_ptr->filterCtx = nullptr;}//釋放混音if (audio_mix_info_ptr->filterCtx){avfilter_free(audio_mix_info_ptr->filterCtx);audio_mix_info_ptr->filterCtx = nullptr;}//釋放輸出if (audio_sink_info_ptr->filterCtx){avfilter_free(audio_sink_info_ptr->filterCtx);audio_sink_info_ptr->filterCtx = nullptr;}avfilter_graph_free(&filterGraph);filterGraph = nullptr;inited = false;}return 0; }//添加一幀,根據(jù)index添加相應(yīng)的輸入流 int AudioMixer::addFrame(uint32_t index, uint8_t *inBuf, uint32_t size) {std::lock_guard<std::mutex> locker(mutex);if(!inited){std::cout<< __PRETTY_FUNCTION__ << "inited return -1!" << std::endl;return -1;}auto iter = audio_input_infos.find(index);if(iter == audio_input_infos.end()){std::cout<< __PRETTY_FUNCTION__ << "audio_input_infos.find(index) return -1!" << std::endl;return -1;}if(inBuf && size > 0){std::shared_ptr<AVFrame> avFrame(av_frame_alloc(), [](AVFrame* ptr){av_frame_free(&ptr);});//設(shè)置音頻參數(shù)avFrame->sample_rate = iter->second.samplerate;avFrame->format = iter->second.format;avFrame->channel_layout = av_get_default_channel_layout(iter->second.channels);avFrame->nb_samples = size * 8 / iter->second.bitsPerSample / iter->second.channels;//根據(jù)音頻參數(shù)分配空間av_frame_get_buffer(avFrame.get(), 1);memcpy(avFrame->data[0], inBuf, size);if(av_buffersrc_add_frame(iter->second.filterCtx, avFrame.get()) != 0){return -1;}}else{//沖刷if(av_buffersrc_add_frame(iter->second.filterCtx, NULL) != 0){return -1;}}return 0; }//獲取一幀 int AudioMixer::getFrame(uint8_t *outBuf, uint32_t maxOutBufSize) {std::lock_guard<std::mutex> locker(mutex);if(!inited){std::cout<< __PRETTY_FUNCTION__ << "inited return -1!" << std::endl;return -1;}std::shared_ptr<AVFrame> avFrame(av_frame_alloc(), [](AVFrame *ptr) { av_frame_free(&ptr); });//獲取輸出幀int ret = av_buffersink_get_frame(audio_sink_info_ptr->filterCtx, avFrame.get());if(ret < 0){return -1;}//根據(jù)音頻計算一幀數(shù)據(jù)的數(shù)量int size = av_samples_get_buffer_size(NULL, avFrame->channels, avFrame->nb_samples, (AVSampleFormat)avFrame->format, 1);if(size > (int) maxOutBufSize){return 0;}//拷貝幀數(shù)據(jù)memcpy(outBuf, avFrame->data[0], size);return size; }main.cpp
#include <iostream> #include "audiomixer.h"using namespace std;#define PCM1_FRAME_SIZE (4096*2) #define PCM2_FRAME_SIZE (4096) #define PCM_OUT_FRAME_SIZE (40000)int main() {cout << "Hello Audiomixer!" << endl;AudioMixer audioMix;//添加輸入流//參數(shù)根據(jù)實際pcm數(shù)據(jù)設(shè)置audioMix.addAudioInput(0, 48000, 2, 32, AV_SAMPLE_FMT_FLT);audioMix.addAudioInput(1, 48000, 2, 16, AV_SAMPLE_FMT_S16);//添加輸出流audioMix.addAudioOutput(44100, 2, 16, AV_SAMPLE_FMT_S16);//初始化if(audioMix.init() < 0){printf("audioMix.init() failed!\n");return -1;}int len1 , len2 = 0;uint8_t buf1[PCM1_FRAME_SIZE];uint8_t buf2[PCM2_FRAME_SIZE];FILE* file1 = fopen("pcm1.pcm", "rb");if(!file1) {printf("fopen pcm1.pcm failed\n");return -1;}FILE *file2 = fopen("pcm2.pcm", "rb");if(!file2) {printf("fopen pcm2.pcm failed\n");return -1;}FILE* file_out = fopen("output.pcm", "wb");if(!file_out) {printf("fopen output.pcm failed\n");return -1;}uint8_t out_buf[PCM_OUT_FRAME_SIZE];uint32_t out_size = 0;int file1_finish , file2_finish= 0;while (1){len1 = fread(buf1, 1, PCM1_FRAME_SIZE, file1);len2 = fread(buf2, 1, PCM2_FRAME_SIZE, file2);if(len1 > 0 || len2 > 0){//通道1if(len1 > 0){if(audioMix.addFrame(0, buf1, len1) < 0){printf("audioMix.addFrame(0, buf1, len1) failed!\n");break;}}else{if(file1_finish == 0){file1_finish = 1;if(audioMix.addFrame(0, NULL, 0) < 0){printf("audioMix.addFrame(0, NULL, 0) failed!\n");}}}//通道2if(len2 > 0){if(audioMix.addFrame(1, buf2, len2) < 0){printf("audioMix.addFrame(1, buf2, len2) failed!\n");break;}}else{if(file2_finish == 0){file2_finish = 1;if(audioMix.addFrame(1, NULL, 0) < 0){printf("audioMix.addFrame(1, NULL, 0) failed!\n");}}}int ret = 0;while ((ret = audioMix.getFrame(out_buf, 10240)) >= 0){//寫入文件fwrite(out_buf, 1, ret, file_out);}}else{printf("read file end!\n");break;}}audioMix.exit();if(file_out)fclose(file_out);if(file1)fclose(file1);if(file2)fclose(file2);cout << "End Audiomixer!" << endl;return 0; }總結(jié)
以上是生活随笔為你收集整理的ffmpeg进行混音,将两路音频pcm数据合成一路输出的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 明基ms527如何投到150英寸?
- 下一篇: 使用ffmpeg 的 filter 给图