FFMpeg音频混合,背景音(二):pcm压缩为aac整体流程

FFmpeg版本:3.3.1

一、整体流程代码

1、基本流程

#include<iostream>
using namespace std;
//用到的C的头文件
extern "C"
{
#include<libavcodec/avcodec.h>
#include<libavformat/avformat.h>
#include<libavutil/avutil.h>
#include<libswresample/swresample.h>
}
//对用到的预编译
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swresample.lib")
int main() 
{
    //注册
    av_register_all();
    avcodec_register_all();
    //定义文件
    char inputFile[] = "audio.pcm";
    char outputFile[] = "audio.aac";
    int ret = 0;
    //找到aac编码器
    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec)
    {
        cout << "avcodec_find_encoder faild" << endl;
        return -1;
    }
    //配置编码器上下文
    AVCodecContext* ac = avcodec_alloc_context3(codec);
    if (!ac)
    {
        cout << "avcodec_alloc_context3 faild" << endl;
        return -1;
    }
    //给编码器设置参数
    ac->sample_rate = 44100; //采样率
    ac->channels = 2; //声道数
    ac->channel_layout = AV_CH_LAYOUT_STEREO; //立体声
    ac->sample_fmt = AV_SAMPLE_FMT_FLTP; //采样格式为32位float即样本类型fltp
    ac->bit_rate = 64000; //比特率,采样率。
    //给音频的帧设置同一个头部
    ac->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    //打开音频编码器
    ret = avcodec_open2(ac, codec, NULL);
    if (ret < 0) 
    {
        cout << "avcodec_open2 faild" << endl;
        return -1;
    }
    //创建一个输出的上下文, 初始化oc
    AVFormatContext *oc = NULL;
    avformat_alloc_output_context2(&oc, NULL, NULL, outputFile);
    if (!oc)
    {
        cout << " avformat_alloc_output_context2 faild" << endl;
        return -1;
    }
    //设置音频流
    AVStream* st = avformat_new_stream(oc, NULL);
    st->codecpar->codec_tag = 0;
    avcodec_parameters_from_context(st->codecpar,ac); //把ac参数拷贝过来
    //类似于print,打印视频或者音频信息,参数分别为输出上下文,音视频(0,1),输出文件名,是否输出
    av_dump_format(oc, 0,outputFile, 1);
    //打开文件流
    ret = avio_open(&oc->pb, outputFile, AVIO_FLAG_WRITE);
    if (ret < 0)
    {
        cout << "avio_open faild" << endl;
        return -1;
    }
    //打开文件IO流
    avio_close(oc->pb);
    //关闭编码器
    avcodec_close(ac);
    avcodec_free_context(&ac);
    avformat_free_context(oc);
    return 0;
}

 2、整体代码如下,右击项目属性,需要把预处理器加入_CRT_SECURE_NO_WARNINGS

#include<iostream>
using namespace std;
//用到的C的头文件
extern "C"
{
#include<libavcodec/avcodec.h>
#include<libavformat/avformat.h>
#include<libavutil/avutil.h>
#include<libswresample/swresample.h>
}
//对用到的预编译
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "swresample.lib")
int main() 
{
    //注册
    av_register_all();
    avcodec_register_all();
    //定义文件
    char inputFile[] = "audio.pcm";
    char outputFile[] = "audio.aac";
    int ret = 0;
    //找到aac编码器
    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec)
    {
        cout << "avcodec_find_encoder faild" << endl;
        return -1;
    }
    //配置编码器上下文
    AVCodecContext* ac = avcodec_alloc_context3(codec);
    if (!ac)
    {
        cout << "avcodec_alloc_context3 faild" << endl;
        return -1;
    }
    //给编码器设置参数
    ac->sample_rate = 44100; //采样率
    ac->channels = 2; //声道数
    ac->channel_layout = AV_CH_LAYOUT_STEREO; //立体声
    ac->sample_fmt = AV_SAMPLE_FMT_FLTP; //采样格式为32位float即样本类型fltp
    ac->bit_rate = 64000; //比特率,采样率。
    //给音频的帧设置同一个头部
    ac->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

    //打开音频编码器
    ret = avcodec_open2(ac, codec, NULL);
    if (ret < 0) 
    {
        cout << "avcodec_open2 faild" << endl;
        return -1;
    }
    //创建一个输出的上下文, 初始化oc
    AVFormatContext *oc = NULL;
    avformat_alloc_output_context2(&oc, NULL, NULL, outputFile);
    if (!oc)
    {
        cout << " avformat_alloc_output_context2 faild" << endl;
        return -1;
    }
    //设置音频流
    AVStream* st = avformat_new_stream(oc, NULL);
    st->codecpar->codec_tag = 0;
    avcodec_parameters_from_context(st->codecpar,ac); //把ac参数拷贝过来
    //类似于print,打印视频或者音频信息,参数分别为输出上下文,音视频(0,1),输出文件名,是否输出
    av_dump_format(oc, 0,outputFile, 1);
    //打开文件流
    ret = avio_open(&oc->pb, outputFile, AVIO_FLAG_WRITE);
    if (ret < 0)
    {
        cout << "avio_open faild" << endl;
        return -1;
    }
    //向输出写入头部信息
    avformat_write_header(oc, NULL);
    //重采样,并写入输出文件
    SwrContext *ctx = NULL;
    //给重采样上下文配置参数:重采样上下文,输出文件省道布局,输出的
    ctx = swr_alloc_set_opts(ctx, ac->channel_layout, ac->sample_fmt, ac->sample_rate,//需要输出的参数
        AV_CH_LAYOUT_STEREO,AV_SAMPLE_FMT_S16, 44100, //输入的参数
        0,0  //不需要偏移和记录日志
        );
    if (!ctx)
    {
        cout << "swr_alloc_set_opts faild" << endl;
        return -1;
    }
    //重采样初始化
    ret = swr_init(ctx);
    if (ret < 0)
    {
        cout << "swr_init faild" << endl;
        return -1;
    }
    //用frame一帧一帧的从源文件读取
    AVFrame* frame = av_frame_alloc();
    frame->format = AV_SAMPLE_FMT_FLTP;
    frame->channels = 2;
    frame->channel_layout = AV_CH_LAYOUT_STEREO;
    frame->nb_samples = 1024; //一帧音频的样本数量
    //创建frame的缓存空间
    ret = av_frame_get_buffer(frame, 0);
    if (ret < 0)
    {
        cout << " av_frame_get_buffer faild" << endl;
        return -1;
    }
    //准备缓存空间专门存放从pcm读取的数据。
    int readSize = frame->nb_samples * 2 * 2;//pcm一帧的大小。双通道。32位
    char* pcms = new char[readSize];

    //打开输入文件
    FILE* fp = fopen(inputFile, "rb");
    for (;;)
    {
        //存储到哪,多大,多少,读取哪个文件
        int len = fread(pcms, 1, readSize, fp);
        if (len <= 0)
        {
            break;
        }
        const uint8_t* data[1];
        data[0] = (uint8_t*)pcms;
        //对一帧的数据重采样,
        len = swr_convert(ctx, frame->data, frame->nb_samples, //重采样后的数据
                data, frame->nb_samples
            );
        if (len <= 0)
        {
            break;
        }
        //AVpacket存放编码后的数据,AVframe存放原始数据
        AVPacket pkt;
        av_init_packet(&pkt);
        //将重采样之后的数据放到编码线程
        ret = avcodec_send_frame(ac, frame);
        if (ret != 0)
        {
            continue;
        }
        //接受编码后的数据
        ret = avcodec_receive_packet(ac, &pkt);
        if (ret != 0)
        {
            continue;
        }
        //对编码后的数据做参数设定,01分别表示音频和视频
        pkt.stream_index = 0; 
        pkt.dts = 0;
        pkt.pts = 0;
        //数据写入输出上下文
        av_interleaved_write_frame(oc, &pkt);
        cout << len << ",";
        //



    }
    delete pcms;
    pcms = NULL;
    //写入音频的索引
    av_write_trailer(oc);



    //关闭打开文件IO流
    avio_close(oc->pb);
    //关闭编码器
    avcodec_close(ac);
    avcodec_free_context(&ac);
    avformat_free_context(oc);
    return 0;
    /*
    严重性    代码    说明    项目    文件    行    禁止显示状态
错误    C4996    'fopen': This function or variable may be unsafe. Consider using fopen_s instead. 
To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. pcm_aac D:\FFMpeg\project\pcm_aac\pcm_aac\main.cpp 115
*/ }

 

posted @ 2020-10-14 15:06  jasonzhangxianrong  阅读(612)  评论(1编辑  收藏  举报