纯前端获取视频第一帧、大小、尺寸、类型等

wangyuanqi

需求背景

最近有个视频上传的需求,需要对上传上传到OSS的视频做一些限制,并且在上传之前判断,视频的大小、尺寸、比例、时长等等。心里一直想着OSS能直接把视频的相关信息返回;毕竟图片是有很多信息返回的;
然而经过确认之后,发现屁都没有……
那就只能自己写了,百度了一下,并没有特别全的方案,那就自己动手写个吧。

视频加载基本介绍

在视频/音频(audio/video)加载过程中,事件的触发顺序如下:

  1. onloadstart (浏览器开始寻找指定资源)
  2. ondurationchange (视频/音频 的时长发生变化时触发)
  3. onloadedmetadata (指定视频/音频 的元数据加载后触发)
  4. onloadeddata (当前帧的数据加载完成且还没有足够的数据播放)
  5. onprogress (下载指定的视频/音频 时触发)
  6. oncanplay (用户可以开始播放视频/音频 时触发)
  7. 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

OSS视频截帧文档,戳这里~

参考文章

获取文件类型

拿文件类型相对来说比较简单,但是遵循万物皆可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;
    }
  }

获取尺寸

先展示部分伪代码,完整的代码可以戳下面的完整代码链接;
revokeObjectURL介绍

  video.onloadedmetadata = () => {
    window.URL.revokeObjectURL(this.video.src);
    let height = video.videoHeight
    let width = video.videoWidth
  }

最后奉上完整的代码 ==> CalcVideo.js

阅读 7.3k

大前端

123 声望
2 粉丝
0 条评论
你知道吗?

大前端

123 声望
2 粉丝
宣传栏