ABPlayer 开发日志(一)

这大概是ABPlayer开发以来的第一个开发日志了,为什么前面好久没发?因为ABPlayer开发难度真的好高好高,特别是一些高级的基本功能实现,并不是那么得容易,不过也就借此机会在这里展示一下ABPlayer(正在成熟中)的核心构思。要是有弹幕播放器开发者恰巧路过,欢迎借鉴,这几本是弹幕播放器的一些核心思想~

开发得各种杂合体

ABPlayer 这次开发杂合了各种现有播放器的各种部件,重写,拼接而成。(重写其实是为了了解怎么运作的,.C发现沿着代码重写一遍就明白都是怎么实现的+干什么的了)

1. 弹幕对象

ABPlayer的实现采用全能的弹幕对象原理(更相似Mukio系列)。全能弹幕是什么?就是指在播放器里,一条弹幕拥有自己的全部功能,对自己负责。比如我们暂停播放,那么全能的弹幕,我们会这样:(以下伪代码)

foreach(comment:Comment in comments:Array)
{
    comment.pause();
}

而对于非全能的弹幕(PAD)系列,则会这样

foreach(cepair:CEPair in comment:Array){
    cepair.effect.pause();
}

有效的不同点是,PAD将Comment-Effect(弹幕文字对象和弹幕移动效果)邦定成CEPair对,在暂停和重放时,梳理一下CEPair,把Effect关掉即停止。而Mukio的处理是把Comment本身制作为一个管理自己的对象。发送后,弹幕管器就“不管”了,若是暂停、换时间,则会通告正在运行的弹幕,弹幕对象本身自己处理效果的运行与停止。

为什么ABPlayer要选这种模式呢,主要是为了后面实现高级移动做准备。在自治的Comment对象下,我们只需要不断让其挂钩,即可叠加移动效果,而CEPair相比之下就局限性比较大了。当然,选这种模式也是因为KnLiveCommentary的运作很类似全能弹幕,比较熟悉。

2. 弹幕管理器——效率与不效率的精髓

相比于弹幕对象,弹幕管理器是弹幕播放器的最核心系统,他负责跟随视频时间轴并准时(相对的)派发弹幕。所有的弹幕对象离开了管理器就不知道如何运行,不知道位置等关键信息,而与之对应,弹幕管理器则需要处理弹幕对象的制作,弹幕进入、退出舞台,暂停启动,视频滚动条拖动,死亡弹幕垃圾回收和各种调度性工作。

很有意思的是,核心的弹幕管理器思想就是如下,这点PAD和Mukio达成了惊人的一致:(为了可读性,依然伪代码)

var timeline:Array;
var running:Array;
function pause(){
    foreach(comment in running){
        stop(comment);//代暂停所需操作
    }
}
function resume(){
    foreach(comment in running){
       resume(comment);//代启动所需操作
    }
}
function enter(comment){
    //初始化
    comment.init();//格式、文字、颜色各种准备
    //进入舞台
    stage.addChild(comment);
    position(comment);//确定位置
    run(comment);//运行弹幕的各种操作
}
function position(comment){
    //这里是效率的重要体现地方 
    //需要处理弹幕使得其定位准确且尽可能减小滚动时的冲撞 
    //一般实现如下,这里千奇百怪的
    //position()时 会扔进去position
    positions:Array;
    if(comment特别大)
        return 占用全屏幕
    if(positions没有)
        return 从头开始的位置Y
    foreach(position in positions){
        if(position不影响,不冲撞)
            return position参数
        else
            下一个空位
    }
    都没有,按照某些方式分配
}
function dispose(comment){
    //如果弹幕全能,它会在自己走完生命周期后,呼叫这个
    //如果不全能,效果完毕后呼叫
    comment.stop();//扔掉各种东西
    stage.removeChild(comment);//拿下舞台,准备回收
    comment.dispose();//回收掉,包括可能的配置,空间,效果对
}
//重头戏
function time(time){
    if(this.oldTIme - this.currentTime太多)
        this.resetOldTime();
    //非用户挑拨时间轴
    this.updateTime();
    cs = this.getAllCommentsInDuration(this.oldTime,this.currentTime);
    //获取期间所有弹幕
    foreach(c in cs){
        enter(c);
    }
}

......

(注意上面代码非常非常的伪…好多复杂的过程被简化了)
播放期间,播放器会时不时“通告”弹幕模块现在的时间,而弹幕模块则会在新旧时间间隔之间寻找弹幕,并派发。

简单被概括成这样(微软画图制作的渣图)

在T02 播放器派发进度,管理器则找到old-new之间所有的弹幕,派发,重置old<=new。下一个new-old又会出现了弹幕

当然,这个策略也不是常能通过,我们还要处理下面的两种情况:

用户一旦掺和进来,事情就复杂了,因为用户能掌控时间

解决了这两个问题,还有一个目前大部分播放器没解决的问题:如果视频缓冲很慢,视频停止播放来缓冲、可是弹幕还在运行,可能出现弹幕走光了等着视频加载的场景…

常上Bili的诸位有没有发现呢

(有关这部分的非常通俗的实现,可以看KnLiveCommentary)

第一日至暂且到此,下一步是研究怎么载入,怎么过滤等。

过滤的设计:

对于过滤弹幕,由于都是全能的,过滤规则可以更灵活到这样:
.width>200  (添加大小匹配)
.color=0xff0000  (颜色匹配)
.text?/{REGEX}/   (文字正则)
.hash=somehash    (发送者HASH)
.lifetime>2000      (显示时间超过XXXX千分秒)
.fontsize>25      (字体太大)
.type<4      (过滤滚动弹幕)
.text,.hash都是字符串可以 = 或 ? 匹配
.type,.fontsize,.width,.height 都是数字,可以 > = <
.color 可数字可字符串,自动转化,只能 = 
同时自带 $windowHeight, $windowWidth, $videoHeight, $videoWidth 参数

比如 .width > $videoWidth * 0.8 即可过滤比现在视频0.8宽的弹幕
(运算只能一种,比如不要 $videoWidth * 0.8 + 1)

看看能允许这些规则的前提下,一些人们还怎么能刷屏呢^_^

10 Comments

  1. 你在回复我留言的同时也给我发了一张Email啊,怎么做到的?最近三单空间很不给力,1freehosting的NS老是出问题,Zymic简直就是残废空间,现在用着x90x无限空间,指不定哪天就挂了,好空间难找啊

    回复

    1. 以前一直用000webhost,比较稳定,速度不快但是还是受得了,而且最好的是免费&各种无限制。最大的缺点就是似乎被天朝滥用了,所以需要先翻到美国的IP注册去…

      我现在的空间年租¥100域名¥60,这个自己看情况了,我觉得不贵也不便宜,就是比较稳定。要是有充裕资金可以去搞VPS。

      回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注