0%

MP4视频首帧加载时间过长的问题

背景

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 后面

加载过程

问题: 播放的时候,还要同时先去下载视频头,导致了耗时较长

解决方案:预加载,在适当时机提前加载视频头部数据,写入本地文件,播放器从本地读取数据,快速构建索引表,进入首帧解码

以上内容参考简书上的博客

谢谢你的鼓励