ea7是什么意思 ea7是什么意思網絡用語( 三 )


解決這個問題的 *** 就是流媒體 , 其帶給我們最直觀體驗就是使媒體文件可以邊下邊播(像我這樣的90后男性最早體會到流媒體好處的應該是源于那款快子頭的播放器),web端如果要使用流媒體,有多個流媒體協議可以供我們選擇 。
HLS和MPEG DASH
HLS (HTTP Live Streaming), 是由 Apple 公司實現的基于 HTTP 的媒體流傳輸協議 。HLS以ts為傳輸格式,m3u8為索引文件(文件中包含了所要用到的ts文件名稱,時長等信息,可以用播放器播放,也可以用vscode之類的編輯器打開查看),在移動端大部分瀏覽器都支持,也就是說你可以用video標簽直接加載一個m3u8文件播放視頻或者直播,但是在pc端,除了蘋果的Safari,需要引入庫來支持 。
用到此方案的視頻網站比如優酷,可以在視頻播放時通過調試查看Network里的xhr請求,會發現一個m3u8文件,和每隔一段時間請求幾個ts文件 。


但是除了HLS,還有Adobe的HDS , 微軟的MSS,方案一多就要有個標準點的東西,于是就有了MPEG DASH 。
DASH(Dynamic Adaptive Streaming over HTTP) ,是一種在互聯網上傳送動態碼率的Video Streaming技術 , 類似于蘋果的HLS,DASH會通過media presentation description (MPD)將視頻內容切片成一個很短的文件片段 , 每個切片都有多個不同的碼率,DASH Client可以根據 *** 的情況選擇一個碼率進行播放,支持在不同碼率之間無縫切換 。
Youtube,B站都是用的這個方案 。這個方案索引文件通常是mpd文件(類似HLS的m3u8文件功能),傳輸格式推薦的是fmp4(Fragmented MP4),文件擴展名通常為.m4s或直接用.mp4 。所以用調試查看b站視頻播放時的 *** 請求,會發現每隔一段時間有幾個m4s文件請求 。

不管是HLS還是DASH們 , 都有對應的庫甚至是高級的播放器方便我們使用,但我們其實是想要學習一點實現 。其實拋開掉索引文件的解析拿到實際媒體文件的傳輸地址,擺在我們面前的只有一個如何將多個視頻數據合并讓video標簽可以無縫播放 。
與之相關的一篇B站文章推薦給感興趣的朋友:我們為什么使用DASH
MediaSource
video標簽src指向一個視頻地址,視頻播完了再將src修改為下一段的視頻地址然后播放,這顯然不符合我們無縫播放的要求 。其實有了我們前面Blob URL的學習,我們可能就會想到一個思路,用Blob URL指向一個視頻二進制數據,然后不斷將下一段視頻的二進制數據添加拼接進去 。這樣就可以在不影響播放的情況下,不斷的更新視頻內容并播放下去,想想是不是有點流的意思出來了 。
要實現這個功能我們要通過MediaSource來實現,MediaSource接口功能也很純粹,作為一個媒體數據容器可以和HTMLMediaElement進行綁定 。基本流程就是通過URL.createObjectURL創建容器的BLob URL,設置到video標簽的src上 , 在播放過程中 , 我們仍然可以通過MediaSource.appendBuffer *** 往容器里添加數據 , 達到更新視頻內容的目的 。
實現代碼如下:
const video = document.querySelector('video');//視頻資源存放路徑 , 假設下面有5個分段視頻 video1.mp4 ~ video5.mp4,之一個段為初始化視頻init.mp4const assetURL = "http://www.demo.com";//視頻格式和編碼信息 , 主要為判斷瀏覽器是否支持視頻格式,但如果信息和視頻不符可能會報錯const mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'; if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) { const mediaSource = new MediaSource(); video.src = http://www.fzline.cn/sh/URL.createObjectURL(mediaSource); //將video與MediaSource綁定,此處生成一個Blob URL mediaSource.addEventListener('sourceopen', sourceOpen); //可以理解為容器打開} else { //瀏覽器不支持該視頻格式 console.error('Unsupported MIME type or codec: ', mimeCodec);}function sourceOpen () { const mediaSource = this; const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec); let i = 1; function getNextVideo(url) { //ajax代碼實現翻看上文,數據請求類型為arraybuffer ajax(url, function(buf) { //往容器中添加請求到的數據,不會影響當下的視頻播放 。sourceBuffer.appendBuffer(buf); }); } //每次appendBuffer數據更新完之后就會觸發 sourceBuffer.addEventListener("updateend", function() { if (i === 1) { //之一個初始化視頻加載完就開始播放 video.play(); } if (i < 6) { //一段視頻加載完成后,請求下一段視頻 getNextVideo(`${assetURL}/video${i}.mp4`); } if (i === 6) { //全部視頻片段加載完關閉容器 mediaSource.endOfStream(); URL.revokeObjectURL(video.src); //Blob URL已經使用并加載 , 不需要再次使用的話可以釋放掉 。} i++; }); //加載初始視頻 getNextVideo(`${assetURL}/init.mp4`);};這段代碼修改自MDN的MediaSource詞條中的示例代碼 , 原例子中只有加載一段視頻,我修改為了多段視頻,代碼里面很多地方還可以優化精簡,這里沒做就當是為了方便我們看邏輯 。

推薦閱讀