實時流(直播流)播放、上牆(大屏播放)解決方案

周見智發表於2018-03-28

場景描述

將實時流採集終端的視訊資料實時推送到另外一個(多個)播放終端,完成遠距離實時視訊播放的功能。典型場景:

(1)遠端檢視監控攝像頭。選擇指定攝像頭,將該攝像頭採集到的實時資料推送到指定播放終端,供值班(監控中心)人員檢視。包括實時視訊上牆,推送到指定大螢幕上;

(2)直播系統。使用者在PC上安裝推流工具,抓取螢幕(麥克風)實時資料,推送給觀看直播的觀眾。

 

解決方案

要完成端到端的流推送,我們需要藉助中介軟體來完成,常用到的有Nginx Rtmp模組,用來中轉視訊資料。實時流採集終端根據給定的地址將資料推送到Nginx流媒體伺服器,播放終端根據給定的地址從Nginx流媒體伺服器上拉取資料,呈現給使用者。

實時流播放結構圖

如果多個使用者需要播放同一個實時流資料,那麼理想情況下,推流端的資料應該可以複用,也就是說,推流端只需要推一路流,供多個播放終端使用。此時推流端和播放端是一對N的關係

多個使用者播放同一個實時流資料

如果播放使用者很多,推流端和播放端數量大,只靠一臺流媒體伺服器轉發資料肯定不行。這時候需要多臺流媒體伺服器協同工作,當有多個流媒體伺服器時,就會出現一個問題:當使用者請求實時流,該如何為它分配流媒體伺服器呢?此時,就會引入另外一個概念:負載均衡。當有多臺流媒體伺服器時,我們需要通過某種策略去計算,得出最適合的流媒體伺服器,比如找出當前負載量最小的伺服器,給使用者使用。

多個流媒體伺服器

如上圖,存在多個流媒體伺服器時,負載均衡需要根據指定的策略計算出最佳的伺服器地址,然後推流端和播放端根據地址分別推流拉流。圖中由計算得出,使用流媒體伺服器1

 

 

實現技術

用到的技術、工具:

(1)CentOS 6.5 + Tomacat 8.0 + Mysql + Spring,java web後臺,接收使用者請求、負載計算、流狀態同步、傳送推流指令等等;

(2)ffmpeg,推流工具,供C++呼叫;

(3)RabbitMQ,web後臺與推流端傳遞訊息;

(4)Nginx 1.12.0 + rtmp module,具體可以檢視官方第三方module list, 流媒體轉發;

(5)VLC C#開發工具,用來拉流,網上有公開API呼叫方法,用來做客戶端demo,後面的截圖都是基於該demo;

(6)jwplayer,實際中web前端實時流播放控制元件。

 

詳細實現

(1)關於Nginx+rtmp模組實現實時流轉發的內容這裡就不再寫了,網上很多教程,也非常簡單,不需要手寫任何程式碼;

(2)Java web後臺採用SpringMVC + Mybatis,只需要實現一些http介面即可;

這裡詳細說一下負載計算這塊的邏輯,該模組與web後臺分開,可以單獨部署。

該模組屬於java 後臺的一部分,當然也可以分開部署,它與web後臺是通過資料庫中的請求表同步資料。接下來是負載均衡中生成rtmp的邏輯,rtmp也就是本文開頭提到的推流\拉流地址了。

推流端和拉流端可以通過給定的rtmp進行推拉流,Nginx流媒體伺服器(具體應該是rtmp模組)在收到推流開始(publish_start)、推流結束(publish_done)、拉流開始(play_start)以及拉流結束(play_done)時,都會按照配置檔案中的配置進行http回撥,該回撥地址配置成java 負載均衡後臺。我們需要在該回撥中更新流媒體伺服器的狀態,比如流媒體伺服器的當前負載數,用於下次負載計算。

 

有時候http回撥會失敗,這就會導致負載均衡模組中儲存的流媒體伺服器的狀態有誤差,所以我們需要主動同步流媒體伺服器的負載狀態:

 

負載計算的另一個非常重要的標準就是檢查流媒體伺服器是否線上,如果不線上,那麼這臺流媒體伺服器就不在我們考慮的範圍之內。主動檢查流媒體伺服器狀態:

 

Demo演示

由於各種原因,這裡只能掛一些demo的圖片:

Demo1

在百度地圖中按區域查詢攝像頭,選擇攝像頭,檢視攝像頭實時視訊資料。流程為:請求視訊->負載計算rtmp->推流開始->拉流開始。百度地圖控制元件請參照之前開源的程式碼:https://github.com/sherlockchou86/BMap.NET

 

Demo2

選擇攝像頭,將攝像頭實時流推到大屏上。流程為:請求大屏上牆(攜帶大屏ID)->計算rtmp->推流開始->拉流開始。下圖為大屏模擬管理器:

 

當大屏就緒後,開始播放,管理器狀態更新:

大屏模擬器介面,支援斷線恢復。關閉終端後,再次開啟,流推送不會中斷:

方案總結

(1)推流端和拉流端是1->N的關係,對於每一路推流,可以同時存在多個拉流端,即推流可以複用。當多個使用者請求同一資源(如同一攝像頭)時,只需要推一路流即可,這時候每個使用者的拉流地址rtmp相同。

(2)推流和拉流之間需要流媒體伺服器作為橋樑,負責實時流的轉發工作。這裡使用的時Nginx+rtmp module,網上有詳細教程。

(3)流媒體伺服器的選擇需要經過負載均衡計算得出,負載計算的策略包含:流媒體伺服器是否線上、負載數(當前播放鏈路)是否達到伺服器的上限、請求的資源是否已被推流(即可以複用,這種情況下,直接返回之前的rtmp即可,不需要重新分配伺服器)。

(4)Nginx+rtmp模組的配置檔案中,有一項是配置‘狀態回撥’的地址,當流媒體伺服器的狀態發生變化時,會通過該回撥告知java 後臺。

 

沒有原始碼提供,有問題的朋友可以留言或者私信。

 

相關文章