在javascript中从视频复制到画布
Posted
技术标签:
【中文标题】在javascript中从视频复制到画布【英文标题】:Copying from video to canvas in javascript 【发布时间】:2021-11-03 05:50:33 【问题描述】:我正在尝试加载视频并将其缩略图绘制到画布中。我遇到的问题是,当视频图像准备好复制时,我找不到触发的事件。当加载数据事件触发时,大小设置正确,但画布图像为空白。如果我取消注释计时器以延迟一秒钟,则画布被填充,但没有延迟它不是。是否有一些我忽略的事件,或者其他方式来告诉视频元素何时能够复制?我尝试了 load、canplay、canplaythrough、loadeddata、progress,但似乎都没有在正确的时间出现。
<html>
<head>
<script>
var video, image, width, height;
function copy(src)
video = document.getElementById('video');
video.addEventListener('loadeddata', x => finishCopy());
video.src = src;
function finishCopy()
width = document.defaultView.getComputedStyle(video).width.replace(/[^.0-]/g, '');
height = document.defaultView.getComputedStyle(video).height.replace(/[^.0-]/g, '');
image = document.getElementById('image');
image.width = width;
image.height = height;
//setTimeout(draw, 1000);
draw();
function draw()
let ctxt = image.getContext('2d');
ctxt.drawImage(video, 0, 0, width, height);
</script>
</head>
<body >
<video id="video" autostart="false" ></video>
<canvas id="image"></canvas>
</body>
</html>
【问题讨论】:
【参考方案1】:虽然loadeddata
事件会在当前帧的数据加载后立即触发,但它并没有给出任何暗示这实际上意味着什么。
然而,在实践中,这意味着在某些情况下,或者在某些浏览器中,它可能能够呈现第一帧 - 尽管您不能依赖它。
解决方案是寻找一个事件,该事件稍后在加载/处理视频的过程中触发。
这些事件发生的顺序如下:
-
加载开始
持续时间变化
加载元数据
加载数据
进展
可以玩
因此,如果我们只使用canplay
事件而不是loadeddata
,事情应该会按预期工作。
这是一个例子:
var video, image, width, height;
function copy(src)
video = document.getElementById('video');
video.addEventListener('canplay', x => finishCopy());
video.src = src;
function finishCopy()
width = parseInt(document.defaultView.getComputedStyle(video).width);
height = parseInt(document.defaultView.getComputedStyle(video).height);
image = document.getElementById('image');
image.width = width;
image.height = height;
draw();
function draw()
let ctxt = image.getContext('2d');
ctxt.drawImage(video, 0, 0, width, height);
copy("https://www.w3schools.com/html/mov_bbb.mp4")
<video id="video" autostart="false"></video>
<canvas id="image"></canvas>
编辑
在使用不同浏览器进行一些测试后,我的解决方案似乎在 Chrome 中失败了。尽管如此,我还是找到了一种在 Chrome 中也可以使用的解决方法。
您可以将一个相当未记录的参数附加到视频的 URL,让您可以指定视频的开始位置甚至范围 (#t=
)。
现在,如果您将起始位置设置为 0.000001 之类的较低值,您仍会看到视频的第一帧,并且可以在画布上进行绘制。
但是我的测试也表明,如果您使用 canplaythrough
事件而不是 canplay
或 loadeddata
,这仅适用于 FireFox 和 Chrome。
这是修改后的示例:
var video, image, width, height;
function copy(src)
video = document.getElementById('video');
video.addEventListener('canplaythrough', x => finishCopy());
video.src = src;
function finishCopy()
width = parseInt(document.defaultView.getComputedStyle(video).width);
height = parseInt(document.defaultView.getComputedStyle(video).height);
image = document.getElementById('image');
image.width = width;
image.height = height;
draw();
function draw()
let ctxt = image.getContext('2d');
ctxt.drawImage(video, 0, 0, width, height);
copy("https://www.w3schools.com/html/mov_bbb.mp4#t=0.000001")
<video id="video" autostart="false"></video>
<canvas id="image"></canvas>
【讨论】:
感谢您的回复,但很抱歉,这对我不起作用。我之前尝试过“canplay”事件,现在还测试了您的示例代码。我检查了画布,然后添加了一个实心边框以确保我正在寻找正确的空间。画布大小是正确的,但它是空白的。我还在 firefox 和 safari 上试过它——它确实在 Safari 上工作,但在 Chrome 或 Firefox 上却不行。我认为它要么是特定于浏览器的,要么可能是时间问题。我笨拙的解决方法确实适用于所有 3。 抱歉 russel - 我只是忘了在 Chrome 中测试它。不过,我找到了另一种解决方法并更新了我的答案。 太棒了!非常感谢您的努力 - 不仅仅是为了解决方案,而是为了了解正在发生的事情。这将使支持其他浏览器变得更加容易。【参考方案2】:如果有人有更好的解决方案,我会很欢迎,但我确实找到了一种方法来做我想做的事,方法是加载元数据,进行搜索,然后在“搜索”事件侦听器中复制图像。我正在使用 Chrome,并且从我所读到的内容中怀疑这可能不是一个通用的解决方案,但由于目前我只支持 Chrome,这似乎可以满足我的需求。
<html>
<head>
<script>
var video, image, width, height;
function copy(src)
video = document.getElementById('video');
video.addEventListener('loadedmetadata', x => video.currentTime = 0);
video.addEventListener('seeked', x => finishCopy());
video.src = src;
function finishCopy()
width = document.defaultView.getComputedStyle(video).width.replace(/[^.0-9]/g, '');
height = document.defaultView.getComputedStyle(video).height.replace(/[^.0-9]/g, '');
image = document.getElementById('image');
image.width = width;
image.height = height;
//setTimeout(draw, 1000);
draw();
function draw()
let ctxt = image.getContext('2d');
ctxt.drawImage(video, 0, 0, width, height);
</script>
</head>
<body >
<button onclick="copy('asd.mp4')">Copy asd.mp4</button>
<br />
<video id="video" preload="metadata" autostart="false" ></video>
<canvas id="image"></canvas>
</body>
</html>
【讨论】:
以上是关于在javascript中从视频复制到画布的主要内容,如果未能解决你的问题,请参考以下文章
如何在 JavaScript 中从末尾切分字符串? [复制]
在基于 Java 的 Web 应用程序中从数据库到前端的实时数据复制
Java中从字符串到sql日期的日期转换给出不同的输出? [复制]