純前端獲取視頻第一幀、大小、尺寸、類型等
最近有個視頻上傳的需求,需要對上傳上傳到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 + '\n';
}
}
</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
}
