核心视频Maven,我正在为.mov文件创建一个自定义视频播放器。我有.mov解析器工作,并使用QTCoreVideo 101示例,我试图播放视频。
我的问题是显示链接getFrameForTime我不知道如何使用时间值来找到正确的帧。
CVTimeStamp中包含的值对我来说没有任何意义。下面是一个1秒视频请求值的示例。谁能解释一下我如何使用这些值在.mov文件中找到正确的帧?
前三个请求-CVTimeStamp的值
1.视频时间:489150134353920.000000 hostTime:2026048145326080.000000视频时标:241500000.000000比率标量:1.000000视频刷新周期:4028320.000000
1.视频时间:489150201462784.000000 hostTime:2026048279543808.000000视频时标:241500000.000000比率标量:0.999985视频刷新周期:4028320.000000
1.视频时间:489156643913728.000000 hostTime:2026074988871680.000000 videoTimeScale:241500000.000000比率标量:1.000000视频刷新周期:4028320.000000
2条答案
按热度按时间mlnl4t2r1#
CVTimeStamp
s在CVTimeStamp参考文档中有解释。videoTimeScale
是一秒钟被划分成的单位数。因此,对于30 fps的视频,它至少需要30(尽管它可以是30 - 60,120,30000等的任何倍数)。videoTime
是当前帧(或场)开始的时间。所以如果你的时基是30000,你在第15帧,你的videoTimeScale
将是30000,你的videoTime
将是15000。您可以通过检查
smpteTime
字段并查看它是否与您期望的匹配来检查是否正确解释了该值。在上面的示例中,它将是0小时、0分钟、0秒、15帧(或00:00:00:15)。有什么原因可以让你只使用操作系统内置的视频解码设备吗?
hc8w905p2#
这是一个很好的问题,cvdisplay链接是可悲的记录不足,我不得不做了大量的阅读和实验,以弄清楚它。首先,你应该阅读http://litherum.blogspot.com/2021/05/understanding-cvdisplaylink.html,它给出了字段的一个很好的概述。正如那里所解释的,在其核心CVDisplayLink让你访问显示时钟(尽管苹果非常努力地掩盖这一事实),以及一种在它和系统单调时钟之间转换的方法。显示时钟在概念上是vsync定时的,在一个vsync之后,增加videoRefreshPeriod。
但事情比这更微妙一些。您可能认为CVDisplayLink回调在每个vsync开始时调用。不幸的是,情况并非如此。正如https://thume.ca/2017/12/09/cvdisplaylink-doesnt-link-to-your-display/和https://twitter.com/natbro/status/939857260313899008#m中所描述的,在现代osx(10.11+)上,回调实际上发生在vsync事件之间的中途。(在旧版本的OSX上,它确实接近开始)。
因此,DisplayLink的
outTime
参数实际上不能保证是下一个vsync的时间。相反,在现代的osx上,它是vsync * 在那之后 *。(在旧的OSX上,它实际上是下一个vsync)。我相信这个想法是,CVDisplayLink假设你将采取略低于1 vsync长度来渲染你的帧,所以因为在现代osx上,它在vsync的中间调用你,它给你的目标是2 vsync。inTime
参数被认为是回调被触发的时刻。然而有趣的是,虽然主机时间确实是这样,但inTime
的videoTime正好对应于最后一个vsync的时刻。至少从osx 13.5开始,视频时间似乎有更强的属性,它永远不会在小于视频刷新周期的分辨率下增加。(不过,我并不认为这种行为是面向未来的,因为苹果文档中没有任何内容可以保证它不会发生)。下面是示例代码,它显示了在vsync周期内CVDisplayLink被触发的确切时间。它这样做是基于
inTime
的videoTime对应于最后一个vsync的假设。这可以转换为主机时间,以给予您上一个vsync的单调主机时间。因此,考虑到所有这些,如果你想做的是找出上一次vsync发生的时间或下一次vsync将发生的时间,你不应该使用
outTime
来实现这一目的。我所能看到的最好的方法(尽管依赖于未记录的行为)是将inTime
(如果你想成为未来的话,四舍五入到最近的displayRefreshPeriod
)作为最后一个vsync,然后添加refreshPeriod以获得下一个vsync。由于你可以将显示时间转换为主机时间,你甚至可以设置自己的计时器[1],以在实际的vsync时间间隔关闭。最后,应该注意的是,有一些CoreVideo帮助函数,如CVGetHostClockFrequency()。这些基本上只是 Package 器,以避免直接与mach_time_base接口[CVGetHostClockFrequency]只是返回(1/(time_num/time_denom))* 1 e9,即从主机秒到mach_absolute_time刻度的转换因子。
[1][https://developer.apple.com/library/archive/technotes/tn2169/_index.html](https://developer.apple.com/library/archive/technotes/tn2169/_index.html)