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)
})`