NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

边看边互动!优酷酷看模式技术揭秘

  • 2020-05-20
  • 本文字数:3951 字

    阅读完需:约 13 分钟

边看边互动!优酷酷看模式技术揭秘

从“叉手礼”、“水盆羊汤”、“酒晕妆”这些唐朝人生活细节,到精美的坊间造型、充满意境的诗词歌赋,《长安十二时辰》不仅以缜密剧情赢得赞誉,更还原了一个真实的大唐长安。在精良制作之上,如何让观众感受 1000 多年前的长安风情、更深度的理解剧情呢?


想必细心的观众已经发现,优酷《长安》中出现了很多有人情味的“黑科技”,比如百科 tips、角色伴侣、剧情进展图等,让用户“边看剧边互动”,这就是优酷的酷看模式。酷看模式在移动端采用了多路流的同屏展示、智能平滑切换、精准同步和动态化渲染等技术。其中动态化渲染、子母屏和多路流同步播放是酷看模式在端侧的核心能力,能够做到多路流、多机位视频帧级同步播放。本文接下来要讲一讲和《长安》相关的背后的一些核心技术。

一、播放器业务框架

优酷的播放器业务框架以一个简单而优雅的模型解构了所有的播放器业务,在该框架下播放业务是由一组彼此独立的插件组合实现的。它适应了复杂的播放业务场景,支持着众多围绕播放业务的团队并行开发。通过技术架构的解耦带来与之相关的技术团队的组织架构的解耦。


  1. 播放器视图模型



如上图所示,该模型可以描述为:


1)播放器由多个层组成;


2)层容器中布局插件;


3)播放器发布消息;


4)插件订阅消息;


5)层和插件信息来自配置文件。


  1. 核心特性


该框架在设计之初就确定了一系列的优良特性作为设计目标,核心的特性列举如下:


1)基于消息,事件驱动


引入事件/订阅的消息机制,插件按需订阅播放器的事件,根据优先级响应和消费消息;


2)按需配置,自由组合


支持从 xml 配置文件加载层和插件的配置信息,各个业务方在接入业务框架时以搭积木的方式排列组合构造播放器;


3)插件解耦,互不依赖


将所有的播放功能及业务模块解耦为彼此独立的插件,插件之间以消息机制进行通信;


4)标准明确,支持扩展


框架会提供一批功能丰富的标准插件,插件可分组管理,业务方可根据自己的需求定制插件来替换默认实现,也可以新增插件;


5)多例共存,彼此隔离


即可有多个播放器在一个页面内同时运行,并且从不同的配置创建。


  1. 为业务开发带来的变化


1)技术架构开放化


以插件的形式隔离和封装不同的业务,清除业务之间的显式依赖。基于新的业务框架,业务方一方面可以将标准插件排列组合创建个性化的播放器,尤其是一些基础插件避免重复劳动;另一方面可以自定义新插件替换默认实现或者添加新业务插件,技术框架层面上支持业务团队独立完成播放器一整套的个性化定制。


2)业务开发标准化


在该播放器框架下,业务插件的顶层设计是统一的、标准化的。包括一致的构造函数、一致的创建过程、一致的生命周期、一致的播放器事件响应机制等。对于不同团队业务代码之间的相互理解和跨团队统一作战都有优势。在标准化的过程中,更容易产出一些通用插件被更多的业务所复用;


3)播放能力服务化


通过引入中间层,播放服务与播放业务边界逐渐清晰,彻底结束业务代码与播放能力代码犬牙交错的局面,彼此松绑,并行前进,播放服务的内聚收敛也具备了向 OTT 等业务类库级输出的可能性。

二、酷看百科

酷看百科主要是在视频播放过程中给出一些类似百科的,辅助用户观看的介绍性内容。技术上的需求主要来自两个方面:


一方面面向运营,运营希望有一个常态化的运营工具,简单的通过运营后台修改配置就完成投放,无需技术同学辅助,客户端也不需要频繁发版本;


另一方面面向用户体验,产品希望能够根据用户的偏好和视频的内容做到 UI 风格多样可动态调整的展示,能够较好的与内容融合。



【图片】剧中关于不良人的解释即为一处百科的投放


核心技术点


为了实现“动态化的内容投放和播放模式切换”,就必须解决两个具体问题。即:


1)播放器如何进行不同播放模式的切换;


2)端侧采用什么技术来实现动态化渲染。


对于问题 1,在播放器业务框架下我们将百科相关的业务也作为一组插件来实现,并且对播放器的业务插件进行分组,利用框架中插件管理器的插件热拔插能力动态的启用和禁用不同组的业务插件。


对于问题 2,我们采用了阿里开源的 Weex 来实现 UI 动态化渲染,无需发版即可实现动态化布局,再结合后端的定投能力,就能够实现按照不同样式模版来动态的投放组件。



weex 架构示意图

三、子母屏

子母屏是酷看中使用较多的一种形态。


所谓子母屏就是将设备区域划分为两大部分,同时投放多屏内容。占据主视频焦点的区域称为母屏,一般用来播放正片;侧边较小的区域称为子屏,一般用来投放与正片内容相关的辅助或者互动性内容。类似于直播比赛时,在画面中引入场边教练采访或者赛况数据。


核心思想:分离母屏正片和子屏的可运营资源


传统做法是直接将“要在副屏展示的内容”通过后期制作,以合流方式直接压入正片视频流中,不过在《长安十二时辰》中我们没有采用这种方式。因为这种方式的缺点很明显:


1)对用户不友好,缺乏互动性且难以按照用户的偏好差异投放;


2)对制作不友好,互动资源和正片资源直接耦合;


3)对运营不友好,严重依赖后期制作无法独立运营;


4)对商业化不友好,广告内容和正片资源直接固化。


这些问题的症结在于合流的方式导致相关内容以一种较为粗放的、固化的方式投放给观众,无视观众的偏好;同样也忽略了多层次精细化的运营需求,这种基于媒体资源的强绑定关系使得正片内容和运营内容组合关系变得固化且单一。


基于此,我们将母屏和子屏的资源解耦。即不在制作时合流,而是让正片内容和运营内容严格分离,分开存储和投放。副屏的内容投放将完全交由运营同学,运营同学从模版库中选择相应的模版即可快速预览和投放,不再依赖后期制作。


核心技术点


我们这里只讲一个较为核心的点即播放器双屏容器,双屏的内容投放是彼此分离的,它是我们后续各种玩法的载体。


  1. 播放器双屏容器


首先要解决的是子母屏容器的搭建问题。


对于双屏容器有一些具体的特性要求:


1)母屏的缩放尺寸能够根据不同的屏幕宽度和视频资源宽度自适应;


2)子屏同母屏一样具有交互性,能够响应用户的手势;


3)母屏上下区域都是可投放可交互的运营位;


4)弹幕、进度条等组件可以根据需求跟随或者脱离母屏。


设计师给出了母屏和子屏可以相互交错叠压的酷炫方案,甚至还有延伸至背景的异形遮罩效果,对于动效同步的要求也较高,母屏缩放和子屏移入的动效同步。为了解决缩放适配问题,我们写了一套自适应的容器布局算法,基本的思路是对母屏的布局按照统一规则进行划分,将子屏嵌入到母屏的某一层中,能够基于服务端下发的配置和视频的尺寸计算出最终子母屏容器的布局模型和动效参数,然后再根据这套模型驱动渲染视图以达到预期效果。


双屏想要具备交互性响应用户手势主要的阻碍在于 Z 轴上有覆盖在视频层上的诸如弹幕等其他的遮罩层会拦截掉系统的触屏事件,为此我们设计了手势插件作为触屏事件的代理,由这个代理按照优先级转发手势事件相关的订阅者,这样就突破了视图层级对手势的限制。



《这就是街舞 2》,边看街舞边给选手投毛巾。

四、双流同步播放

在解决了子母屏的自动布局和交互性问题之后,用子母屏来承载双路流的视频同步播放则是更具挑战的问题。


双路流播放有两个备选方案:


1)单播放器实例,子屏和母屏共同作为一个或者一组播放器插件存在,共享上下文;


2)双播放器实例,子屏和母屏各作为一个播放器实例存在,具有各自的上下文;


我们选择了双实例的方案,因为:


1)产品形体来看,主副屏之间的主从关系是相对明确的,体现为副屏对主屏的单向状态订阅和同步;


2)工程角度来看,保持模型的简单性是有益的,避免因为有两个播放器引入复杂的上下文结构;


双路流的观影体验设计较为超前的,在当前的硬件条件下,能够让配置不是很高的用户也能够畅享酷看模式是非常有挑战的。



《长安十二时辰》双流投放效果,母屏为正片,副屏为张小敬服饰介绍


  1. 主要的困难点


1)系统性的误差控制,需要全链路来保证


从视频生产开始,视频剪辑工具可能就具有 10ms 的以上误差,然后再经过运营平台录入锚点,如果运营工具做不到帧对齐级别的锚点自动计算,那么最终对齐的效果也会受人工计算锚点偏差的影响;事实上,从生产到投放,再到端侧解码渲染,这个系统误差一直在累积传递,对于这个误差的控制是个系统工程。


2)播放器对做精准对齐提供的工具有限


播放器基础 Api 本身执行也在 10m 这个量级,例如启动、暂停、Seek、变速等接口以及一些状态回调都是异步的,甚至系统的 sleep 精度也是有限的,这些方法本身的执行时机和耗时都是不确定的,调用这些 Api 实现 40ms 级别的同步就好像大象捉老鼠一般困难。


3)设备多样性和运行时随机性造成的适配困难


Android 设备碎片化严重,性能分布频谱宽广,在单次追帧同步过程中,运行时状态满随机性较大,无法事先给出全局通用的经验值作为参数进行补偿。


  1. 两个播放器同步的解决思路:


1)首先要解决同步位置的锚定,这个位置目前是以主视频时间轴为基准,这里采纳主视频的时钟,有音频时钟,视频时钟或者外部时钟三种选择;


2)要解决对齐的技术手段本身不精准的问题,对齐的技术手段较多,对齐的过程根本上是一个“调节-反馈-修正”的递归过程,虽然模型相对简单,但是需要达到想要的效果具体实现并不容易,涉及较多的实现技巧,例如提供更加精准的 seek 接口,尽量让这些 Api 产生的误差偏离方向一致,这样我们就便于在累积误差上做补偿;


3)由于机型千差万别,运行时状态又充满随机性。这里就需要逐一梳理,消除随机性的影响。例如,为了适应网络状态的随机性,实现全局统一的缓存策略;为了平抑个体性能差异,我们引入了部分统计学的方法来做追帧补偿,统计当前设备最近几次追帧差值的方差和标准差作为下一次补偿追帧的参数;针对人眼对播放速度变化的敏感性,训练变速追帧的最佳变速曲线等。


通过架构设计、工程优化、算法升级和有针对性适配,打出全链路的组合拳,最终实现了多路流精准的同步播放,呈现了不错的效果。



《这就是街舞 2》中的同步效果


作者 | 阿里文娱无线开发专家 卜道


2020-05-20 17:571032

评论

发布
暂无评论
发现更多内容

架构师训练营第三小结(9.28-10.4)

zjzj2017

Redis-技术专题-基础介绍

洛神灬殇

如何高质量学习与正确运用设计模式

木香丘

学习 设计模式 实战

Python 为什么不支持 switch 语句?

Python猫

Python 编程

LeetCode题解:226. 翻转二叉树,递归,JavaScript,详细注释

Lee Chen

大前端 LeetCode

第四周作业

极客大学架构师训练营

架构师训练营第四周作业

尹斌

爆赞!这份《Java核心宝典》绝对是面试复习的最佳选择

Java架构之路

Java 程序员 面试 编程语言

架构师训练营第三周学习总结

Gosling

极客大学架构师训练营

深入剖析go中字符串的编码问题——特殊字符的string怎么转byte?

Gopher指北

后端 string utf-8 Go 语言

Malagu 框架介绍

木香丘

云计算 开源 Serverless 架构 框架

Hazelcast IMDG 带你瞬间进入内存计算的时代

张磊

分布式计算 内存管理 分布式缓存 分布式内存网格

架构师训练营第三周课后作业

Gosling

极客大学架构师训练营

2N方定点算法

武夷梅占

php 数据库 分布式 算法 后端

极客时间架构 1 期:第 3 周代码重构 - 命题作业

Null

缓存服务-技术专题-解决方案

洛神灬殇

架构师1期-代码重构作业

ltl3884

极客大学架构师训练营

架构师训练营第三周作业(9.28-10.4)

zjzj2017

有这些要素,架构才完整

北风

架构 架构师之道 架构方法

Redis-技术专题- 热点Key如何解决

洛神灬殇

实用威胁建模指南(一)

亚伦碎语

敏捷 安全设计 系统安全 #威胁建模

极客时间架构 1 期:第 3 周代码重构 - 学习总结

Null

Serverless 多云解决方案 Malagu

木香丘

云计算 Serverless 架构 云原生 Malagu

spring-boot-route(九)整合JPA操作数据库

Java旅途

Java Spring Boot jpa

发几张国庆的照片

亨利笔记

容器 k8s Harbor 镜像

架构师训练营第 1 期第 4 周学习总结

好吃不贵

架构师训练营第 1 期第 4 周作业

好吃不贵

极客大学架构师训练营

3. CocoaPods 命令解析 - CLAide

Edmond

ruby ios objective-c CocoaPods PackageManager

架构师训练营第四周学习总结

尹斌

单例模式

魏小龙

入行架构师之前,这7项技能你要先了解一下

Java架构师迁哥

边看边互动!优酷酷看模式技术揭秘_文化 & 方法_阿里巴巴文娱技术_InfoQ精选文章