15 - FFmpeg 音频混音(过滤器)

过滤器链接流程

                                                      +--------+
auto_aresample_0:default--[48000Hz flt:stereo]--input0|  amix  |default--[48000Hz flt:stereo]--auto_aresample_2:default
auto_aresample_1:default--[48000Hz flt:stereo]--input1| (amix) |
                                                      +--------+

                                              +---------------+
aformat:default--[48000Hz s16:stereo]--default|     sink      |
                                              | (abuffersink) |
                                              +---------------+

+-----------+
|  output   |default--[48000Hz s16:stereo]--auto_aresample_0:default
| (abuffer) |
+-----------+

+-----------+
|  output   |default--[48000Hz s32:stereo]--auto_aresample_1:default
| (abuffer) |
+-----------+

                                                       +-----------+
auto_aresample_2:default--[48000Hz s16:stereo]--default|  aformat  |default--[48000Hz s16:stereo]--sink:default
                                                       | (aformat) |
                                                       +-----------+

                                             +------------------+
output:default--[48000Hz s16:stereo]--default| auto_aresample_0 |default--[48000Hz flt:stereo]--amix:input0
                                             |   (aresample)    |
                                             +------------------+

                                             +------------------+
output:default--[48000Hz s32:stereo]--default| auto_aresample_1 |default--[48000Hz flt:stereo]--amix:input1
                                             |   (aresample)    |
                                             +------------------+

                                           +------------------+
amix:default--[48000Hz flt:stereo]--default| auto_aresample_2 |default--[48000Hz s16:stereo]--aformat:default
                                           |   (aresample)    |
                                           +------------------+

测试密令

ffmpeg -i FirstTest.mp3 -i SecondTest.mp3 -filter_complex amix=inputs=2:duration=longest:dropout_transition=3 out.mp3 -y

/**
 * ffmpeg -i FirstTest.mp3 -i SecondTest.mp3 -filter_complex amix=inputs=2:duration=longest:dropout_transition=3 out.mp3 -y
 * -filter_complex:这个参数表示使用一个复杂的过滤器。
 * amix 是一个用于音频混合的过滤器。
 * complex 表示我们将要应用一个比简单过滤器更复杂的操作
 * inputs=2 指明我们有两个输入音频流需要进行混合。
 * duration=longest:指定混合的时长策略
 * longest 表示混合的持续时间将取两个音频文件中较长的那个。
 * dropout_transition=3:这是一个过渡参数
 * dropout_transition=3 则是指定在音频丢失时的过渡时间(单位为秒)。这里设置为3秒,表示在一个音频渐渐退场时,会持续这样的过渡时间。
 * -y:这个参数表示自动覆盖输出文件而不提示。如果 out.mp3 已存在,FFmpeg 将直接用新的文件替换它。
 */

全局配置

extern "C"
{
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>

#include "libavformat/avformat.h"

#include "libavutil/time.h"
#include "libavutil/log.h"
#include "libavutil/avutil.h"
#include "libavutil/mem.h"
#include "libavutil/parseutils.h"
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/samplefmt.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/avassert.h"
#include "libavutil/common.h"
#include "libavutil/mathematics.h"

#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"
#include "libavfilter/avfilter.h"

#include "libavcodec/avcodec.h"
#include "libavcodec/bsf.h"

#include "libswscale/swscale.h"
#include "libswresample/swresample.h"

#include <math.h>
}

#include <iostream>
#include <string>
#include <memory>
#include <map>
#include <mutex> 

#define OUT_BUFFER_SIZE 2 * 2 * 1024

// 跟格式匹配
// 一个 32 - sample - 4个字节 * 双通道 * 1024个采样点
#define FIRST_FRAME_SIZE 2 * 2 * 1024
#define SECOND_FRAME_SIZE 4 * 2 * 1024

// ffplay -ar 48000 -ac 2 -f s16le output.pcm
#define FIRST_FILE "/home/king/ffmpeg_src/lessonCode/ZeroVoiceEducation/05_lesson/resource/48KHZ_S16_2CH.pcm"
/**
 * ffmpeg -i input.mp4 -vn -ar 48000 -ac 2 -f s32le 48KHZ_S32_2CH_PCM.pcm
 * ffplay -ar 48000 -ac 2 -f s32le 48KHZ_S32_2CH.pcm
 * */
#define SECOND_FILE "/home/king/ffmpeg_src/lessonCode/ZeroVoiceEducation/05_lesson/resource/48KHZ_S32_2CH.pcm"

// ffplay -ar 48000 -ac 2 -f s16le output.pcm
#define OUT_FILE "output.pcm"

封装一个AudioMIxer

#include "Global.h"
using namespace std;

struct AudioInfo
{
    uint32_t SampleRate;       // 采样率
    uint32_t channels;         // 声道数
    uint32_t PreSampleBitSize; // 单样本比特数
    AVSampleFormat format;
    string name;

    AVFilterContext *FilterCtx;
};

class AudioMixer
{
public:
    AudioMixer();
    ~AudioMixer();
    bool AddAudioInput(uint32_t index/*通道号*/, uint32_t SampleRate, uint32_t channels, uint32_t PreSampleBitSize, AVSampleFormat format);
    bool AddAudioOutput(uint32_t SampleRate, uint32_t channels, uint32_t PreSampleBitSize, AVSampleFormat format);

    bool Initialize(const char *duration = "longest");

    bool AddFrame(uint32_t index, uint8_t *InBuf, uint32_t size);
    int GetFrame(uint8_t *OutBuf, uint32_t MaxOutBufSize);

    void SetErrorString(int ret);

private:
    string ErrorString_;
    bool IsInitialize_;
    mutex MutexLock_;

    map<uint32_t, AudioInfo> InputAudioInfo_;

    shared_ptr<AudioInfo> OutputAudioInfo_;
    shared_ptr<AudioInfo> MixAudioInfo_;
    shared_ptr<AudioInfo> SinkAudioInfo_;

    AVFilterGraph *FilterGraph_;
};
#include "AudioMixer.h"

AudioMixer::AudioMixer()
{
    IsInitialize_ = false;
    OutputAudioInfo_ = nullptr;
    FilterGraph_ = nullptr;
    /**
     * 这一行将 MixAudioInfo_ 指向一个新的 AudioInfo 对象。
     * new AudioInfo 动态分配了一个 AudioInfo 类型的对象,并返回其指针。
     * reset 方法会将 MixAudioInfo_ 的现有指针(如果有的话)释放掉,确保没有内存泄漏,
     * 然后将其指向新的 AudioInfo 对象。
     **/
    MixAudioInfo_.reset(new AudioInfo);
    MixAudioInfo_->name = "amix"; // 混音使用

    SinkAudioInfo_.reset(new AudioInfo);
    SinkAudioInfo_->name = "sink"; // 输出
}

AudioMixer::~AudioMixer()
{
    // 在构造时自动获取锁,在析构时自动释放锁。适用于函数或代码块内部,确保锁在作用域结束时正确释放。
    lock_guard<mutex> locker(MutexLock_);

    if (IsInitialize_ == true)
    {
        for (auto iter : InputAudioInfo_)
        {
            if (iter.second.FilterCtx != nullptr)
            {
                avfilter_free(iter.second.FilterCtx);
            }
        }

        InputAudioInfo_.clear();

        if (OutputAudioInfo_ != nullptr && OutputAudioInfo_->FilterCtx != nullptr)
        {
            avfilter_free(OutputAudioInfo_->FilterCtx);
            OutputAudioInfo_->FilterCtx = nullptr;
        }

        if (MixAudioInfo_->FilterCtx != nullptr)
        {
            avfilter_free(MixAudioInfo_->FilterCtx);
            MixAudioInfo_->FilterCtx = nullptr;
        }

        if (SinkAudioInfo_->FilterCtx != nullptr)
        {
            avfilter_free(SinkAudioInfo_->FilterCtx);
            SinkAudioInfo_->FilterCtx = nullptr;
        }

        avfilter_graph_free(&FilterGraph_);
        FilterGraph_ = nullptr;
        IsInitialize_ = false;
        av_log(NULL, AV_LOG_WARNING, "[~AudioMixer] end -- line:%d\n", __LINE__);
    }
}

/** 单样本
 * S16 -- 16 bits
 * S32 -- 32 bits
 */
bool AudioMixer::AddAudioInput(uint32_t index, uint32_t SampleRate, uint32_t channels, uint32_t PreSampleBitSize /*单样本*/, AVSampleFormat format)
{
    lock_guard<mutex> locker(MutexLock_);

    if (IsInitialize_ == true) // 初始化之前添加流
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::AddAudioInput] IsInitialize_ == true | 初始化之前添加流 -- line:%d\n", __LINE__);
        return false;
    }
    // find 返回迭代器指向当前查找元素的位置否则返回map::end()位置
    if (InputAudioInfo_.find(index) != InputAudioInfo_.end())
    { // 已经存在返回
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::AddAudioInput] This audio is already in the InputAudioInfo_ -- line:%d\n", __LINE__);
        return false;
    }

    // 初始化一个 input
    // FilterInfo 是 InputAudioInfo_[index] 的别名
    auto &FilterInfo = InputAudioInfo_[index];
    // 初始化音频相关的参数
    FilterInfo.SampleRate = SampleRate;
    FilterInfo.channels = channels;
    FilterInfo.PreSampleBitSize = PreSampleBitSize;
    FilterInfo.format = format;
    FilterInfo.name = string("input") + to_string(index);

    av_log(NULL, AV_LOG_INFO, "[AudioMixer::AddAudioInput] InputAudioInfo_[%d], SampleRate:%d, channels:%d, PreSampleBitSize:%d, format:%d, name:%s -- line:%d\n",
           index, FilterInfo.SampleRate, FilterInfo.channels, FilterInfo.PreSampleBitSize, FilterInfo.format, FilterInfo.name.c_str(), __LINE__);

    return true;
}

bool AudioMixer::AddAudioOutput(uint32_t SampleRate, uint32_t channels, uint32_t PreSampleBitSize, AVSampleFormat format)
{
    lock_guard<mutex> locker(MutexLock_);

    if (IsInitialize_ == true) // 初始化之前添加流
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::AddAudioOutput] IsInitialize_ == true | 初始化之前先添加输出流 -- line:%d\n", __LINE__);
        return false;
    }
    // 初始化输出相关的参数 只有一个输出
    OutputAudioInfo_.reset(new AudioInfo);
    OutputAudioInfo_->SampleRate = SampleRate;
    OutputAudioInfo_->channels = channels;
    OutputAudioInfo_->PreSampleBitSize = PreSampleBitSize;
    OutputAudioInfo_->format = format;
    OutputAudioInfo_->name = "output";

    av_log(NULL, AV_LOG_INFO, "[AudioMixer::AddAudioOutput] SampleRate:%d, channels:%d, PreSampleBitSize:%d, format:%d, name:%s -- line:%d\n",
           OutputAudioInfo_->SampleRate, OutputAudioInfo_->channels, OutputAudioInfo_->PreSampleBitSize, OutputAudioInfo_->format, OutputAudioInfo_->name.c_str(), __LINE__);

    return true;
}

bool AudioMixer::Initialize(const char *duration)
{
    lock_guard<mutex> locker(MutexLock_);
    if (IsInitialize_ == true)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] IsInitialize_ == true -- line:%d\n", __LINE__);
        return false;
    }
    if (InputAudioInfo_.size() == 0)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] No audio input! -- line:%d\n", __LINE__);
        return false;
    }

    FilterGraph_ = avfilter_graph_alloc();
    if (FilterGraph_ == nullptr)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] FilterGraph_ == nullptr -- line:%d\n", __LINE__);
        return false;
    }

    // 初始化一个音频混合过滤器
    char args[512] = {0};
    // 在过滤器图中创建一个新的过滤器实例
    const AVFilter *MixAudioFilter = avfilter_get_by_name("amix"); // 混音
    MixAudioInfo_->FilterCtx = avfilter_graph_alloc_filter(FilterGraph_, MixAudioFilter, "amix");
    /**
     * inputs=输入流数量,duration= 决定流的结束
     * dropout_transition= 输入流结束时,容量重整时间 |(longest最长输出时间,shortest最短,first第一个输入持续的时间)
     **/
    snprintf(args, sizeof(args), "inputs=%ld:duration=%s:dropout_transition=0", InputAudioInfo_.size(), duration);
    int ret = avfilter_init_str(MixAudioInfo_->FilterCtx, args); // 用提供的参数初始化一个过滤器。
    if (ret != 0)
    {
        SetErrorString(ret);
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] av filter init str MixAudioInfo_->FilterCtx error:%s! -- line:%d\n", ErrorString_.c_str(), __LINE__);
        return false;
    }

    // 初始化一个输出过滤器
    const AVFilter *AudioBufferSinkFilter = avfilter_get_by_name("abuffersink");
    SinkAudioInfo_->FilterCtx = avfilter_graph_alloc_filter(FilterGraph_, AudioBufferSinkFilter, "sink");
    ret = avfilter_init_str(SinkAudioInfo_->FilterCtx, nullptr);
    if (ret != 0)
    {
        SetErrorString(ret);
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] av filter init str SinkAudioInfo_->FilterCtx error:%s! -- line:%d\n", ErrorString_.c_str(), __LINE__);
        return false;
    }

    // 初始化一个输入过滤器
    for (auto &iter : InputAudioInfo_)
    {
        const AVFilter *AudioBufferFilter = avfilter_get_by_name("abuffer");
        snprintf(args, sizeof(args), "sample_rate=%d:sample_fmt=%s:channel_layout=0x%x",
                 iter.second.SampleRate,
                 av_get_sample_fmt_name(iter.second.format),
                 av_get_default_channel_layout(iter.second.channels));

        av_log(NULL, AV_LOG_INFO, "[AudioMixer::Initialize] input:%d args:%s! -- line:%d\n", iter.first, args, __LINE__);
        if (FilterGraph_ == nullptr || AudioBufferFilter == nullptr || OutputAudioInfo_->name.c_str() == nullptr)
        {
            av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] av filter init str SinkAudioInfo_->FilterCtx error:%s! -- line:%d\n", ErrorString_.c_str(), __LINE__);
        }
        iter.second.FilterCtx = avfilter_graph_alloc_filter(FilterGraph_, AudioBufferFilter, OutputAudioInfo_->name.c_str());

        ret = avfilter_init_str(iter.second.FilterCtx, args);
        if (ret != 0)
        {
            SetErrorString(ret);
            av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] av filter init str InputAudioInfo_[%d].FilterCtx error:%s! -- line:%d\n", iter.first, ErrorString_.c_str(), __LINE__);
            return false;
        }
        ret = avfilter_link(iter.second.FilterCtx, 0, MixAudioInfo_->FilterCtx, iter.first);
        if (ret != 0)
        {
            av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] InputAudioInfo_[%d].FilterCtx ---> MixAudioInfo_->FilterCtx error:%s -- line:%d\n", iter.first, ErrorString_.c_str(), __LINE__);
            return false;
        }
    }

    if (OutputAudioInfo_ != nullptr)
    {
        const AVFilter *OutputAudioFormatFilter = avfilter_get_by_name("aformat");
        snprintf(args, sizeof(args), "sample_fmts=%s:sample_rates=%d:channel_layouts=0x%lx",
                 av_get_sample_fmt_name(OutputAudioInfo_->format),
                 OutputAudioInfo_->SampleRate,
                 av_get_default_channel_layout(OutputAudioInfo_->channels));
        OutputAudioInfo_->FilterCtx = avfilter_graph_alloc_filter(FilterGraph_, OutputAudioFormatFilter, "aformat");
        ret = avfilter_init_str(OutputAudioInfo_->FilterCtx, args);
        if (ret != 0)
        {
            SetErrorString(ret);
            av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] av filter init str OutputAudioInfo_->FilterCtx error:%s! -- line:%d\n", ErrorString_.c_str(), __LINE__);
            return false;
        }
        ret = avfilter_link(MixAudioInfo_->FilterCtx, 0, OutputAudioInfo_->FilterCtx, 0);
        if (ret != 0)
        {
            SetErrorString(ret);
            av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] avfilter link MixAudioInfo_->FilterCtx, OutputAudioInfo_->FilterCtx error:%s! -- line:%d\n", ErrorString_.c_str(), __LINE__);
            return false;
        }
        ret = avfilter_link(OutputAudioInfo_->FilterCtx, 0, SinkAudioInfo_->FilterCtx, 0);
        if (ret != 0)
        {
            SetErrorString(ret);
            av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] avfilter link OutputAudioInfo_->FilterCtx, SinkAudioInfo_->FilterCtx error:%s! -- line:%d\n", ErrorString_.c_str(), __LINE__);
            return false;
        }
    }
    ret = avfilter_graph_config(FilterGraph_, NULL);
    if (ret < 0)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::Initialize] avfilter graph config error:%s! -- line:%d\n", ErrorString_.c_str(), __LINE__);
        return false;
    }
    IsInitialize_ = true;

    string GraphString = avfilter_graph_dump(FilterGraph_, NULL);
    if (GraphString.c_str() != nullptr)
    {
        FILE *GraphFile = fopen("GraphFile.txt", "w"); // 打印 filterfraph 的 具体情况
        if (GraphFile != nullptr)
        {
            fwrite(GraphString.c_str(), 1, GraphString.size(), GraphFile);
            fclose(GraphFile);
        }
    }
    return true;
}

bool AudioMixer::AddFrame(uint32_t index, uint8_t *InBuf, uint32_t size)
{
    lock_guard<mutex> locker(MutexLock_);
    if (IsInitialize_ == false)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::AddFrame] IsInitialize_ == false -- line:%d\n", __LINE__);
        return false;
    }
    auto iter = InputAudioInfo_.find(index);
    if (iter == InputAudioInfo_.end())
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::AddFrame] iter == InputAudioInfo_.end() -- line:%d\n", __LINE__);
        return false;
    }
    // AVFrame *frame = av_frame_alloc();
    if (InBuf != nullptr && size > 0)
    {
        /**
         * 调用 av_frame_alloc() 分配一个 AVFrame 结构的内存,并返回指向该结构的指针。
         * 使用这个指针创建一个 shared_ptr,这样在 shared_ptr 对象生命周期结束时,会调用指定的 lambda 表达式作为删除器。
         * 删除器使用 av_frame_free() 释放 AVFrame 结构的内存,确保资源得到正确管理。
         **/
        shared_ptr<AVFrame> frame(av_frame_alloc(), [](AVFrame *ptr)
                                  { av_frame_free(&ptr); });
        frame->sample_rate = iter->second.SampleRate;
        frame->format = iter->second.format;
        frame->channel_layout = av_get_default_channel_layout(iter->second.channels);
        frame->nb_samples = size * 8 / iter->second.PreSampleBitSize / iter->second.channels;

        av_frame_get_buffer(frame.get(), 1);
        memcpy(frame->extended_data[0], InBuf, size);

        int ret = av_buffersrc_add_frame(iter->second.FilterCtx, frame.get());
        if (ret != 0)
        {
            SetErrorString(ret);
            av_log(NULL, AV_LOG_ERROR, "[AudioMixer::AddFrame] av buffersrc add frame error:%s -- line:%d\n", ErrorString_.c_str(), __LINE__);
            return false;
        }
    }
    else
    {
        int ret = av_buffersrc_add_frame(iter->second.FilterCtx, nullptr);
        if (ret != 0)
        {
            SetErrorString(ret);
            av_log(NULL, AV_LOG_ERROR, "[AudioMixer::AddFrame] av buffersrc add frame error:%s -- line:%d\n", ErrorString_.c_str(), __LINE__);
            return false;
        }
    }

    return true; // 所有操作成功
}

int AudioMixer::GetFrame(uint8_t *OutBuf, uint32_t MaxOutBufSize)
{
    lock_guard<mutex> locker(MutexLock_);
    if (IsInitialize_ == false)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::GetFrame] IsInitialize_ == false -- line:%d\n", __LINE__);
        return -1;
    }

    shared_ptr<AVFrame> frame(av_frame_alloc(), [](AVFrame *ptr)
                              { av_frame_free(&ptr); });

    int ret = av_buffersink_get_frame(SinkAudioInfo_->FilterCtx, frame.get());
    if (ret < 0)
    {
        if (ret == -541478725 || ret == -11)
        {
            SetErrorString(ret);
            av_log(NULL, AV_LOG_DEBUG, "[AudioMixer::GetFrame] buffersink get frame:%s -- line:%d\n", ErrorString_.c_str(), __LINE__);
            return -1;
        }
        SetErrorString(ret);
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::GetFrame] buffersink get frame error:%s  -- line:%d\n", ErrorString_.c_str(), __LINE__);
        return -1;
    }
    int size = av_samples_get_buffer_size(NULL, frame->channels, frame->nb_samples, (AVSampleFormat)frame->format, 0);
 
    if (size > MaxOutBufSize)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixer::GetFrame] get size > MaxOutBufSize -- line:%d\n", __LINE__);
        return -1;
    }
    memcpy(OutBuf, frame->extended_data[0], size);
    return size;
}

void AudioMixer::SetErrorString(int ret)
{
    ErrorString_.clear();
    char errbuf[1024] = {0};
    av_strerror(ret, errbuf, sizeof(errbuf) - 1);
    ErrorString_ = errbuf;
}

封装manage

#include "Global.h"
#include "AudioMixer.h"

using namespace std;

class AudioMixManage
{
public:
    AudioMixManage();
    ~AudioMixManage();
    // 添加输入输出源
    bool AddSources();
    // 初始化
    bool ManageInitialize();
    // 写文件
    bool WriteMixDocument();

private:
    AudioMixer mixer_;

    FILE *FIRST_IN_AUDIO_;
    FILE *SECOND_IN_AUDIO_;
    FILE *OUT_AUDIO_;

    const char *FirstInFileName_;
    const char *SecondInFileName_;
    const char *OutFileName_;

    uint8_t OutBuffer_[OUT_BUFFER_SIZE]; // 读取帧
    size_t OutSize_;

    uint8_t FirstBuffer_[FIRST_FRAME_SIZE]; // 临时读写数据
    size_t FirstSize_;

    uint8_t SecondBuffer_[SECOND_FRAME_SIZE];// 临时读写数据
    size_t SecondSize_;

    bool FirstFinish_;
    bool SecondFinish_;
};
#include "MixManage.h"

AudioMixManage::AudioMixManage()
{
    FIRST_IN_AUDIO_ = nullptr;
    SECOND_IN_AUDIO_ = nullptr;
    OUT_AUDIO_ = nullptr;

    FirstInFileName_ = FIRST_FILE;
    SecondInFileName_ = SECOND_FILE;
    OutFileName_ = OUT_FILE;

    OutSize_ = 0;
    FirstSize_ = -1;
    SecondSize_ = -1;

    memset(OutBuffer_, 0, OUT_BUFFER_SIZE);
    memset(FirstBuffer_, 0, FIRST_FRAME_SIZE);
    memset(SecondBuffer_, 0, SECOND_FRAME_SIZE);

    FirstFinish_ = false;
    SecondFinish_ = false;
}

AudioMixManage::~AudioMixManage()
{
    if (OUT_AUDIO_ != nullptr)
    {
        fclose(OUT_AUDIO_);
    }
    if (FIRST_IN_AUDIO_ != nullptr)
    {
        fclose(FIRST_IN_AUDIO_);
    }
    if (SECOND_IN_AUDIO_ != nullptr)
    {
        fclose(SECOND_IN_AUDIO_);
    }
    av_log(NULL, AV_LOG_WARNING, "[%s] end! -- line:%d\n", __FUNCTION__,__LINE__);
}

bool AudioMixManage::AddSources()
{
    // 输入流
    bool ret = mixer_.AddAudioInput(0, 48000, 2, 16, AV_SAMPLE_FMT_S16);
    if (ret == false)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixManage::AddSources] mixer_.AddAudioInput error! -- line:%d\n", __LINE__);
        return false;
    }
    ret = mixer_.AddAudioInput(1, 48000, 2, 32, AV_SAMPLE_FMT_S32);
    if (ret == false)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixManage::AddSources] mixer_.AddAudioInput error! -- line:%d\n", __LINE__);
        return false;
    }
    // 输出流
    ret = mixer_.AddAudioOutput(48000, 2, 16, AV_SAMPLE_FMT_S16);
    if (ret == false)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixManage::AddSources] mixer_.AddAudioOutput error! -- line:%d\n", __LINE__);
        return false;
    }
    return true;
}

bool AudioMixManage::ManageInitialize()
{
    // 打开输入/输出文件
    FIRST_IN_AUDIO_ = fopen(FirstInFileName_, "rb");
    SECOND_IN_AUDIO_ = fopen(SecondInFileName_, "rb");
    OUT_AUDIO_ = fopen(OutFileName_, "wb");
    if (FIRST_IN_AUDIO_ == nullptr || SECOND_IN_AUDIO_ == nullptr || OUT_AUDIO_ == nullptr)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixManage::ManageInitialize] open file error! -- line:%d\n", __LINE__);
        return false;
    }
    if (mixer_.Initialize("longest") < 0)
    {
        av_log(NULL, AV_LOG_ERROR, "[AudioMixManage::ManageInitialize] open fil  e error! -- line:%d\n", __LINE__);
        return false;
    }
    return true;
}

bool AudioMixManage::WriteMixDocument()
{
    uint16_t ReadCount = 0;
    while ((FirstFinish_ == false || SecondFinish_ == false))
    {
        SecondSize_ = fread(SecondBuffer_, 1, SECOND_FRAME_SIZE, SECOND_IN_AUDIO_);
        FirstSize_ = fread(FirstBuffer_, 1, FIRST_FRAME_SIZE, FIRST_IN_AUDIO_);

        if (++ReadCount % 50 == 0)
        {
            av_log(NULL, AV_LOG_INFO, "[AudioMixManage::WriteMixDocument] FirstSize:%ld, SecondSize:%ld ReadCount:%d -- line:%d\n", FirstSize_, SecondSize_, ReadCount, __LINE__);
        }
        if (FirstSize_ > 0)
        {
            if (mixer_.AddFrame(0, FirstBuffer_, FirstSize_) == false)
            {
                av_log(NULL, AV_LOG_ERROR, "[AudioMixManage::WriteMixDocument] mixer_.AddFrame error! -- line:%d\n", __LINE__);
                break;
            }
        }
        else
        {
            if (FirstFinish_ == false)
            {
                FirstFinish_ = true;
                if (mixer_.AddFrame(0, nullptr, 0) == false)
                {
                    av_log(NULL, AV_LOG_ERROR, "[AudioMixManage::WriteMixDocument] mixer_.AddFrame error! -- line:%d\n", __LINE__);
                }
            }
        }

        if (SecondSize_ > 0)
        {
            if (mixer_.AddFrame(1, SecondBuffer_, SecondSize_) == false)
            {
                av_log(NULL, AV_LOG_ERROR, "[AudioMixManage::WriteMixDocument] mixer_.AddFrame error! -- line:%d\n", __LINE__);
                break;
            }
        }
        else
        {
            if (SecondFinish_ == false)
            {
                SecondFinish_ = true;
                if (mixer_.AddFrame(1, nullptr, 0) == false)
                {
                    av_log(NULL, AV_LOG_ERROR, "[AudioMixManage::WriteMixDocument] mixer_.AddFrame error! -- line:%d\n", __LINE__);
                }
            }
        }

        int ret = 0;
        while ((ret = mixer_.GetFrame(OutBuffer_, OUT_BUFFER_SIZE)) >= 0)
        {
            OutSize_ += ret;
            if ((OutSize_ % OUT_BUFFER_SIZE == 0) && (ReadCount % 25 == 0))
            {
                av_log(NULL, AV_LOG_INFO, "[AudioMixManage::WriteMixDocument] mix audio:%d, write sum to size_:%ld -- line:%d\n", ret, OutSize_, __LINE__);
            }
            fwrite(OutBuffer_, 1, ret, OUT_AUDIO_);
        }
    }
    return true;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值