【騰訊Bugly乾貨分享】從0到1打造直播 App

本文來自於騰訊bugly開發者社區,非經做者贊成,請勿轉載,原文地址:http://dev.qq.com/topic/5811d42e7fd6ec467453bf58javascript

做者:李智文html

概要

分享內容前端

互聯網內容載體變遷歷程,文字——圖片/聲音——視頻——VR/AR——…….。從直播1.0秀場時代(YY),2.0遊戲直播(鬥魚、虎牙、熊貓)到現在全民直播3.0泛生活娛樂時代(映客、花椒),國外直播app(Meerkat 、Periscope),隨着VA/AR/MR提出的沉浸式視聽體驗,直播4.0時代很快就能到來。java

在這個全民娛樂的時代,直播已經火得不要不要的,各大公司都有本身的直播產品。本文主要從直播的一些基本知識,一步步打造直播app。直播那麼火的背後有什麼樣的技術支撐呢?android

先將這些APP按照視頻網站按照視頻網站、彈幕視頻、直播平臺、在線秀場、移動短視頻、移動直播來劃分類別。再按照內容和社交這個維度來進行區分,能夠明顯看出視頻網站、彈幕網站和直播平臺更偏內容,他們對內容的需求更加高,用戶在上面進行社交沉澱相對比較淺。ios

然後面三者更加偏向社交,他們強調人而不強調內容。因此短時間內不會有大的競爭關係,只是前三類、後三者之間的競爭會出現。nginx

大致框架 基本是下圖這個套路:git

錄製->編碼->網絡傳輸->解碼->播放github

以上爲直播的總體流程,根據該流程分爲如下技術點:web

  1. 怎樣錄製直播視頻
  2. 怎樣實時上傳直播視頻
  3. 怎樣播放直播視頻
  4. 直播間的用戶是如何交互

1、移動視頻直播發展

PC直播(固定場所)——>移動端(形式自由)。

隨着愈來愈多的直播類 App 上線,移動直播進入了史無前例的爆發階段,目前大多數移動直播以 Native 客戶端爲主。可是H5端的直播在移動直播端也承載着不可替代的做用,例如 H5 有着傳播快,易發佈的優點。

完整的直播包括:

  1. 視頻錄製端 電腦上的音視頻輸入設備或者手機端的攝像頭或者麥克風,目前以移動端的手機視頻爲主。
  2. 視頻播放端 能夠是電腦上的播放器,手機端的 Native 播放器,還有 H5 的 video 標籤等。
  3. 流媒體服務器端 用來接受視頻錄製端提供的視頻源,同時提供給視頻播放端流服務。目前開源的流媒體有RED5,CRTMPD,NGINX-RTMP,SRS。

2、錄製視頻

如何生產視頻數據

封裝格式的主要做用是把視頻碼流和音頻碼流按照必定的格式存儲在一個文件中。

爲何要分封裝格式和視頻編碼格式呢? 這個其實跟網絡分七層模型一個原理。解耦和,下降依賴,底層給上層提供基礎功能,底層和上層都均可以單獨擴展,能夠以多種方案組合編碼與封裝,好比MP4與H26四、MP4與MPEG、TS與H264等等。好比這裏面的這邊文章的編碼就只負責將最原始的音頻和視頻數據就行壓縮,而壓縮完的數據要怎麼組織就拜託給上層的封裝,封裝接到視頻音頻數據負責給數據編號,指定同步協議,加入字幕等操做。通過封裝後,獲得的就是能夠播放的上面提到的視頻文件MP4或者MKV等等。把這個過程反過來就是上圖描述的視頻播放的過程。

一、流媒體源

  1. PC端的攝像頭、屏幕 對於PC端的流媒體源,可使用Open Broadcaster Software串流(支持多種直播平臺)。

  2. 移動端iOS、Android的攝像頭和麥克風。 iOS、Android主要是系統提供的API實現。

  3. webRTC (Web Real-Time Communication) webRTC是一個支持網頁瀏覽器進行實時語音對話或視頻對話的技術,能夠在網頁瀏覽器中進行採集、傳輸、播放,缺點是隻在 PC 的 Chrome 上支持較好,移動端支持不太理想。

使用 webRTC 錄製視頻基本流程是

  1. 調用window.navigator.webkitGetUserMedia() 獲取用戶的PC攝像頭視頻數據。
  2. 將獲取到視頻流數據轉換成 window.webkitRTCPeerConnection (一種視頻流數據格式)。
  3. 利用webscoket將視頻流數據傳輸到服務端

因爲許多方法都要加上瀏覽器前綴,因此不少移動端的瀏覽器還不支持 webRTC,因此真正的視頻錄製仍是要靠客戶端(iOS,Android)來實現,效果會好一些。

二、編碼

推薦Andorid4.3(API18)或以上使用硬編,如下版本使用軟編;iOS使用全硬編方案。

  1. 軟編碼: libffmpeg
  2. 硬編碼: MediaCodec(sdk level 16+, Android 4.1, 4.1.1, the JELLY_BEAN)

三、封裝

FLV(Flash Video)是Adobe公司設計開發的一種流行的流媒體格式,FLV可使用Flash Player進行播放,FLV封裝格式的文件後綴一般爲「.flv」。整體上看,FLV包括文件頭(File Header)和文件體(File Body)兩部分,其中文件體由一系列的Tag組成。

特色:視頻文件體積輕巧、封裝簡單

每一個Tag前面還包含了Previous Tag Size字段,表示前面一個Tag的大小。Tag的類型能夠是視頻、音頻和Script,每一個Tag只能包含以上三種類型的數據中的一種。圖2展現了FLV文件的詳細結構。

Tag Data

  1. Audio Tag

  2. Video Tag

  3. Script Tag(控制幀)或叫meta data tag 該類型Tag又一般被稱爲Metadata Tag,會放一些關於FLV視頻和音頻的元數據信息如:duration、width、height等。一般該類型Tag會跟在File Header後面做爲第一個Tag出現,並且只有一個。

如圖以Android爲例的推流的流程圖:

3、視頻推流(Stream)

如何推 往哪裏推

一、協議

國內常見公開的直播協議有幾個:RTMP、HDL(HTTP-FLV)、HLS、RTP。

RTMP

Real Time Messaging Protocol是 Macromedia 開發的一套視頻直播協議,如今屬於 Adobe。

使用RTMP技術的流媒體系統有一個很是明顯的特色:使用 Flash Player 做爲播放器客戶端,而Flash Player 如今已經安裝在了全世界將近99%的PC上,所以通常狀況下收看RTMP流媒體系統的視音頻是不須要安裝插件的。用戶只須要打開網頁,就能夠直接收看流媒體。

和 HLS 同樣均可以應用於視頻直播,區別是 RTMP 基於 flash 沒法在 iOS 的瀏覽器裏播放,可是實時性比 HLS 要好。因此通常使用這種協議來上傳視頻流,也就是視頻流推送到服務器。

rtmp如今大部分國外的CDN已不支持,在國內流行度很高。緣由有幾個方面:

  1. 開源軟件和開源庫的支持穩定完整。如鬥魚主播經常使用的OBS軟件,開源的librtmp庫,服務端有nginx-rtmp插件。
  2. 播放端安裝率高。只要瀏覽器支持FlashPlayer就能播放RTMP的直播。相對其餘協議而言,RTMP協議初次創建鏈接的時候握手過程過於複雜(RTMP協議自己的交互是基於TCP),視不一樣的網絡情況會帶來給首開帶來100ms以上的延遲。基於RTMP延遲在2~5秒。

HTTP-FLV

即便用HTTP協議流式的傳輸媒體內容,直接向後臺上傳編碼後的流媒體數據。相對於RTMP,HTTP更簡單和廣爲人知,並且不擔憂被Adobe的專利綁架。內容延遲一樣能夠作到2~5秒,打開速度更快,由於HTTP自己沒有複雜的狀態交互。因此從延遲角度來看,HTTP-FLV要優於RTMP。

SRS2.0支持該協議:GitHub

HLS

即Http Live Streaming,是由蘋果提出基於HTTP的流媒體傳輸協議。HLS有一個很是大的優勢:HTML5能夠直接打開播放;這個意味着能夠把一個直播連接經過微信等轉發分享,不須要安裝任何獨立的APP,有瀏覽器便可,因此流行度很高。社交直播APP,HLS能夠說是剛需 。

Issue:SRS3.0提出了一種加強型HLS+

RTP

Real-time Transport Protocol,用於Internet上針對多媒體數據流的一種傳輸層協議。

實際應用場景下常常須要RTCP(RTP Control Protocol)配合來使用,能夠簡單理解爲RTCP傳輸交互控制的信令,RTP傳輸實際的媒體數據。 RTP在視頻監控、視頻會議、IP電話上有普遍的應用,由於視頻會議、IP電話的一個重要的使用體驗:內容實時性強。

對比與上述3種或實際是2種協議,RTP和它們有一個重要的區別就是默認是使用UDP協議來傳輸數據,而RTMP和HTTP-FLV是基於TCP協議傳輸。

  • UDP:單個數據報,不用創建鏈接,簡單,不可靠,會丟包,會亂序;
  • TCP:流式,須要創建鏈接,複雜,可靠 ,有序。

實時音視頻流的場景不須要可靠保障,所以也不須要有重傳的機制,實時的看到圖像聲音,網絡抖動時丟了一些內容,畫面模糊和花屏,徹底不重要。TCP爲了重傳會形成延遲與不一樣步,如某一截內容由於重傳,致使1秒之後纔到,那麼整個對話就延遲了1秒,隨着網絡抖動,延遲還會增長成2秒、3秒,若是客戶端播放是不加以處理將嚴重影響直播的體驗。


是否有除了HLS外更低延遲的方案?

HLS的優勢點是顯而易見的:移動端無需安裝APP使用兼容HTML5的瀏覽器打開便可觀看,全部主流的移動端瀏覽器基本都支持HTML5,在直播的傳播和體驗上有巨大的優點。

下面是 HTTP-FLV、HLS 、 RTMP 的對比:

二、推流

所謂推流,就是將咱們已經編碼好的音視頻數據發往視頻流服務器中,經常使用的第三方庫 librtmp-iOS 進行推流,librtmp 封裝了一些核心的 API 供使用者調用。例如推流 API 等等,配置服務器地址,便可將轉碼後的視頻流推往服務器。通常的推流服務器都配置了服務器端信息。

推流SDK

百度雲推流SDK: 官方文檔 七牛推流SDK: Github上的官方源碼及說明 網易雲推流SDK:官方文檔 騰訊雲推流SDK:官方文檔 其餘推流SDK: https://github.com/daniulive/SmarterStreaming https://github.com/leixiaohua1020/simplest_ffmpeg_mobile https://github.com/begeekmyfriend/yasea https://github.com/simple-rtmp-server/srs-sea

推流服務器

那麼如何搭建一個推流服務器呢?

簡單的推流服務器搭建,服務器支持 RTMP ,大概須要如下幾個步驟:

  1. 安裝一臺 nginx 服務器。
  2. 安裝 nginx 的 RTMP 擴展,目前使用比較多的是 https://github.com/arut/nginx-rtmp-module
  3. 配置 nginx 的 conf 文件
  4. 重啓 nginx,將 RTMP 的推流地址寫爲 rtmp://ip:1935/hls/mystream, 其中 hls_path 表示生成的 .m3u8 和 ts 文件所存放的地址,hls_fragment 表示切片時長,mysteam 表示一個實例,即未來要生成的文件名能夠先本身隨便設置一個。 更多配置能夠參考:https://github.com/arut/nginx-rtmp-module/wiki/

下面是 nginx 的配置文件

騰訊雲直播

[後臺SDK]主要是調用騰訊雲API。

[服務器API]提供了直播控制檯api概覽:

  • 建立直播頻道 CreateLVBChannel
  • 查詢直播頻道列表 DescribeLVBChannelList
  • 查詢直播頻道詳情 DescribeLVBChannel
  • 修改直播頻道 ModifyLVBChannel
  • 批量啓用直播頻道 StartLVBChannel
  • 批量中止直播頻道 StopLVBChannel
  • 查詢直播頻道當前併發收看數 DescribeLVBOnlineUsers
  • 刪除直播頻道 DeleteLVBChannel
  • 建立錄製任務 CreateRecord
  • 終止錄製任務 StopRecord
  • 查詢已錄製分片列表 DescribeRecord
  • 建立截圖任務 CreateLVBShot
  • 終止截圖任務 StopLVBShot
  • 查看隊列消息 DescribeQueueLog

騰訊雲直播方案總體流程

方案根據騰訊雲的快速對接,最終造成閉環邏輯。

  • APP
    1. 視頻源推流
    2. 向後臺發起建立直播頻道請求
    3. 向後臺發起中止直播請求
  • 後臺
    1. 向騰訊雲發起建立、刪除(刪除前先關閉)直播頻道請求
    2. 直播頻道緩存隊列,處理殭屍頻道
    3. 向APP客戶端推送直播URL
  • Web
    1. PC端的流視頻播放器
    2. 移動客戶端的流視頻播放器

流程圖

  • Step1:建立頻道 客戶端發起直播請求,後臺調用CreateLVBChannel,由返回的channel_id調用DescribeLVBChannel查看頻道信息。 後臺向客戶端返回推流url和Web直播地址(非flv流視頻地址)。
  • Step2:SDK推流 推流SDK
  • Step3:刪除頻道 APP端推流結束,向後臺發送請求刪除頻道,只有關閉的頻道是能夠刪除的,因此後臺刪除一個頻道以前,要先經過中止直播頻道接口StopLVBChannel,先將頻道狀態置爲中止,以後在調用刪除直播頻道接口DeleteLVBChannel對頻道進行刪除。

4、播放直播視頻

如何看

下載直播視頻有如下方式:

  1. HLS
  2. rtmp
  3. flv

好看的指標參數 碼率:影響體積,與體積成正比:碼率越大,體積越大;碼率越小,體積越小。 幀率:影響畫面流暢度,與畫面流暢度成正比:幀率越大,畫面越流暢;幀率越小,畫面越有跳動感。若是碼率爲變量,則幀率也會影響體積,幀率越高,每秒鐘通過的畫面越多,須要的碼率也越高,體積也越大。 分辨率:影響圖像大小,與圖像大小成正比:分辨率越高,圖像越大;分辨率越低,圖像越小。

一、HLS

對於H5視頻播放,可使用 HLS(HTTP Live Streaming)協議播放直播流,iOS和 Android 都自然支持這種協議,配置簡單,直接使用 video 標籤便可。

使用 video在移動客戶端上播放直播視頻:

<video controls autoplay>
	<source src="xxx.m3u8" type="application/vnd.apple.mpegurl"/>
</video>

HTTP Live Streaming

HLS是一個由蘋果公司提出的基於HTTP的流媒體網絡傳輸協議。

HLS直播最大的不一樣在於,直播客戶端獲取到的,並非一個完整的數據流。

HLS協議在服務器端將直播數據流存儲爲連續的、很短時長的媒體文件(MPEG-TS格式),而客戶端則不斷的下載並播放這些小文件,由於服務器端老是會將最新的直播數據生成新的小文件,這樣客戶端只要不停的按順序播放從服務器獲取到的文件,就實現了直播。

因而可知,基本上能夠認爲,HLS是以點播的技術方式來實現直播。因爲數據經過HTTP協議傳輸,因此不用考慮防火牆或者代理的問題,並且分段文件的時長很短,客戶端能夠很快的選擇和切換碼率,以適應不一樣帶寬條件下的播放。不過HLS的這種技術特色決定了延遲通常老是會高於普通的流媒體直播協議。

每個 .m3u8 文件,分別對應若干個 ts 文件,這些 ts 文件纔是真正存放視頻的數據,m3u8 文件只是存放了一些 ts 文件的配置信息和相關路徑,當視頻播放時,.m3u8 是動態改變的,video 標籤會解析這個文件,並找到對應的 ts 文件來播放,因此通常爲了加快速度,.m3u8 放在 Web 服務器上,ts 文件放在 CDN 上。

支持的視頻流編碼爲H.264,音頻流編碼爲AAC。

簡單講就是把整個流分紅一個個小的,基於 HTTP 的文件來下載,每次只下載一些,前面提到了用於 H5 播放直播視頻時引入的一個 .m3u8 的文件,這個文件就是基於 HLS 協議,存放視頻流元數據的文件。

  • HLS的分段策略,基本上推薦是10秒一個分片,固然,具體時間還要根據分好後的分片的實際時長作標註
  • 爲了緩存等方面的緣由,在索引文件中會保留最新的三個分片地址,以「滑動窗口」的形式進行刷新。

.m3u8 文件,其實就是以 UTF-8 編碼的 m3u 文件,這個文件自己不能播放,只是存放了播放信息的文本文件。 打開以後就是這個樣子:

#EXTM3U                     m3u文件頭,必須放在第一行
#EXT-X-MEDIA-SEQUENCE       第一個TS分片的序列號
#EXT-X-TARGETDURATION       每一個分片TS的最大的時長
#EXT-X-ALLOW-CACHE          是否容許cache
#EXT-X-ENDLIST              m3u8文件結束符
#EXTINF                     extra info,分片TS的信息,如時長,帶寬等
#EXTM3U
#EXT-X-TARGETDURATION:11
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:10.133333,
fileSequence0.ts
#EXTINF:10.000666,
fileSequence1.ts
#EXTINF:10.667334,
fileSequence2.ts
#EXTINF:9.686001,
fileSequence3.ts
#EXTINF:9.768665,
fileSequence4.ts
#EXTINF:10.000000,
fileSequence5.ts
#EXT-X-ENDLIST

ts 文件,就是存放視頻的文件:

HLS只請求基本的HTTP報文,與實時傳輸協議(RTP)不一樣,HLS能夠穿過任何容許HTTP數據經過的防火牆或者代理服務器。它也很容易使用內容分發網絡來傳輸媒體流。

HLS 的請求播放流程

  1. HTTP 請求 m3u8 的 url。
  2. 服務端返回一個 m3u8 的播放列表,這個播放列表是實時更新的,通常一次給出5段數據的 url。
  3. 客戶端解析 m3u8 的播放列表,再按序請求每一段的 url,獲取 ts 數據流。

HLS直播延時

咱們知道 hls 協議是將直播流分紅一段一段的小段視頻去下載播放的,因此假設列表裏面的包含5個 ts 文件,每一個 TS 文件包含5秒的視頻內容,那麼總體的延遲就是25秒。由於當你看到這些視頻時,主播已經將視頻錄製好上傳上去了,因此時這樣產生的延遲。固然能夠縮短列表的長度和單個 ts 文件的大小來下降延遲,極致來講能夠縮減列表長度爲1,而且 ts 的時長爲1s,可是這樣會形成請求次數增長,增大服務器壓力,當網速慢時回形成更多的緩衝,因此蘋果官方推薦的 ts 時長時10s,因此這樣就會大改有30s的延遲。因此服務器接收流,轉碼,保存,切塊,再分發給客戶端,這裏就延時的根本緣由。

更多關於延遲的問題能夠參考蘋果官方地址: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html

HLS優點

可是 H5 直播視頻卻有一些不可替代的優點:

  1. 傳播性好,利於分享等操做。
  2. 能夠動態發佈,有利於實時迭代產品需求並迅速上線。
  3. 不用安裝 App,直接打開瀏覽器便可。

二、RTMP

RTMP協議是應用層協議,是要靠底層可靠的傳輸層協議(一般是TCP)來保證信息傳輸的可靠性的。在基於傳輸層協議的連接創建完成後,RTMP協議也要客戶端和服務器經過「握手」來創建基於傳輸層連接之上的NetConnection連接,在Connection連接上會傳輸一些控制信息,如SetChunkSize,SetACKWindowSize。其中CreateStream命令會建立一個NetStream連接,用於傳輸具體的音視頻數據和控制這些信息傳輸的命令信息。他們的關係如圖所示:

RTMP Message

RTMP協議傳輸時會對數據作本身的格式化,這種格式的消息咱們稱之爲RTMP Message,而實際傳輸的時候爲了更好地實現多路複用、分包和信息的公平性,發送端會把Message劃分爲帶有Message ID的Chunk,每一個Chunk多是一個單獨的Message,也多是Message的一部分,在接受端會根據chunk中包含的data的長度,message id和message的長度把chunk還原成完整的Message,從而實現信息的收發。

  1. Basic Header(基本的頭信息) chunk stream ID(流通道Id)和chunk type(chunk的類型,2位fmt),chunk stream id通常被簡寫爲CSID,用來惟一標識一個特定的流通道,chunk type決定了後面Message Header的格式。長度有一、2或3個字節
  2. Message Header(消息的頭信息) Message Header的格式和長度取決於Basic Header的chunk type,共有4種不一樣的格式,由上面所提到的Basic Header中的fmt字段控制。包含timestamp,timestamp delta,message length,message type id,msg stream id,和0(表示與上一個相同)。
    • timestamp(時間戳):佔用3個字節,所以它最多能表示到16777215=0xFFFFFF=2 24-1, 當它的值超過這個最大值時,這三個字節都置爲1,這樣實際的timestamp會轉存到Extended Timestamp字段中,接受端在判斷timestamp字段24個位都爲1時就會去Extended timestamp中解析實際的時間戳。
    • message length(消息數據的長度):佔用3個字節,表示實際發送的消息的數據如音頻幀、視頻幀等數據的長度,單位是字節。注意這裏是Message的長度,也就是chunk屬於的Message的總數據長度,而不是chunk自己Data的數據的長度。
    • message type id(消息的類型id):佔用1個字節,表示實際發送的數據的類型,如8表明音頻數據、9表明視頻數據。
    • msg stream id(消息的流id):佔用4個字節,表示該chunk所在的流的ID,和Basic Header的CSID同樣,它採用小端存儲的方式,
  3. Extended Timestamp(擴展時間戳) 4個字節,當擴展時間戳啓用時,timestamp字段或者timestamp delta要全置爲1,表示應該去擴展時間戳字段來提取真正的時間戳或者時間戳差。注意擴展時間戳存儲的是完整值,而不是減去時間戳或者時間戳差的值。
  4. Chunk Data(塊數據) 用戶層面上真正想要發送的與協議無關的數據,長度在(0,chunkSize]之間。

RTMP在收發數據的時候並非以Message爲單位的,而是把Message拆分紅Chunk發送,並且必須在一個Chunk發送完成以後才能開始發送下一個Chunk。每一個Chunk中帶有MessageID表明屬於哪一個Message,接受端也會按照這個id來將chunk組裝成Message。


舉個例子

chunk表示例1

首先包含第一個Message的chunk的Chunk Type爲0,由於它沒有前面可參考的chunk,timestamp爲1000。type爲0的header佔用11個字節,假定CSID爲3<127,所以Basic Header佔用1個字節,再加上Data的32個字節,所以第一個chunk共44=11+1+32個字節。

第二個chunk和第一個chunk的CSID,TypeId,Data的長度都相同,所以採用Chunk Type=2,timestamp delta=1020-1000=20,所以第二個chunk佔用36=3+1+32個字節。

第三個chunk和第二個chunk的CSID,TypeId,Data的長度和時間戳差都相同,所以採用Chunk Type=3省去所有Message Header的信息,佔用33=1+32個字節。

第四個chunk和第三個chunk狀況相同,也佔用33=1+32個字節。

最後實際發送的chunk以下:

chunk表示例2 注意到Data的Length=307>128,所以這個Message要切分紅幾個chunk發送,第一個chunk的Type=0,Timestamp=1000,承擔128個字節的Data,所以共佔用140=11+1+128個字節。

第二個chunk也要發送128個字節,其餘字段也同第一個chunk,所以採用Chunk Type=3,此時時間戳也爲1000,共佔用129=1+128個字節。

第三個chunk要發送的Data的長度爲307-128-128=51個字節,仍是採用Type=3,共佔用1+51=52個字節。

最後實際發送的chunk以下:

Q:爲何RTMP要將Message拆分紅不一樣的Chunk呢? A:經過拆分,數據量較大的Message能夠被拆分紅較小的「Message」,這樣就能夠避免優先級低的消息持續發送阻塞優先級高的數據,好比在視頻的傳輸過程當中,會包括視頻幀,音頻幀和RTMP控制信息,若是持續發送音頻數據或者控制數據的話可能就會形成視頻幀的阻塞,而後就會形成看視頻時最煩人的卡頓現象。同時對於數據量較小的Message,能夠經過對Chunk Header的字段來壓縮信息,從而減小信息的傳輸量。

阻塞 vs. CPU Chunk的默認大小是128字節,在傳輸過程當中,經過一個叫作Set Chunk Size的控制信息能夠設置Chunk數據量的最大值,在發送端和接受端會各自維護一個Chunk Size,能夠分別設置這個值來改變本身這一方發送的Chunk的最大大小。大一點的Chunk減小了計算每一個chunk的時間從而減小了CPU的佔用率,可是它會佔用更多的時間在發送上,尤爲是在低帶寬的網絡狀況下,極可能會阻塞後面更重要信息的傳輸。小一點的Chunk能夠減小這種阻塞問題,但小的Chunk會引入過多額外的信息(Chunk中的Header),少許屢次的傳輸也可能會形成發送的間斷致使不能充分利用高帶寬的優點,所以並不適合在高比特率的流中傳輸。在實際發送時應對要發送的數據用不一樣的Chunk Size去嘗試,經過抓包分析等手段得出合適的Chunk大小,而且在傳輸過程當中能夠根據當前的帶寬信息和實際信息的大小動態調整Chunk的大小,從而儘可能提升CPU的利用率並減小信息的阻塞機率。

來源於《帶你吃透RTMP》


播放一個RTMP協議的流媒體須要通過如下幾個步驟:握手,創建鏈接,創建流,播放。RTMP鏈接都是以握手做爲開始的。創建鏈接階段用於創建客戶端與服務器之間的「網絡鏈接」;創建流階段用於創建客戶端與服務器之間的「網絡流」;播放階段用於傳輸視音頻數據。

握手(HandShake)

一個RTMP鏈接以握手開始,雙方分別發送大小固定的三個數據塊

  1. 握手開始於客戶端發送C0、C1塊。服務器收到C0或C1後發送S0和S1。
  2. 當客戶端收齊S0和S1後,開始發送C2。當服務器收齊C0和C1後,開始發送S2。
  3. 當客戶端和服務器分別收到S2和C2後,握手完成。

理論上來說只要知足以上條件,如何安排6個Message的順序都是能夠的,但實際實現中爲了在保證握手的身份驗證功能的基礎上儘可能減小通訊的次數,通常的發送順序是這樣的:

  1. Client發送C0+C1到Sever
  2. Server發送S0+S1+S2到Client
  3. Client發送C2到Server,握手完成

創建網絡鏈接(NetConnection)

  1. 客戶端發送命令消息中的「鏈接」(connect)到服務器,請求與一個服務應用實例創建鏈接。
  2. 服務器接收到鏈接命令消息後,發送確認窗口大小(Window Acknowledgement Size)協議消息到客戶端,同時鏈接到鏈接命令中提到的應用程序。
  3. 服務器發送設置帶寬(Set Peer Bandwitdh)協議消息到客戶端。
  4. 客戶端處理設置帶寬協議消息後,發送確認窗口大小(Window Acknowledgement Size)協議消息到服務器端。
  5. 服務器發送用戶控制消息中的「流開始」(Stream Begin)消息到客戶端。
  6. 服務器發送命令消息中的「結果」(_result),通知客戶端鏈接的狀態。
  7. 客戶端在收到服務器發來的消息後,返回確認窗口大小,此時網絡鏈接建立完成。

服務器在收到客戶端發送的鏈接請求後發送以下信息: 主要是告訴客戶端確認窗口大小,設置節點帶寬,而後服務器把「鏈接」鏈接到指定的應用並返回結果,「網絡鏈接成功」。而且返回流開始的的消息(Stream Begin 0)。

創建網絡流(NetStream)

  1. 客戶端發送命令消息中的「建立流」(createStream)命令到服務器端。
  2. 服務器端接收到「建立流」命令後,發送命令消息中的「結果」(_result),通知客戶端流的狀態。

推流流程

  1. 客戶端發送publish推流指令。
  2. 服務器發送用戶控制消息中的「流開始」(Stream Begin)消息到客戶端。
  3. 客戶端發送元數據(分辨率、幀率、音頻採樣率、音頻碼率等等)。
  4. 客戶端發送音頻數據。
  5. 客戶端發送服務器發送設置塊大小(ChunkSize)協議消息。
  6. 服務器發送命令消息中的「結果」(_result),通知客戶端推送的狀態。
  7. 客戶端收到後,發送視頻數據直到結束。

播流流程

  1. 客戶端發送命令消息中的「播放」(play)命令到服務器。
  2. 接收到播放命令後,服務器發送設置塊大小(ChunkSize)協議消息。
  3. 服務器發送用戶控制消息中的「streambegin」,告知客戶端流ID。
  4. 播放命令成功的話,服務器發送命令消息中的「響應狀態」 NetStream.Play.Start & NetStream.Play.reset,告知客戶端「播放」命令執行成功。
  5. 在此以後服務器發送客戶端要播放的音頻和視頻數據。

5、直播中的用戶交互

對於直播中的用戶交互大體能夠分爲:

  1. 送禮物
  2. 發表評論或者彈幕
  3. 對於送禮物,在 H5 端能夠利用 DOM 和 CSS3 實現送禮物邏輯和一些特殊的禮物動畫,實現技術難點不大。

對於彈幕來講,要稍微複雜一些,可能須要關注如下幾點:

  1. 彈幕實時性,能夠利用 webscoket 來實時發送和接收新的彈幕並渲染出來。
  2. 對於不支持 webscoket 的瀏覽器來講,只能降級爲長輪詢或者前端定時器發送請求來獲取實時彈幕。
  3. 彈幕渲染時的動畫和碰撞檢測(即彈幕不重疊)等等

Html5直播聊天室組件

該組件主要適用於基於Html5的web 大羣互動直播場景。具有以下特色: 1)支持匿名身份入羣,粉絲與主播進行親密互動 2)支持多人聊天,主播同一個賬號多標籤頁收發消息,粉絲再多也不用愁 3)支持多種聊天方式,文本,表情,紅包,點贊,想怎麼互動就怎麼互動 4)支持不一樣優先級消息的頻率控制,一鍵在手,權利盡在掌握中 5)對互動直播場景進行了專門的優化,參與人數多,消息量再大也能從容應對

前端技術點

  1. 秒開
  2. 時延
  3. 流暢
  4. 清晰度

6、總結

目前較爲成熟的直播產品,大體都是以 Server 端、 H5直播前端 和 Native(Android,iOS)搭配實現直播。

主要從android客戶端出發,從最初的錄製視頻到客戶端觀看直播的整個流程,給出了各個技術點的概要和解決方案,從0到1完成了簡單的直播實現。從0到1易,從1到100還有更多的技術細節有待研究。


更多精彩內容歡迎關注bugly的微信公衆帳號:

騰訊 Bugly是一款專爲移動開發者打造的質量監控工具,幫助開發者快速,便捷的定位線上應用崩潰的狀況以及解決方案。智能合併功能幫助開發同窗把天天上報的數千條 Crash 根據根因合併分類,每日日報會列出影響用戶數最多的崩潰,精準定位功能幫助開發同窗定位到出問題的代碼行,實時上報能夠在發佈後快速的瞭解應用的質量狀況,適配最新的 iOS, Android 官方操做系統,鵝廠的工程師都在使用,快來加入咱們吧!

相關文章
相關標籤/搜索