Skip to content

截取视频帧为 image

在各大视频应用中大部分支持上传视频根据帧自定义封面,视频截取帧通常分为客户端和服务端两种实现方式,服务端可以借助 ffmpeg 等工具实现视频帧的截取,这种方式会消耗大量服务器资源,在并发场景下会严重影响吞吐量,通常适用于对安全性较高等场景。为了降低服务器压力,客户端可以通过 canvas 对上传视频根据指定帧截取并转为图片,大致原理如下:

  • 创建一个 video 元素,根据帧时间设置 video currentTime 属性表示当前播放视频时间,并设置 autoplay 开启自动播放,最后通过 URL.createObjectURL()将上传视频转换为一个临时的 URL 并显示。
  • 监听 video 播放事件,根据 video 通过 canvas drawImage()绘制为 image,最后使用 canvas toBlob()获取帧文件及帧图片 URL。
ts
/**
 * 绘制video
 * @param video video元素
 * @returns 返回一个Promise,Promise的值为一个对象,对象包含blob(帧文件)、url(帧图片)
 */
function drawVideo(video: HTMLVideoElement) {
  return new Promise((resolve) => {
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    // 设置canvas的宽高为video元素的宽高
    canvas.width = video.videoWidth
    canvas.height = video.videoHeight
    // 绘制内容
    ctx?.drawImage(video, 0, 0, canvas.width, canvas.height)
    canvas.toBlob((blob) => {
      resolve({
        blob,
        url: URL.createObjectURL(blob!),
      })
    })
  })
}

/**
 *
 * @param videoFile 视频文件对象
 * @param time 截取帧时间
 * @returns 返回一个Promise,Promise的值为一个对象,对象包含blob(帧文件)、url(帧图片)
 */
function captureFrame(videoFile: File, time: number = 0) {
  return new Promise((resolve) => {
    const video = document.createElement('video')
    // 定格时间
    video.currentTime = time
    // 开启自动播放
    video.autoplay = true
    // 监听video播放事件,根据video通过canvas绘制为image
    video.oncanplay = async () => {
      const frame = await drawVideo(video)
      resolve(frame)
    }
    // URL.createObjectURL()可以将文件或媒体数据(如图片、视频等)转换为一个临时的 URL,通常用于实时预览上传的图片或视频
    video.src = URL.createObjectURL(videoFile)
  })
}

Released under the MIT License.