PVPlayer在渲染(render)所有多媒体数据是都需要保持一个暂时的同步,也就是通常所说的A/V同步。为了达到同步,需要如下一些信息:媒体回放的时钟,媒体数据的时间戳,从Sink中获取的时间信息(比如从音频设备设定的特定的采样率来获取的播放速率)。图1描述了与同步相关的PVPlayer模块之间的关系。
图1与同步相关的模块及关系
一、媒体时钟
PVMFMediaClock,媒体时钟主要负责维持一个时间的引用,从而保持媒体回放的节奏,获取和实现媒体播放的同步。
1、媒体时钟的特点
1.1时间源
媒体时钟可以作为一个时间源提供给多媒体,它本身可能来自于系统时钟或其他时间源(比如音频设备时钟)。它可以给多媒体提供一个时间基准,同时来维护该时间基准。
1.2时钟观察者
媒体时钟可以把自己作为一个观察者,来通知对象时钟状态的改变。以下接口实现了其作为观察者的角色:
PVMFMediaClockObserver:用来通知时钟基值,时钟计数的更新,时钟的调整;
PVMFMediaClockStateObserver:用来通知时钟状态的改变;
PVMFMediaClockNotificationsObs:用来获取回调通知。
1.3NPT映射
媒体时钟是一个单调递增的时钟,而媒体在播放时却可能需要Seek到任意位置,为了控制媒体的播放,使其正确Render,媒体时钟需要在媒体时钟时间和NPT之间维护一个NPT(normalplay time)映射,任意对媒体播放位置的改变将会通知进行一次映射。图2描述了媒体时钟和NPT之间的映射。
图中的箭头和带颜色的区段描述了Seek的次序以及每次播放的时间段,Mediaclock和NPT之间相同的颜色区间即对应了相应的映射。由此可以看出其映射公式为(以第二段为例):NPT= (media_time- 5550 + 380) 。
图2媒体时钟与NPT间的映射
1.4时钟的回调
在媒体时钟上设置回调是组件采取动作的基础,这些回调可以减少在时钟发生改变时,组件自己需要设置他们的时钟。媒体时钟采用输入特定时间窗口来取代绝对时间,这样可以使得处于竞争状态的任务或线程可以尽可能早的得到响应。
1.5延迟处理
当集成了多个不同媒体流的Sinks来输出一个多媒体时,每个Sink都可能会有不同程度的延迟,为了弥补不同媒体流之间的延迟从而同步播放,就需要进行延迟处理。每个Sink都向媒体时钟注册自己的延迟,最后由媒体时钟来调整最终的调度的延迟。
1.6NPT时钟转换
当一个新的NPT开始时,用户可以给媒体时间设置一个绝对时间。用户还可以任意调整NPT的方向(比如向前,向后)。
二、时间戳
为了及时准确地输出媒体数据,就不得不考虑媒体数据中包含的时间戳信息以及媒体回放时钟。如果时间戳值等于当前回放时间,则媒体数据是同步的,需要进行Render;如果时间戳小于当前回放时间,则说明媒体数据到达时间晚了;反之,如果时间戳大于当前回放时间,则说明媒体数据到达时间早了。如何处理这些来早的或来晚的媒体数据则取决于PVPlayer引擎的配置,通常情况下,来早的数据需要等待,直到播放时间到达;来晚的数据则会被丢弃而不被Render。但有时候来晚的数据也会被Render。
三、同步音频
音频数据的Render通常不需要外部时钟来进行同步,因为音频设备通常会被配置一定的采样率来消化音频数据。因此,音频设备被配置的这个采样率通常也作为媒体回放时钟的速率。
1、Render开始时的同步
一旦媒体时钟开始后,就必须要求媒体数据尽可能快地被Render,然而硬件在Render时很可能需要额外的时间,或者硬件需要等到更多的媒体数据被缓存。因此会导致媒体时钟的开始时间与媒体数据真正被输出的时间不一致,从而导致PVPlayer报告给应用程序的播放进度与真实播放进度产生误差。为了解决这一问题,采用了在硬件没有开始输出媒体数据时,媒体时钟就处于暂停状态,当硬件开始输出媒体数据时给媒体时钟发一个消息来通知媒体时钟也开始运行。这样就可以保证在媒体时钟开始的时候,媒体数据也开始进行输出。
图3开始输出的同步示例
图3描述了在有一定初始延迟时开始输出的同步例子。
作为一个主动态的MIO组件,无论时钟状态为暂停还是运行,PVPlayer都向MIO组件传送数据,而MIO组件也应该继续接受和缓存数据,并决定何时把数据发送到硬件。
而作为一个被动态的MIO组件,只有当时钟状态为运行时,PVPlayer才向MIO组件发送数据,而接收到数据的MIO组件也需要将收到的数据立即发送给硬件。
2、重新定位后的同步
当应用程序请求重新定位媒体播放位置时,MIO组件和硬件缓存的数据需要被立即释放,并且在新的位置开始播放。
图4描述了重新定位后如何实现媒体的同步的示例。
图4重新定位后的同步示例
3、播放中的同步
尽管硬件消费数据的速率应该与媒体时钟的速率是一致的,但毕竟他们是单独运行的,因此不可避免的会有一些不同。通常情况下,这中差距是很小的,然而随着播放的进行,差距将会被积累,最终导致不同步。
图5播放中的同步示例
因此,为了控制在短时间内播放时钟与音频输出进程差距在很小的范围内,需要不时地调整两者之间的差,使之小于一个特定的阈值。
四、同步视频
与音频输出相比,视频的输出需要参考一个时钟来决定何时输出一个特定的视频帧,视频帧的输出要尽可能的与该帧的时间戳相一致。PVPlayer维护了一个与音频播放同步的播放时钟,因此,一旦视频输出与播放时钟同步,那么也就意味着视频输出与音频输出同步。
五、音视频同步
音视频同步是音频同步和视频同步的终极目标。在PVPlayer架构中,媒体时钟需要调整以便与音频输出过程相一致,而对于视频输出来说,在输出一个视频帧时要使得该帧的时间戳与媒体时钟同步。因此音频输出设备、视频帧的时间戳与媒体时钟的结合便造就了A/V同步。
图6描述了参与音视频同步模块之间的交互过程。
图6A/V同步交互过程
六、参考文献
1、MediaI/O Developer's Guide OpenCORE 2.02, rev. 1
2、PVMFMediaClockGuide OpenCORE 2.0, ver 1
3、PVPlayerSDK Developer's Guide OHA 1.0, rev. 1