背景
MP4 格式的课程视频从打开播放器到第一帧画面显式,加载时间过长
时间埋点
博客作者使用的是 ijkPlayer ,我们项目中使用的是 ExoPlayer ,不过这个关系不太大。给播放器加载过程埋点的时候需要关闭播放器自己打印的日志,否则会打印很多无关的内容。在本地视频模式和在线视频模式下分别打印关键方法的耗时。
从作者分析的数据可以看到,在线模式下,首帧耗时为 4.967s ,在线模式下首帧耗时 0.257s ,然后发现主要耗时是 avformat_open_input 方法(Exoplayer中方法可能是另一个)
avformat_open_input 方法
这个函数的主要作用是打开一个输入流并且读取它的头部信息。
分析视频结构
请求视频头部信息,在 MP4 格式下即为请求 moov 数据,可以使用 Media Parser 解析问题视频如下:
从图可以看出, moov 在视频文件尾部。本地播放时,可以通过指针快速定位到 moov ;在线播放时,需要先加载一部分头部数据,如 fytp、free、madat 等,计算出 moov 的偏移量,再通过 Http Range Bytes 请求 moov 数据。
moov 数据约有 2.2M ,在线播放视频时,avformat_open_input 方法需要获取全部的 moov 数据,建立索引表后再解析音视频数据。而本地播放无需这个网络请求。
结论及解决方案
视频头过大导致的首帧过慢
问题:视频头过大,导致下载时间比较长,然后首帧出来就比较迟了
解决方案:避免加载提及过大的视频头:1)将长视频拆分为多个短视频,减少 moov 的长度 2)使用轻量级格式,如分段FLV(爱奇艺、优酷)、DASH (YoTuBe、B站)等方案
结构特性导致首帧过慢
问题: moov 在视频文件尾部,多了一次 seek 请求操作,这个问题比上述的问题要轻
解决方案:在服务端使用 ffmpeg 命令将 moov 文件移到 ftyp 后面
加载过程
问题: 播放的时候,还要同时先去下载视频头,导致了耗时较长
解决方案:预加载,在适当时机提前加载视频头部数据,写入本地文件,播放器从本地读取数据,快速构建索引表,进入首帧解码
以上内容参考简书上的博客