• 首页
  • html5
  • MP4Box 借用HTML5 file api 本地读取 mp4 头信息

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

html5.jpg

上一篇博文介绍了 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 控件 <input type='file' id='fileinput' onchange='drop()'>

定义一个 滚动条效果

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;">出自:<a style="color:white;" href="http://yijiebuyi.com/blog/a5cd9f53202cf1dbb10cf53e4726fca8.html" >MP4Box 借用HTML5 file api 本地读取 mp4 头信息</a></p><br/>';
               }
           }

           $('#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>
   

运行页面我们看下效果

upload.png

上传一个mp4 看看

boke.png

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



回到顶部