FFmpeg 入门学习 08–打开音视频解码器

使用 FFmpeg 进行音视频解码,其实是一套标准操作,按照固定的流程进行实现即可。

使用 FFmpeg 进行音视频解码的基本流程、及用到的关键 API 接口和 结构体,如下图所示:

FFmpeg 入门学习 08--打开音视频解码器

音视频解码管理基类

概述

使用 FFmpeg 对视频流解码和音频流解码的基本流程是一样的,因此可以使用同一个基类对相关资源进行管理。

解码器初始化

在使用 FFmpeg 对视频流解码和音频流解码之前,需要根据封装格式查找并打开对应的音视频解码器

打开音视频解码器

本文以软解(CPU 解码)为例进行实现。

代码示例

在 Decoder 类中增加 avCodecIni 接口,用于初始化解码器:

emplate<typename T>
class Decoder
{
public:
    Decoder(int packetSize,int frameSize, WaitAndNotify &packet_wait):packetQueue( new Queue<AVPacket>(packetSize)),frameQueue( new Queue<AVFrame>(frameSize)), packetFullWait(packet_wait){};
    ~Decoder() ;
public:
    void            setAVFormatContext(AVFormatContext*    format){ formatContext = format;}
    void            setStreamIndex(int m_index){ streamIndex = m_index;}
    int             getStreamIndex() const { return streamIndex;}

    int             avCodecIni();//解码器初始化

protected:
    AVFormatContext*                formatContext = nullptr;//封装格式上下文,外部传入
    AVCodecContext*                 codecContext{ nullptr };//解码上下文
    const AVCodec*                  codec{ nullptr };//解码器

    AVFrame*                        currentFrame{ nullptr };//解码临时帧

    Queue<AVPacket>*             packetQueue{ nullptr };// packet 队列
    Queue<AVFrame>*              frameQueue{ nullptr }; //frame 队列
    int                             streamIndex{ -1 };//流索引,外部传入

    WaitAndNotify     &packetFullWait;// 用于唤醒解封装线程
};

avCodecIni 方法实现如下:

template<typename T>
int Decoder<T>::avCodecIni() {
    //创建解码上下文
    codecContext = avcodec_alloc_context3(nullptr);
    AVDictionary* opts = nullptr;
    std::shared_ptr<AVDictionary*> optsCloser(&opts, av_dict_free);//用于自动关闭 opts
    if (codecContext == nullptr) return -1;

    //获取解码器
    if (avcodec_parameters_to_context(codecContext, formatContext->streams[streamIndex]->codecpar) < 0)
    {
        return -1;
    }
    codecContext->pkt_timebase = formatContext->streams[streamIndex]->time_base;
    codec = avcodec_find_decoder(codecContext->codec_id);
    if (codec == nullptr)
    {
        return -1;
    }

    if( codec->type == AVMEDIA_TYPE_AUDIO)
    {
        static_cast<T *>(this)->paramsIni(codecContext);
    }

    //打开解码器
    if (avcodec_open2(codecContext, codec, &opts) < 0)
    {
        return -1;
    }
    formatContext->streams[streamIndex]->discard = AVDISCARD_DEFAULT;//丢弃无用的数据包
    currentFrame = av_frame_alloc();

    return 0;
}

作者:litanyuan | 来源:公众号——编程猿来如此

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论