记一次被获取video首帧坑惨的经历

2,005 阅读2分钟

背景

老生常谈的东西:js获取video首帧,一直都知道大概怎么做,但也是第一次实践,往往这种东西都是深坑一般的存在。

开搞

首先有一个东西,就是canvas。它的上面有一个getContext方法,这个方法获得一个绘图上下文,并且可以开始绘制。canvas还有一个方法就是drawImage,这个方法接受一个image或者video对象,可以获取该对象的图像。

void ctx.drawImage(image, dx, dy);
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

好,现在我们有了工具,那现在要实现的就是 创建一个video对象,把我们的video的url放进去,然后设置好长宽,监听video的事件,再使用上面所说的drawImage方法就可以得到一个base64的图片。 video几个事件该如何去选择:

play: play 和 autoplay开始播放时触发
pause: 暂停时触发
waiting: 等待数据,并非错误
playing: 正在播放时触发,常常在 获取当前时长和总时长
ended: 播放结束时触发
loadeddata: 是当当前的数据已经加载完,但是,没有足够的数据去加载下一帧,会触发该事件

我这里是使用了loadeddata这个事件

 		let video = document.createElement('video')
        video.setAttribute('crossOrigin', 'anonymous')// 处理跨域 实际屁用没有
        video.setAttribute('src', url)
        video.setAttribute('width', 400)
        video.setAttribute('height', 240)
        video.addEventListener('loadeddata', function () {
            let canvas = document.createElement('canvas')
            let width = video.width // canvas的尺寸和图片一样
            let height = video.height
            canvas.width = width
            canvas.height = height
            console.log(this, video)
            canvas.getContext('2d').drawImage(this, 0, 0, width, height) // 绘制canvas
            dataURL = canvas.toDataURL('image/jpeg') // 转换为base64
        })

现在让我们来试一下这些代码的运行情况 哇 黑屏,玩个鬼啊。这是咋回事呢。 emmm 大概感觉是当前这个时间不对,那我来手动设置一下当前视频的时间。

video.currentTime = 0.1

ok 这就可以完成了获取视频第一帧。

你以为这就完了? 太年轻了

之前的都是在chrome中,现在上真机。 在iphone上没有图片,翻找资料,哦哦哦~,原来是iphone不会自动加载,所以直接加上autoplay和muted属性,

        video.setAttribute('autoplay', true)
        video.setAttribute('muted', true)

但是 iphone会默认播放时是全屏的,哪怕你没有把这个video写进html里面。所以,加上行内播放。

        video.setAttribute('playsinline', true)
        video.setAttribute('webkit-playsinline', true)

再加一个小延时,用promise封装一下,然后就可以用啦。 完整代码:

	/**
     * 截取第一帧
     */
    getVideoBase64(url) {
      return new Promise(function (resolve, reject) {
        let dataURL = ''
        let video = document.createElement('video')
        video.setAttribute('crossOrigin', 'anonymous')// 处理跨域
        video.setAttribute('src', url)
        video.setAttribute('autoplay', true)
        video.setAttribute('muted', true)
        video.setAttribute('playsinline', true)
        video.setAttribute('webkit-playsinline', true)
        video.setAttribute('width', 400)
        video.setAttribute('height', 240)
        video.currentTime = 0.1
        video.addEventListener('loadeddata', function () {
          setTimeout(() => {
            let canvas = document.createElement('canvas')
            let width = video.width // canvas的尺寸和图片一样
            let height = video.height
            canvas.width = width
            canvas.height = height
            canvas.getContext('2d').drawImage(this, 0, 0, width, height) // 绘制canvas
            dataURL = canvas.toDataURL('image/jpeg') // 转换为base64
            resolve(dataURL)
          }, 100)
        })
      })
    },

坑点

网上资料繁杂,但是都不管用。但是我这个是我自己实践出来的,而且可以用。ios和安卓真的不一样,这个显示那个不显示的,适配是个恶心的东西