🍉截取视频片段为gif

162 阅读1分钟

没错 这个是目录

本次内容采用vue3 进行演示


如果你需要gif裁剪为gif 请移步笔者此篇文章


准备工作

  • 搭建一个 vue +vite的工程

  • 下载 gif.js gifuct-js两个包

  • vite.config.js的配置optimizeDeps中添加两个依赖

image.png

截取视频片段转成gif

先说思路

  • video标签播放的时候 我们读取某一帧的视频流,并且依次保存每一帧
  • 使用gif.js 把依次保存的帧转成gif

初始代码

<template>
  <div>
    <h1>Vedio to gif</h1>
    <div>
      <video ref="videoRef" src="@/assets/demo.mp4" controls autoplay />
      <div class="controls">
        <button :disabled="isRecording" @click="startCapture"> 开始录制 </button>
        <button :disabled="!isRecording" @click="stopCapture"> 停止录制 </button>
      </div>
      <div v-if="progress > 0" class="progress"> 处理中: {{ progress }}%  </div>
      
      <div v-if="gifUrl" class="output">
        <h3>录制的GIF:</h3>
        <img :src="gifUrl"  alt="GIF 预览" />
        <button @click="downloadGif">下载GIF</button>
        <button @click="extractFrames">提取帧</button>
      </div>
    </div>
  </div>
</template>

<script setup>
import GIF from 'gif.js'
import { onUnmounted, ref } from 'vue'
const videoReady = ref(true)
const videoRef = ref(null)
const isRecording = ref(false)
const progress = ref(0)
const gifUrl = ref(null)
const frames = ref([]) // 保存提取的帧

let gifRecorder = null
let captureInterval = null


</script>

<style scoped>

</style>

初始化gif渲染器

// 初始化GIF录制器
const initGifRecorder = () => {
  if (gifRecorder) {
    gifRecorder.abort()
  }
  gifRecorder = new GIF({
    workers: 2,
    quality: 10,
    width: videoRef.value?.videoWidth || 320,
    height: videoRef.value?.videoHeight || 240,
    workerScript: '/gif.worker.js' // 确保这个文件在public目录下
  })
  console.log('GIF捕捉器初始化成功')
  
  gifRecorder.on('progress', p => {
    progress.value = Math.round(p * 100)
  })

  gifRecorder.on('finished', blob => {
    gifUrl.value = URL.createObjectURL(blob)
    // 自动下载
    // downloadGif()
    // 重置状态
    isRecording.value = false
    progress.value = 0
  })
}

点击播放

// 开始录制
const startCapture = () => {
  if (!videoRef.value || isRecording.value || !videoReady.value) return
  initGifRecorder()
  isRecording.value = true
  captureInterval = setInterval(captureFrame, 100)
}

点击停止

// 停止录制
const stopCapture = () => {
  if (!isRecording.value) return

  clearInterval(captureInterval)
  gifRecorder.render()
  console.log('结束录制')
}

提取帧逻辑

const extractFrames = () => {
  if (!videoRef.value) return

  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')

  canvas.width = videoRef.value.videoWidth
  canvas.height = videoRef.value.videoHeight

  // 确保视频帧已渲染
  if (videoRef.value.readyState >= 2) {
    // >= 2 表示视频数据已加载
    ctx.drawImage(videoRef.value, 0, 0, canvas.width, canvas.height)
    gifRecorder.addFrame(ctx, {
      copy: true,
      delay: 100
    })
  }
}

// 清理
onUnmounted(() => {
  if (gifRecorder) {
    gifRecorder.abort()
  }
  clearInterval(captureInterval)
})

下载逻辑

const downloadGif = () => {
  const a = document.createElement('a')
  a.href = gifUrl.value
  a.download = `capture-${Date.now()}.gif`
  a.click()
}

完整代码如下