FFMPEG编码实现:pcm编码为acc

 本程序流程:
1、创建输出码流的上下文AVFormatContext,并初始化
2、打开输出文件:avio_open2()
3、创建新流:avformat_new_stream()   //用于保存音频流信息,一个完整的视频文件包含多个流信息:视频流、音频流、字幕流等
4、创建编码器上下文并设置编码参数
5、查找编码器并打开编码器
6、写入文件头信息:avformat_write_header()
7、打开输入文件
8、循环读取输入文件的yuv值,并进行编码;编码成功写入文件:av_write_frame()
9、对编码器中剩余数据编码
10、写入文件尾信息:av_write_trailer()
11、释放资源

音频编码流程和视频编码大致相同,部分解析可查看FFMPEG编码实现:将YUV文件编码为H264

/*
* 编码 pcm->acc
*/
#include <iostream>
#include <cstdio>
using namespace std;
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
//#include <libswresample/swresample.h> //音频重采样库
}a
const char* infile = "out.pcm";
const char* outfile = "out.aac";
int audiocount = 0;

int encodec_one_frame_audio(AVFormatContext *ctx, AVCodecContext *codec_ctx, AVPacket pkt, AVFrame *frame)
{
    int ret = 0;
    if (ret = avcodec_send_frame(codec_ctx, frame) != 0)
    {
        cout << "send audio packet to decodec error" << endl;
        return -1; 
    }
    while(ret >= 0)
    {
        ret = avcodec_receive_packet(codec_ctx, &pkt);
        if (ret == 0)
        {
            //int audio_buffersize = av_samples_get_buffer_size(NULL, codec_ctx->channels, codec_ctx->frame_size, AV_SAMPLE_FMT_S16P, 1); //获取音频数据大小
            cout << "channels = " << codec_ctx->channels << "rate = " << codec_ctx->sample_rate  << "sample_fmt = " << codec_ctx->sample_fmt << endl; //输出音频的通道数、采样率和采样格式(这里输出8,为AV_SAMPLE_FMT_FLTP)
            if(av_write_frame(ctx, &pkt) < 0)
            {
                cout << "write error" << endl;
                return -4;//写入文件失败,可选择退出程序
            }
            audiocount++; //计数,输出看写入的第几个数据包
            cout << "write pcm one frame succeed, this is " << audiocount << endl;
        }
        else if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
        {
            cout << "receive audio frame  error, need again" << endl;
            return -2; //接收到的数据无效 需要重新读入
        }
        else
        {
            cout << "avcodec_receive_frame audio error  code:" << ret << endl;
            return -3; //编码错误,可选择直接退出程序
        }
    }
    return 0; //解码成功
}
int main(int argc, char** argv)
{
    AVFormatContext* afc = avformat_alloc_context(); //初始化上下文结构体AVFormatContext
    AVOutputFormat* outformate;
    outformate = av_guess_format(NULL, outfile, NULL);
    if(outformate == NULL)
    {
        cout << "outformat error" << endl;
        return -1;
    }
    afc->oformat = outformate;
    if(avio_open2(&afc->pb, outfile, AVIO_FLAG_READ_WRITE, NULL, NULL) < 0) //已读写的方式打开输出文件,赋值IO上下文pb
    {
        cout << "open outfile error" << endl;
        return -1;
    }
    AVStream *newstream = avformat_new_stream(afc, NULL); //创建新流,用作音频流
    if(newstream == NULL)
    {
        cout << "new stream create error" << endl;
        return -1;
    }

    AVCodec *codec =  avcodec_find_encoder(acc->codec_id); //这里也可以使用avcodec_find_encoder_by_name("aac")
    if(codec == NULL)
    {
        cout << "open encodec error" << endl;
        return -1;
    }

    //设置编码参数
    AVCodecContext* acc = avcodec_alloc_context3(NULL);
    avcodec_parameters_to_context(acc, newstream->codecpar);//acc = newstream->codec;新版本丢弃了AVStream::codec成员,增加了codecpar成员,利用avcodec_parameters_to_context()赋值
    acc->codec_id = afc->oformat->audio_codec;
    acc->codec_type = AVMEDIA_TYPE_AUDIO; //编码器类型
    acc->sample_fmt =  AV_SAMPLE_FMT_FLTP; //音频采样格式//AV_SAMPLE_FMT_S16有些库不支持AV_SAMPLE_FMT_S16
    acc->sample_rate = 48000; //采样率
    acc->channel_layout = AV_CH_LAYOUT_STEREO; //声道布局
    acc->channels = 2; //通道数

    if (avcodec_open2(acc, codec, NULL) < 0)
    {
        cout << "open encodec error" << endl;
        return -1;
    }

    AVFrame* aframe = av_frame_alloc();
    aframe->nb_samples = acc->frame_size;
    aframe->format = acc->sample_fmt;
    int audiosize = av_samples_get_buffer_size(NULL, acc->channels, acc->frame_size, acc->sample_fmt, 1);
    uint8_t *pcmdata; //用于存放输入文件的pcm数据信息
    pcmdata = (uint8_t*)av_malloc(audiosize);

    AVPacket pkt;
    av_new_packet(&pkt, audiosize);//av_packet_init(&pkt);//(AVPacket*)av_malloc(sizeof(AVPacket));
    //写文件头信息
    avformat_write_header(afc, NULL);

    FILE* inF = fopen(infile, "rb");
    
    while (true)
    {
        if(fread(pcmdata, 1, audiosize, inF) <= 0)
        {
            if(feof(inF))
                break;
            else
            {
                cout << "read data error" << endl;
                return -1;
            }
        }
        aframe->data[0] = pcmdata;

        int re = encodec_one_frame_audio(afc, acc, pkt, aframe);
        if (re == -3 || re == -1 || re == -4)
        {
            cout << "encodec error" << endl;
            return -1;
        }
    }
    //再次编码输出解码器中的数据,否则会丢失部分数据
    int re = encodec_one_frame_audio(afc, acc, pkt, NULL);
    if (re == -3 || re == -1 || re == -4)
    {
        cout << "encodec error" << endl;
        return -1;
    }
    //写文件尾
    av_write_trailer(afc, NULL);
    //释放资源
    fclose(inF);
    av_packet_unref(&pkt);
    av_frame_free(&aframe);
    avcodec_free_context(&acc);
    avformat_close_input(&afc);
    return 0;
}

 

 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值