概述
最近在linux服务器上做ffmpeg混音的一个测试,网上找了一个代码,加上自己写了cmakelist。自己写cmake比较少,记录一下。ffmpeg为4.3版本
下面四个为我创建的文件
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;
}
//根据index保存是否已经存在
if(audio_input_infos.find(index) != audio_input_infos.end())
{
return -1;
}
//
auto& filterInfo = audio_input_infos[index];
//设置音频相关参数
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;
}
//设置音频相关参数
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=输入流数量
//duration=决定流的结束(longest最长输入时间,shortest最短,first第一个输入持续的时间)
//dropout_transition= 输入流结束时,音量重整时间
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)
{
//转换格式
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_ptr
if(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_ptr
if(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();
//释放格式转换
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;
}
//添加一帧,根据index添加相应的输入流
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);});
//设置音频参数
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;
//根据音频参数分配空间
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;
}
//根据音频计算一帧数据的数量
int size = av_samples_get_buffer_size(NULL, avFrame->channels, avFrame->nb_samples, (AVSampleFormat)avFrame->format, 1);
if(size > (int) maxOutBufSize)
{
return 0;
}
//拷贝帧数据
memcpy(outBuf, avFrame->data[0], size);
return size;
}
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);
//多个通道时,混音持续到时间最长的一个通道为止
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;
//转换格式
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
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;
//添加输入流
//参数根据实际pcm数据设置
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 failedn");
return -1;
}
FILE *file2 = fopen("pcm2.pcm", "rb");
if(!file2) {
printf("fopen pcm2.pcm failedn");
return -1;
}
FILE* file_out = fopen("output.pcm", "wb");
if(!file_out) {
printf("fopen output.pcm failedn");
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)
{
//通道1
if(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");
}
}
}
//通道2
if(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;
}
CMakeLists.txt
#=======================================================================
#Cmake最低版本要求
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(audiomix) #项目名称
#允许gdb调试
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
#添加C++11支持及其他选项
set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS} -g")
#=========================================================================
#添加所有头文件
include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/."
"${CMAKE_CURRENT_SOURCE_DIR}/../../ffmpeg/ffoutput/include"
)
#将所有的源文件
file(GLOB td_src
"${CMAKE_CURRENT_SOURCE_DIR}/*"
)
#添加动态库so
link_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/../../ffmpeg/ffoutput/lib"
)
#=========================================================================
#生成可执行文件
add_executable(audiomix ${td_src})
#添加链接库
target_link_libraries(audiomix
avfilter
avformat
swscale
swresample
avcodec
avdevice
avutil
pthread
z
lzma
)
最后
以上就是害怕小笼包为你收集整理的ffmepg cmake链接编译的全部内容,希望文章能够帮你解决ffmepg cmake链接编译所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复