RTMP直播應用與延時分析

直播應用中,RTMP和HLS基本上能夠覆蓋全部客戶端觀看,
HLS主要是延時比較大,RTMP主要優點在於延時低。

git

1、應用場景

低延時應用場景包括:
  .  互動式直播:譬如2013年大行其道的美女主播,遊戲直播等等
     各類主播,流媒體分發給用戶觀看。用戶能夠文字聊天和主播互動。
  .  視頻會議:咱們要是有同事出差在外地,就用視頻會議開內部會議。
     其實會議1秒延時無所謂,由於人家講完話後,其餘人須要思考,
     思考的延時也會在1秒左右。固然若是用視頻會議吵架就不行。
  .  其餘:監控,直播也有些地方須要對延遲有要求,
     互聯網上RTMP協議的延遲基本上可以知足要求。


github

2、RTMP和延時

1. RTMP的特色以下:

1) Adobe支持得很好:
   RTMP其實是如今編碼器輸出的工業標準協議,基本上全部的編碼器(攝像頭之類)都支持RTMP輸出。
   緣由在於PC市場巨大,PC主要是Windows,Windows的瀏覽器基本上都支持flash,
   Flash又支持RTMP支持得很是好。
2) 適合長時間播放:
   由於RTMP支持的很完善,因此能作到flash播放RTMP流長時間不斷流,
   當時測試是100萬秒,即10天多能夠連續播放。
   對於商用流媒體應用,客戶端的穩定性固然也是必須的,不然最終用戶看不了還怎麼玩?
   我就知道有個教育客戶,最初使用播放器播放http流,須要播放不一樣的文件,結果就總出問題,
   若是換成服務器端將不一樣的文件轉換成RTMP流,客戶端就能夠一直播放;
   該客戶走RTMP方案後,通過CDN分發,沒據說客戶端出問題了。
3)延遲較低:
   比起YY的那種UDP私有協議,RTMP算延遲大的(延遲在1-3秒),
   比起HTTP流的延時(通常在10秒以上)RTMP算低延時。
   通常的直播應用,只要不是電話類對話的那種要求,RTMP延遲是能夠接受的。
   在通常的視頻會議應用中,RTMP延時也能接受,緣由是別人在說話的時候咱們通常在聽,
   實際上1秒延時沒有關係,咱們也要思考(話說有些人的CPU處理速度尚未這麼快)。
4) 有累積延遲:
   技術必定要知道弱點,RTMP有個弱點就是累積偏差,緣由是RTMP基於TCP不會丟包。
   因此當網絡狀態差時,服務器會將包緩存起來,致使累積的延遲;
   待網絡情況好了,就一塊兒發給客戶端。
   這個的對策就是,當客戶端的緩衝區很大,就斷開重連。


後端

2. HLS低延時

主要有人總是問這個問題,如何下降HLS延遲。
HLS解決延時,就像是爬到楓樹上去捉魚,奇怪的是還有人喊,看那,有魚。
你說是怎麼回事?


我只能說你在參與謙哥的魔術表演,錯覺罷了。
若是你真的確信有,請用實際測量的圖片來展現出來,參考下面延遲的測量。


瀏覽器

3. RTMP延遲的測量

如何測量延時,是個很難的問題,
不過有個行之有效的方法,就是用手機的秒錶,能夠比較精確的對比延時。


通過測量發現,在網絡情況良好時:
  . RTMP延時能夠作到0.8秒左右。
  . 多級邊緣節點不會影響延遲(和SRS同源的某CDN的邊緣服務器能夠作到)
  . Nginx-Rtmp延遲有點大,估計是緩存的處理,多進程通訊致使?
  . GOP是個硬指標,不過SRS能夠關閉GOP的cache來避免這個影響.
  . 服務器性能過低,也會致使延遲變大,服務器來不及發送數據。
  . 客戶端的緩衝區長度也影響延遲。
    譬如flash客戶端的NetStream.bufferTime設置爲10秒,那麼延遲至少10秒以上。


緩存

4. GOP-Cache

什麼是GOP?就是視頻流中兩個I幀的時間距離。
GOP有什麼影響?
Flash(解碼器)只有拿到GOP才能開始解碼播放。
也就是說,服務器通常先給一個I幀給Flash。
惋惜問題來了,假設GOP是10秒,也就是每隔10秒纔有關鍵幀,
若是用戶在第5秒時開始播放,會怎麼樣?
第一種方案:等待下一個I幀,
也就是說,再等5秒纔開始給客戶端數據。
這樣延遲就很低了,老是實時的流。
問題是:等待的這5秒,會黑屏,現象就是播放器卡在那裏,什麼也沒有,
有些用戶可能覺得死掉了,就會刷新頁面。
總之,某些客戶會認爲等待關鍵幀是個不可饒恕的錯誤,延時有什麼關係?
我就但願能快速啓動和播放視頻,最好打開就能放!


第二種方案:立刻開始放,
放什麼呢?
你確定知道了,放前一個I幀。
也就是說,服務器須要老是cache一個gop,
這樣客戶端上來就從前一個I幀開始播放,就能夠快速啓動了。
問題是:延遲天然就大了。


有沒有好的方案?
有!至少有兩種:
編碼器調低GOP,譬如0.5秒一個GOP,這樣延遲也很低,也不用等待。
壞處是編碼器壓縮率會下降,圖像質量沒有那麼好。


服務器

5. 累積延遲

除了GOP-Cache,還有一個有關係,就是累積延遲。
服務器能夠配置直播隊列的長度,服務器會將數據放在直播隊列中,
若是超過這個長度就清空到最後一個I幀:


固然這個不能配置過小,
譬如GOP是1秒,queue_length是1秒,這樣會致使有1秒數據就清空,會致使跳躍。


有更好的方法?有的。
延遲基本上就等於客戶端的緩衝區長度,由於延遲大多因爲網絡帶寬低,
服務器緩存後一塊兒發給客戶端,現象就是客戶端的緩衝區變大了,
譬如NetStream.BufferLength=5秒,那麼說明緩衝區中至少有5秒數據。


處理累積延遲的最好方法,是客戶端檢測到緩衝區有不少數據了,若是能夠的話,就重連服務器。
固然若是網絡一直很差,那就沒有辦法了。

網絡

映客 LFLiveKit 推流

1、直播現狀簡介session

想作一套像映客的直播系統?Linkee.10數據結構

1.技術實現層面:app

技術相對都比較成熟,設備也都支持硬編碼。IOS還提供現成的 Video ToolBox框架,能夠對攝像頭和流媒體數據結構進行處理,但Video ToolBox框架只兼容8.0以上版本,8.0如下就須要用x264的庫軟編了。

github上有現成的開源實現,推流、美顏、水印、彈幕、點贊動畫、濾鏡、播放都有。技術其實不是很難,並且如今不少雲廠商都提供SDK,七牛雲、金山雲、樂視雲、騰訊雲、百度雲、鬥魚直播伴侶推流端,功能幾乎都是同樣的,沒啥亮點,不一樣的是整個直播平臺服務差別和接入的簡易性。後端如今 RTMP/HTTP-FLV 清一色,App掛個源站直接接入雲廠商或CDN就OK。想作一套像映客的直播系統?

2.直播優化層面

其實最難的難點是提升首播時間、服務質量即Qos(Quality of Service,服務質量),如何在丟包率20%的狀況下還能保障穩定、流暢的直播體驗,須要考慮如下方案:

1.爲加快首播時間,收流服務器主動推送 GOP :(Group of Pictures:策略影響編碼質量)所謂GOP,意思是畫面組,一個GOP就是一組連續的畫面至邊緣節點,邊緣節點緩存 GOP,播放端則能夠快速加載,減小回源延遲

想作一套像映客的直播系統?

GOP.1

2.GOP丟幀,爲解決延時,爲何會有延時,網絡抖動、網絡擁塞致使的數據發送不出去,丟完以後全部的時間戳都要修改,切記,要不客戶端就會卡一個 GOP的時間,是因爲 PTS(Presentation Time Stamp,PTS主要用於度量解碼後的視頻幀何時被顯示出來) 和 DTS 的緣由,或者播放器修正 DTS 和 PTS 也行(推流端丟GOD更復雜,丟 p 幀以前的 i 幀會花屏)

想作一套像映客的直播系統?

幀.2

3.純音頻丟幀,要解決音視頻不一樣步的問題,要讓視頻的 delta增量到你丟掉音頻的delta以後,再發音頻,要不就會音視頻不一樣步

4.源站主備切換和斷線重連

5.根據TCP擁塞窗口作智能調度,當擁塞窗口過大說明節點服務質量不佳,須要切換節點和故障排查

6.增長上行、下行帶寬探測接口,當帶寬不知足時下降視頻質量,即下降碼率

7.定時獲取最優的推流、拉流鏈路IP,儘量保證提供最好的服務

8.監控必需要,監控各個節點的Qos狀態,來作整個平臺的資源配置優化和調度

想作一套像映客的直播系統?

直播過程.3

9.若是產品從推流端、CDN、播放器都是自家的,保障 Qos 優點很是大

10.當直播量很是大時,要加入集羣管理和調度,保障 Qos

11.播放端經過增長延時來減小網絡抖動,經過快播來減小延時

3.運營成本和客戶體驗

根據網上的數據,鬥魚 TV 爲 3 億人民幣,戰旗 TV 爲 1.5 億人民幣,龍珠爲 1.2 億人民幣,虎牙爲 3000 萬 + 人民幣。

運營和推廣:這個就比較燒錢了,一些作移動直播、遊戲直播、秀場直播的A輪至少得上千萬。

用戶體驗:流暢、不卡頓、不花屏、斷線重連、丟包策略、首畫加載速度、豐富的禮物系統,爲了提升用戶體驗,能夠在後臺加載其餘頁面數據,但要在用戶體驗和內存優化方面找到平衡點。

2、流媒體傳輸

1.TCP:TCP爲點對點的協議,雖然能保證了數據傳輸的可靠性,可是對服務器資源耗費較大,在數據流大的場合難以保證數據流傳輸的實時性。

2.UDP:UDP爲不可靠傳輸協議,不須要維護鏈接狀態,也不認爲每一個數據包都必須到達接受端,所以網絡負荷比TCP小,傳輸速度也要比TCP快;但在網絡越擁擠時,越有更多的數據包丟失。

3.RTMP:RTMP一個專門爲高效傳輸視頻,音頻和數據而設計的協議。它經過創建一個二進制TCP鏈接或者鏈接HTTP隧道實現實時的視頻和聲音傳輸。

4.FFmpeg:FFmpeg是一套能夠用來記錄、轉換數字音頻、視頻,並能將其轉化爲流的開源計算機程序。採用LGPL或GPL許可證。它提供了錄製、轉換以及流化音視頻的完整解決方案

想作一套像映客的直播系統?

協議差別.4

3、項目搭建:採集端

1.目前比較知名的有VideoCore

目前國內不少知名的推流框架都是對VideoCore的二次開發。這個框架主要使用C++寫的,支持RTMP推流,但對於iOS開發者來講有點晦澀難懂(精通C++的除外)。想開源和免費的能夠選擇如今的幾個知名項目VideoCore + GPUImage+基於GPU的美顏濾鏡 ,播放用IJKPlayer本身修改。

2.國內比較火的LiveVideoCoreSDK

框架提供IOS蘋果手機的RTMP推流填寫RTMP服務地址,直接就能夠進行推流,SDK下載後簡單的工程配置後能直接運行,實現了美顏直播和濾鏡功能,基於OpenGL,先後攝像頭隨時切換,提供RTMP鏈接狀態的回調。

這個框架是國內比較早的一款推流框架有很多在使用這個SDK,功能很是齊全,做者也比較牛,用來學習推流採集相關內容很是好,可是集成到工程中有些困難(對於我來講)。總的來講這是一款很是厲害的推流SDK,幾乎所有使用C++寫的,編譯效率很是好,若是有實力的話推薦使用這個框架來作本身項目的推流端。

3.可讀性比較好的推流LFLiveKit

框架支持RTMP(Real Time Messaging Protocol ):實時消息傳輸協議,Adobe公司的。

HlS (HTTP Live Streaming) :蘋果自家的動態碼率自適應技術。主要用於PC和Apple終端的音視頻服務。包括一個m3u(8)的索引文件,TS媒體分片文件和key加密串文件。

推薦這個框架第一是由於它主要使用OC寫的,剩下的用C語言寫的,框架文件十分清晰,這對不精通C++的初學者提供了很大的便利,而且拓展性很是強,支持動態切換碼率功能,支持美顏功能。

4.美顏功能

美顏的話通常都是使用的GPUImage基於OpenGl開發,純OC語言,這個框架十分強大,能夠作出各類不一樣濾鏡,可拓展性高。若是對美顏沒有具體思路能夠直接用BeautifyFace,能夠加入到項目中,很方便的實現美顏效果。

4、項目具體搭建

1.如何實現美顏?

美顏功能使用的是BeautifyFace,它能夠很快速的實現美顏功能,效果不錯,它的底層仍是基於的GPUImage,對GPUImage十分喜好的Developer,能夠參照BeautifyFace,寫出一個屬於本身的美顏功能,而且添加各類濾鏡。

2.懸浮TabBar的實現

這個TabBar看着像是用自定義TabBar作的,但事實上它仍是用的系統的TabBar,給系統的tabBar.backgroundImage設置一張設計好的背景圖片。

想作一套像映客的直播系統?

TabBar.8

添加後會發現頂部有一條陰影線,而且TabBar的高度也不夠。陰影線與上圖綠色線條之間變成了透明顏色,實現下面方法隱藏陰影線,而且調高TabBar的高度。

想作一套像映客的直播系統?

TabBar.9

//隱藏陰影線

[[UITabBar appearance] setShadowImage:[UIImage new]];

- (void)setupTabBarBackgroundImage { UIImage *image = [UIImage imageNamed:@"tab_bg"]; CGFloat top = 40; // 頂端蓋高度

CGFloat bottom = 40 ; // 底端蓋高度

CGFloat left = 100; // 左端蓋寬度

CGFloat right = 100; // 右端蓋寬度

UIEdgeInsets insets = UIEdgeInsetsMake(top, left, bottom, right); // 指定爲拉伸模式,伸縮後從新賦值

UIImage *TabBgImage = [image resizableImageWithCapInsets:insets resizingMode:UIImageResizingModeStretch]; self.tabBar.backgroundImage = TabBgImage;

[[UITabBar appearance] setShadowImage:[UIImage new]];

[[UITabBar appearance] setBackgroundImage:[[UIImage alloc]init]];

}//自定義TabBar高度- (void)viewWillLayoutSubviews { CGRect tabFrame = self.tabBar.frame;

tabFrame.size.height = 60;

tabFrame.origin.y = self.view.frame.size.height - 60; self.tabBar.frame = tabFrame;

}

3.播放端的實現

播放端用的針對RTMP優化過的ijkplayer(),ijkplayer是基於FFmpeg的跨平臺播放器,這個開源項目已經被多個 App 使用,其中映客、美拍和鬥魚使用了 ijkplayer(5700+⭐️) 。在本文的末未提供了,已經打包好的ijkplayer,直接拖入項目就可使用。省去了編譯的過程(編譯十分麻煩,而且容易出錯)。

- (void)goPlaying { //獲取url

self.url = [NSURL URLWithString:_liveUrl];

_player = [[IJKFFMoviePlayerController alloc] initWithContentURL:self.url withOptions:nil]; UIView *playerview = [self.player view]; UIView *displayView = [[UIView alloc] initWithFrame:self.view.bounds]; self.PlayerView = displayView;

[self.view addSubview:self.PlayerView]; // 自動調整本身的寬度和高度

playerview.frame = self.PlayerView.bounds;

playerview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

[self.PlayerView insertSubview:playerview atIndex:1];

[_player setScalingMode:IJKMPMovieScalingModeAspectFill];

}

4.推送端的實現

使用的是LFLiveKit,推流端能夠選擇不少GitHub上的開源項目替代LFLiveKit,好比上面所提到的VideoCore,和LiveVideoCoreSDK。商用的話能夠選擇各大廠商的SDK,網易直播雲、七牛、騰訊、百度、新浪、其中金山直播雲本人用過。使用直播雲的好處就是能快速上線App,功能十分齊全,能夠播放器和推流端,服務器一套下來,有專業客服人員幫助集成到工程中,缺點就是流量費太貴了,具體能夠了解下各大廠商的收費標準。

- (UIButton*)startLiveButton{ if(!_startLiveButton){

_startLiveButton = [UIButton new]; //位置

_startLiveButton.frame = CGRectMake((XJScreenW - 200) * 0.5, XJScreenH - 100, 200, 40);

_startLiveButton.layer.cornerRadius = _startLiveButton.frame.size.height * 0.5;

[_startLiveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

[_startLiveButton.titleLabel setFont:[UIFont systemFontOfSize:16]];

[_startLiveButton setTitle:@"開始直播" forState:UIControlStateNormal];

[_startLiveButton setBackgroundColor:[UIColor grayColor]];

_startLiveButton.exclusiveTouch = YES;

__weak typeof(self) _self = self;

[_startLiveButton addBlockForControlEvents:UIControlEventTouchUpInside block:^(id sender) {

_self.startLiveButton.selected = !_self.startLiveButton.selected; if(_self.startLiveButton.selected){

[_self.startLiveButton setTitle:@"結束直播" forState:UIControlStateNormal];

LFLiveStreamInfo *stream = [LFLiveStreamInfo new];

stream.url = @"rtmp://daniulive.com:1935/live/stream238";

[_self.session startLive:stream];

}else{

[_self.startLiveButton setTitle:@"開始直播" forState:UIControlStateNormal];

[_self.session stopLive];

}

}];

} return _startLiveButton;

}

stream.url是服務器的地址,推流完成後使用VLC播放

相關文章
相關標籤/搜索