视频网站的弹幕原理和开源代码分享

 

随着视频网站和直播网站的兴起,弹幕的功能算是一个核心元素,弹幕最初是由日本视频网站Niconico引入的,国内除了在Bilibili和AcFun等弹幕视频网站中使用之外,其他主流视频网站中的视频播放器也支持弹幕,对于视频网站和直播网站来说,弹幕的交互实时性更高,更加受欢迎。

本文重点介绍一下弹幕的基本原理,以及JavaScript和HTML的代码实现方式,最后分享一个弹幕的开源库。

关于视频网站建设,可以参考我们之前的通过Drupal构建自建视频课程平台

 

 

弹幕基础知识

单条弹幕的属性

  1. 模式:滚动弹幕、逆向弹幕、顶部弹幕、底部弹幕。
  2. 基本属性:正文、出现时间、持续时间、字体、字号、颜色等样式。
  3. 容器:块级元素,一般是与视频大小相同的区域。

弹幕的特性:

  1. 空间的独立性:虽然在同一个元素内展现,但空间计算上每种弹幕模式处于不同层,每种模式也可以有多层,每层内的弹幕占位不会重叠。
  2. 渲染的确定性:如果弹幕容器和渲染的列表固定不变,在没有用户交互(比如暂停单条弹幕)的情况下,每次渲染每条弹幕所出现的位置和顺序都是固定的。
  3. 各模式的统一性:每种模式的弹幕的生存时间保持一致。

弹幕的基本模式:

  1. 滚动弹幕:自右向左匀速滚动过屏幕的弹幕,以自上而下的优先度展示。
  2. 逆向弹幕:自左向右匀速滚动过屏幕的弹幕,以自上而下的优先度展示,逆向弹幕是相对于滚动弹幕的相反方向滚动的弹幕展示模式。
  3. 顶部弹幕:自上而下静止居中的弹幕、以自上而下的优先度展示。
  4. 底部弹幕:自下而上静止居中的弹幕、以自下而上的优先度展示。

弹幕的使用场景:

  1. 点播视频互动,把评论搬到弹幕上来
  2. 直播互动,直播视频中,可以直接通过弹幕讨论、互动
  3. 视频内容增强,比如对视频中某些内容进行解释,描述等
  4. 标记视频亮点,对视频中的高亮进行提示等
  5. 网页互动,比如弹幕可以点赞,回复等
  6. 互动上墙,大屏的投票可以通过弹幕来实现交互大墙
  7. 蒙版弹幕,可以对某系地方不想让用户看到,可以通过弹幕掩盖
  8. 非文字弹幕,比如表情、红包等等交互效果

 

弹幕的实现原理

弹幕本身不是对视频的操作,其实是给视频上面加DIV等DOM元素,也就是给视频上面加层,然后展示我们想要的内容即可,目前弹幕的主要实现有两种方式:

  1. Canvas
  2. HTML+CSS

首先,这种我们自然想到用Canvas,使用Canvas能很方便地绘制动画,并且获得非常不错的性能,目前前端不少动画都是通过Canvas去做。不过对于基于Canvas的动画而言,最大的问题就是“交互性”上面。

如果用HTML+CSS的方式实现,我们可以很简单地通过监听原生DOM事件去知道哪一条弹幕与用户鼠标发生了交互。但是通过Canvas,我们只能通过监听画布的事件,然后做一堆遍历计算坐标的骚操作去确定是哪一条弹幕。从鹅厂的视频网站可以看到,他们的弹幕是可交互的,所以他们使用了HTML+CSS的实现方式;而B站的弹幕是非交互的,它提供Canvas和HTML+CSS可选,默认是前者。

虽然功能性上两者的实现会有点差异,但弹幕的基本原理都是一样。

所以弹幕本身就是对DIV元素的操作,DIV层一般在Video层上面,类似下面的图,不过也有放在Video层下面,弹幕层在底下,详情参考这篇文章的介绍 https://github.com/logcas/a-barrage 

 

 

 

 

弹幕实现的技术细节

我们先分析一下文档管理系统的基本需求以及功能点,

从上图可以看到,弹幕是很清晰地分成了一行一行,我把它们称为“轨道”。每一个弹幕都只在轨道上从右往左移动,不会越界。那么,要实现弹幕功能,首先我们必须把弹幕分成若干个轨道,然后再在合适的时间把弹幕“塞”进去让它平移。

每一个轨道会有两个属性:

barrages: T[] = []
offset: number = 0

barrages为一个弹幕数组,offset则是已占据的宽度。offset用于滚动弹幕时,弹幕轨道添加弹幕前判断最佳轨道;当弹幕类型时固定时无作用。barrages存放当前轨道上可现实的弹幕实例。

每一个轨道实例管理自己轨道中的数组,主要进行进行增、删、重置以及更新offest的操作。

添加新弹幕

push(...items: T[]) {
  this.barrages.push(...items)
}

删除弹幕
remove(index: number) {
  if (index < 0 || index >= this.barrages.length) { return }
  this.barrages.splice(index, 1)
}

重置轨道

reset() {
  this.barrages = [] this.offset = 0
}

更新剩余轨
updateOffset() {
  const endBarrage = this.barrages[this.barrages.length - 1]
  if (endBarrage && isScrollBarrage(endBarrage)) {
    const { speed } = endBarrage this.offset -= speed
} }
 
 

拿来即用-开源的方案

 

在知名的男性交友网站github上,已经有一款很好用的弹幕开源解决方案,并且是国产的,叫abarrage,同时实现了Canvas和HTML+CSS的模式,要用的话直接在github把源代码撸下来,并且有在线的体验地址,效果非常不错。

A-Barrage 同时支持Canvas渲染和HTML+CSS的渲染模式,你可以根据实际情况采用不同的渲染引擎进行弹幕的渲染。其中,Canvas是非交互式渲染,也就是说,采用Canvas渲染的弹幕并不会有任何的交互操作,纯展示性质;HTML+CSS是交互式渲染,如果你的网站允许用户与弹幕之间进行一些交互(如点赞、回复等),那么可以采用HTML+CSS的渲染模式,它会结合浏览器的DOM事件进行响应。

github地址: https://github.com/logcas/a-barrage 

测试地址: https://logcas.github.io/a-barrage/example/css3.html