揭秘盒马鲜生 Android 短视频秒播优化方案 (2)

重写 Adapter 的 onBindViewHolder, 用于创建播放器,并预加载解码视频内容,播放器控制解析到首帧时暂停。此时 onSurfaceCreated 尚未回调,画面未渲染至屏幕。

监听 onPageRelase 控制即将移除屏幕的播放器暂停,并 seekTo (0),方便滑回屏幕时立即播放。

监听 onPageSelected 控制即将进入屏幕的播放器开始播放。注意:由于在 onBindViewHolder 期间已解码完成,这里只需要进入屏幕 1px,就会立即触发 Surface 的绘制(只会执行一次),即进入窗口的内容会显示视频的首帧画面。

重写 Adapter 的 onViewRecycled, 由于当前 holder 即将移出屏幕,移出方向上屏幕外的 holder 将被回收。此时回收并销毁播放器。

多播放器 + RecyclerView 原理图


多播放器 + RecyclerView 原理图

三播放器让沉浸式短视频的体验大幅提高,主要解决了以下问题:

上下滑动过程中,进入屏幕的画面为视频的第一帧画面,并且不会有视觉上的顿挫。

正式播放前预创建播放器,并加载和解码,节省了播放视频之前的准备工作。(ps:这里还包括了下载的过程)。

由于提前加载和解码,进入屏幕时,触发 Surface 瞬间渲染,视觉上无感知,因此播放视频前不再需要封面图,避免了封面图和首帧不一致导致的闪屏问题。

预下载优化

前面讲到了多播放器实现翻页秒播能力,在体验上有了非常大的改善,但由于预创建的播放器在加载时,同时需要下载视频文件,导致这里的下一个播放器准备好视频的时间会增加到 1s 左右。如果用户在播放器加载解码完成前滑至该视频,则会出现明显的黑屏,带来非常差的体验。

由于预加载的时间过长,且无法预知用户是否会快速滑动。这里需要提前进行下载和快速滑动检测。

关于预下载,我们首先要知道播放器内部播放过程。这里的本地代理是视频缓存机制实现的,具体参照下一章节。

播放器内部流程


播放器内部流程

预下载策略

这里,我们为了节约请求网络数据的过程,在播放之前提前下载视频的首帧片段,采用如下策略:

文件大小:下载 1MB 视频文件的方式进行提前首帧下载。(ps:经测试 1MB 已包含了首帧,且文件相对较小)。

提前量:提前 5 个下载量(pageSize 为 10 的情况)。

并发情况:下载采用同步队列下载(避免异步下载导致带宽占用,正常播放的视频卡顿)。

快滑优化:快滑清除下载队列,避免快滑过程中频繁触发下载。

下载时机:loadMore 时将前 5 个推入队列;onPageSelected 时,跳过下一个开始起算 5 个视频推入队列(下一个视频由预加载的播放器自动下载,这里重复下载会导致视频花屏)。

快滑定义

当用户快速翻页时(onPageSelected 调用之前又滑了一下),onPageSelected 不会触发,onPageRelease 会触发多次。在 onPageRelease 中判断 release position 与 current postion 的差值如果 > 1 则表示用户至少快速翻页 1 次,此时定义为快滑状态,应当停止预下载和播放器预加载。
当 onPageSelected 回调时,说明用户没有继续翻页,此时取消快滑状态。开始执行预下载和恢复播放器预加载。

预下载流程图


预下载流程图

缓存优化

目前盒马使用的播放器为淘宝内部播放器。 播放器本身不存在文件缓存和预下载功能。在播放器重新创建后,即便是同一个视频也不会有文件缓存,需要重新下载。这里引入一个开源缓存框架 “com.danikula:videocache”。

方案原理

播放器播放的地址代理给本地的缓存服务,缓存服务负责转发数据流的同时进行文件保存如:
视频地址为:https://****.mp4。
本地代理地址为::8888 (假设端口号分配为 8888)。
代理后的地址为: 本地代理地址 + 视频地址(URL 编码)。
即::8888/https%3A%2F%2F****.mp4

揭秘盒马鲜生 Android 短视频秒播优化方案

后续优化展望

关于多媒体的优化工作还有很多可以做。除了沉浸式秒播的场景外,我们还可以:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zypxjg.html