FFplay外部时钟分析—ffplay.c源码分析
作者:罗上文,微信:Loken1,公众号:FFmpeg弦外之音
FFplay 播放器有 3 个时间:
1,视频流的播放时刻,(视频时钟)
2,音频流的播放时刻,(音频时钟)
3,预定的时间,预定的播放时刻,实际上就是物理世界的自然时间,(外部时钟)
上图中的 14:00:00:123
就是其中一个预定的时间,完全准确的情况下,会在 14:00:00:123
播放第 4 帧视频 ,播放第 7 帧音频。
但是,计算机系统是分时系统,大部分情况不会那么准确,有可能发生以下的情况。
在 14:00:00:133
的时候才播放第 4 帧视频。
在 14:00:00:143
的时候才播放第 7 帧音频。
因此:
在 14:00:00:133
的时候,视频时钟比外部时钟慢 0.01s。
在 14:00:00:143
` 的时候,音频时钟比外部时钟慢 0.02s。
可以通过以下命令设置 外部时钟为主时钟:
ffplay -sync ext -i juren-30s.mp4
当外部时钟设置为主时钟的时候,在《FFplay视频同步分析》提到的3处视频同步代码,全部都会生效。在 《FFplay音频同步分析》提到的音频同步代码也会生效。
外部时钟只会赋值一次,会取音频时钟,或者视频时钟来赋值,主要看播放的第一帧是音频还是视频。
这是合理的,因为从上面第一张图可以看出来,第一帧的时候,音频时钟或者视频时钟 是跟外部时钟一样的。外部时钟的起始值就是第一帧的时间。
从第一帧开始,外部时钟才开始跑起来。
为什么外部时钟只会赋值一次?
因为只需要把第一帧的 pts + 物理世界里消逝的时间,就能知道当前的外部时钟播放到哪里了。
外部时钟 的赋值在 sdl_audio_callback()
跟 video_refresh()
里,这两个都是播放线程,就看谁先播放第一帧,谁就去赋值外部时钟。
可以看到,赋值 外部时钟的函数是 sync_clock_to_slave()
函数,我们来看一下这个函数的实现,如下:
可以看到,只有外部时钟不为空,才会跑进去 set_clock()
。当然如果超过 AV_NOSYNC_THRESHOLD
也会跑进去,不过一般这个条件不会成立。
总结,外部时钟,实际上就是记录现在已经到达了哪个预定的播放时刻。
当视频流离自己预定的播放时刻距离太远的时候,超过了同步阈值,就会调整视频的速度。
当音频流离自己预定的播放时刻距离太远的时候,超过了同步阈值,就会调整音频的速度。
感谢 NETINT(镕铭微电子) 赞助《FFmpeg原理》免费版一书的服务器费用,下面是 VPU 产品介绍