当前位置: 首页 > Web前端 > HTML5

视频播放新探索

时间:2023-04-05 14:04:44 HTML5

前端同学想要使用HTML5播放视频,必须要用到video标签,但是大部分同学只会用到比较简单的功能,其实它有不凡的力量等着我们去发现。首先我们来看视频最基本的用法:使用src属性你的浏览器不支持视频标签。使用source标签你的浏览器没有支持video元素。这是MDN给出的关于视频的基本用例。下面我们简单介绍一下这两种方式的区别。src只能给video一个播放地址。当浏览器不支持该视频格式的解码时,会出现错误,导致视频播放失败。为了解决这个问题,使用了source标签。多个source标签用来介绍不同格式的视频,从上到下依次解析,直到遇到上面的代码。当浏览器不支持ogg格式时,浏览器会自动播放foo.mp4。实用技巧我们会发现,在使用video:src属性播放视频时,经常会出现播放失败的情况。我们可以做些什么来提高视频播放的质量?这种情况一般使用CDN。为了更加安全,不同的CDN厂商一般分为主CDN和备份CDN。那么问题来了,我们如何利用视频本身的特点,结合CDN来保证我们视频播放的质量呢?<视频控件>你的浏览器不支持video元素。不难看出source标签不仅支持不同视频格式的自动切换,同样适用于切换失败video格式,即main.mp4是网络问题无法获取时浏览器会自动切换成backup.mp4。进阶技巧如果你浏览视频,你会发现很多网站的视频都是这样的:>如果直接访问blob的地址,发现不存在。该地址是映射Blob对象的DOMString。其实video属性src是支持Blob的,只是新标准用srcObject属性代替了这个功能。目前的代码可以这样写:constmediaSource=newMediaSource();const视频=文档。createElement('video');try{video.srcObject=mediaSource;}catch(error){video.src=URL.createObjectURL(mediaSource);}在这段代码中,除了Blob对象,还有一个MediaSource对象,让视频具有非凡威力的主要因素是浏览器对MediaSource对象的支持,这让JavaScript有更大的空间来操作视频。关于如何使用MediaSource本文不做介绍,大家可以自行查看,我们想说的是视频结合MediaSource可以做什么?清晰度无缝切换在VOD领域,mp4是最常见、兼容性最好的视频容器,但是mp4也有它的局限性,比如常见的清晰度切换,我们无法像youtube那样实现无缝切换。我们可以看看普通mp4播放的网络请求和youtube视频播放的网络请求的区别。图1.1普通mp4的下载请求流程图1.2Youtube视频的下载请求流程从这两张图不难看出,mp4默认使用http一次请求所有视频数据,而Youtube是多次请求。当然,这种描述很不专业,但确实很形象。造成这种差异的原因是video不支持流式视频数据,Youtube使用的是流式视频容器webm,而mp4是非流式的。如何清楚地解释流式视频数据?从专业的角度,很难三言两语说清楚,但是翻译成大白话,流式视频数据支持分段独立播放,非流式视频数据则不能。也就是说,对于一个10M的视频文件,流式视频可以请求0~1M的数据单独播放,非流式视频则不能。上面我们已经描述了视频格式的区别,接下来要说的是第一张图片中的视频加载是由浏览器控制的。通过为视频的src属性配置视频地址,触发播放后浏览器开始下载。JS不能干涉。Youtube的视频加载由JS控制。大家可以再看看第二张图的网络请求类型:xhr,足以证明这一点。弄清了以上两点之后,就要说说分辨率切换了。这个需求大家都很熟悉,但是直接使用mp4格式进行无缝分辨率切换还是比较困难的。先解释一下“无缝分辨率切换”的概念:从播放一种分辨率的视频到另一种分辨率的流畅切换过程,画面和声音都不会停止。理解了这个概念,大家应该知道mp4和视频无缝切换是多么的困难了。一方面,视频不支持流式视频格式,另一方面,视频的加载不受JS控制。通过切换视频的src属性,必然会导致画面中断,重新请求视频数据等。有同学想过用两个视频结合z-index来做,但是当你生成另一个视频加载视频的时候,并不能保证两张图片严格一致,即使原图停顿片刻,使用另一个视频通过currentTime属性与其同步,切换还是看到画面闪烁,基本无法与Youtube的无缝切换体验相抗衡。而且会造成更多的流量浪费。后面的原因可以研究一下mp4容器和webm容器的异同点,也可以看看视频解码相关的文章。另一种方法是将所有的mp4格式转码为hls、webm等流媒体视频格式。但是这种看似可行的方法实际上会带来很大的成本开销,比如转码大量的视频会消耗很高的机器资源,双存储成本,CDN成本的两倍等等。事实上,我们也研究了新的技术问题来解决这种背景下清晰度的无缝切换。首先,我们改变了mp4视频的播放流程,不再直接使用视频的src来播放,因为我们没有操作的余地。Video不仅支持src属性还支持Blob对象,我们使用的是后者。播放流程如下:图1.3新的mp4视频播放流程请求mp4视频数据,可以结合videoRange服务实现精准加载。编写解析器对加载的部分mp4视频数据进行解复用,将解复用后的视频数据转为fmp4格式传给MediaSource使用视频解码完成播放,然后清晰度切换流程如下:图1.4mp4示意图视频分辨率切换请求mp4视频数据原理图,可以结合videoRange服务实现精准加载。编写解析器对加载的部分mp4视频数据进行解复用,将解复用后的视频数据转为fmp4格式传给MediaSource使用视频解码完成播放,然后清晰度切换流程如下:图1.5mp4视频分辨率切换过程示意图这个过程看似繁琐,但是所有的操作都是在浏览器端完成的,也就是说都是JS实现的。这样一来,之前提到的所有成本问题都不存在,并且可以实现youtube相同体验的无缝切换。如果你也想使用这个功能,不需要再执行上面的过程,可以使用如下代码:importPlayerfrom'xgplayer';import'xgplayer-mp4';letplayer=newPlayer({el:document.querySelector('#mse'),url:[{src:'/mp4/',type:"video/mp4"},{src:'/mp5/',type:'video/mp4'}]});player.emit('resourceReady',[{name:'HD',url:'/mp4/',cname:'HD'},{name:'UltraHD',url:'/mp5/',cname:'超高清'}]);如果你对这段代码有任何疑惑,或者想详细了解它背后是如何实现的,可以参考文档或者Github。为了节省视频流量,我们通常使用video直接加载视频,大致是这样的:图2.1视频默认下载截图我随便找了一个视频,请看视频总时长是02:08,播放的时候到00:05,浏览器一直下载到01:30,如果用户停止观看,下载的视频将被浪费。当然,不断的seek也会造成更多的流量浪费。根据我们之前的统计,在短视频领域,用户搜索的频率是80%,所以这部分流量是可以省下来的。具体原理如下:图2.2播放器加载视频原理设置每次加载数据包的大小设置预加载时间开启加载队列,完成第一个数据包下载,判断是否缓冲时间和预加载时间满足,不满足则请求下一个数据包的具体实现代码如下:importPlayerfrom'xgplayer';导入“xgplayer-mp4”;constplayer=newPlayer({id:'vs',url:'//abc.com/a/mp4',preloadTime:10});这样,视频播放时始终只预加载10秒的数据,从而保证了流量的节省。所有代码均来自带解析器的西瓜播放器,可以节省流量,Github