弹幕封装组件:LNDanmakuPlayer

803 阅读5分钟

这个文章的前置文章是:LNDanmakuMaster

这个文档主要LNDanmakuMaster中最重要的组件LNDanmakuPlayer;这个组件的代码量应该是整个框架中最多的;其他的主要组件通常都带有Abstract支持定义,但LNDanmakuPlayer没有,这意味着它是不可替代的。

LNDanmakuPlayer结构

LNDanmakuPlayer的责任与Controller类似,他不展示内容、也不更新数据;更多的时候他只是在发号施令(ps:核心人物自己一般不会亲自动手):

@interface LNDanmakuPlayer ()
<
LNDanmakuClockDelegate,
LNDanmakuContrainerViewDelegate,
LNDanmakuAbstractDispatcherDelegate,
LNDanmakuAbstractDispatcherSmoothGrainDataSource
>
@property (nonatomic, strong) LNDanmakuClock *clock;
@property (nonatomic, strong) LNDanmakuContainerView *containerView;
@property (nonatomic, strong) NSMutableArray<LNDanmakuAbstractTrackController *> *trackControllerMArr;
@property (nonatomic, strong) LNDanmakuDispatcher *dispatcher;
@property (nonatomic, strong) NSMutableArray <id<LNDanmakuClockDelegate>> *clockDelegateMArr;
@property (nonatomic, assign) LNDanmakuPlayerStatus status;
@property (nonatomic, strong) LNDanmakuPool *layerPool;
@property (nonatomic, strong) LNDanmakuPool *viewPool;
@property (nonatomic, strong) NSMutableArray <LNDanmakuTrackGroup *> *trackGroupMArr;
@property (nonatomic, strong) NSMutableSet <LNDanmakuAbstractTrackController *> *trackControllerNoRepeatMSet;
@property (nonatomic, assign) NSInteger maxSmoothGrainNum;
@property (nonatomic, assign) NSInteger restSmoothGrainNum;
@end

LNDanmakuPlayer工作涵盖的范围:

  • 包含了:clock、containerView、trackController、Pool、trackGroup等组件。
  • 实现了:clock、containerView、dispatcher的代理和数据源
  • 除此之外,还负责时钟信号一对多转发、播放状态维护、重复检查、吞吐量限制(maxSmoothGrainNum)、弹幕回收等工作。
  • 作为LNDanmakuMaster的门面类,LNDanmakuPlayer需要向外界提供各种控制方法,为了划分这些方法的职责,我为其划分了类别,除默认类之外还包含:(Track)、(Data)、(Control)、(TrackGroup)、(Recover)五个类别,各个类别提供方法的用途见下面这个详细的表格。
类别名作用
()默认类别,定义使用到的其他组件,维护播放器状态。
(Track)控制轨道的插入、移除。
(Data)控制弹幕数据的插入、弹幕视图复用。
(Control)控制Player播放状态包括:开始、暂停、恢复、结束四个基本控制方法;各个子组件的清空方法;针对单点弹幕的移除方法。
(TrackGroup)轨道组专用类别,包括:插入、移除轨道组;向轨道组中插入弹幕。
(Recover)恢复操作专用类别:LNDanmakuMaster支持视频seek后迅速恢复功能,恢复功能指视频从一个时间点切换至另一个时间点后,弹幕播放器也可以瞬间将展示的弹幕切换至对应时间点的状态,而不是清空后重新从右侧飘至中央(这个功能之后进行介绍)。

LNDanmakuPlayer工作方式

LNDanmakuPlayer实现的逻辑较多,这里描述一条普通的弹幕进入LNDanmakuPlayer中后经历的所有流程,来把Player和之前讲述的其他组件串在一起。

注意:以下所有名词均去掉LNDanmaku前缀;暂不考虑轨道组的情况;Player中使用的轨道是最常见的那种横向轨道。

阶段1:放置阶段

  • 我们得到了一个来自网络的弹幕模型,这个模型可能是使用http分段请求的,也可能是内嵌在音视频流中的,我们不关心来源,但我们确信他是一个NSObject类型的对象,称之为XXModel。
  • 一个专用的弹幕工厂为XXModel生产一个Attributes包装了这个XXModel,把XXModel放在customObj属性上,这个工厂是与业务相关的,所以他不在LNDanmakuMaster框架中。
  • 这个Attributes被释放到了Player中(通常视频播放进度会不断产生回调并释放那些可播放的弹幕)。
  • Player不会自行处理弹幕,将其转交给Dispatcher处理。
  • Dispatcher接收到Attributes后将Attributes放置到队尾,就是之前区分高低优先级的那条队列。

阶段2:更新阶段

  • 开启状态的Clock产生了下一段更新信号。
  • Player接收到更新信号后,拿到了信号中一小段“流逝的时间”,这个时间是距离上次clock发出信号的间隔,Player把这个信号和时间信息转发给自己的TrackControllers和Dispatcher(这个先后顺序是固定的)。
  • TrackController收到信号后更新了已有的轨道,在他们的存活时间中扣除了信号传来那段“流逝的时间”,并使用自己的track重新摆放了这些弹幕的位置。
  • Dispatcher收到信号后遍历了Player的轨道列表,然后找到能放下自己队首弹幕的轨道,把队首的弹幕放到轨道上。
  • TrackController接收到弹幕后存储弹幕,然后将弹幕的presentView/presentLayer放置到ContainerView上,在之后的周期中与更新其他弹幕一样更新这条弹幕。

阶段3:卸载阶段

  • 在阶段2,TrackController更新时,会遇到那些存活时间超过了预定时间的弹幕。
  • TrackController调用ContainerView移除弹幕,并将其从自己的存储结构中移除,并代理给Player一个卸载回调。
  • Player收到轨道控制器的卸载回调后,走回收逻辑,将Attributes的presentLayer/presentView存入Pool中,释放Attributes。

除了TrackController卸载回调外,dispatcher的溢出丢弃、手动移除等时机也会进行Attributes回收。

总结

LNDanmakuPlayer是这个框架的门面类,封装其他组件并对外提供调用方法和时机代理;在构建好一个Player后,弹幕相关的全部操作都可以通过操作Player完成,不必与内部的其他组件交互。

结束语

至此,LNDanmakuMaster这个框架的全部组件已经介绍完了,除了基础文档中介绍的这些组件外,LNDanmakuMaster有一些额外策略或动画的实现:分布策略的计算、pop的动画、吞吐量控制策略等,这些策略并不是使用这个框架所必须的,所以我把它们当成了一些可选项,不在此一一介绍。

最后,感谢各位同仁读我的文章也欢迎使用我的框架。