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;
}