ffmpeg 解码 h264数据

解码流程说明

1 注册编解码组件

avcodec_register_all();

2 获取解码器

AVCodec *avcodec_find_decoder(enum AVCodecID id);
参数 :
id: 需要解码的数据格式
返回值: 解码器指针

3 获取解码器上下文

AVCodecContext *avcodec_alloc_context3(const AVCodec *codec);
参数:
codec: 解码器指针
返回值: 解码器上下文指针

4 打开解码器

int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
参数:
avctx: 解码器上下文指针
codec: 解码器指针
options: 其他
返回值: 0 成功, 其他 失败

5 准备输入输出数据

输入数据:
AVPacket m_packet = new AVPacket;
av_init_packet(m_packet);

输出数据
AVFrame *m_frame;
m_frame = av_frame_alloc();

6 解码

int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
const AVPacket *avpkt);
参数:
avctx: 解码器上下文指针
picture: 解码器输出数据指针
avpkt: 解码器输入数据指针
got_picture_ptr: 指针, 如果为NULL 则 没有数据被解码, 如果 不为NULL 则有数据被解码
返回值: 解码数据的长度 , 如果为0 则解码失败

7 关闭解码器, 释放数据

关闭解码器
avcodec_close(m_context);
释放解码器
av_free(m_context);
释放 定义的 m_frame
av_frame_free(&m_frame);
删除new的 m_packet
delete m_packet;
m_packet = NULL

代码

CH264Decoder.h

#pragma once
extern "C" 
{
#include <libavcodec/avcodec.h>
}
struct AVCodec;
struct AVCodecContext;
struct AVFrame;
struct AVPacket;
class CH264Decoder
{
public:
    CH264Decoder();
    virtual ~CH264Decoder();
    bool Init();
    void Exit();    
    bool CH264Decoder::Decode(const void *ptr, size_t len, std::function<void(CH264Decoder *pDecoder, AVFrame *pFrame)> lpfnCallback);
protected:
    AVCodec           *m_codec;
    AVCodecContext    *m_context;
    AVFrame           *m_frame;
    AVPacket          *m_packet;
};

CH264Decoder.cpp

#include "stdafx.h"
#include "H264Decoder.h"
CH264Decoder::CH264Decoder()
    : m_codec(NULL) 
    , m_context(NULL)
    , m_frame(NULL)
    , m_packet(NULL)
{
}
CH264Decoder::~CH264Decoder()
{
}
bool CH264Decoder::Init()
{
    // 注册所有组件
    avcodec_register_all();
    // AVPacket 存放原始数据
    m_packet = new AVPacket;
    av_init_packet(m_packet);
    // 获取解码器
    m_codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!m_codec)
    {
        return false;
    }
    // 获取解码器上下文
    m_context = avcodec_alloc_context3(m_codec);
    //判断读取码流的状态 ,可能以截断的方式来读取
    if (m_codec->capabilities&CODEC_CAP_TRUNCATED)
        m_context->flags |= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */
    // 打开解码器
    if (avcodec_open2(m_context, m_codec, NULL) < 0) 
    {
        return false;
    }
    // AVFrame 存放从AVPacket中解码出来的数据
    // av_frame_alloc 分配 AVFrame
    m_frame = av_frame_alloc();
    return true;
}
void CH264Decoder::Exit()
{
    if (m_context)
    {
        avcodec_close(m_context);
        av_free(m_context);
        m_context = NULL;
    }
    if (m_frame)
    {
        av_frame_free(&m_frame);
        m_frame = NULL;
    }
    if (m_packet)
    {
        delete m_packet;
        m_packet = NULL;
    }
}
bool CH264Decoder::Decode(const void *ptr, size_t len, std::function<void(CH264Decoder *pDecoder, AVFrame *pFrame)> lpfnCallback)
{
    int declen, got_frame;
    if (ptr && len)
    {
        m_packet->data = (uint8_t*)ptr;
        m_packet->size = len;
        while (m_packet->size > 0)
        {
            declen = avcodec_decode_video2(m_context, m_frame, &got_frame, m_packet);
            if (declen < 0) {
                return false;
            }
            if (got_frame && lpfnCallback) {
                lpfnCallback(this, m_frame);
            }
            if (m_packet->data) {
                m_packet->size -= declen;
                m_packet->data += declen;
            }
        }
    }
    else
    {
        m_packet->data = NULL;
        m_packet->size = 0;
        declen = avcodec_decode_video2(m_context, m_frame, &got_frame, m_packet);
        if (declen < 0) {
            return false;
        }
        if (got_frame && lpfnCallback) {
            lpfnCallback(this, m_frame);
        }
    }
    return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值