使用FFmpeg做视频解码
本文主要基于以下文档:
https://blog.csdn.net/leixiaohua1020/article/details/18893769
https://blog.csdn.net/leixiaohua1020/article/details/38868499
https://www.jianshu.com/p/d8375bea9ac3
一、视频播放器的原理
视频播放器播放一个互联网上的视频文件,需要经过以下几个步骤:解协议,解封装,解码视音频,视音频同步。如果播放本地文件则不需要解协议,为以下几个步骤:解封装,解码视音频,视音频同步。过程如图所示:
解协议的作用,就是将流媒体协议的数据,解析为标准的相应的封装格式数据。视音频在网络上传播的时候,常常采用各种流媒体协议,例如HTTP,RTMP,或是MMS等等。这些协议在传输视音频数据的同时,也会传输一些信令数据。这些信令数据包括对播放的控制(播放,暂停,停止),或者对网络状态的描述等。解协议的过程中会去除掉信令数据而只保留视音频数据。例如,采用RTMP协议传输的数据,经过解协议操作后,输出FLV格式的数据。
解封装的作用,就是将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如MP4,MKV,RMVB,TS,FLV,AVI等等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV格式的数据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。
解码的作用,就是将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据。音频的压缩编码标准包含AAC,MP3,AC-3等等,视频的压缩编码标准则包含H.264,MPEG2,VC-1等等。解码是整个系统中最重要也是最复杂的一个环节。通过解码,压缩编码的视频数据输出成为非压缩的颜色数据,例如YUV420P,RGB等等;压缩编码的音频数据输出成为非压缩的音频抽样数据,例如PCM数据。
视音频同步的作用,就是根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来。
二、视频解码流程
1、调用了FFmpeg中的libavformat和libavcodec两个库完成视频解码工作,包括了封装格式的解析
- 注册组件
av_register_all()
注册所有的编解码器,复用/解复用器等等组件
- 打开封装格式->打开文件
avformat_open_input()
打开一个输入流(文件或者网络地址)
- 查看视频流
avformat_find_stream_info()
获取媒体的信息
- 查找视频解码器
avcodec_find_decoder()
1、查找视频流索引位置
2、根据视频流索引,获取解码器上下文
3、根据解码器上下文,获得解码器ID,然后查找解码器
- 打开解码器
avcodec_open2()
- 读取视频压缩数据->循环读取
在解码时两个存储数据的结构体如下:
AVFrame:存储一帧解码后的像素数据
AVPacket:存储一帧(一般情况下)压缩编码数据
得到视频解码的流程图如下:
2、对只包含视频编码数据“裸流”(例如H.264、HEVC码流文件),而不能是包含封装格式的媒体数据(例如AVI、MKV、MP4)进行解码。
流程如下:
此时相对于第一个过程,在使用函数上有了一些变化。此外,在“libavcodec+libavformat”的视频解码器中,使用avformat_open_input()和avformat_find_stream_info()就可以解析出输入视频的信息(例如视频的宽、高)并且赋值给相关的结构体。因此我们在初始化的时候就可以通过读取相应的字段获取到这些信息。在只有“libavcodec”的解码器则不能这样,由于没有上述的函数,所以不能在初始化的时候获得视频的参数。“纯净”的解码器中,可以通过avcodec_decode_video2()获得这些信息。因此我们只有在成功解码第一帧之后,才能通过读取相应的字段获取到这些信息。
相应代码请参考文章开头链接。
上一篇: 视频GPU硬解码方案对比
下一篇: IO流知识点浅析