danmu-plugin-desgin

弹幕插件的设计与实现

Posted by Mickey on September 16, 2017

看吃鸡直播的时候,突发奇想想实现一套适用于H5video的弹幕插件,如何设计一个高性能、精准度的弹幕是件很很有挑战性、也很有趣的事情,插件的地址在danmu-plugin,欢迎大家提出意见

danmu-plugin

看过弹幕播放的截图后,我们思考一下,实现上图所示的弹幕插件有哪些基本的问题需要考虑的

  • 弹幕的管理
  • 弹幕的大小,速度和颜色控制
  • 不同字号的弹幕位置计算
  • 弹幕的碰撞检测(包含一个追击问题)

弹幕的数据结构

对于直播来说,弹幕是持续从后台接口拉取的,这点与视频弹幕不同,我们在拿到弹幕数据之后,对字段进行补齐,弹幕的字段如下所示:

  • size 弹幕的字号
  • color 弹幕的颜色
  • speed 弹幕1s钟滚动的px数值
  • content 弹幕的内容

轨道的数据结构

  • trackHeight 轨道的高度
  • thresholdV 轨道当前的弹幕限制速度
  • isExistWaitDanmu 轨道是否存在还未完全进入video视口的弹幕
  • danmuNum 轨道中滚动弹幕个数
  • lastScrollDanmu 最后添加进轨道的弹幕元素,用于追击插入弹幕的时候使用

弹幕的播放方案

这个是弹幕播放比较难的一个问题了,再说这个问题之前,不得不说一下弹幕的动画原理:利用绝对定位。稍微理解前端性能问题的同学都知道,如果不把“动画元素”脱离文档流,大量的reflow和repaint会使浏览器“累死”。知道绝对定位以后,下一步就是控制弹幕的位置了。

如果我们有一个弹幕那就不是问题了,设置弹幕的起始位置就是播放器的右顶点(top:0;right:播放器的.width)。可是,那么多的弹幕如何计算每个将要入场的弹幕的起始位置呢?

首先,可以把视频播放器想象成为一个有着很多条轨道的跑道,如果当前跑道能够容纳下弹幕,则使用一条轨道就行,如果一条轨道不够的话,那就用两条~

那么,什么情况下,弹幕能够被送上跑道呢?

  • 轨道上没有其他弹幕的时候
  • 轨道上有其他弹幕,但是我的速度比轨道上滚动的弹幕速度慢,我不会撞到他
  • 轨道上有其他弹幕,我的速度也比他快,但是在他滚出播放器之前,我不会撞到他(追击问题)

上述三种情况,弹幕是可以被送上轨道的~

几个关键点

  1. 需要持续的拉去弹幕数据,并将数据更新到弹幕插件的danmuList中
  2. 插件会定时去请求轨道,遍历danmuList查看是否有能送上轨道的弹幕
  3. 弹幕播放完毕之后,插件会删除DOM中的节点,同时更新当前轨道的速度限制

后续想法

目前版本的插件只适用于直播的弹幕,不会保留发射的弹幕,后续想兼容视频的弹幕播放,就需要考虑弹幕与视频内容的匹配等等问题,敬请期待~