如何确定 html 视频元素上的预期 frame-rate

How to determine the intended frame-rate on an html video element

有没有办法确定 html 视频元素中播放内容的预期帧速率?

视频元素是否知道预期的 FPS 或帧数,或者只是 "guess"(可能是 24fps)并以猜测的速度播放?

以下是我未成功的尝试:

我的下一次尝试更复杂:通过将帧捕获到 canvas 元素来对视频进行采样,并通过确定像素何时发生变化来计算帧数。

在我进行复杂的尝试之前,有没有人有更简单的答案?

了解视频的帧率并没有您想象的那么有用。
浏览器使用一些技巧来匹配电影的帧率和屏幕的刷新率,所以如果你查看 currentTime 属性,你会看到 actual 帧持续时间(== currentTime - 之前的 currentTime)不是一个常数,它因帧而异。

在此示例视频中:http://jsfiddle.net/3qs46n4z/3/ 模式为:
4-1-5-1 :
21.3 时 4 帧 + 32 时 1 帧 + 21.3 时 5 帧 + 32 时 1 帧。

因此,如果您想始终在 canvas 上显示最新帧同时避免透支,解决方案可能是:
- 在每个 rAF 上,查看视频的当前时间:
• 相同的 ? -> 什么也不做。
• 改变了吗? -> 更新框架。

无论您想做什么,比较两个 currentTime === 两个数字可能比比较两个 imageData 更快;-)

编辑:查看规范以找到我所说的证据,我发现了这个注释的细微差别:

 Which frame in a video stream corresponds to a particular playback position is defined by the video stream's format.

(4.8.6 注释 http://www.w3.org/TR/2011/WD-html5-20110113/video.html

严格来说只能说(当前时间相同)表示(帧相同)
我只能打赌倒数是真的=>不同的时间意味着不同的帧。
在上面的示例中,Chrome 试图通过尝试获得 45 Hz ( = 60 / 2 + 60 / 4) 来匹配我 60Hz 计算机上电影的 24Hz,最接近 48 = 2*24。 对于创建的 21 个帧,我不知道它是插值还是只是复制帧。它肯定会根据 browser/device(尤其是 Gpu)而改变。我敢打赌任何最新的台式机或功能强大的智能手机都会进行插值。

无论如何,鉴于检查 imageData 的成本很高,您最好绘制两次而不是检查。

Rq1:我想知道在多大程度上使用 Xor 模式 + 一次针对 0 32 位进行测试可以缩短比较时间。 (getImageData 慢。)

Rq2:我确定有一种 hacky 方法可以使用 'sync' 视频和显示器的播放速率,并知道哪一帧是真正的(== 未插值)帧。 (所以两个通过这里 1)同步 2)倒带和检索帧)。

Rq3 :如果您的目的是获取每个视频帧 并且仅获取 视频帧,则浏览器不是最佳选择。如上所述,(桌面)浏览器会进行插值以尽可能接近显示帧速率。这些帧在原始流中 而不是 。甚至还有一些高端“3D”(2D+时间)插值设备,其中甚至不打算显示初始帧(!)。 另一方面,如果您对(插值的)输出流没问题,则对 rAF 的轮询将提供您看到的 每个 帧(您不会错过任何一帧(显然您的应用程序除外)正忙着做别的事情)。

Rq4:插值(== 无重复帧)在 recent/decent GPU 驱动的桌面上的可能性为 99.99%。

Rq5:确保预热您的函数(在启动时调用它们 100 次)并且不创建垃圾以避免 jit / gc 暂停。

这是我用来计算视频 fps 的代码。它有时确实有±1的误差。

function getframerat(){
  document.getElementsByClassName("vid-info")[0].textContent = "Calculating..."
  //first timeout is your choise, you can replace this timeout with any other conditional checks. 
  //Just make sure video is playing, that's the important part.
  setTimeout(function(){
    let getframerates = document.getElementsByClassName("video")[0].getVideoPlaybackQuality().totalVideoFrames
    setTimeout(function(){
      getframerates = document.getElementsByClassName("video")[0].getVideoPlaybackQuality().totalVideoFrames - getframerates;
      if(getframerates < 11) getframerat()
      else if(getframerates%2 != 0) getframerat()
      else document.getElementsByClassName("vid-info")[0].textContent = getframerates;
    },1000)
  },1000)
}