B 站在互动视频领域上的探索
如果无法正常显示,请先停止浏览器的去广告插件。
1. B 站在互动视频领域上的探索
李李超然
bilibili 移动技术部 ⾼高级开发⼯工程师
2. 在此键⼊入姓名
在此键⼊入tittle
3. ⾃自我介绍
我 ,李李超然,哔哩哔哩,移动端,播放器器,弹幕内核,互动视频
兴趣 ,数学物理理,计算机图形学,游戏
4. ⽬目录
• 互动视频的业务特点
• 后端逻辑抽象⽅方式
• 前端引擎技术⽅方案
• 优化⼯工程结构
5. 挑战 1:需求⾛走向难以预估
⿊黑镜:潘达斯奈奈基
隐形守护者
什什么是互动视频 ... ?
⽤用户操作可以影响视频内容
6. 性取向测♂试!av65760443
进来!由你抽卡! av59272883
B 站视频⽣生态 UGC 内容为主
视频作者的需求难以预估 …
7. 挑战 2:客户端升级率不不够⾼高
App 更更新后 7 天覆盖率 70%,之后增速缓慢 …
很多核⼼心⽤用户⾮非常抵触升级客户端 …
强制⽤用户升级,会引起⽤用户不不满 …
客户端技术⽅方案必须向前兼容!
8. 挑战 3:逻辑和样式需要在 4 端统⼀一
创作者需要所⻅见即所得的编辑器器
内容创作者
Web 编辑器器
预览界⾯面看到的效果和各终端⽤用户看到的效果⼀一致
观影⽤用户
Android 客户端
iOS 客户端
Web 播放端
9. ⽬目录
• 互动视频的业务特点
• 后端逻辑抽象⽅方式
• 前端引擎技术⽅方案
• 优化⼯工程结构
10. 数据结构:有向图
节点:视频⽚片段
边:选项按钮
暴暴露露,任务失败
开枪
遭遇敌⼈人
⾛走正⻔门离开
暗中观察
获得绝密情报
从下⽔水道逃脱
任务成功
11. 数据结构:隐藏数值
选项按钮可以指定出现条件
被点击时可以改变隐藏数值
在⼀一起
告⽩白
出现条件:好感度 > 0
准备⼥女女友⽣生⽇日宴
准备礼物
好感度 = 好感度 + 5
告⽩白
暗中观察
好感度 = 好感度 - 5
相谈甚欢
出现条件:好感度 <= 0
你是⼀一个好⼈人
12. 图结构可能很复杂 …
剧本杀了了Ta av66384875
13. 服务端与客户端的协作⽅方式
谁处理理互动逻辑? 优势 劣势
客户端 低延迟
可离线游玩 难以快速响应新的需求
难以兼容历史版本
服务端 服务端发版⽅方便便
⽤用户⽆无需升级客户端 ⾼高延迟
对客户端框架设计要求⾼高
14. 拥抱变化:客户端尽可能⽆无状态
需求不不稳定
需要快速迭代
服务端处理理所有逻辑
保持灵动
服务端
(2) 处理理互动逻辑
客户端尽可能⽆无状态
提交剧情树
下发逻辑(图,语义结构)?
下发 UI 和交互细节(样式)?
(3) 下发展示内容
(1) 提交⽤用户选择
编辑器器
播放端
15. ⽬目录
• 互动视频的业务特点
• 后端逻辑抽象⽅方式
• 前端引擎技术⽅方案
• 优化⼯工程结构
16. UI 渲染⽅方案
直接使⽤用原⽣生控件
(eg. UIKit) 抽象双端原⽣生控件
(eg. Reactive Native)
⽆无法跨平台,代码复⽤用率低 ⽆无法⾃自由绘制,⾃自由度太受限
WebView
(HTML / CSS) Direct UI
(eg. Flutter)
性能不不佳 性能好,但复杂度⾼高,包体积⼤大
按实际需要⾃自研:降低复杂度和包体积
17. 跨平台
轻:~8,000 ⾏行行代码
JNI / GLES
Android 播放端
跨平台:代码公⽤用率 70%+
OC++ / GLES
引擎 C++
图形接⼝口 OpenGL ES
WASM / WebGL
WASM / WebGL
业务逻辑脚本化 JS
JavaScriptCore
iOS 播放端
Web 播放端
Web 编辑器器
18. 整体结构
业务逻辑——快速迭代
UI ⽪皮肤样式
各类选项逻辑
与外部代码互通
…
抽象图形接⼝口——简单的 2D 游戏引擎
Node Tree
Animation
RPC
Script Engine
抽象基础能⼒力力——消除平台差异
Thread Pool File System Network Touch Event
Surface GLES Context V-sync Signal Font Render
19. 设备⽆无关的坐标系
(1, 1)
Y
(1, 1)
Y
(0.3, 0.2)
X
O (0, 0)
(0.3, 0.2)
X
O (0, 0)
20. Node Tree:空间
{
}
// sky
x: 0.5, y: 0.5,
width: 1, height: 1,
background_color: "blue",
children: [
{
// body ...
children: [
{
// rotor ...
}, {
// missle ...
x: 0, y: 0.2
}
]
}
]
结构:树,节点-> 平移,旋转,缩放,透明度,shader,⼿手势
21. Node Tree:时间
{
}
start_time: 12.2,
duration: 4.3,
children: [
// ...
]
00:00
02:34
Root Layer
Layer1
Sublayer1
Layer2
Sublayer2
22. Animation
直升⻜飞机的螺旋桨,从 02:34 开始,在接下来的 4 秒内,旋转⻆角度,线性地,从 45 度,变化到 90 度
Node
{
Start Time
Duration
Property
Time
Function
From
Value
start_time: 0,
duration: 100,
animations: [
// fade in
{ start: 0, duration: 0.3, property: "alpha", from: 0, to: 1, time_func: “ease_in" },
],
}
// fade out
{ start: 99.7, duration: 0.3, property: "alpha", from: 1, to: 0, time_func: “ease_out" },
children: [ /* ... */ ]
To
Value
23. ⽬目录
• 互动视频的业务特点
• 后端逻辑抽象⽅方式
• 前端引擎技术⽅方案
• 优化⼯工程结构
24. 随视频时钟演化的渲染层
⼴广告
弹幕
弹幕蒙版
视频画⾯面
字幕
+ 关注
25. 随视频时钟演化的渲染层
播控⾯面板
随剧情出现的功能⼊入⼝口 gl context & threads
game loop
弹幕 / CC 字幕 gl context & threads
game loop
选项按钮 (互动视频) gl context & threads
game loop
视频画⾯面 gl context & threads
game loop
all in one
gl context & threads
game loop
⼤大幅减少渲染⽬目标切换
⼤大幅减少线程切换
26. 随视频时钟演化的渲染层
播控⾯面板
⽤用户操作播控⾯面板影响时钟
播放 & 暂停 / 快进快退 / 倍速播放 / 缓冲
每⼀一帧:渲染层读取时钟当前时刻
随剧情出现的功能⼊入⼝口
弹幕 / CC 字幕
选项按钮 (互动视频)
视频画⾯面
根据获取的视频时钟时间,结算动画
class Clock {
public:
double GetCurrentTime() const;
double GetPlaybackRate() const;
视频播放时钟
void SetCurrentTime(double time);
void SetPlaybackRate(double rate);
private:
// …
};
27. 动态化
服务端
逻辑向客户端迁移
低延迟
保持灵动
下发 JS 逻辑
客户端:JSBinding
客户端:C++ Engine
JavaScriptCore
28. 动态化
C++
auto parent_node = std::make_shared<Node>();
parent_node->SetPosition(0.2, 0.3);
auto child_node = std::make_shared<TextNode>("Hi From Cpp");
parent_node->AddChild(child_node);
JavaScript
parentNode = Node.Create();
parentNode.position = [0.2, 0.3];
childNode = TextNode.Create("Hi From JS");
parentNode.addChild(childNode);
29. 总结
挑战: 需求⽅方向难以预估,需要快速迭代,需要多端统⼀一逻辑和样式
后端: 有向图,节点->视频,边->逻辑
前端: 基于 GLES 的跨端渲染,基于 JS 的跨端逻辑,时间轴元素统⼀一时钟
30.
31.