上一节讲解了 编辑SDK 的架构,这一节在来基于图7讲讲 编辑SDK 的运行机制。
- 1.经过上一节的介绍,我们都知道了 WSMediaPlayerView 是整个 编辑SDK 的顶级类。所以我们由 WSMediaPlayerView 入手,先看图片最上面。
- 1.可以看见 WSMediaPlayerView 中会维护一个 30ms的定时循环,这个循环中会不断的调用 draw frame 来驱动 WSMediaPlayer/NativeWSMediaPlayer 进行视频/音频的播放。
- 2.与此同时,最左边的用户会通过 play、pause、seek 等 API 来更新 NativeWSMediaPlayer 的状态。
- 3.需要注意的是,WSMediaPlayerView 的定时循环不会被用户的 play、pause、seek 等操作所中断的。
- 2.再来看看图片左边,这是 WSMediaPlayer 的内部播放机制。要点为 三个循环,两个播放,我们还是自底向上解析。
- 1.VideoDecodeService:它内部维护了一个可阻塞循环与一个先进先出队列——BlockingQueue,当我们开始播放视频或者 seek 视频到某个时间点的时候,VideoDecodeService 会记录这个开始的时间点,然后不断的解码当前时间点之后的每一帧,每解码出一帧便把这一帧放入 BlockingQueue 中。当队列中的元素达到最大值时,当前的循环就会被阻塞,直到外部将 BlockingQueue 中的 Top 帧消费了,那么循环又会被启动继续解码。需要注意的是:VideoDecodeService 只在视频播放的时候提供视频帧,因为在这个情况下 BlockingQueue 中的视频帧的顺序就是视频真正播放的顺序。
- 2.VideoFramePool:它内部维护了一个可阻塞请求循环与一个LruCachePool。一般情况下 VideoFramePool 的循环是处于阻塞状态的。当外部 seek 视频的时候,循环会接收到一个请求并开始处理这个请求,如果 LruCachePool 中有 Cache 被命中了,那么就直接返回 Cache,否则将会立即从视频中解码出这个请求中时间点的视频帧存到 LruCachePool 中然后再返回。需要注意的是:VideoFramePool 只在视频 seek 的时候提供视频帧,因为我们的 seek 操作是随机的,所以在这个情况下 VideoDecodeService 无法使用。
- 3.AudioDecodeService:它与 VideoDecodeService 类似,也维护了一个可阻塞循环与先进先出队列,内部的其他行为也类似,只是将视频帧换成了音频帧。
- 4.FrameRenderer:
- 1.当视频 seek 的时候,其会从 VideoFramePool 中取出 seek 时刻的视频帧绘制它。
- 2.当视频处于 playing 状态时,它的 drawFrame 方法就会不断被 WSMediaPlayerView 通过定时循环调用并从 VideoDecodeService 中取出当前帧通过 Open GL 绘制它。
- 5.AudioPlayer:当视频处于 playing 状态时,它也会不断被 WSMediaPlayerView 通过定时循环驱动着从 AudioDecodeService 中取出当前的音频帧,然后通过反向代理将音频帧交给 Java 层的 AudioPlayer 进行播放。
四、VideoDecodeService解析
上一章大概的讲了讲整个 编辑SDK 的整体架构和运行机制,但其实整个 编辑SDK 内部的每一个部分的细节都非常多,所以这一章我会先