这个文章的前置文章是:LNDanmakuMaster
这个文档主要介绍LNDanmakuMaster中最重要的组件LNDanmakuPlayer;这个组件的代码量应该是整个框架中最多的,.m文件中包含了500行左右的代码;其他的主要组件通常都带有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的动画、吞吐量控制策略等。