上传文件时如何获取视频长度
上传时如何获取视频长度
思路
首先,获取视频长度,我们通过浏览器自带的API就可以获取,如下:
<!-- html -->
<video src="xxx.mp4"></video>
<!-- JS -->
const oVideo = document.getElementById('video');
oVideo.duration; // 此属性就可以拿到时间
此时可以发现,src中只能填入路径,但是上传文件我们只有文件,所以问题就集中在如何拿到路径
-
思路一:通常预览图片的时候,我们会将文件转成
base64
然后赋值给src
,那么此时视频是不是可以同理呢.. -
思路二:
URL.createObjectURL()
此方法能创建一个临时的URL,和此窗口的生命周期绑定,刚好符合
MDN解释
静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。
注意URL.revokeObjectURL() 方法来释放
- 思路三:既然拿到了file 对象,能不能直接从中获取信息
从file对象的属性中来看 没有此类信息, 那么如何来解决呢?
分析mp4
文件,总所周知,计算机上所有的文件都是以2进制的形式存在,各种不同类型的文件都是有不同的规则来组织起来的,本质都是0和1,那么以mp4
为例,在文件的二进制中,肯定有对于时长的描述,借助JS中操作二进制数据的能力处理Uint8Array、DataView、ArrayBuffer
那么主要问题就是知道文件规范...
代码实现
- 方法一 (文件过大就会慢)
function change (e) {
const file = oFile.files[0];
let reader = new FileReader();
const oVideo = document.createElement('video');
const aBlob = new Blob([file],{type:'video/mp4'})
reader.onload = function(result) {
// console.log(reader.result);
oVideo.src = reader.result
}
reader.readAsDataURL(aBlob);
// oVideo.preload = 'metadata';
oVideo.onloadedmetadata = function (e) {
// 视频总长度,秒为单位
console.log('....', oVideo.duration);
}
// document.body.appendChild(oVideo);
}
- 方法二
const file = oFile.files[0];
const oVideo = document.createElement('video');
// oVideo.preload = 'metadata';
oVideo.onloadedmetadata = function (e) {
// 视频总长度,秒为单位
console.log( '....', oVideo.duration);
}
oVideo.src = URL.createObjectURL(file)
注意:preload="metadata"
> 提示尽管作者认为用户不需要查看该视频,不过抓取元数据(比如:长度)还是很合理的。
上述两种方式都是借用Video
元素提供的API和onloadedmetadata
事件实现
- 方法三
function change2 () {
const file = oFile.files[0];
console.log(file)
file.arrayBuffer().then(res => {
console.log(res)
const ui8 = new Uint8Array(res);
const view = new DataView(res)
console.log(ui8)
console.log(view)
analysis(view);
})
}
function analysis (view) {
// 下标
let idx = 0;
for(; idx < view.byteLength ;) {
boxHeader = analysisHeaderBox(view, idx);
console.log(boxHeader, '...')
// 找到moov 处理
if (boxHeader.type === 'moov') {
// 跳过头
const son = view.buffer.slice(idx + 8, view.byteLength);
analysis(new DataView(son));
}
if (boxHeader.type === 'mvhd') {
// 跳过头
const son = view.buffer.slice(idx + 8, boxHeader.size);
analysisMvhdBox(new DataView(son));
}
// 偏移
idx += boxHeader.size;
}
}
// box header 中的 size 和 type
function analysisHeaderBox (view, offset) {
const size = view.getUint32(offset);
offset += 4;
let type = analysisBoxType(
view.getUint8(offset),
view.getUint8(offset + 1),
view.getUint8(offset + 2),
view.getUint8(offset + 3)
);
return {
size,
type
};
}
// 根据码点获取字符串
function analysisBoxType () {
let str = '';
for(var i = 0; i < arguments.length; i++) {
str += String.fromCharCode(arguments[i]);
}
return str;
}
function analysisMvhdBox (view) {
console.log(view, '...')
const timescale = view.getUint32(12);
const duration = view.getUint32(16);
console.log(timescale, duration, duration/timescale, '...')
}
扩展
通过第三种方式,有以下好处
-
可解析不同的文件类型,可以获取文件内容中的信息
-
并且不依赖于
BOM
环境 即使在node
环境下也是能使用。 -
就算没有后缀或者后缀错误也可以判断出来文件是不是MAP4或其他类型
参考
参考:
https://blog.csdn.net/w5025/article/details/123097108
http://www.360doc.com/content/20/0902/20/49586_933661079.shtml