html5:在画布内显示视频

bcs8qyzn  于 2022-11-20  发布在  HTML5
关注(0)|答案(5)|浏览(340)

是否可以将html5视频作为画布的一部分显示?
基本上与在画布中绘制Image的方式相同。

context.drawVideo(vid, 0, 0);

谢谢!

qaxu7uf2

qaxu7uf21#

var canvas = document.getElementById('canvas');
var ctx    = canvas.getContext('2d');
var video  = document.getElementById('video');

video.addEventListener('play', function () {
    var $this = this; //cache
    (function loop() {
        if (!$this.paused && !$this.ended) {
            ctx.drawImage($this, 0, 0);
            setTimeout(loop, 1000 / 30); // drawing at 30fps
        }
    })();
}, 0);

我猜上面的代码是自我解释的,如果下面不留下评论,我会试着解释上面的几行代码

编辑

这里有一个在线示例,专门为您提供:)


第一次

wrrgggsh

wrrgggsh2#

下面是一个解决方案,它使用了更现代的语法,并且比已经提供的解决方案更简洁:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const video = document.querySelector("video");

video.addEventListener("play", () => {
  function step() {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
});

一些有用的链接:

pqwbnv8z

pqwbnv8z3#

使用画布显示视频

显示视频与显示图像非常相似。细微的区别在于onload事件和需要渲染每一帧视频的事实,否则您将只看到一帧而不是动画帧。
下面的演示与示例有一些细微的区别。静音功能(在视频下单击静音/声音打开以切换声音)和一些错误检查,以捕捉IE9+和Edge,如果他们没有正确的驱动程序。

保持答案最新。
user 372551之前的回答已过期它使用setTimeout和33.333..ms的速率,setTimeout将舍入到33 ms,这将导致帧每两秒丢失一次,如果视频帧速率高于30,可能会丢失更多帧。使用setTimeout也会产生视频剪切,因为setTimeout无法与显示硬件同步。

目前还没有可靠的方法可以确定视频帧速率,除非您事先知道视频帧速率,否则您应该在浏览器上以最大显示刷新率显示视频。60 fps
给出的最佳答案是当时(6年前)的最佳解决方案,因为requestAnimationFrame没有得到广泛支持(如果有的话),但requestAnimationFrame现在是主流浏览器的标准,应该使用它来代替setTimeout,以减少或删除丢帧,并防止剪切。

示例演示。

载入影片并设定为循环播放。影片将不会播放,直到您按一下它。再次按一下将会暂停。影片下方有一个静音/声音开启按钮。影片预设为静音。
请注意IE9+和Edge的用户。您可能无法播放视频格式WebM,因为它需要额外的驱动程序来播放视频。可以在tools. google.comDownload IE9+ WebM support找到这些驱动程序
第一个

画布附加功能

使用画布渲染视频为您提供了更多关于显示和混合FX的选项。下图显示了使用画布可以获得的一些FX。使用2D API提供了大量创造性的可能性。
与答案Fade canvas video from greyscale to color x1c 0d1x相关的图片
请参阅上述演示中的视频标题,了解上述图片中内容的属性。

dsekswqp

dsekswqp4#

你需要更新currentTime视频元素,然后在画布上绘制帧。不要在视频上初始化play()事件。
您也可以使用例如此插件https://github.com/tstabla/stVideo

jgwigjjp

jgwigjjp5#

我从the answer from 2018 about requestAnimationFrame开始,然而,它有三个问题。

  • 不必要的复杂
  • 有一种新的方式来处理这个任务(大约从2020年开始)
  • 将事件侦听器附加到play事件会引发性能问题

首先,事件侦听器可以简单地连接到执行所需处理的函数,并调度对它自身的下一次调用,而不需要将它 Package 在一个匿名函数中,并调用另一个requestAnimationFrame
其次,不要使用requestAnimationFrame,该函数会在浏览器能够处理的最快速度下调度对回调函数的下一次调用(一般为60 Hz),这会导致大量的处理工作负载。video.requestVideoFrameCallback仅在视频进入下一帧时调用回调。这可以减少视频以低于60 FPS的速度运行时的工作负载,并且在视频不播放时完全无需进行任何处理,从而显著提高性能。
第三,每当您将视频发送给video.play()时(每次将新视频加载到video元素中并通知它开始播放时,以及在使用video.pause()后恢复播放时),都会触发附加到play事件的事件侦听器。每次视频被告知play()时,就会在画布上绘制一次视频(加上您正在进行的任何其他处理),这会快速累积。
如果您确定只播放一个想要暂停和继续播放的视频,您可以通过更改播放速率来切换播放/暂停,例如video.playbackRate = !video.playbackRate。如果您要将多个视频加载到此元素中,最好完全放弃play事件侦听器,并在加载第一个视频时插入对step()的手动调用。请注意,这在video元素上是活动的,而不是在特定加载的视频上,因此您需要设置并检查一个标志,以确保在加载第一个视频时只调用step(),或者在创建新的视频帧请求之前取消任何活动的视频帧请求(如下所示)。

let animation_handle;
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const video = document.querySelector("video");
video.addEventListener('loadeddata', video_load_callback, false);

function video_load_callback() {
    video.cancelVideoFrameCallback(animation_handle);
    step()
}
function step() { // update the canvas when a video proceeds to next frame
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
    animation_handle = video.requestVideoFrameCallback(step);
}

相关问题