這篇文章主要介紹了關於html5中標籤video播放的新解析,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
前端同學要使用HTML5 播放器視頻,必然會使用video 標籤,不過大多數同學只是使用了較簡單的功能,其實它本身擁有不凡之力有待我們發現。
首先,我們先來看下video 最基礎的用法:
#使用src 屬性
<video> 你的浏览器不支持 <code>video</code> 标签。 </video>
使用source 標籤
<video> <source> <source> Your browser does not support the <code>video</code> element. </source></source></video>
這是MDN 關於video 給出的基本用例。這裡我們簡單介紹下兩種方法的不同,src 只能賦予 video 一個播放位址,當瀏覽器不支援這種影片格式的解碼時就會出現錯誤,導致影片播放失敗。為了解決這個問題才有了 source 標籤,利用多個 source 標籤引入不同格式的視頻,從上到下解析直到遇到看上述程式碼當瀏覽器不支援 ogg 格式時,瀏覽器會自動播放 foo.mp4。
我們會發現使用 video:src 屬性播放影片的時候會經常出現播放失敗,我們該怎麼做能提升影片播放的品質?
這種情況一般都使用 cdn,為了更保險一般還會將不同的 cdn 廠商分為主用 cdn 和備用 cdn。那麼問題來了,我們怎麼利用 video 本身的特性並結合 cdn 來保證我們的影片播放品質?
<video> <source> <source> Your browser does not support the <code>video</code> element. </source></source></video>
不難看出,source 標籤不僅支援不同視訊格式的自動切換,也適用於相同視訊格式的失敗切換,即main.mp4 因網路問題無法取得時瀏覽器會自動切換到backup. mp4 。
如果大家瀏覽影片的時候,可以發現很多網站的video 是這個樣子的:
<video> </video>
如果直接造訪blob 這個位址發現並不存在。
這個位址就是要映射Blob 物件的DOMString,其實video 屬性src 支援Blob 的,不過新的標準是使用srcObject 屬性來取代這一個功能,目前程式碼可以這樣寫:
const mediaSource = new MediaSource(); const video = document.createElement('video'); try { video.srcObject = mediaSource; } catch (error) { video.src = URL.createObjectURL(mediaSource); }
在這段程式碼中除了Blob 對象,還有MediaSource 對象,讓video 擁有不凡之力的主要因素是瀏覽器對MediaSource 對象的支持,才讓JavaScript 對video 有了更大的操縱空間。關於如何使用 MediaSource 不在本文講述,大家可以自行查閱,我們要說的是 video 結合 MediaSource 可以做哪些事情?
點播領域裡mp4 是最普遍、相容性最好的影片容器,不過mp4 也有它的局限性,例如常見的清晰度切換,我們是無法像youtube一樣做到無縫切換的。我們可以看下普通的mp4播放的網路請求和youtube影片播放的網路請求的區別。
圖1.1 普通mp4的下載請求流程
圖1.2 Youtube影片下載請求流程
這兩張圖不難看出,在預設情況下mp4 使用一次http 請求所有的視訊數據,Youtube 則分次請求。當然這個描述很不專業,但確實有形象。造成這種差異的是 video 不支援串流的視訊數據,Youtube 採用的是串流的視訊容器 webm,而 mp4 則是非串流式的。那要如何解釋清楚流式的視訊資料呢,從專業的角度三言兩語很難說清楚,但用大白話翻譯過來就是串流的視訊資料支援分段獨立播放,非串流的不可以。換句話說一個10M的影片文件,串流的影片可以把0~1M的資料請求回來單獨播放,但是非串流的不可以。
上面我們描述了影片格式的不同,接下來我們要說的是第一張圖中的影片載入是瀏覽器來控制的,透過給video 的src 屬性配置影片位址,觸發播放之後瀏覽器就會開始下載了,JS干涉不了。而 Youtube 的影片載入是透過JS來控制的,各位可以再次看下第二張圖的網路請求類型:xhr,足以證明這一點。
上面两点搞清楚之后我们就该说下清晰度切换的事情了。这个需求大家都不陌生,但是直接使用 mp4 格式做无缝清晰度切换,难度还挺大的。先解释下“无缝清晰度切换”的概念:从播放一个分辨率的视频到另一个分辨率且保证画面、声音不停顿的平滑切换过程。了解了这个概念,大家应该知道了用 video 无缝切换 mp4 有多难。一方面,video 是不支持流式的视频格式的,一方面,video 的加载是不受JS控制的。通过切换 video 的 src 属性,必然会导致画面中断、重新请求视频数据等。有的同学想到说利用两个 video 再结合 z-index 来搞,但是当你生成另一个video去加载视频的时候,无法保证两个画面是严格一致的,即使将原来的画面暂停到一个时刻,用另一个视频通过 currentTime 属性与之同步,切换仍然看到画面闪烁,基本无法和 Youtube 无缝切换的体验匹敌。而且还会造成更多流量的浪费,背后的原因大家可以研究下 mp4 容器和 webm 容器的异同,也可以看下视频解码相关的文章。
还有一种方法就是将 mp4 格式统统转码到流式的视频格式比如 hls、webm 等。不过这种看上去可行的方式实际上会带来很大的成本开销,如将大量视频做转码会消耗高昂的机器资源、双倍存储的费用、CDN的双倍费用等等。其实我们也是在这种背景下研究出来新的技术问题解决清晰度无缝切换的。
首先,我们改变对 mp4 视频的播放流程,不再直接使用 video 的 src 来播放,因为我们没有任何可以操作的空间。video不仅支持 src 属性还支持 Blob 对象,我们就是利用后者。播放的流程如下:
图1.3 mp4 视频新播放流程
来请求 mp4 视频数据,这样可以结合视频 Range 服务,做到精确加载。
编写解析器将加载回来的部分 mp4 视频数据进行解复用
将解复用的视频数据转成 fmp4 格式并传递给 MediaSource
使用 video 进行解码完成播放
然后在做清晰度切换的时候流程如下:
图1.4 mp4视频清晰度切换原理示意图
来请求 mp4 视频数据,这样可以结合视频 Range 服务,做到精确加载。
编写解析器将加载回来的部分 mp4 视频数据进行解复用
将解复用的视频数据转成 fmp4 格式并传递给 MediaSource
使用 video 进行解码完成播放
然后在做清晰度切换的时候流程如下:
图1.5 mp4视频清晰度切换流程示意图
这个过程看上去比较繁琐,但是所有的操作都是在浏览器端完成,也就是说都是JS来实现的。这样之前说的所有成本问题都不存在,还能做到youtube相同体验的无缝切换。如果大家也想使用这个功能不需要自己再去实现一遍上述流程,可以使用如下代码:
import Player from 'xgplayer'; import 'xgplayer-mp4'; let player = new Player({ el:document.querySelector('#mse'), url: [{src:'/mp4/',type:"video/mp4"},{src:'/mp5/',type:'video/mp4'}] }); player.emit('resourceReady', [{name: '高清', url: '/mp4/',cname:'高清'}, {name: '超清', url: '/mp5/',cname:'超清'}]);
如果对这段代码有什么疑惑或者想深入了解下它背后是如何实现的可以参考 文档 或者 Github。
我们平时直接使用video加载视频,大概是这样的:
图2.1 video默认下载截图
我随便找了个视频,大家看下视频总长度是 02:08,在播放到 00:05 的时候,浏览器已经下载到 01:30 了,如果用户终止观看,下载的视频就这样被浪费掉了。当然,如果不断的 seek 也会造成较多的流量浪费。按照我们之前的统计在短视频领域,用户 seek 的频率在 80%,所以这部分流量是可以节省掉的。具体原理如下:
图2.2 播放器加载视频原理
设置每次加载的数据包大小
设置预加载时长
开启加载队列,完成第一次数据包下载,判断缓冲时间和预加载时长是否满足,不满足请求下一个数据包
具体实现代码如下:
import Player from 'xgplayer'; import 'xgplayer-mp4'; const player = new Player({ id:'vs', url:'//abc.com/a/mp4', preloadTime:10 });
这样就实现了视频在播放过程中永远只预加载10秒的数据,进而保证节省流量。
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
以上是關於html5中標籤video播放的新解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!