本节主要讲AVPacket中的数据解码到AVFrame中的过程。
前置知识点
1.FFmpeg数据结构简介
AVFormatContext:封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息
AVInputFormat:每种封装格式对应一个该结构体
AVStream:视频文件每个视频(音频)流对应一个该结构体
AVCodecContext:编码器上下文结构体,保存了视频(音频)编解码相关信息
AVCodec:每种视频(音频)编解码器对应一个该结构体
AVPacket:存储一帧压缩编码数据
AVFrame:存储一帧解码后像素(采样)数据
2.AVCodecInternal
AVCodecContext中持有一个AVCodecInternal变量,保存了AVCodecContext的各种状态信息,详细如下:
3.AVCodec
编解码器的结构体,详细如下:
源码分析
由于作者也在学习阶段,本系列文章的规划路线也是参照了雷神总结的视频播放流程图。而本篇文章的起点也就是avcodec_decode_video2。所以,让我们从avcodec_decode_video2开始一步一步分析吧~
首先来看一下avcodec_decode_video2的注释和实现:
avcodec_decode_video2
compat_decode
在这里我们发现,avcodec_decode_video2这个函数已经被废弃掉了,新的函数为avcodec_send_packet() 和 avcodec_receive_frame(),而新的avcodec_decode_video2也是通过调用这两个函数来实现的。那么接下来我们来看看这两个函数
avcodec_send_packet
代码中我们可以看到,通过av_bsf_send_packet发送数据,通过decode_receive_frame_internal解码数据,接下来看这两个函数
av_bsf_send_packet
av_packet_move_ref
这里完成了将AVPacket中的数据放入了指定的AVCodecContext->AVCodecInternal->DecodeFilterContext->AVBSFContext->AVPacket中
decode_receive_frame_internal
解码数据时,根据是否指定了解码方式,分为调用receive_frame和调用decode_simple_receive_frame两种方式:
1)receive_frame
2)decode_simple_receive_frame
decode_simple_receive_frame中直接调用了decode_simple_internal
解码时调用了AVCodec的decode函数,以AYUV为例
send的过程就是以上这些,接下来我们看一下receive的过程:
avcodec_receive_frame
总结
旧API:avcodec_decode_video2
新API:avcodec_send_packet与avcodec_receive_frame
avcodec_decode_video2:新版本中的实现也是使用新的API来完成
avcodec_send_packet:通过av_bsf_send_packet发送数据,通过decode_receive_frame_internal解码数据,将AVPacket中的数据放入了指定的AVCodecContext->AVCodecInternal->DecodeFilterContext->AVBSFContext->AVPacket中;解码数据时,根据是否指定了解码方式,分为调用receive_frame和调用decode_simple_receive_frame,解码时调用了AVCodec的decode函数
avcodec_receive_frame:如果存在可以已解码的数据,则直接取出使用,否则调用decode_receive_frame_internal自行解码。decode_receive_frame_internal的解码流程同上。