日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ffmpeg进行混音,将两路音频pcm数据合成一路输出

發(fā)布時間:2023/12/1 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ffmpeg进行混音,将两路音频pcm数据合成一路输出 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

ffmpeg進行混音,將兩路音頻pcm數(shù)據(jù)合成一路輸出
audiomixer.h

#ifndef AUDIOMIXER_H #define AUDIOMIXER_H#include <map> #include <mutex> #include <cstdio> #include <cstdint> #include <string> #include <memory>extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavfilter/buffersink.h> #include <libavfilter/buffersrc.h> #include <libavutil/opt.h> }class AudioMixer { public:AudioMixer();virtual ~AudioMixer();//添加音頻輸入通道int addAudioInput(uint32_t index, uint32_t samplerate, uint32_t channels, uint32_t bitsPerSample, AVSampleFormat format);//添加音頻輸出通道int addAudioOutput(const uint32_t samplerate, const uint32_t channels, const uint32_t bitsPerSample, const AVSampleFormat format);//多個通道時,混音持續(xù)到時間最長的一個通道為止int init(const char* duration = "longest");int exit();int addFrame(uint32_t index, uint8_t *inBuf, uint32_t size);int getFrame(uint8_t *outBuf, uint32_t maxOutBufSize);private:struct AudioInfo{AudioInfo(){filterCtx = nullptr;}AVFilterContext *filterCtx;uint32_t samplerate;uint32_t channels;uint32_t bitsPerSample;AVSampleFormat format;std::string name;};AVFilterGraph* filterGraph;bool inited;std::mutex mutex;//輸入std::map<uint32_t, AudioInfo> audio_input_infos;//轉(zhuǎn)換格式std::shared_ptr<AudioInfo> audio_output_info_ptr;//輸出std::shared_ptr<AudioInfo> audio_sink_info_ptr;//混音std::shared_ptr<AudioInfo> audio_mix_info_ptr;};#endif // 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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲色图欧美色 | 国产中文字幕第一页 | 亚洲天堂免费在线观看视频 | 欧美性插插 | 91精东传媒理伦片在线观看 | 一级全黄毛片 | 久久高清无码视频 | 中文在线观看视频 | 色欲久久久天天天综合网 | 久久久三区| 欧美亚洲第一区 | 亚洲欧美在线播放 | 青娱乐超碰 | 69久久| 久久久久久久综合 | 亚洲aa在线观看 | 亚洲五月激情 | 亚洲高清自拍 | 国产欧美综合一区二区三区 | 神马久久av| 日日操日日操 | 麻豆视频国产精品 | 激情六月丁香 | 少妇精品视频一区二区 | 69久人妻无码精品一区 | 免费九九视频 | 先锋影音资源av | 超碰在线最新 | 国产伦精品一区二区三区视频孕妇 | 北条麻妃99精品青青久久 | 日韩成人动漫在线观看 | 精品久久人人妻人人做人人 | 天天舔天天射天天干 | jizz国产 | 全部免费毛片 | 日韩中文字幕一区二区三区 | 在线视频亚洲 | 天堂网在线最新版www中文网 | av动漫在线免费观看 | 国产欧美日韩精品在线 | 黄色片大全| 日本zzjj | 国产资源在线免费观看 | 午夜综合网 | 精品少妇人妻av免费久久久 | 亚洲成av人片在线观看无 | 涩涩天堂 | 国产色综合网 | japanese国产在线 | xxxx国产视频| 亚洲日本国产 | 国产亚洲精品熟女国产成人 | 日韩区欧美区 | 国产黄大片在线观看画质优化 | 色噜噜狠狠狠综合曰曰曰 | 大吊av | 国产在线观看99 | 日韩喷潮 | 97自拍网| 国产精品三级视频 | 国产中年熟女高潮大集合 | www.99在线 | 99热偷拍 | 免费在线国产精品 | 国产精品自拍偷拍视频 | 国产精品视频免费播放 | 日韩国产一区二区 | 女同调教视频 | 免费黄色入口 | 福利视频三区 | 天天视频天天爽 | 国产美女www爽爽爽 www.国产毛片 | 天天舔天天爱 | 先锋影音一区二区 | 顶级嫩模啪啪呻吟不断好爽 | 99这里只有精品 | 无码人妻精品一区二区50 | 国产精品成人网 | 国产片91 | 高清精品xnxxcom | 天天色综合1 | 久久久久久一级片 | 黄大色黄大片女爽一次 | 吖v在线| 成人av在线网站 | 日本免费一区二区在线 | 午夜伦视频 | 日日狠狠久久偷偷四色综合免费 | 成人影片网址 | 亚洲日本久久 | 少妇av网 | 黄色xxxxx| 麻豆精品 | 久久福利在线 | 亚洲区一 | 找av导航 | 国产毛片毛片毛片毛片毛片毛片 | 中日韩精品在线 | 亚洲精品一区二区三区婷婷月 |