js 获取视频任意秒封面

216 阅读1分钟

1.需求

在项目涉及视频上传操作,但是视频封面获取是个问题,如果要直接显示视频,那就要将视频直接展示出来,相当于上传之后再下载,影响性能,经过搜索和实践,有一个传入任意秒截取画面的方法

2.实现

(1)视频获取封面方法如下,添加一个vide标签将对应时间的视频画面渲染到canvas上,然后调用canvasToImage方法,并返回img的dataUrl,即base64字符串

    //获取视频封面算法 file 视频文件 time 秒数 例:1秒  1
   function getVideoCover (file, time) {
    return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
    const blobUrl = URL.createObjectURL(file);
    const video = document.createElement('video');

    video.addEventListener('canplay', () => {
        video.currentTime = time;
    });

    video.addEventListener('seeked', () => {
        const canvas = document.createElement('canvas');
        const context = canvas.getContext('2d');

        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        context.drawImage(video, 0, 0, canvas.width, canvas.height);

        const dataUrl = canvas.toDataURL('image/png');

        resolve(dataUrl);
    });

    video.src = blobUrl;
    video.load();
};
reader.onerror = reject;
reader.readAsArrayBuffer(file.slice(0, 10 * 1024 * 1024)); // 读取视频文件的前 10MB
});
}

(2)因为返回的是dataUrl,并且是promise,需要在使用时,在then结果中将base64转化为png dataUrl转为文件的方法为

function dataUrlToFile (dataUrl, filename) {
    const arr = dataUrl.split(',');
    const mime = arr[0].match(/:(.*?);/)[1];
    const bstr = atob(arr[1]);
    let n = bstr.length;
    const uint8Array = new Uint8Array(n);
    while (n--) {
        uint8Array[n] = bstr.charCodeAt(n);
    }
        return new File([uint8Array], filename, { type: mime })
    }

(3)使用示例

在promise的回调方法中调用结果,并转换图片,这里取了第一秒的视频图片

this.getVideoCover(file, 1).then(res => {
    const videoCover = dataUrlToFile(res, 'cover.png')
    const coverXhr = new XMLHttpRequest()
    const coverFormData = new FormData()
    coverFormData.append('file', videoCover)
    coverXhr.open('POST', '/api/sys-storage/image/upload')
    coverXhr.setRequestHeader('Fawkes-Auth', this.accessToken)
    coverXhr.onload = () => {
        const result = JSON.parse(coverXhr.responseText)
        Api.updateAssets({ id: resStr.data.id, ext: result.data.fileToken }).then(res => {
        })
    }
    coverXhr.send(coverFormData)
})`