需求背景
最近有个视频上传的需求,需要对上传上传到OSS的视频做一些限制,并且在上传之前判断,视频的大小、尺寸、比例、时长等等。心里一直想着OSS能直接把视频的相关信息返回;毕竟图片是有很多信息返回的;
然而经过确认之后,发现屁都没有……
那就只能自己写了,百度了一下,并没有特别全的方案,那就自己动手写个吧。
视频加载基本介绍
在视频/音频(audio/video)加载过程中,事件的触发顺序如下:
- onloadstart (浏览器开始寻找指定资源)
- ondurationchange (视频/音频 的时长发生变化时触发)
- onloadedmetadata (指定视频/音频 的元数据加载后触发)
- onloadeddata (当前帧的数据加载完成且还没有足够的数据播放)
- onprogress (下载指定的视频/音频 时触发)
- oncanplay (用户可以开始播放视频/音频 时触发)
- oncanplaythrough (可以正常播放且无需停顿和缓冲时触发)
写个小代码
获得时长
找了一个相对好一点的方案,然后准备改巴改巴……
html
upload! (ღ˘⌣˘ღ)
js
上传之后可以看到如下结果:
从这个例子里可以看到,已经可以成功的拿到时长的数据了,但是在真实的项目中如果每次都需要在html代码里加video标签,这会是一件很麻烦且不规范的事情。
so ~
html部分 可以优化一下,动态去创建节点。在现代浏览器中,可以使用带有非追加视频元素的URL API URL.createObjectURL()来加载文件的内容;
URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。 详细介绍=>
this.video = document.createElement('video')
this.video.preload = 'metadata'
this.video.src = URL.createObjectURL(file)
获取视频第一帧
方案一
通过创建canvas标签,利用其drawImage() 方法在画布上绘制该视频,然后运用toDataURL方法转换canvas上的图片为base64格式,并将base64格式的图片作为video标签的poster属性。
需要注意的是,由于canvas无法对跨域的图片进行操作,需要提前处理好跨域问题。
核心实现代码如下:
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('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;
canvas.getContext("2d").drawImage(video, 0, 0, width, height); //绘制canvas
dataURL = canvas.toDataURL('image/jpeg'); //转换为base64
resolve(dataURL);
});
})
}
方案二
可以选择使用第三方平台实现。七牛云、阿里云等云端存储平台功能强大,不仅具有海量的存储功能,平台封装的还有很多功能丰富的API。这次使用的是阿里云OSS,以OSS为例,说明一下视频截取方法。
如存储在阿里云平台的视频名称为:
http://a-image-demo.oss-cn-qingdao.aliyuncs.com/demo.mp4
那么如果想要实现截取视频的某一帧其实很方便,只需在视频的url后面这样拼接即可:
http://a-image-demo.oss-cn-qingdao.aliyuncs.com/demo.mp4?x-oss-process=video/snapshot,t_7000,f_jpg,w_800,h_600,m_fast
OSS视频截帧文档,戳这里~
参考文章
获取文件类型
拿文件类型相对来说比较简单,但是遵循万物皆可Function的原则,还是封装一下吧
getFileType (fileName) {
var exts = fileName.split('.');
var ext = "";
if (exts != undefined) {
if (exts.length <= 1 && fileName.indexOf('=')>-1) {//直接输入上传到azure之后生成的文件地址
console.log('输入是文件地址:', exts);
return false
} else {
ext = exts[exts.length - 1];
ext = ext.toLowerCase();
return ext
}
} else {
return false
}
}
获取文件大小
/**
* [fileLengthFormat 格式化文件大小]
* @param {[int]} total [文件大小] Byte
* @param {[int]} n {1: "KB", 2: "MB", 3: "GB", 4: "TB"}
* @return {[string]} [带单位的文件大小的字符串]
*/
fileLengthFormat(total, n) {
var format;
var len = total / (1024);
if (len > 1000) {
return this.fileLengthFormat(len, ++n)
} else {
switch (n) {
case 1:
format = len.toFixed(2)
break;
case 2:
format = len.toFixed(2)
break;
case 3:
format = len.toFixed(2)
break;
case 4:
format = len.toFixed(2)
break;
}
return +format;
}
}
获取尺寸
先展示部分伪代码,完整的代码可以戳下面的完整代码链接;
revokeObjectURL介绍
video.onloadedmetadata = () => {
window.URL.revokeObjectURL(this.video.src);
let height = video.videoHeight
let width = video.videoWidth
}
最后奉上完整的代码 ==> CalcVideo.js