生成一个thumbnail/snapshot的特定时间文件输入选中的视频文件
Generate a thumbnail/snapshot of a video file selected by a file input at a specific time
如何在视频中的特定时间在后台静默地抓取通过 <input type="file">
选择的视频文件的快照(即没有可见元素、闪烁、声音等)?
主要有四个步骤:
- 创建
<canvas>
和 <video>
个元素。
- 将
URL.createObjectURL
生成的视频文件的 src
加载到 <video>
元素中,并等待它加载 通过侦听被触发的特定事件.
- 将视频时间设置为您要拍摄快照的时间点并监听其他事件。
- 使用canvas抓图。
第 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);
请注意视频元素具有属性 muted
。不要放置 autoplay
或 controls
等任何其他属性。另请注意,它们都有 class snapshot-generator
。这样我们就可以为它们设置样式,使它们不碍事:
.snapshot-generator {
display: block;
height: 1px;
left: 0;
object-fit: contain;
position: fixed;
top: 0;
width: 1px;
z-index: -1;
}
有些浏览器将它们设置为 display: none
,但其他浏览器会遇到严重问题,除非它们呈现在页面上,因此我们只是将它们做得很小,以便它们基本上不可见。 (不过不要将它们移出视口,否则您可能会在页面上看到一些丑陋的滚动条。)
第 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 需要匹配视频的尺寸( 而不是 <video>
元素)才能获得正确的图像。此外,我们正在设置 canvas 的内部 .height
和 .width
属性, 而不是 canvas height/width CSS 样式值。
snapshot的值是一个数据URI,基本上就是一个以data:image/jpeg;base64
开头的字符串,然后是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 格式的!将其发送到您的服务器,将其作为 <img>
元素的 src
或其他任何内容。
比如解码成二进制,直接写入文件(trim前缀在前),就变成了JPEG图片文件。
您还可以使用它在上传视频时提供视频预览。如果您将其作为 <img>
的 src
,请使用完整数据 URI (不要删除前缀).
如何在视频中的特定时间在后台静默地抓取通过 <input type="file">
选择的视频文件的快照(即没有可见元素、闪烁、声音等)?
主要有四个步骤:
- 创建
<canvas>
和<video>
个元素。 - 将
URL.createObjectURL
生成的视频文件的src
加载到<video>
元素中,并等待它加载 通过侦听被触发的特定事件. - 将视频时间设置为您要拍摄快照的时间点并监听其他事件。
- 使用canvas抓图。
第 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);
请注意视频元素具有属性 muted
。不要放置 autoplay
或 controls
等任何其他属性。另请注意,它们都有 class snapshot-generator
。这样我们就可以为它们设置样式,使它们不碍事:
.snapshot-generator {
display: block;
height: 1px;
left: 0;
object-fit: contain;
position: fixed;
top: 0;
width: 1px;
z-index: -1;
}
有些浏览器将它们设置为 display: none
,但其他浏览器会遇到严重问题,除非它们呈现在页面上,因此我们只是将它们做得很小,以便它们基本上不可见。 (不过不要将它们移出视口,否则您可能会在页面上看到一些丑陋的滚动条。)
第 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 需要匹配视频的尺寸( 而不是 <video>
元素)才能获得正确的图像。此外,我们正在设置 canvas 的内部 .height
和 .width
属性, 而不是 canvas height/width CSS 样式值。
snapshot的值是一个数据URI,基本上就是一个以data:image/jpeg;base64
开头的字符串,然后是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 格式的!将其发送到您的服务器,将其作为 <img>
元素的 src
或其他任何内容。
比如解码成二进制,直接写入文件(trim前缀在前),就变成了JPEG图片文件。
您还可以使用它在上传视频时提供视频预览。如果您将其作为 <img>
的 src
,请使用完整数据 URI (不要删除前缀).