使用ffmpeg进行解码的流程是固定的,就如同iOS开发一样,从viewDidLoad,viewWillApear,viewDidAppear,苹果都已经把需要调用的方法顺序告诉我们了,需要我们做的就是把自己业务代码合理的放到对应的位置。
视频解码基本流程
- 注册需要支持的文件格式以及对应的编解码器
- 打开文件
- 从文件中提取数据流信息
- 从数据流(视频数据流/音频数据流/字幕数据流)中找到对应的视频数据流
- 从视频数据流中找到对应的解码器
- 打开解码器
- 为解码帧提供内存分配。
- 从视频数据流中读取原始数据帧
- 对原始数据帧进行解码放入前面申请的解码帧中。
- 展示解码帧
- 继续读取数据帧,然后解码展示。
以上就是视频解码的固定套路,看上去基本符合我们的正常逻辑。但是在具体说明之前还需要介绍一些基本的概念。
ffmpeg数据结构
在ffmpeg中有几个非常重要的数据结构,AVStream以及AVPacket,AVFrame,AVFormatContext,AVCodecContext。
->AVFormatContext //描述整个文件的对象。包含了诸如文件包含的视频流,音频流等
---->AVStream //描述一个数据流
------->AVCodecContext //描述与数据流相关的编解码相关数据的对象。
--------->AVPacket //网络传输中的一包数据,是被特定算法压缩过的数据对象
------------>AVFrame //由AVPacket解压缩过后得到的数据帧对象
以上概念也不需要太纠结,在实际使用中正常结合代码理解就好了。
现在结合代码进行具体的解释,由于把代码拆散容易让刚接触的人感觉茫然,因此我会把整个能跑通的代码放上来,然后加上注释。
视频解码以及展示
以下代码中会包含一些已经deprecated的方法,但是由于接口封装相对来说直接易懂,因此没有替换成最新的api。另外需要重点关注ffmpeg的视频解码流程而不是SDL的api使用。
main.mm文件
extern "C"{ //C++中需要申明extern "C"来确定引入c文件
#include "SDL.h"
#include "SDL_thread.h"
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>