在这样一个图像化极其重要的时代,从视频中提取精彩瞬间,即视频帧截图的技术,已成为前端开发中的一个亮点。JavaScript作为网页动态效果和交互的主力军,其在视频处理领域能力逐渐被挖掘和重视,尤其是视频帧截图技术的应用,为网站和应用程序提供了更为丰富和直观的用户体验。

在一些媒体网站上传作品后,通常都会让你选择视频中的某个画面作为封面,这个封面可以吸引观众的注意力,让他们对你的视频产生兴趣。那么,如何实现视频帧截图呢?本文将介绍如何使用JavaScript来实现这一功能。
在这里插入图片描述

大体为以下流程:
在这里插入图片描述

选择视频文件定格帧

选择本地视频文件

<input type="file">
const input = document.querySelector('input');
  input.onchange = async (e) => {
  const file = e.target.files[0];
  console.log(file);
}

创建一个video标签,把视频文件放到video标签中。使用 createObjectURL 方法把视频文件对象转为一个url。

const video = document.createElement("video");
video.src = URL.createObjectURL(file);
// 设置视频自动播放
video.autoplay = true;
// 设置视频播放的时间点
video.currentTime = 10;

使用 createObjectURL 创建的URL是一个blob:开头的临时路径,这个路径可以在浏览器中直接访问,访问到的内容就是上传的视频文件。当页面关闭后,此路径也随之失效。
在这里插入图片描述

通过 currentTime 设置需要截图的时间点,由于创建的video标签未加到页面中,所以这里设置了自动播放后,不会继续播放10s后的内容,而是停留在10s的位置。

绘制视频帧

现在视频停留在了指定帧的位置,接下来就通过 canvas来绘制当前帧。

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = vdo.videoWidth;
canvas.height = vdo.videoHeight;
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
document.body.appendChild(canvas);

在这里插入图片描述

转为图片地址

将canvas内容转为一个可用img标签展示的url地址,这个过程需要两步:

  • 使用toBlob方法创造一个Blob对象
  • 使用createObjectURL方法把对象转为可访问的URL
function drawVideo(vdo) {
    return new Promise((resolve) => {
        const canvas = document.createElement("canvas");
        const ctx = canvas.getContext("2d");
        canvas.width = vdo.videoWidth;
        canvas.height = vdo.videoHeight;
        ctx.drawImage(vdo, 0, 0, canvas.width, canvas.height);
        canvas.toBlob((blob) => {
            resolve({
                blob,
                url: URL.createObjectURL(blob)
            });
        })
    })
}

由于 toBlob 是采用回调函数的方式调用,所以封装drawVideo 方法返回为一个promise。
在这里插入图片描述
从上图可以看到抖音平台下面展示的预览图同样也是以blob:开头的临时地址。

截图全流程

当video标签设置url后,不能马上截图,视频加载需要一个过程,要等视频可以播放后再截图。

video.oncanplay = async () => {
    const frame = await drawVideo(video);
}

封装完整的截图方法,由于oncanplay 同样是一个异步方法,这里也需要返回一个promise

function captureFrame(file, time) {
    return new Promise((resolve) => {
        const video = document.createElement("video");
        video.autoplay = true;
        video.currentTime = time;
        video.src = URL.createObjectURL(file);
        video.oncanplay = async () => {
            const frame = await drawVideo(video);
            resolve(frame);
        }
    })
}

获取视频时长,按照每1秒的间隔截一张图

const video = document.createElement("video");
video.src = URL.createObjectURL(file);
// 视频加载完成后,才能获取到视频的时长
video.onloadedmetadata = async () => {
    for (let index = 0; index < video.duration; index++) {
        const frame = await captureFrame(file, index);
        // 将截图加入到页面中展示
        const img = document.createElement("img");
        img.src = frame.url;
        img.style.width = "100px";
        document.body.appendChild(img);
    }
};

尽管视频帧截图技术带来了许多便利,但在实际应用过程中也面临着一些挑战:

  • 性能问题:处理大量或高分辨率视频时的性能消耗较大,可能影响页面加载速度和用户体验。解决方案包括优化图片尺寸、使用异步加载技术、以及在服务器端进行视频处理等。
  • 浏览器兼容性:不同浏览器对视频解码和渲染的支持程度不同,可能导致在某些浏览器上无法正确显示视频帧截图。解决这一问题的方法包括使用广泛支持的编解码器和格式,以及提供替代的媒体格式。
  • 用户体验:如何让用户方便快捷地选择和保存截图是一个需要解决的问题。提供直观的用户界面和明确的操作指导是提升用户体验的关键。

随着前端技术的不断进步,未来视频帧截图技术将变得更加高效和用户友好。Web Assembly和FFmpeg等技术的发展有望进一步提升前端处理视频的能力,使得视频帧截图更加迅速和精确。

关注公众号【前端筱园】,回复“视频帧截图”获取本案例源码及素材

写在最后

欢迎访问我的个人网站:www.dengzhanyong.com

欢迎加入前端筱园交流群:
描述文字
关注我的公众号【前端筱园】,不错过每一篇推送

描述文字
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐