这个播放器调用了FFmpeg
中的libavformat
和libavcodec
两个库完成了视频解码工作。但是这不是一个“纯净”的解码器。
该解码器中libavformat
完成封装格式的解析,而libavcodec
完成解码工作。
一个“纯净”的解码器,理论上说只需要使用libavcodec
就足够了,并不需要使用libavformat
。本文记录的解码器就是这样的一个“纯净”的解码器,它仅仅通过调用libavcodec
将H.264/HEVC
等格式的压缩视频码流解码成为YUV
数据。
流程图
本文记录的纯净版本的基于FFmpeg
的解码器的函数调用流程图如下图所示。需要注意的是,此解码器的输入必须是只包含视频编码数据“裸流”(例如H.264
、HEVC
码流文件),而不能是包含封装格式的媒体数据(例如AVI
、MKV
、MP4
)。
流程图中关键函数的作用如下所列:
avcodec_register_all()
:注册所有的编解码器。
avcodec_find_decoder()
:查找解码器。
avcodec_alloc_context3()
:为AVCodecContext
分配内存。
avcodec_open2()
:打开解码器。
avcodec_decode_video2()
:解码一帧数据。
有两个平时“不太常见”的函数:
av_parser_init()
:初始化AVCodecParserContext
。
av_parser_parse2()
:解析获得一个Packet
。
两个存储数据的结构体如下所列:
AVFrame
:存储一帧解码后的像素数据
AVPacket
:存储一帧(一般情况下)压缩编码数据
AVCodecParser
AVCodecParser
用于解析输入的数据流并把它分成一帧一帧的压缩编码数据。
比较形象的说法就是把长长的一段连续的数据“切割”成一段段的数据。他的核心函数是av_parser_parse2()
。它的定义如下所示。
/**
* Parse a packet.
*
* @param s parser context.
* @param avctx codec context.
* @param poutbuf set to pointer to parsed buffer or NULL if not yet finished.
* @param poutbuf_size set to size of parsed buffer or zero if not yet finished.
* @param buf input buffer.
* @param buf_size input length, to signal EOF, this should be 0 (so that the last frame can be output).
* @param pts input presentation timestamp.
* @param dts input decoding timestamp.
* @param pos inpu