跳到主要内容

MP4Box 借用HTML5 file api 本地读取 mp4 头信息

· 阅读需 5 分钟
一介布衣
全栈开发者 / 技术写作者
  • 文章目录
  • 最近遇到一个需求

  • 给 file 控件的change 事件绑定函数:

  • 运行页面我们看下效果

  • 上传一个mp4 看看

  • 上一篇博文介绍了 html5 file api

html5 提供了一套可以操作本地文件的 api ,但是有一定的局限性

必须由用户发起一个事件,所以你不要妄想着用户浏览器加载某个站点时,主动去读取他本地硬盘的资料....不可能的.

你的浏览器必须支持 html5 的 file api ,所以你也不要妄想去兼容IE6

用户发起行为比如: file upload 操作, 文件拖拽 等.

最近遇到一个需求

  • 1.本地上传视频要保存到七牛服务器
    2.提交切割视频任务 (大文件切割成多份)
    3.返回视频截图 (按视频长短截取图片,供管理员审核视频内容)

    • 七牛这边提供的有 js-sdk 和 node.js 2种调用方法

我们的处理过程是, 浏览器发起上传事件 --> 请求自己服务器api 获取 token --> 拿到 token 调用 七牛 js-sdk 上传视频到七牛服务器

七牛根据 token ,解析出任务列表,完成任务后 调用 我们服务器的 api 返回任务数据 (截图,切割,视频压缩转码 url 等)

这里需要注意:
浏览器上传文件到七牛时 所带的 token,里面包含了所有一切一切需要七牛做的任务....

当然,你也可以先上传文件到七牛,然后接口去请求七牛api 执行各种各样的 任务也是可以的.
但是,我们希望浏览器上传时,只请求七牛一次,同时把任务都定制好,告诉七牛,剩下的工作就是,坐等七牛回调 api 传过来 任务数据.

但是我们有一个任务是根据视频时长去截图,返回截图供管理员审核
那么问题来了

如何在浏览器上传视频文件时,就知道视频的播放时长呢????

  • 这就是今天和大家分享的内容

浏览器通过 html5 file api 读取 mp4 头信息,获取视频播放长度.

用的的开源包 MP4Box
github地址: https://github.com/gpac/mp4box.js/

MP4Box 及支持服务器,也支持浏览器直接调用,今天的内容只包括 浏览器调用 MP4Box.js 本地读取 mp4 头信息.获取时长

首先下载 MP4Box.js 然后页面引用

然后定义一个 file 控件

定义一个 滚动条效果

0%

再来一个信息输入显示的地方

给 file 控件的change 事件绑定函数:

<script>

var mp4box;

var progressbar;
var progresslabel;
var fileinput;

var chunkSize = 1024 * 1024; // bytes

function dragenter(e) {
e.stopPropagation();
e.preventDefault();
}

function drop(e) {
var file;

if (!e) {
file = document.getElementById('fileinput').files[0];
}
else {
file = e.dataTransfer.files[0];
}
if (file) {
parseFile(file);
}
}

function initialize() {
mp4box = new MP4Box(false);
}

function parseFile(file) {
var fileSize = file.size;
var offset = 0;
var self = this; // we need a reference to the current object
var readBlock = null;
var startDate = new Date();

initialize();

mp4box.onError = function (e) {
console.log("mp4box failed to parse data.");
};

var onparsedbuffer = function (mp4box, buffer) {
console.log("Appending buffer with offset " + offset);
buffer.fileStart = offset;
mp4box.appendBuffer(buffer);
}

var onBlockRead = function (evt) {
if (evt.target.error == null) {
onparsedbuffer(mp4box, evt.target.result); // callback for handling read chunk
offset += evt.target.result.byteLength;
progressbar.progressbar({value: Math.ceil(100 * offset / fileSize)});
} else {
console.log("Read error: " + evt.target.error);
return;
}
if (offset >= fileSize) {
progressbar.progressbar({value: 100});
console.log("Done reading file (" + fileSize + " bytes) in " + (new Date() - startDate) + " ms");
mp4box.flush();
finalizeUI();
return;
}

readBlock(offset, chunkSize, file);
}

readBlock = function (_offset, length, _file) {
var r = new FileReader();
var blob = _file.slice(_offset, length + _offset);
r.onload = onBlockRead;
r.readAsArrayBuffer(blob);
}

readBlock(offset, chunkSize, file);
}

function finalizeUI() {
var content = '';
if (!mp4box || !mp4box.moovStartSent) {
content += 'mp4 : 否<br/>';
} else {
var info = mp4box.getInfo();
var videoLength = 0;

content += 'mp4 : 是<br/>';
content += '创建时间:' + info.created + '<br/>';
content += '视频时长:' + info.duration + ' 毫秒<br/>';

if (info.tracks && info.tracks.length > 0) {
info.tracks.forEach(function (item) {
if (item.size){
videoLength += parseInt(item.size);
}
if(item.video){
content+='分辨率:'+item.video.height+ 'X'+ item.video.width+' <br/>';
}
});

content += '视频大小:' + videoLength / (1000 * 1000) + ' M <p style="color:white;"> }
}

$('#content').html('').html(content);

}

window.onload = function () {
progressbar = $('#progressbar');
progresslabel = $('#progress-label');
fileinput = $('#fileinput');

progressbar.progressbar({
value: 0,
change: function () {
progresslabel.text(
progressbar.progressbar("value") + "%");
},
complete: function () {
progresslabel.text("Loading Completed!");
}
});
fileinput.button();

}
</script>

运行页面我们看下效果

上传一个mp4 看看

大功告成,本地读取视频头信息成功.
对于mp4 的头信息,不一定放在头部,有时也会出现在尾部.如果你愿意用 file api 自己分析视频文件,找到头信息所在位置,然后解析出来也是可以的.
只是费时费力, MP4Box.js 帮我们做了很多繁杂的工作,调用 getInfo 方法准备获得视频头信息.