使用帧图片模拟视频播放

216 阅读1分钟

需求描述

使用帧图片来模拟视频的播放,有点像做动画了嗷。但是只是作为一个纯前端的小demo,所以需要自己准备图片数据。

材料准备

找到一个免费网站,可以将MP4视频逐帧提取为一张张的图片。网址如下:
www.img2go.com/convert-to-…
优点:免费
缺点:会丢帧(10s左右的视频生成的图片大概是105张)

将这105张图片存放在本地的assets目录下:

image.png

核心代码

<!-- html  -->
<img :src="imgUrl" alt="" >

// js
const intervalId = ref(null)
const frameCount = ref(100)
const currentFrame = ref(0)
// 每帧的持续时间,控制帧率为每秒15帧
const frameDuration = ref(1000 / 15)
// 图片地址
const imgUrl = ref('')
let lastTime = ref(0)
const updateFrame = (timestamp) => {
  if(!lastTime.value) {
    lastTime.value = timestamp
  }
  const elapsed = timestamp - lastTime.value
  if (elapsed > frameDuration.value) {
    if (currentFrame.value === frameCount.value) {
      currentFrame.value = 0;
    } else {
      currentFrame.value++
    }
      let a = 0
      if (currentFrame.value < 10) {
        a = `00${currentFrame.value}`
      } else if (currentFrame.value > 10 && currentFrame.value < 100) {
        a = `0${currentFrame.value}`
      } else {
        a = currentFrame.value
      }
      imgUrl.value = new URL(`/src/assets/frames/10s_${a}.jpg`, import.meta.url).href
      console.log('imgUrl', imgUrl)

      lastTime.value = timestamp
    }
    intervalId.value = requestAnimationFrame(updateFrame)
}

// 在需要播放的时候去执行如下语句
// 开始播放帧图片
intervalId.value = requestAnimationFrame(updateFrame)

// 在关闭时需执行如下语句
cancelAnimationFrame(intervalId.value

思路:

拿到105张图片后,合适的时间间隔(假如每秒需要25帧,那么就是40ms)去切换到下一张,以此类推。

遇到的问题:

画面频闪

解决方法:

1、不要使用document.xxx.style.backgroundImage = xxx 的方式
2、不要使用setInterval(update, 40)的方式
3、使用requestAnimationFrame的方式去代替setInterval,但是requestAnimationFrame的回调函数执行次数通常是每秒60次,通过在回调函数中判断时间间隔来迂回的实现自己想要的每秒n帧的效果
4、使用vue3提供的transition动画过渡一下

缺点:

问了下gpt:

image.png

所以最终大概率不会采取这种方式,只是作为备选方案。