1. 程式人生 > >HTML5 視訊直播(三)

HTML5 視訊直播(三)

提醒:本文最後更新於 1349 天前,文中所描述的資訊可能已發生改變,請謹慎使用。

連續寫了兩篇有關視訊直播的文章之後,有同學問我為什麼沒有 WebRTC 相關內容。實際上一開始我就說過,我的需求是在移動 WEB 端上直播視訊,而移動端瀏覽器現階段對「WebRTC 的支援度」非常不樂觀,所以我就直接無視它了。但我一時為了標題美觀,活生生地把「移動 WEB 端」寫成了「HTML5」,所以為了嚴謹我還是補上這一篇吧。

WebRTC(Web Real-Time Communication),中文一般翻譯為「Web 實時通訊」。它由一組標準、協議和 JavaScript API 組成,用於實現端到端的音視訊及資料共享。與其他瀏覽器通訊機制不同,WebRTC 通過 UDP 傳輸資料,而我們早已熟知的 XMLHttpRequest、WebSocket 都基於 TCP。

縱觀整個瀏覽器市場,其實只有 Google 和 Mozilla 兩家公司對 WebRTC 比較上心,Firefox 22 和 Chrome 23 就開始就支援了它;Microsoft 是搞了自己的一套標準,後續可能會跟 WebRTC 融合,但至少 IE 不會支援現階段的 WebRTC 標準;Apple 也許是因為有 FaceTime 可以很好地實現 Apple 裝置間的多媒體通訊,壓根就沒打算在 Safari 中增加對 WebRTC 的支援;至於 Opera,換核心後基本等同於 Chrome,這下更要被人無視了。

初識 WebRTC

WebRTC 涉及到很多複雜技術,不過好在瀏覽器已經把大多數複雜工作抽象成為下面三個 API:

  • MediaStream:獲取音訊和視訊流;
  • RTCPeerConnection:音訊和視訊資料通訊;
  • RTCDataChannel:任意應用資料通訊;

MediaStream 對應的是 JS 裡的 navigator.getUserMedia() 方法,它負責從底層平臺獲取音視訊流。音視訊流經過 WebRTC 音視訊引擎的自動優化、編碼和解碼,就可以直接用或傳輸到各種目的地用。這裡有個 Demo,就是用 getUserMedia 獲取視訊流,再把每一幀都轉成 ASCII 字元播放。總之 MediaStream API 設計得很簡單,使用起來也很方便。

RTCPeerConnection

用來建立和維護端到端連線,並提供高效的音視訊流傳輸。整個 WebRTC 提供的 API 中,要數這個最複雜:

首先,要建立端到端連線,不可避免要解決 NAT 穿透問題,RTCPeerConnection 為此引入了 ICE(Interactive Connectivity Establishment)框架。ICE 致力於在端之間建立一條有效的通道,優先直連,其次用 STUN 協商,再不行只能用 TURN 轉發。

STUN(Session Traversal Utilities for NAT)協議,解決了三個問題:1)獲得外網 IP 和埠;2)在 NAT 中建立路由條目,繫結外網埠,使得到達外網 IP 和埠的入站分組能找到應用程式,不被丟棄;3)定義了一個簡單的 keep-alive 機制,保證 NAT 路由條目不會因為超時而被刪除。STUN 伺服器必須架設在公網上,可以自己搭建,也可以使用第三方提供的公開服務,例如 Google 的「stun:stun.l.google.com:19302」。

TURN(Traversal Using Relays around NAT)協議,依賴外網中繼裝置在兩端之間傳遞資料。簡單說就是通過兩端都可以訪問的 TURN 服務轉發訊息,間接把兩端連起來。TURN 還會嘗試使用 TCP 建立,而不僅僅是 UDP,可靠性大大增強,頻寬成本也隨著大幅提升。根據 Google 的統計,UDP 服務中,有 8% 左右的情況下需要 TURN。

其次,要建立端到端的通道,還是需要藉助服務端來交換和協商一些資訊,這個過程被稱之為 Signaling。WebRTC 並沒有規則 Signaling 必須使用某種協議,而把選擇權交給了應用程式。我們可以選用不同方式(XMLHttpRequest、WebSocket),採用已有的 SIP、Jingle、ISUP 等發信協議,來建立通道。

通常,在 WebRTC 應用中,建立通道這一步都是優先走 WebSocket,並支援降級為 HTTP。一來支援 WebRTC 的瀏覽器肯定都支援 WebSocket;二來 WebSocket 實時性更好一些。特別需要注意的是,WebSocket 只用來輔助建立端到端連線,一旦連線建立,信源在端到端之間的傳輸就完全不需要服務端了(當然 TURN 這種中繼模式就另當別論)。

RTCDataChannel 用來支援端到端的任意應用資料交換。建立 RTCPeerConnection 連線之後,除了可以傳輸音視訊流,還可以開啟一個或多個通道用來傳輸任何文字或二進位制內容,這就是 RTCDataChanel。DataChannel API 在使用上跟 WebSocket 非常類似,功能上都可以用來在端到端之間傳輸資料,但是本質上他們還是有區別的:

首先,WebRTC 端與端之間是對等的,DataChannel 可以由任何一方發起;這與 WebSocket 連線只能由客戶端發起不同; 其次,WebSocket 的會話層協議 TLS 是可選的;而 WebRTC 的會話層協議 DTLS 是必須的,這表明通過 WebRTC 傳輸的資料一定會被加密; 再者,WebSocket 執行在 TCP 之上,每條訊息天然有序並可靠;而 DataChannel 可以通過 SCTP 的交付屬性選項來指定訊息是有序還是亂序,是可靠還是部分可靠,部分可靠時還可以指定使用超時重傳還是計數重傳策略。

現階段 DataChannel 執行在下列協議之上:

  • SCTP(Stream Control Transmission Protocol),流控制傳輸協議,提供了一些與 TCP 類似的特性;
  • DTLS(Datagram Transport Layer Security),傳輸內容加密,UDP 版的 TLS;
  • UDP(User Datagram Protocol),使用者資料報協議,整個 WebRTC 的基礎;

這裡我並不打算完整地介紹如何從零開始使用 WebRTC,類似的文章網上大把。這裡推薦幾篇文章,後幾篇中文的出自同一個作者,寫得比較通俗易懂:

另外還推薦《Web 效能權威指南》這本書,它的第 3 章「UDP 的構成」和第 18 章「WebRTC」對 UDP 內網穿透和 WebRTC 有比較詳細的介紹。

一對多直播

前面說過,WebRTC 是用來解決端到端的實時通訊問題,也就是說它很適合用在網路電話這種需要雙向視訊通話的場景上。網上大部分 WebRTC 的 Demo 也都是在頁面上放兩個 Video,分別來播 localStream 和 RemoteStream。那麼究竟 WebRTC 能否用來實現單向一對多直播呢?當然可以,而且貌似還很簡單:

  • 首先必須有一個專門負責呼叫 getUserMedia 採集音視訊的頁面,我稱之為信源服務;
  • 開啟直播頁面時,建立到信源服務的 PeerConnection,並通過 DataChannel 通知信源服務;
  • 信源服務收到通知後,通過對應 PeerConnection 的 addStream 方法提供直播流;
  • 直播頁面監聽 PeerConnection 的 onaddstream 事件,將獲得的直播流用丟給 Video 播放;

為了方便,我使用了 PeerJS 這個開源專案來驗證上面這個過程。PeerJS 對 WebRTC Api 進行了封裝,使用更簡單。它還提供了用來輔助建立連線的 Signaling 服務,在官網註冊一個 Api Key 就能用。也可以通過 PeerJS Server 搭建自己的服務,只需要通過 npm install peer 裝好 peer 後,再通過下面這行命令啟動就可以了:

peerjs --port 9000 --key peerjs

啟動好 Peer Server,在頁面中引入 peer.js 就可以開始玩了。首先實現信源服務:

//由於其它端都要連它,指定一個固定的 ID
var peer = new Peer('Server', {
    host: 'qgy18.qgy18.com', 
    port: 9003, 
    path: '/',
    config: {
        'iceServers': [
              { url: 'stun:stun.l.google.com:19302' }
        ]
    }
});

navigator.getUserMedia({ audio: false, video: true }, function(stream) {
    window.stream = stream;
}, function() { /*...*/ });

peer.on('connection', function(conn) {
    conn.on('data', function(clientId){
        var call = peer.call(clientId, window.stream);

        call.on('close', function() { /*...*/ });
    });
});

然後就是直播服務:

//隨機生成一個 ID
var clientId = (+new Date).toString(36) + '_' + (Math.random().toString()).split('.')[1];

var peer = new Peer(clientId, {
    host: 'qgy18.qgy18.com', 
    port: 9003, 
    path: '/',
    config: {
        'iceServers': [
              { url: 'stun:stun.l.google.com:19302' }
        ]
    }
});

var conn = peer.connect('Server');

conn.on('open', function() {
    conn.send(clientId);
});

peer.on('call', function(call) {
    call.answer();
    call.on('stream', function(remoteStream) {
        var video = document.getElementById('video');
        video.src = window.URL.createObjectURL(remoteStream);
    });

    call.on('close', function() { /*...*/ });
});

直播頁面通過指定 ID 的方式跟信源服務建立端到端連線,然後通過 DataChannel 告訴信源服務自己的 ID,信源服務收到訊息後,主動把直播流發過來,直播頁面應答後播放就可以了。整個過程原理就這麼簡單,這裡有一個「完整的 Demo」。

看完上面的 Demo,你也許會想原來使用 WebRTC 直播這麼簡單,隨便找臺帶攝像頭的電腦,開個瀏覽器就能提供直播服務,那還搞 HLS、RTMP 什麼的幹嘛。

實際上,現實並沒有那麼美好,這個 Demo 也就玩玩兒還可以,真正使用起來問題還大著呢!

首先,雖然說在 WebRTC 直播方案中,服務端只扮演橋樑的工作,實際資料傳輸直接發生在端到端之間,但前面說過仍然會有 8% 的情況完全不能直連。要保證服務的高可用性,還是得考慮部署 TURN 這種複雜而昂貴的中轉服務。

其次,Chrome 對每個 Tab 允許連線的終端數有限制,最多 256 個。實際上,在我最新的 Retina Macbook Pro 上,差不多有 10 個連線時,Chrome 就開始變得無比卡,風扇呼呼地轉,記憶體被吃掉 6G,CPU 一直跑滿,網路吞吐開始忙不過來,直播服務也開始變得極其不穩定。

所以實際使用方案中,一般還是需要 Media Server 的支援,把「端到多端」變成「端到 Media Server 到多端」的架構。Media Server 可以有更好的效能和頻寬,可以自己實現 WebRTC 協議,也就有了支援更多使用者的可能。

我找到一個名為 Janus 的 WebRTC Gateway,這個開源專案用 C 語言實現了對 WebRTC 的支援。Janus 自身實現得很簡單,提供外掛機制來支援不同的業務邏輯,配合官方自帶外掛就可以用來實現高效的 Media Server 服務。

Janus 官方提供的 Demo 在這裡,我也嘗試在我的 VPS 上部署了一套。Janus 有個 Streaming 外掛,可以接受 GStreamer 推送的音視訊流,然後通過 PeerConnection 推送給所有的使用者。由於 GStreamer 可以直接讀攝像頭,也就不用再走 WebRTC 的 MediaStream 獲取視訊,這樣架構就變成了傳統的伺服器到端了。整個過程比較複雜和曲折,這裡不寫了,有興趣的同學可以單獨找我討論。

--EOF--

提醒:本文最後更新於 1349 天前,文中所描述的資訊可能已發生改變,請謹慎使用。

相關推薦

HTML5 視訊直播

提醒:本文最後更新於 1349 天前,文中所描述的資訊可能已發生改變,請謹慎使用。 連續寫了兩篇有關視訊直播的文章之後,有同學問我為什麼沒有 WebRTC 相關內容。實際上一開始我就說過,我的需求是在移動 WEB 端上直播視訊,而移動端瀏覽器現階段對「WebRTC 的支援度」非常不樂觀,所以我就

HTML5 視訊直播

提醒:本文最後更新於 776 天前,文中所描述的資訊可能已發生改變,請謹慎使用。 前不久工作中遇到了在移動 WEB 端直播視訊的需求,研究了一下相關技術,記錄一下。 目前 WEB 上主流的視訊直播方案有 HLS 和 RTMP,移動 WEB 端目前就只有 HLS 能用,我們重點介紹它。 upda

HTML5 視訊直播

提醒:本文最後更新於 1355 天前,文中所描述的資訊可能已發生改變,請謹慎使用。 上篇部落格中,我介紹了目前移動端唯一可行的 HTML5 直播方案:HLS。實際上,HLS 除了上回提到過的延遲很大這個缺點之外,在 iOS 的 Safari 瀏覽器中還只能全屏播放,也無法做到自動播放,這個是 i

HTML5的學習HTML5標籤

3.HTML5新新增的標籤 標籤 描述 <article> 定義文章。 <aside> 定義頁面內容之外的內容。 <audio&g

即時通訊音視訊開發視訊編解碼之編碼基礎

前言 即時通訊應用中的實時音視訊技術,幾乎是IM開發中的最後一道高牆。原因在於:實時音視訊技術 = 音視訊處理技術 + 網路傳輸技術 的橫向技術應用集合體,而公共網際網路不是為了實時通訊設計的。 系列文章 《即時通訊音視訊開發(一):視訊編解碼之理論概述》 《即時通訊音視訊

web前端基礎教學視訊分享bootstrap基礎教學

【寫在前面】 清酒一盞,花前月下 拄杖忙學輕聲碼,誰怕,一行程式碼任天明。 夜起燈落,願伴你尋夢! 【分享與你】 bootstrap教學視訊分享,我不會說這是年輕時候我花5塊錢網上買的 連結:https://pan.baidu.com/s/1RlKn6kZ_ty4wA9pp8g7NhQ

HTML5學習筆記canvas畫布基礎

、基本內容       Canvas在HTML頁面提供畫布的功能, 在畫布中繪製各種圖形       Canvas繪製的圖形與HTML頁面無關,無法通過DOM獲取繪製的圖形,也無法為繪製的圖形繫結DOM事件,只能使用Canvas提供的API 二、Canvas用途      

從Android原生角度看移動html5開發APP之上拉載入

在mui框架中上拉載入其實很簡單了,框架已經幫助我們基本實現了。 mui的上拉載入和下拉重新整理類似,都屬於pullRefresh外掛,使用過程如下: 1、頁面滾動到底,顯示“正在載入...”提示(mui框架提供) 2、執行載入業務資料邏輯(開發者提供) 3、載入完畢,隱藏

基於深度學習的視訊檢測 目標跟蹤

搭建環境 基於 darkflow (yolo-v2)和 sort/deep_sort 實現目標檢測與追蹤 安裝依賴 #sort $sudo pip install numba $sudo pip install matplotlib $

Linux下實現視訊讀取---Buffer的準備和資料讀取

前面主要介紹的是:V4L2 的一些設定介面,如亮度,飽和度,曝光時間,幀數,增益,白平衡等。今天看看V4L2 得到資料的幾個關鍵ioctl,Buffer的申請和資料的抓取。 1. 初始化 Memory Mapping 或 User Pointer I/O. int ioct

視訊直播知識點

基於上篇文章說到影響直播效能指標的因素,下面來講講如何解決優化(理論篇)。 一、低端裝置如何上高效能地採集和編碼? 攝像頭採集輸出的是圖片,一張圖的體積並不會小,如果採集的頻次很高,編碼的幀率很高,每張圖都經過編碼器,那麼編碼器又可能會出現過載。 這個時候,可以考慮

基於Html5 Plus + Vue + Mui 移動App開發-文件操作讀取、保存、更新數據

mes das parse 移動 分享 gif ont 包括 ole   實全資訊采用基於Html5 Plus + Vue + Mui 移動App。主要實現功能包括: 實現搜索站點設置 實現搜索關鍵字定義 實現搜索資訊保存、刪除功能。 主界面實現關鍵字搜

基於html5 plus + Mui 移動App開發-食全庫

  食全庫-食品安全知識庫。   食品安全(food safety)指食品無毒、無害,符合應當有的營養要求,對人體健康不造成任何急性、亞急性或者慢性危害。根據倍諾食品安全定義,食品安全是“食物中有毒、有害物質對人體健康影響的公共衛生問題”。食品安全也是一門專門探討在食品加工、儲存、銷售等過程中確保食品衛生及

【移動開發】關於一對一視訊交友直播延遲優化

6 月底釋出了一個針對視訊直播的實時流網路 LiveNet 和完整的直播雲解決方案,很多開發者對這個網路和解決方案的細節和使用場景非常感興趣。 結合實時流網路 LiveNet 和直播雲解決方案的實踐,我們用一系列文章,更系統化地介紹當下大熱的視訊直播各環節的關鍵技術,幫助視訊直播創業者們更全面、深入地瞭解視

HTML5學習筆記視訊與音訊處理

一、<video>  1、<video>是H5的新標籤,用來處理視訊,在此之前,各網站用來處理視訊一直使用flash技術     flash的缺點有以下幾方面,首先原生瀏覽器原生不支援,需要外掛,其次過多的使用會導致網站效能變差,最後就是

【Android 進階】仿抖音系列之列表播放視訊

在上一篇【Android 進階】仿抖音系列之列表播放視訊(二)中,我們實現列表播放視訊,這一篇我們來對其做些優化。 【Android 進階】仿抖音系列之翻頁上下滑切換視訊(一) 【Android 進階】仿抖音系列之列表播放視訊(二) 【Android 進階】仿抖音

HTML5 and CSS 入門

1.Nest Many Elements within a Single Div Element div元素,也被稱作division(層)元素,是一個盛裝其他元素的通用容器。 所以可以利用CSS的繼承關係把div上的CSS傳遞給它所有子元素。 你可以用<div>來標

Android錄製小視訊

      之前的文章講到半屏錄製小視訊,不過微信不已經全屏了麼,我們的專案也要與時俱進不是。在仿微信全屏錄製的過程中,有兩點需要注意的地方:      1.camera的預覽大小設定  

資料庫視訊——總結篇

** 前言 從接觸到學習資料庫也有一段時間了,不同階段對資料庫的認識和理解也是不一樣的。對於較早知道的知識,通過看資料庫視訊更加深入的理解了;對於現在剛知道的知識,通過看資料庫視訊拓寬了瞭解的知識面。本篇博文僅對資料庫中涉及到的知識點進行總結

python資料採集練習 根據指定av號下載bilibili視訊【用selenium操縱瀏覽器行為】

selenium庫可以控制瀏覽器行為。我們用selenium庫可以抓取我們所需的網頁全部資訊。 注意:要選擇與你瀏覽器相相容版本的驅動配合使用 關於selenium詳細教程這裡不累述,本程式使用的是Chrome瀏覽器,並且中會用到如下幾個函式: from sel