最近被告知要做一个给视频指定时间段截图的功能,不多BB上代码,使用了ivewUI。
效果图:
<template>
<div class="home-page">
<div class="upload">
<Upload
multiple
type="drag"
style="width:200px"
:before-upload="UploadVideo"
action=""
>
<div style="padding: 20px 0">
<Icon type="ios-cloud-upload" size="52" style="color: #24345f"></Icon>
<p>点击或拖拽上传</p>
</div>
</Upload>
</div>
<div class="myCover">
<div class="pic" v-for="(item, index) in showCoverArr" :key="index">
<img :src="item" />
</div>
</div>
</div>
</template>
方法
import utilsTool from "@/lib/utils/index"; //已经封装好,直接调用
data() {
return {
videoInfo: {
url: "",
play: false,
},
cutTime: ['3', '20', '66'], //截图时间点,建议采用%,通过%乘视频时长获取截屏时间
showCoverArr: [],
};
},
UploadVideo(file) {
this.showCoverArr = [];
console.log(file);
if (!/^video\/mp4$/.test(file.type)) {
this.$Message.warning("视频格式不正确,只支持“.mp4”");
return false;
}
if (file.size / 1024 / 1024 > 100) {
this.$Message.warning("视频大小不能超过100M");
return false;
}
let url = URL.createObjectURL(file);
this.videoInfo.src = url;
console.log(url);
this.cutVideoCover(url, 0);
},
// 视频封面截图(传入截屏时间点)
cutVideoCover(url, index) {
utilsTool.GetVideoCover({
url: url,
time: this.cutTime[index],
success: (res) => {
this.showCoverArr.push(res.base64); //给展示列表传入截图的URL
console.log(
"第",index+1,"张",
"总",this.cutTime.length,"张"
);
if(parseInt(this.showCoverArr.length)<parseInt(this.cutTime.length)){
this.cutVideoCover(url, index+=1);
}else {
console.log(this.showCoverArr)
}
},
});
},
封装的绘制部分
//压缩图片
function clipAndCompressCover({ media, currentWidth, currentHeight, success }) {
// eslint-disable-next-line no-unused-vars
const that = this;
const canvas = document.createElement("canvas");
const area = canvas.getContext("2d");
const currentScale = currentWidth / currentHeight;
const targetScale = 750 / 420;
let targetWidth = 0;
let targetHeight = 0;
let clipWidth = 0;
let clipHeight = 0;
let quality = 0.95; // 不要用1,会额外增大base64大小。
// 根据视频宽高,决定截图大小
if (currentScale >= targetScale) {
targetHeight = currentHeight > 420 ? 420 : currentHeight;
targetWidth = targetHeight * currentScale;
} else {
targetWidth = currentWidth > 750 ? 750 : currentWidth;
targetHeight = targetWidth / currentScale;
}
clipWidth = targetWidth > 750 ? 750 : targetWidth;
clipHeight = targetHeight > 420 ? 420 : currentHeight;
canvas.width = clipWidth;
canvas.height = clipHeight;
area.drawImage(
media,
(clipWidth - targetWidth) / 2,
(clipHeight - targetHeight) / 2,
targetWidth,
targetHeight
);
var handler = function() {
const base64 = canvas.toDataURL("image/jpeg", quality);
getMediaSize({ src: base64 }).then(response => {
if (response.size / 1024 > 100) {
quality -= 0.1;
if (quality > 0.2) {
handler();
}
} else {
success && success(base64);
}
});
};
handler();
}
//绘制视频封面图片
const GetVideoCover = ({ url, time, success }) => {
const video1 = document.createElement("video");
video1.src = url;
video1.style.cssText = "position:fixed; top:0; left:-100%; visibility:hidden";
video1.onloadeddata = function() {
let currentTime = time; //截图时间点
video1.addEventListener("timeupdate", function() {
clipAndCompressCover({
media: video1,
currentWidth: video1.videoWidth,
currentHeight: video1.videoHeight,
success: function(base64) {
video1.remove(video1);
success({
base64: base64
})
}
});
});
video1.currentTime = currentTime < 0 ? 1 : currentTime;
};
// edge浏览器必须要追加到dom中,才能顺利执行相关事件。
document.body.appendChild(video1);
};
// 获取媒体资源的大小,返回一个Promise对象。用于解决无法直接获取视频或图片的文件大小。
function getMediaSize({
src
}) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
// eslint-disable-next-line no-unused-vars
xhr.onreadystatechange = _ => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
resolve({
size: xhr.response.size
});
} else {
reject();
}
}
};
xhr.open('get', URL.createObjectURL(transformBase64ToBlob(src)));
xhr.responseType = 'blob';
xhr.send();
});
}
function transformBase64ToBlob(base64) {
let byteString;
if (base64.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(base64.split(',')[1]);
} else {
byteString = unescape(base64.split(',')[1]);
}
const mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
const ia = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
const blob = new Blob([ia], {
type: mimeString
});
return blob;
}
export default {
GetVideoCover,
};
至此,截图生成的base64编码都有了,只需要放到页面展示即可