纯前端:提取视频某一帧显示在页面上

用户在发帖等场景中上传视频,需要提取视频帧作为封面来暗示视频上传成功;本文采用HTML video + canvas的方法提取视频帧第0秒作为封面。

1. 获取上传的文件

前端使用<input type="file">上传文件,当然也可以使用各大UI的uploader组件如移动端的van-uploader。其底层都是<input type="file">。

用户上传文件后,可以通过input的change事件获取上传后的File对象,File继承自Blob对象

js 复制代码
const handleChange = (e) => {
    const file = e.target.files[0]
}

2. File对象转换

看这张图:

首先需要明确我们需要将File转换成什么类型。方法中需要创建一个Video DOM对象,将文件加载到video.src中,所以需要将File转化为ObjectURL

js 复制代码
// file是上面获取到的File对象
const url = URL.createObjectURL(file)

然后创建一个Video对象,这里不需要将它插入到HTML中,使用video.load()也可以触发Video的各种加载事件

js 复制代码
const video = document.createElement('video')
video.src = url
video.load()

3. 在seeked事件中提取视频帧

video事件中loadeddata在视频加载完成后触发,seeked在移动视频时间位置时触发。理论上在loadeddata后就可以提取视频帧,但是实际开发中可能会遇到第一帧纯黑的情况。与系统内置软件展示的不一样。所以可以在video准备好后将视频移动到第0秒,在seeked事件中提取

js 复制代码
//loadeddata后移动视频位置到第0秒
video.addEventListener('loadeddata', loadeddataHandler, false)
const loadeddataHandler = () => {
    video.currentTime = 0
}

移动位置后就可以在seeked中捕获移动完成的事件,canvas的context可以使用drawImage方法直接获取当前位置的视频帧。所以先从HTML中获取canvas的context

js 复制代码
// 获取canvas的context
const canvas = document.getElementByTag("canvas")
const context = canvas.getContext("2d")

使用context.drawImage提取将video画到canvas中。其中参数的意义:video DOM对象,截取位置左上角x,截取位置左上角y,截取的宽度,截取的长度

js 复制代码
canvas.width = video.videoWidth
canvas.height = video.videoHeight
context.drawImage(video, 0,  0, video.videoWidth, video.videoHeight)

drawImage在seeked事件中进行,截取完成后记得移除video事件,video=null释放内存

js 复制代码
video.addEventListener('seeked', seekedHandler, false)
const seekedHandler = async () => {
    canvas.width = video.videoWidth
    canvas.height = video.videoHeight
    context.drawImage(video, 0,  0, video.videoWidth, video.videoHeight)

    video.removeEventListener('loadeddata', loadeddataHandler, false)
    video.removeEventListener('seeked', seekedHandler, false)
}

至此,我们就提取了封面并回显在用户界面中 最后记得将创建的Object URL释放掉,防止内存泄漏URL.revokeObjectURL(url)

从canvas中保存封面

获取到的视频帧不但要回显,还需要上传到服务器。

将canvas图像转化成File对象可以遵循以下步骤: canvas -> base64(data url) -> Blob -> File

js 复制代码
// 首先使用canvas.toDataURL('image/png')将canvas转化为base64图片
url = canvas.value!.toDataURL('image/png')

// 通过fetch方法,获取文件成blob
const res = await fetch(url)

// 将Blob转化成File
new File([await res.blob()], 'cover', { type: 'image/png' })

总结

通过HTML video加载用户上传视频文件,然后通过loadeddata, seek等事件定位视频帧,通过canvas的context.drawImage绘制video的方式可以提取视频帧并回显

将canvas -> base64(data url) -> Blob -> File可以获取到视频的File对象上传到服务器。

相关推荐
小小龙学IT7 小时前
Go 语言 reflect 反射包深度解析:从 Type/Value 到三大定律与工业实践
前端·golang
小溪学编程7 小时前
C语言篇:枚举类型
java·c语言·前端
xingpanvip7 小时前
星盘接口开发文档:推算星座接口指南
前端·php
Da Da 泓7 小时前
HTML浅浅入门
前端·html
এ慕ོ冬℘゜7 小时前
es6基础
前端·javascript·es6
熊猫钓鱼>_>7 小时前
从2D平铺到3D沉浸:我用HarmonyOS 7端侧AI做了一个全程数据不出设备的空间化私密相册
前端·人工智能·3d·华为·华为云·harmonyos·鸿蒙
孔令飞8 小时前
Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中指针引用Go中
前端
溪语流沙8 小时前
【Web全栈进阶】PostgreSQL上手:Docker跑库 + 把早报站从SQLite迁过去
前端·docker·postgresql
IT_陈寒8 小时前
SpringBoot自动配置的坑:你以为的捷径可能是弯路
前端·人工智能·后端
paopaokaka_luck8 小时前
高校社团管理(AI辅助任务分配、协同过滤算法推荐、ECharts数据可视化、活动参与闭环、校园交流与反馈、器材借还管理)
java·前端·javascript·spring boot·数据分析·echarts