使用C++ 封装一个FFmpeg通用性Muxer和Encoder组件-2 AV_Encoder

编码器的主要作用


源码github

1 初始化编码器
2 编码
3 获取每一帧数据
4 返回相关的参数

AudioEncoder 类的定义( 视频的逻辑差不多 相对于的注解就写了一部分)

av_rescale_q () 时间基转换函数  不同时间基之间的转换
#include <vector>
extern "C"
{
    
    
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
}
class AudioEncoder
{
    
    
public:
    AudioEncoder();
    ~AudioEncoder();
    int InitAAC(int channels, int sample_rate, int bit_rate);
//    int InitMP3(/*int channels, int sample_rate, int bit_rate*/);
    void DeInit();  // 释放资源
    AVPacket *Encode(AVFrame *frame, int stream_index, int64_t pts, int64_t time_base);
    int Encode(AVFrame *farme, int stream_index, int64_t pts, int64_t time_base,
               std::vector<AVPacket *> &packets);
    int GetFrameSize(); // 获取一帧数据 每个通道需要多少个采样点
    int GetSampleFormat();  // 编码器需要的采样格式
    AVCodecContext *GetCodecContext();
    int GetChannels();
    int GetSampleRate();
private:
    int channels_ = 2;
    int sample_rate_ = 44100;
    int bit_rate_ = 128*1024;
    int64_t pts_ = 0;
    AVCodecContext * codec_ctx_ = NULL;
};

音频编码器的实现

#include "AudioEncoder.h"

AudioEncoder::AudioEncoder()
{
    
    

}

AudioEncoder::~AudioEncoder()
{
    
    
    if(codec_ctx_) {
    
    
        DeInit();
    }
}

// 通过 传入的参数 初始化参数  
int AudioEncoder::InitAAC(int channels, int sample_rate, int bit_rate)
{
    
    
    channels_ = channels;
    sample_rate_ = sample_rate;
    bit_rate_ = bit_rate;
	// 初始化编码器
    AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if(!codec) {
    
    
        printf("avcodec_find_encoder AV_CODEC_ID_AAC failed\n");
        return -1;
    }
    codec_ctx_ = avcodec_alloc_context3(codec);
    if(!codec_ctx_) {
    
    
        printf("avcodec_alloc_context3 AV_CODEC_ID_AAC failed\n");
        return -1;
    }
	//设置编码器相关参数
    codec_ctx_->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    codec_ctx_->bit_rate = bit_rate_;
    codec_ctx_->sample_rate = sample_rate_;
    codec_ctx_->sample_fmt = AV_SAMPLE_FMT_FLTP;
    codec_ctx_->channels = channels_;
    codec_ctx_->channel_layout = av_get_default_channel_layout(codec_ctx_->channels);
	//  打开编码器
    int ret = avcodec_open2(codec_ctx_, NULL, NULL);
    if(ret != 0) {
    
    
        char errbuf[1024] = {
    
    0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avcodec_open2 failed:%s\n", errbuf);
        return -1;
    }
    printf("InitAAC success\n");
    return 0;
}

void AudioEncoder::DeInit()
{
    
    
    if(codec_ctx_) {
    
    
        avcodec_free_context(&codec_ctx_);  // codec_ctx_被设置为NULL
//        codec_ctx_ = NULL;  // 不需要再写
    }
}
	

AVPacket *AudioEncoder::Encode(AVFrame *frame, int stream_index, int64_t pts, int64_t time_base)
{
    
    
    if(!codec_ctx_) {
    
    
        printf("codec_ctx_ null\n");
        return NULL;
    }
    pts = av_rescale_q(pts, AVRational{
    
    1, (int)time_base}, codec_ctx_->time_base);
    if(frame) {
    
    
        frame->pts = pts;
    }
    int ret = avcodec_send_frame(codec_ctx_, frame);
    if(ret != 0) {
    
    
        char errbuf[1024] = {
    
    0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avcodec_send_frame failed:%s\n", errbuf);
        return NULL;
    }
    AVPacket *packet = av_packet_alloc();
    ret = avcodec_receive_packet(codec_ctx_, packet);
    if(ret != 0) {
    
    
        char errbuf[1024] = {
    
    0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("aac avcodec_receive_packet failed:%s\n", errbuf);
        av_packet_free(&packet);
        return NULL;
    }
    packet->stream_index = stream_index;
    return packet;
}
//
int AudioEncoder::Encode(AVFrame *frame, int stream_index, int64_t pts, int64_t time_base,
                         std::vector<AVPacket *> &packets)
{
    
    
    if(!codec_ctx_) {
    
    
        printf("codec_ctx_ null\n");
        return NULL;
    }
     // 通过time_base转换函数 获得pts  
    pts = av_rescale_q(pts, AVRational{
    
    1, (int)time_base}, codec_ctx_->time_base);
    if(frame) {
    
    
    	//设置对应的pts
        frame->pts = pts;
    }
    // frame 送入编码器 
    int ret = avcodec_send_frame(codec_ctx_, frame);
    if(ret != 0) {
    
    
        char errbuf[1024] = {
    
    0};
        av_strerror(ret, errbuf, sizeof(errbuf) - 1);
        printf("avcodec_send_frame failed:%s\n", errbuf);
        return NULL;
    }
   // 从编码器中获取 编码出的packet  
    while(1)
    {
    
    
        AVPacket *packet = av_packet_alloc();
        ret = avcodec_receive_packet(codec_ctx_, packet);
        packet->stream_index = stream_index;
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
    
    
            ret = 0;
            av_packet_free(&packet);
            break;
        } else if (ret < 0) {
    
    
            char errbuf[1024] = {
    
    0};
            av_strerror(ret, errbuf, sizeof(errbuf) - 1);
            printf("aac avcodec_receive_packet failed:%s\n", errbuf);
            av_packet_free(&packet);
            ret = -1;
        }
        printf("AAC pts:%lld\n", packet->pts);
        //编码的文件存入动态数组中
        packets.push_back(packet);
    }
    return ret;
}

int AudioEncoder::GetFrameSize()
{
    
    
    if(codec_ctx_)
        return codec_ctx_->frame_size;
    return 0;
}

int AudioEncoder::GetSampleFormat()
{
    
    
    if(codec_ctx_)
        return codec_ctx_->sample_fmt;

    return -1;  // AV_SAMPLE_FMT_NONE
}

AVCodecContext *AudioEncoder::GetCodecContext()
{
    
    
    return codec_ctx_;
}

int AudioEncoder::GetChannels()
{
    
    
    if(codec_ctx_)
        return codec_ctx_->channels;

    return -1;
}


int AudioEncoder::GetSampleRate()
{
    
    
    if(codec_ctx_)
        return codec_ctx_->sample_rate;

    return -1;
}

猜你喜欢

转载自blog.csdn.net/qq_33329316/article/details/124159191