我编写了许多播放器应用程序(适用于 Windows),它们结合了视频和音频,并且需要在两者之间进行精确同步。在 Windows 音频中,您基本上准备缓冲区(只是音频样本值的数组)并将它们排队到音频子系统进行播放;当每个缓冲区完成播放时,子系统会对您的应用程序进行回调,并且您的应用程序使用每个回调来 1) 将下一帧渲染到屏幕,以及 2) 准备要排队到音频子系统的下一个音频块。
例如,假设您在内存中有一些视频帧,您希望以每秒 50 帧的速度播放,与单声道、每个样本 2 个字节和每秒 44,100 个样本的音频同步。这意味着您的音频缓冲区需要每个大小为 882 个样本 (44,100 / 50 = 882),因此每个缓冲区只是一个包含 882 个元素的短(2 字节)整数数组。您至少需要两个缓冲区,但实际上更多更好(缓冲区的权衡是更多的缓冲区意味着更流畅的播放,但代价是启动延迟更长和内存占用更大)。
视频的帧需要以相同的方式“缓冲”,以便始终准备好渲染至少一帧;将单个图像传输到 PC 屏幕是如此之快,以至于它实际上是即时的,而不是您需要担心的事情。唯一关心的是提取或组成帧的任何方法。这些方法至少需要足够快以跟上播放速率,或者它们需要在播放之前充分缓冲,这也会导致更长的启动延迟和更大的内存占用(这些问题对于视频来说比它们用于音频,具有任何合理的分辨率)。
当应用程序开始播放时,它会预先加载所有带有音频的缓冲区并将它们排队等待播放;然后,它同时开始播放并将第一帧渲染到屏幕上。用户看到第一帧并听到前 20 毫秒的音频(20 毫秒 = 1/50 秒)。此时,音频子系统将播放从第一个缓冲区切换到第二个缓冲区,并对应用程序进行回调。然后应用程序将第二帧渲染到屏幕上,并用下一个可用的音频块填充第一个缓冲区,然后将这个第一个缓冲区再次排队到音频子系统。
只要应用程序有可用的音频和视频数据来不断填充缓冲区和帧,这个过程就会继续,你会看到/听到视频。