如何在特定时间无声地在后台(即没有可见元素,闪烁,声音等)在特定时间捕获通过<input type="file">
选择的视频文件的快照?
最佳答案
有四个主要步骤:
<canvas>
和<video>
元素。 src
生成的视频文件的URL.createObjectURL
加载到<video>
元素中,并通过侦听被触发的特定事件来等待其加载。 第1步-创建元素
这非常简单:只需创建一个
<canvas>
和一个<video>
元素,然后将它们附加到<body>
(或者在任何地方,这都没有关系):var canvasElem = $( '<canvas class="snapshot-generator"></canvas>' ).appendTo(document.body)[0];
var $video = $( '<video muted class="snapshot-generator"></video>' ).appendTo(document.body);
请注意,video元素具有
muted
属性。不要放置任何其他属性,例如autoplay
或controls
。还要注意,它们都具有snapshot-generator
类。因此,我们可以为它们两者设置样式,以使它们不受影响:.snapshot-generator {
display: block;
height: 1px;
left: 0;
object-fit: contain;
position: fixed;
top: 0;
width: 1px;
z-index: -1;
}
有些浏览器将它们设置为
display: none
,但是其他浏览器除非将它们呈现在页面上,否则都会遇到严重的问题,因此我们将它们缩小以使它们基本上不可见。 (不过,请勿将它们移到视口(viewport)之外,否则您可能会在页面上看到一些难看的滚动条。)第2步-加载视频
这是开始变得棘手的地方。您需要收听事件以了解何时继续。不同的浏览器将触发不同的事件,不同的时间和顺序,因此,我将节省您的精力。在视频准备就绪之前,必须至少触发一次三个事件:他们是:
为这些事件设置事件处理程序,并跟踪触发了多少事件。一旦三个都被解雇,您就可以继续。请记住,由于其中一些事件可能会触发多次,因此您只想处理每种触发类型的第一个事件,并丢弃后续触发。 我使用了jQuery的
.one
,它可以解决这个问题。var step_2_events_fired = 0;
$video.one('loadedmetadata loadeddata suspend', function() {
if (++step_2_events_fired == 3) {
// Ready for next step
}
}).prop('src', insert_source_here);
源应该只是通过
URL.createObjectURL(file)
创建的对象URL,其中file
是文件对象。步骤3-设定时间
该阶段与上一个阶段相似:设置时间,然后监听事件。在上一个代码的
if
块中:$video.one('seeked', function() {
// Ready for next step
}).prop('currentTime', insert_time_here_in_seconds);
幸运的是,这一次是唯一的事件,因此非常清楚简洁。最后...
步骤4-抓取快照
这一部分仅使用
<canvas>
元素来截取屏幕截图。在seeked
事件处理程序中:canvas_elem.height = this.videoHeight;
canvas_elem.width = this.videoWidth;
canvas_elem.getContext('2d').drawImage(this, 0, 0);
var snapshot = canvas_elem.toDataURL();
// Remove elements as they are no longer needed
$video.remove();
$(canvas_elem).remove();
Canvas 需要匹配视频的尺寸(元素的而不是)以获取正确的图像。另外,我们设置 Canvas 的内部
<video>
和.height
属性,而不是 Canvas 的高度/宽度CSS样式值。 快照的值是数据URI,它基本上只是一个以
.width
开头的字符串,然后是base64数据。我们最终的JS代码应如下所示:
var step_2_events_fired = 0;
$video.one('loadedmetadata loadeddata suspend', function() {
if (++step_2_events_fired == 3) {
$video.one('seeked', function() {
canvas_elem.height = this.videoHeight;
canvas_elem.width = this.videoWidth;
canvas_elem.getContext('2d').drawImage(this, 0, 0);
var snapshot = canvas_elem.toDataURL();
// Delete the elements as they are no longer needed
$video.remove();
$(canvas_elem).remove();
}).prop('currentTime', insert_time_here_in_seconds);
}
}).prop('src', insert_source_here);
庆祝!
您的镜像在base64中!将其发送到您的服务器,将其作为
data:image/jpeg;base64
元素的src
或其他内容。例如,您可以将其解码为二进制文件,然后直接将其写入文件(首先删除前缀),该文件将成为JPEG图像文件。
您还可以使用此功能在上传视频时提供视频预览。如果将其作为
<img>
的src
放置,请使用完整数据URI (不要删除前缀)。