ffmpeg api pcm转aac

本文详细介绍了使用FFmpeg进行PCM格式音频文件到AAC编码的完整流程,包括打开输出上下文、选择编码器、设置参数、音频重采样、编码并写入AAC文件。关键步骤包括配置通道数、采样率、编码器选择及处理不支持的采样格式。
摘要由CSDN通过智能技术生成

编码流程:


avformat_alloc_output_context2();      //打开输出音频上下文句柄;
avcodec_find_encoder();                     //查找编码器
avcodec_alloc_context3();                   //创建编码器上下文
//初始化编码器参数

codecCtx->channels       = 2;                   //通道数量
codecCtx->channel_layout = AV_CH_LAYOUT_STEREO; //通道类型
codecCtx->sample_rate    = 8000;                //采样率
codecCtx->sample_fmt     = AV_SAMPLE_FMT_FLTP;  //采样数据格式
if (!check_sample_fmt(codec, codecCtx->sample_fmt)) 
{
     fprintf(stderr, "Encoder does not support sample format %s",
            av_get_sample_fmt_name(codecCtx->sample_fmt));
     exit(1);
}

codecCtx->bit_rate = 64000;                       //码率
codecCtx->flags   |= AV_CODEC_FLAG_GLOBAL_HEADER; //公共头部


avcodec_open2();                                //打开编码器
avformat_new_stream();                      //创建AVstream语音通道
avcodec_parameters_from_context(); //从编码器上下文获取编码参数
avio_open();                                         //创建并初始化AVIOContext
avformat_write_header();                     //写文件头
av_frame_alloc();                                 //初始化语音帧
fread();                                                 //读pcm语音
swr_convert();                                      //语音重采样
avcodec_send_frame();                       //发送一帧音频给编码器
avcodec_receive_packet();                  //接收编码数据
av_interleaved_write_frame();             //写编码数据
av_write_trailer();                                 //写文件尾

代码

#include <iostream>
#include <string>

extern "C"{
#include "libavutil/samplefmt.h"
#include "libavutil/timestamp.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswresample/swresample.h"

}

using namespace std;

AVFormatContext *fmt_cntx    = NULL;
AVCodec         *codec       = NULL;
AVCodecContext  *codecCtx    = NULL;
AVStream        *astream = NULL;
SwrContext      *swrCtx      = NULL;
AVFrame         *frame  = NULL;

/* check that a given sample format is supported by the encoder */
static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
{
    const enum AVSampleFormat *p = codec->sample_fmts;
    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == sample_fmt)
            return 1;
        p++;
    }
    return 0;
}
int main()
{
    cout<<"ffmpeg pcm to aac"<<endl;
    const char* pcm_file = "test.wav";
    const char* aac_file = "out.aac";
    
    FILE *fp = fopen(pcm_file,"rb");
    if(!fp)
    {
        cout<<"open fille "<<pcm_file<<" fail"<<endl;
        return -1;
    }
    //创建输出上下文
    int ret = avformat_alloc_output_context2(&fmt_cntx, NULL, NULL, aac_file);
    if (ret < 0) {
        cout<<"avformat_alloc_output_context2 fail"<<endl;
        exit(0);
    }
    
     //查找编码器
    codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec) {
        cout<<"avcodec_find_encoder fail"<<endl;
        return -1;
    }
    codecCtx = avcodec_alloc_context3(codec);
    if(!codecCtx)
    {
        cout<<"avcodec_alloc_context3 fail"<<endl;
        return -1;
    }
    
    //av_dump_format(fmt_cntx, 0, aac_file, 1);
    
    //初始化编码器参数
    codecCtx->channels       = 2;                   //通道数量
    codecCtx->channel_layout = AV_CH_LAYOUT_STEREO; //通道类型
    codecCtx->sample_rate    = 8000;                //采样率
    codecCtx->sample_fmt     = AV_SAMPLE_FMT_FLTP;  //采样数据格式
    if (!check_sample_fmt(codec, codecCtx->sample_fmt)) 
    {
        fprintf(stderr, "Encoder does not support sample format %s",
                av_get_sample_fmt_name(codecCtx->sample_fmt));
        exit(1);
    }

    codecCtx->bit_rate = 64000;                       //码率
    codecCtx->flags   |= AV_CODEC_FLAG_GLOBAL_HEADER; //公共头部
    
    //打开编码器
    ret = avcodec_open2(codecCtx, codec, NULL);
    if (ret != 0) {
        cout<<"avcodec_open2 fail"<<endl;
        return -1;
    }
    //创建AVstream
    astream = avformat_new_stream(fmt_cntx,NULL);
    astream ->codecpar->codec_tag = 0;
    avcodec_parameters_from_context(astream->codecpar,codecCtx);

    //创建并初始化AVIOContext
    ret = avio_open(&fmt_cntx->pb,aac_file,AVIO_FLAG_WRITE);
    if (ret < 0)
    {
        cout << "avio_open error" << endl;
        return -1;
    }
    //写文件头
    ret = avformat_write_header(fmt_cntx,NULL);

    swrCtx = swr_alloc();
    if(!swrCtx)
    {
        cout<<"swr_alloc fail"<<endl;
    }
    swrCtx = swr_alloc_set_opts(
            swrCtx,
            codecCtx->channel_layout,        //输出通道类型
            codecCtx->sample_fmt,            //输出采样格式
            codecCtx->sample_rate,           //输出采样率
            av_get_default_channel_layout(1),//输入通道类型
            AV_SAMPLE_FMT_S16,               //输入采样格式
            8000,                            //输入采样率
            0, 0);
    ret = swr_init(swrCtx);
    if(ret < 0)
    {
        cout<<"swr init fail"<<endl;
        return -1;
    }


    frame =  av_frame_alloc();
    frame->format   = AV_SAMPLE_FMT_FLTP;
    frame->channels = 2;
    
    frame->channel_layout = AV_CH_LAYOUT_STEREO;
    frame->nb_samples     = 1024;              //一帧音频存放的样本数量
    ret = av_frame_get_buffer(frame,0);
    if (ret < 0)
    {
        cout << "av_frame_get_buffer error" << endl;
        return -1;
    }
    //读取pcm数据一帧样本的大小  样本数*通道数*存储格式16位
    int readSize = frame->nb_samples * 1* 2;
    
    char *buf = (char*)malloc(readSize);
    memset(buf,0,readSize);
    int len = 0;
    while((len = fread(buf,1,readSize,fp)) > 0)
    {
        cout<<"read len="<<len<<endl;
        const uint8_t *data[1];
        data[0] = (uint8_t*)buf;
        len = swr_convert(swrCtx, 
                          frame->data, 
                          frame->nb_samples,
                          data, 
                          frame->nb_samples);
        
        if(len <=0)
            break;
            
        AVPacket pkt;
        av_init_packet(&pkt);
        ret = avcodec_send_frame(codecCtx,frame);
        if (ret != 0) continue;
        while(ret >= 0)
        {
            ret = avcodec_receive_packet(codecCtx,&pkt);
            if (ret != 0) continue;
            //音频封装成aac文件
            pkt.stream_index = 0;
            pkt.pts = 0;
            pkt.dts = 0;
            ret = av_interleaved_write_frame(fmt_cntx,&pkt);
        }
    }
    
    free(buf);
    buf = NULL;
    
    //写文件尾
    av_write_trailer(fmt_cntx);
    //关闭输出流
    avio_close(fmt_cntx->pb);
    //清理封装输出上下文
    avformat_free_context(fmt_cntx);
    //关闭编码器
    avcodec_close(codecCtx);
    //清理编码器上下文
    avcodec_free_context(&codecCtx);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值