纯前端获取视频第一帧、大小、尺寸、类型等
最近有个视频上传的需求,需要对上传上传到OSS的视频做一些限制,并且在上传之前判断,视频的大小、尺寸、比例、时长等等。心里一直想着OSS能直接把视频的相关信息返回;毕竟图片是有很多信息返回的;
然而经过确认之后,发现屁都没有……
那就只能自己写了,百度了一下,并没有特别全的方案,那就自己动手写个吧。
视频加载基本介绍
在视频/音频(audio/video)加载过程中,事件的触发顺序如下:
- onloadstart (浏览器开始寻找指定资源)
- ondurationchange (视频/音频 的时长发生变化时触发)
- onloadedmetadata (指定视频/音频 的元数据加载后触发)
- onloadeddata (当前帧的数据加载完成且还没有足够的数据播放)
- onprogress (下载指定的视频/音频 时触发)
- oncanplay (用户可以开始播放视频/音频 时触发)
- oncanplaythrough (可以正常播放且无需停顿和缓冲时触发)
写个小代码
获得时长
找了一个相对好一点的方案,然后准备改巴改巴……
html
<div id="input-upload-file" class="box-shadow"> <span>upload! (ღ˘⌣˘ღ)</span> <input type="file" class="upload" id="fileUp" name="fileUpload"> </div> <pre id="infos"></pre>
js
<script> var myVideos = []; window.URL = window.URL || window.webkitURL; document.getElementById('fileUp').onchange = setFileInfo; function setFileInfo() { var files = this.files; myVideos.push(files[0]); var video = document.createElement('video'); video.preload = 'metadata'; video.onloadedmetadata = function() { window.URL.revokeObjectURL(video.src); var duration = video.duration; // 得到时长 myVideos[myVideos.length - 1].duration = duration; updateInfos(); } video.src = URL.createObjectURL(files[0]); } function updateInfos() { var infos = document.getElementById('infos'); infos.textContent = ""; for (var i = 0; i < myVideos.length; i++) { infos.textContent += myVideos[i].name + " duration: " + myVideos[i].duration + ' '; } } </script>
上传之后可以看到如下结果:
从这个例子里可以看到,已经可以成功的拿到时长的数据了,但是在真实的项目中如果每次都需要在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
获取文件类型
拿文件类型相对来说比较简单,但是遵循万物皆可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; } }
获取尺寸
video.onloadedmetadata = () => { window.URL.revokeObjectURL(this.video.src); let height = video.videoHeight let width = video.videoWidth }