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

ffmpeg进行混音,将两路音频pcm数据合成一路输出
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

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;
}





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 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)
        {
            //通道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;
}

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页