Android弹幕实现现状与原理浅析

弹幕实现对比

目前的弹幕实现方案,主要有以下几种实现方式。

Android View实现

通过Android已有的控件实现布局、绘制,高效的话需要自定义缓存逻辑,复用弹幕itemView,主要是text的绘制、样式处理以及位移动画的实现。

B站Danmaku

开源的弹幕库:https://github.com/bilibili/DanmakuFlameMaster
比较成熟稳定,功能齐全,满足现有的所有场景需要,通过canvas绘制。主要功能点:

  • 基础弹幕精确还原绘制、支持mode7特殊弹幕
  • 多核机型优化,高效的预缓存机制
  • 支持多种显示效果选项实时切换、实时弹幕显示支持、自定义字体、换行
  • 运动弹幕、多种弹幕参数设置、弹幕屏蔽
    项目缺点:
    1,没有实现OpenGL ES的绘制,官方库一直没有更新维护,这个绘制方式是TODO状态;
    2,SurfaceView和TextureView的实现有一些问题:焦点问题导致的弹幕不显示,TextureView也无法显示弹幕(官方demo也存在问题,主要是setSurfaceTextureListener设置监听了也没有任何回调,这就很伤),待分析解决。

AkDanmaku

https://github.com/KwaiAppTeam/AkDanmaku
KS推出的弹幕库,支持基本的弹幕处理和显示、倍速播放等;支持弹幕悬停等交互响应操作;支持丰富的弹幕文本样式,以及自定义样式扩展;性能良好,方便扩展,支持丰富的运动动画效果,尤其是弹幕动画,并支持自定义渲染。
缺点:
1,需要引入一个游戏引擎渲染库(libGDX - Java跨平台游戏开发框架打造出 Android Native 图形处理框架)
2,会增加多个平台的so文件,增加问题定位的难度;
3,对现有的项目改动较大,上层的View,数据层,弹幕管理都需要一定的改造;
4,兼容性和稳定性,未在我们项目中线上实践,暂未知。不过由于底层依赖的引擎开源且比较稳定,问题应该也不大。

OpenGL实现

可以将上层cavans绘制好的bitmap上传到GPU绘制,即使用OpenGL来实现更高效的绘制、平移动画。针对我们项目的特点,我认为目前比较合适的实现方案:基于B站弹幕库已有逻辑的基础上,补充OpenGL的渲染实现。目前B站开源库并没有OpenGL的实现,我认为可行,但有一定的难度。AkDanmaku的上层也是canvas绘制,底层也是OpenGL去绘制。这是我目前比较推荐并且接下来将尝试实现的方案,后续再补充文档。

Danmaku实现原理

支持的样式非常丰富,动画也是有姿有色,不限于水平移动,还支持各种复杂动画,支持弹幕重叠,隐藏、显示,停止、播放,支持纯文本,也支持图文混排。

B站弹幕库实现demo

1,bitmap处理

1,弹幕很重要的一个点就是bitmap的处理,并且通过缓存bitmap可以更高效的实现弹幕缓存。这个库对bitmap的处理使用了ndkbitmap库:bitmap = NativeBitmapFactory.createBitmap(w, h, config);
libndkbitmap.so(ndk)源码:https://github.com/Bilibili/NativeBitmapFactory
Java_tv_cjump_jni_NativeBitmapFactory_createBitmap,通过在native heap上创建Bitmap,会减小java heap的压力,避免OOM。

2,实现流程和主要类

Danmaku流程

各个类说明:

  1. R2LDanmaku : 一个弹幕对象, 里面包含x、y坐标, 缓存的Bitmap等属性。
  2. DanmakuView : 用来承载弹幕显示的View,普通view的绘制方式,所以DanmakuView在有大量弹幕时Graphics占用内存会比较多。
  3. DanmakuSurfaceView:单独开辟一个Surface来处理弹幕的绘制操作,即绘制操作是可以在子线程(DrawHandler),不会造成主线程的卡顿,即双缓冲绘制,内存及耗电量低、绘制及时,但是sdk24以下不支持动画和截图。
  4. DanmakuTextureView:同上,但能像普通View那样能被缩放、平移,也能加上动画(SurfaceView需要android7.0以上才支持),TextureView doesn't support displaying a background drawable。内存和耗电稍高、绘制会有1-3帧的延迟、但是支持动画和截图。
  5. DrawHandler : 一个绑定了异步HandlerThread的Handler, 控制整个弹幕的显示逻辑。DrawHandler调度引起DanmakuView的渲染。
  6. CacheManagingDrawTask : 维护需要绘制的弹幕列表, 控制弹幕缓存逻辑;将弹幕添加到弹幕集合danmakuList中;CacheManagingDrawTask.CacheManager创建弹幕缓存DrawingCache
  7. DrawingCacheHolder : 弹幕缓存的实现,缓存的是Bitmap, 与BaseDanmaku绑定。
  8. DanmakuRenderer : 对弹幕做一些过滤、碰撞检测、测量、布局、缓存等工作。
  9. Displayer : 持有Canvas画布, 绘制弹幕。
  10. 通过Choreographer来不断驱动渲染DanmakuView。

3,目前的问题

1,性能稍微有点问题
目前的版本可能存在ANR,内存泄露和多线程问题,渲染的性能有待提升。
2,帧率偏低
早先未做任何弹幕优化的分支,mock大量弹幕,很多帧率在40以内,不过这个跟房间其他逻辑的影响关系比较大,合并公屏和房间性能优化,这个问题会有明显改善。这个属于周边环境治理,主推做法还是用SurfaceView渲染,双缓冲会更稳,弹幕显示不容易受主线程卡顿的影响。

3,使用其他渲染View却有问题
直接换成DanmakuSurfaceView后,弹幕帧率会显著提升且比较稳定,但是有bug需要解决:如层级问题(仅在视频上方一级问题也不大,否则就只能TextureView展示,但是这个性能相对差,所以相比性能来讲,可以业务回避层级问题),偶现闪烁消失的问题(两个SurfaceView打架,抢焦点的问题)。
换成DanmakuTextureView,弹幕居然无法显示(官方demo也是如此,待研究)。
4,弹幕管理是否合适?

所以需要找出原因并解决以上问题,才好拓展OpenGL的实现(因为OpenGL需要基于GLSurfaceView或者GLTextureView实现,也会有3的问题,所以需要先处理已有的问题)。

AkDanmaku

AkDanmaku 弹幕引擎结合了移动平台原生渲染流程和游戏引擎的架构理念,在提供完备功能和高性能保障的前提下,提升了扩展性,降低了维护成本,使得开发高级弹幕特效功能变得更容易。该引擎主要针对移动平台短视频播放中的弹幕场景提供包含弹幕流程与数据处理、弹幕展现以及特效处理等功能的全场景解决方案,具备功能全面、高性能、易扩展和维护等特性。更多信息可以看github介绍。

主要功能

  1. 基于libGDX - 跨平台 Java 游戏开发框架和 ECS 架构实现 Android Native 图形处理框架,提供上层的弹幕 UI 和动效处理等能力。
  2. 多线程调度模型,将渲染、逻辑处理分离,保证性能。
  3. 具备缓存机制,提升性能和空间利用率
  4. 支持基本的弹幕处理和显示能力、倍速播放等
  5. 支持弹幕悬停等交互响应操作
  6. 支持丰富弹幕的文本样式,以及自定义样式扩展
  7. 支持丰富的运动动画效果

libGDX 是一个基于 OpenGL (ES) 的跨平台 Java 游戏开发框架,适用于 Windows、Linux、macOS、Android、浏览器和 iOS。 它为快速原型设计和快速迭代提供了一个久经考验的稳健环境。所以基于这个实现,就已经具备良好性能的基础。

弹幕效果

AkDanmaku效果

这个demo效果,跟B站demo的效果相比,基本上功能都能对应实现。

工作流程图

AkDanmaku流程图

SDK 层中 DanmakuView 与 DanmakuPlayer 的设计参考了 Android 原生平台的视频播放场景(VideoView & MediaPlayer)的 API 设计。
底层内核 DanmakuEngine 包含基于 libGDX 框架实现的 ECS 管理器,负责建立、维护 ECS 系统,并作为弹幕 API 的内部调用实现。其中,act() 与 draw() 方法分别为弹幕运算与绘制的入口。

多线程调度

  1. 运算流程:ActionThread 负责流程中的数据处理和逻辑运算,最终的处理结果转化为可用于显示环节直接使用的 RenderObject List,并通知系统进行下一帧的刷新。
  2. 绘制流程:RenderThread 专注于弹幕绘制,通过拿到运算流程的结果数据 - RenderObject List 直接调用原生平台的绘制 API 进行弹幕绘制,并通知引擎准备下一帧的结果运算。
  3. 缓存流程:CacheThread 专注于整个流程中的缓存处理。

初步研究

使用AkDanmaku的话,只有继承View的DanmakuView用于UI展示,重写onDraw(canvas: Canvas) 方法,将canvas丢给danmakuPlayer?.draw(canvas)绘制。
但是这个绘制,怎么跟libGDX交互的,需要了解libGDX是怎么工作的才能明白。


image.png

初步测试,整体性能是ok的,能满足现有的功能需求,比较流畅,弹幕帧率60+,也方便拓展。不过肯定也会有一些问题。

未来计划

1,针对B站弹幕库,尝试修复多个SurfaceView同时出现时弹幕的层级问题。
2,将Danmaku源码扩展OpenGL渲染。
3,基于AkDanmaku继续测试研究,对比效果、测试性能。

仅供学习交流,如有问题,请留言联系杜小菜。

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容

  • 前言 Google Play应用市场对于应用的targetSdkVersion有了更为严格的要求。从 2018 年...
    申国骏阅读 63,900评论 14 98
  • 《来,我们说说孤独》 1·他们都在写孤独 一个诗人 如果 不说说 内心的孤独 不将孤独 写进诗里 是不是很掉价呢 ...
    听太阳升起阅读 4,369评论 1 7
  • 自幼贫民窟长大的女子,侥幸多念了两本书,枉以为可以与人平起平坐。可是人生从来都是接力赛,我们却天真的当成了百米冲刺...
    Leeanran阅读 5,759评论 1 5
  • 云舒老师,姓甚名谁,男的女的,多大岁数,这些我全然不知。之所以要写写云舒老师,完全是因为他写的文章,如一个巨大的磁...
    数豆者m阅读 2,327评论 5 9
  • """1.个性化消息: 将用户的姓名存到一个变量中,并向该用户显示一条消息。显示的消息应非常简单,如“Hello ...
    她即我命阅读 2,854评论 0 5