zoukankan      html  css  js  c++  java
  • js获取视频编码格式信息

    遇到问题

    在开发中,测试反馈了一个问题,就是在前端上传视频后,视频无法回显,显示黑屏。
    于是我要来了测试上传的视频,看了下后缀名是.mp4, 用vlc打开播放正常,于是我开始了爬坑之旅。

    查找原因

    因为后缀名和播放都是正常的,先考虑是不是视频编码格式问题。
    首先查看MDN文档,查看html支持的视频格式,了解到支持的视频后缀有如下: mp4, webm, ogg,那我们的mp4的视频类型应该没有问题的。
    那就开始看看视频编码格式问题,查看视频编码的方法我们就用vlc打开视频:

    可以看到,显示的codec是mp4v:

    为了验证是不是编码格式的问题,用录屏软件和手机分别拍摄了一些视频做了测试,测试结果如下:

    视频格式 视频编码信息(VLC) 网页能否正常播放
    ev录制mp4 H264-MPEG-4 AVC(part10 avc1) 正常
    ev录制avi MPEG-4 Video(FMP4) 异常
    ev录制flv Flash-Video (FLV1) 异常
    ev录制wmv MS-MPEG-4-Video v3(MP43) 异常
    qq桌面端录制 MPEG-4 Video(MP4V) 异常
    qq手机端录制 H264-MPEG-4 AVC(part10 avc1) 正常
    tim录制 H264-MPEG-4 AVC(part10 avc1) 正常
    微信录制 H264-MPEG-4 AVC(part10 avc1) 正常

    根据上述结果可以看到,编码格式(codec)和文件类型(type,后缀名)会导致视频无法正常播放。

    备注:
    ev是windows下的一款录屏软件,测试提供的视频就是用qq桌面端功能录制的视频。

    解决问题

    目前前端操作,获取文件类型倒是比较简单,一般传输图片、文本等等都是根据file.type和file.name来判断是否允许上传。

    但是我们这里只获取name和type也无法判断,我们上传的视频能否正常播放了。我找了很久的之后,发现了github上大神的写的一个框架 mp4box.js 可以帮助我们解决这个问题。

    mp4box

    1. 安装

    npm i mp4box -S

    1. 导入

    import MP4Box from 'mp4box'

    1. 校验代码
    async videoBeforeUpload(file) {
        const isVideo = file.type === 'video/mp4' || file.type === 'video/ogg' || file.type === 'video/webm';
        const isLt30M = file.size / 1024 / 1024 < 30;
        if (!isVideo) {
            this.$message.warning('请上传正确格式的视频!');
            return Promise.reject()
        } else {
            if (!isLt30M) {
                 this.$message.warning('上传视频文件大小不能超过 30MB!');
                 return Promise.reject()
            }
        }
    
           // 正确的视频后缀会有mime信息
        let result = await this.checkVideoCode(file)
        let valid = this.getCodecValid(result.mime)
        if (!valid) {
            this.$message.error('请上传正确的视频编码格式')
            return Promise.reject()
        }
    },
    
    async checkVideoCode(file) {
        return new Promise((resolve, reject) => {
            const mp4boxFile = MP4Box.createFile();
            const reader = new FileReader();
            reader.readAsArrayBuffer(file);
            reader.onload = function (e) {
                const arrayBuffer = e.target.result;
                arrayBuffer.fileStart = 0;
                mp4boxFile.appendBuffer(arrayBuffer);
            };
            mp4boxFile.onReady = function (info) {
                resolve(info)
            };
            mp4boxFile.onError = function (info) {
                reject(info)
            };
        })
    },
    
    getCodecValid(str) {
        let arr = str.split(';')
        return !!(arr[1].includes('mp4a') || arr[1].includes('avc1'));
    },
    
    

    因为我是用了elementUI框架的组件,所以返回的值都是promise类型,大家自行修改为return false 就行了。因为判断codec 我感觉比较复杂(我懒),所以我用了和类型判断和getCodecValid 简单的判断了一下编码格式。
    通过这两种方式,我们可以获取到不能播放的视频格式了。接下来的处理大家各取所需,可以让用户继续传,但是没办法观看,让后端转码。或者直接拦截,不让用户传。或者提示,你传了可以,网页观看不了,自己下载下来观看。

    其他框架

    在发现和解决问题的过程中,我发现了几个不错的视频组件和转码框架。

    1. bilibili的flv格式视频播放解决方案:flv.js
    2. 视频播放组件:Mui Player
    3. 常用的视频处理库:video.js

    补充测试视频codec信息

    视频格式 视频编码信息(VLC) codec信息(MP4BOX) 网页能否正常播放
    ev录制mp4 H264-MPEG-4 AVC(part10 avc1) video/mp4; codecs="avc1.42c028"; profiles="isom,iso2,avc1,mp41" 正常
    ev录制avi MPEG-4 Video(FMP4) null 异常
    ev录制flv Flash-Video (FLV1) null 异常
    ev录制wmv MS-MPEG-4-Video v3(MP43) null 异常
    qq桌面端录制 MPEG-4 Video(MP4V) application/mp4; codecs="mp4v"; profiles="isom,iso2,mp41" 异常
    qq手机端录制 H264-MPEG-4 AVC(part10 avc1) video/mp4; codecs="avc1.640020,mp4a.40.2"; profiles="isom,iso2,avc1,mp41" 正常
    tim录制 H264-MPEG-4 AVC(part10 avc1) video/mp4; codecs="avc1.64001f,mp4a.40.2"; profiles="isom,iso2,avc1,mp41" 正常
    微信录制 H264-MPEG-4 AVC(part10 avc1) video/mp4; codecs="mp4a.40.2,avc1.64001f"; profiles="mp42,isom" 正常

    参考

    1. 使用 JS 获取视频 Codec
    2. MDN上关于video的基础使用
    3. MDN上视频内容和音频
    4. MDN上HTML的媒体支持:audio和video元素
    有疑问或者问题,请留言,本人常在回复比较及时。
    作者:Cirry
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    mysql用户密码修改
    Java List java.lang.UnsupportedOperationException
    python __dict__
    pytest.fixture
    Python __metaclass__ 解释
    Python __new__()方法,为对象分配内存 返回对象的引用
    git 常用操作
    boto3 dynamodb 一些简单操作
    conda, pip, virtualenv 区别
    list去重后不改变排序
  • 原文地址:https://www.cnblogs.com/cirry/p/14866813.html
Copyright © 2011-2022 走看看