10

我需要检测 HTML 5 中视频的所有帧更改,我尝试了以下代码,但我无法获得所有更改,我只能每秒获得 8 或 9 次更新。

<body>
    <canvas id="Canvas" width="800" height="450" style="position:absolute; left:5; top:5">Can't Load Canvas</canvas>
    <video id="videoPlay" muted controls>
        <source src="assets/soccer.webm" type="video/webm">
            <source src="assets/soccer.mp4" type="video/mp4">
            Your browser does not support the video tag.
    </video>
</body>
<script type="text/javascript">
            videoPlay.addEventListener('timeupdate', function (){
                putOverlay();
            });
            function putOverlay(){                  
                console.log(videoPlay.currentTime);
                console.log("another frame");
            }
    </script>
</html>

我也尝试了以下代码,但是随着时间的推移,使用计时器时,帧和计时器给出的值之间会失去同步。

<body>
        <canvas id="LeCanvas" width="800" height="450" style="position:absolute; left:5; top:5">Can't Load Canvas</canvas>
        <!-- Video -->
        <video id="videoPlay"  controls>
            <source src="assets/soccer.webm" type="video/webm">
            <source src="assets/soccer.mp4" type="video/mp4">
            Your browser does not support the video tag.
        </video>
    </body>
    <!-- Play Video-->  
    <script>
        //Play Damn Video
        var videoPlay = $('#videoPlay')[0];
        videoPlay.play(1);
    </script>
    <!-- Canvas Animation  -->
    <script>
        //Animation
        function animate() {
            console.log("frame change");
        }       
        setInterval(animate, 1000/29.97); 
    </script>

对我的问题有什么建议吗?

对不起我的英语

问候亚历克斯

4

1 回答 1

31

如上面评论中所述,timeupdate每 15-250 毫秒触发一次,实际上它似乎更接近 250 毫秒。似乎timeupdate旨在提供足够的准确性来显示currentTime每一秒。因此,您最好的选择是运行一个计时器,该计时器以您想要的速率运行并currentTime在每次迭代时进行查询。

但是,您应该使用requestAnimationFrame而不是使用setIntervalor even 。这将大约每 16 毫秒 (60fps) 运行一次,但它会与视频卡刷新率同步。如果您使用,您可能会在某些设备上看到闪烁或屏幕撕裂,尤其是移动设备。它还允许浏览器在选项卡不可见时限制您的帧速率,以节省 CPU 周期(以及电池使用量)。setTimeoutsetTimeout

这也比setInterval因为,如果由于某种原因您的渲染代码花费的时间超过您分配的 30 或 16 毫秒,setInterval可能会堆积调用并导致时间问题,但requestAnimationFrame会跳过帧让您回到正轨。

假设你已经使用了上面的 polyfill,代码看起来像这样:

var video = document.getElementById('videoPlay'),
    lastTime = -1;
function draw() {
    var time = video.currentTime;
    if (time !== lastTime) {
        console.log('time: ' + time);
        //todo: do your rendering here
        lastTime = time;
    }

    //wait approximately 16ms and run again
    requestAnimationFrame(draw);
}

draw();

上面的代码对时间进行了检查,以确保您不会连续两次绘制同一帧。您实际上并不需要它,但它会为您节省几个 CPU 周期。但是在画布上绘制视频时,帧比 currentTime 报告的帧晚几毫秒。所以如果你暂停视频然后跳来跳去,你几乎肯定会落后一帧。通常,如果自上次绘制以来 currentTime 没有改变但视频已暂停,我将在每个周期再绘制半秒左右。或者你可以花时间检查一下。

于 2013-06-11T15:32:59.370 回答