前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基于MSE实现web前端视频预加载

基于MSE实现web前端视频预加载

原创
作者头像
iceman要早睡
发布2019-01-08 19:55:45
4.6K0
发布2019-01-08 19:55:45
举报
文章被收录于专栏:web前端音视频web前端音视频

在MSE标准提出前,js无法处理buffer级别的视频资源,video标签本身的一些限制导致业务方很难对视频流进行过多干涉处理,今天我们主要来聊一下如果通过MSE,容器软编解码等技术来实现mp4文件“真正”意义上的预加载,预处理。

一.背景

刷过抖音的同学应该都熟悉抖音的UI交互方式,上下滑动可以随时切换视频。这种设计对于普通用户而言,可以很快切走自己不感兴趣的,更快刷到自己感兴趣的视频。于开发和产品同学而言,通过统计用户在特定视频的停留时长,点赞评论等行为,可以进一步优化推荐算法和运营策略。

BUT,上下滑动的交互方式就意味着要进行资源预加载(在浏览当前视频的时候,已经在加载邻下临近的几个其它视频资源),类似于我们的图片瀑布流加载模式,图片预加载我们常用的方式为:

var img =new Image();

img.onload =function(){

? ? ? ? //加载完成回调

}

img.src='xxx';

通常我们会用上面的方式封装一个img loader模块用来实现图片预加载

但是对于视频资源这种预加载方式也可行吗???

很显然不行。

video标签本身也有关于预下载的属性preload,但是大多数浏览器对它其实支持非常差,这个属性并没有起到我们想要的效果。

二.现行方案及其缺陷

方案1:

将多段视频拼接成一个视频,借助video对象的currentTime调整播放点位置来达到多个视频播放时候无缓存的假象,单其实只有一个视频。

方案2:

创建多个video标签,对于暂时不播放的video先调用play()再调用pause(),然后等真正需要播放它的时候再次调用play()达到类似先激活的状态。

------------------------------------------------------------------------------------------------------------

上述方案在解决一个页面只有2个或者3-5个视频的场景时候勉强可用,但也都存在缺陷,并不适合抖音,微视这样的业务场景。

三.基于MSE及软编解码的新方案

首先,我们改变对 mp4 视频的播放流程,不再直接使用 video 的 src 来播放,因为我们没有任何可以操作的空间。video不仅支持 src 属性还支持 Blob 对象,我们就是利用后者。播放的流程如下:

流程图
流程图

对于MSE,想了解更多的同学可以去https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API,查阅,当然网上也有很多资料

简单来说MSE它允许JS脚本动态构建媒体流,允许JS传送媒体块到H5媒体元素。这种接口的应用可以让h5播放器实现持续添加数据进行播放,从而摆脱传统只依赖video的src属性的方式。

video.src = window.URL.createObjectURL(this.mediaSource);

结合URL.createObjectURL及MSE一系列API,我们可以将加载好的视频流buffer注入video进行播放,

MSE在其中扮演了buffer流的管理及桥接工作,因为MSE支持的是fmp4格式,所以对于mp4文件我们需要在加载队列之后进行一个容器层级的软编解码。关于容器格式与视频编解码的区别可参考https://yanhaijing.com/html/2016/03/12/html5-video/

综上所述,实现流程如下:

1. 编写加载器loader,请求 mp4 视频数据。 2. 编写解析器将 mp4 视频数据进行解复用,流处理等?。 3. 将解复用的视频数据转成 fmp4 格式并传递给 MediaSource。 4. 通过createObjectURL将MediaSource与?video 进行关联,完成播放。

流级别处理包含:多段mp4流合并,剔除/替换mp4流音轨,字幕,裁剪视频长度,清除无用视频流buffer等。

模块设计图:

体验demo:

http://sqimg.qq.com/qq_product_operations/test/mse.html

(安卓手Q webview(x5),安卓微信 webview(x5),chrome都支持)

ios手Q,ios微信的webview, safari暂时不支持

demo的实现代码如下

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
	<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,viewport-fit=cover"/>
	<meta name="apple-mobile-web-app-capable" content="yes">
	<meta name="apple-mobile-web-app-status-bar-style" content="black">
	<meta name="apple-itunes-app" content="app-id=444934666">
	<meta name="format-detection" content="telephone=no">
    <title></title>
    <style type="text/css">
    	/*手QH5页面通用css基础样式*/
    	html,body, div, p, ol, ul, li, table, tbody, tr, td, textarea,
        form, input, h1, h2, h3, h4, h5, dl, dt, dd, img, iframe, header, nav,
        section, article, footer, figure, figcaption, menu, a, p,button {padding: 0;margin: 0; -webkit-user-select: none; -moz-user-select: none; -webkit-text-size-adjust: none;-webkit-touch-callout: none;}
        html ,body{ width: 100%; height: 100%;}
        body { font-size: 62.5%; font: 16px "Helvetica Neue", Helvetica, STHeiTi, "\5FAE\8F6F\96C5\9ED1", sans-serif; min-width: 320px; margin: 0 auto;}
        em{ font-style: normal;}
        a, span { text-decoration: none;display: inline-block;}
        a:link, a:visited{ color: #fff; text-decoration:none;}
        a,button{outline: none; -webkit-tap-highlight-color:rgba(0,0,0,0);}
        button{border:none; background: transparent;}
        li {list-style: none;}
        /*业务侧css样式*/
    </style>	  
</head>
<body>
    <video id="j-video" x-webkit-airplay="true" webkit-playsinline="true" preload="auto" style="width:100%;margin-top:50px;"></video>
    <div id="pros0" style="width:100%;margin-top:30px;">视频加载进度:</div>
    <button id="btn" onclick="play()" style="margin-top:20px;font-size:24px;color:blueviolet;">点我播放</button>
    <div id="noTips"></div>
    <!--业务js脚步区域-->
    <script src="http://sqimg.qq.com/qq_product_operations/test/mp4box.all.js"></script>
    <script type="text/javascript">

            

            var video = document.getElementById('j-video');
            var sourceBufferArr =[];
            var assetURL = 'http://sqimg.qq.com/qq_product_operations/test/mov_bbb.mp4';



            //http加载模块
            function fetchAB(url, cb) {
                var xhr = new XMLHttpRequest;
                xhr.open('get', url);
                xhr.responseType = 'arraybuffer';
                xhr.onprogress = function (event) {
                    if (event.lengthComputable) {
                        var loaded = parseInt(event.loaded / event.total * 100) + "%";
                        document.getElementById('pros0').innerText = 'demo视频加载进度:'+loaded;
                    }
                }
                xhr.onload = function () {
                    cb(xhr.response);
                };
                xhr.send();
            };


            //buffer解析模块
            function dealBuffer(url){
                var mp4box = new MP4Box();
                mp4box.onReady = function (info) {
                    console.log(info)
                    //mediaSource.duration = Math.floor(info.duration / 1000);

                    for (var i = 0; i < info.tracks.length; i++) {
                        var track = info.tracks[i];
                        var mime = 'video/mp4; codecs=\"' + track.codec + '\"';
                        console.log(mime)

                        if (MediaSource.isTypeSupported(mime) && track.type=='video') {
                            try{
                                var sb = mediaSource.addSourceBuffer(mime);
                                sourceBufferArr.push(sb)
                                mp4box.setSegmentOptions(track.id, sb, { nbSamples: 4000 });
                            }catch(e){
                                document.getElementById('pros0').style.display = 'none';
                                document.getElementById('btn').style.display = 'none';
                                document.getElementById('noTips').innerText = '不支持MSE';
                            }
                        }
                    }

                    var initSegs = mp4box.initializeSegmentation();
                    var pendingInits = 0;
                    for (var i = 0; i < initSegs.length; i++) {
                        var sb = initSegs[i].user;
                        sb.addEventListener("updateend", function (e) {
                            pendingInits--;
                            if (pendingInits === 0) {
                                mp4box.start();
                            }
                        });
                        sb.appendBuffer(initSegs[i].buffer);
                        pendingInits++;
                    }

                }
                var b=null;
                mp4box.onSegment = function (id, sb, buffer, sampleNum) {   //生成一个片都会触发一次
                    console.log(sb+'>>>'+id+'>>>'+sampleNum);
                    sb.appendBuffer(buffer);
                }
                fetchAB(url, function (buffer) {
                    buffer.fileStart = 0
                    mp4box.appendBuffer(buffer)
                    mp4box.flush();
                });
            }

            //关联MSE到video
            if(window.MediaSource){
                window.mediaSource = new MediaSource();
                video.src = window.URL.createObjectURL(mediaSource); 
                dealBuffer(assetURL);
            }else{
                document.getElementById('pros0').style.display = 'none';
                document.getElementById('btn').style.display ='none';
                document.getElementById('noTips').innerText='不支持MSE';
            }

            function play(){
                video.currentTime =0;
                video.play();
            }
	</script>
</body>
</html>

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.背景
  • 二.现行方案及其缺陷
  • 三.基于MSE及软编解码的新方案
  • 模块设计图:
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com