srs 低延時直播應用

低延時直播應用

 

直播應用中,RTMP和HLS基本上可以覆蓋所有客戶端觀看(參考:DeliveryHLS),HLS主要是延時比較大,RTMP主要優勢在於延時低。

低延遲的部署實例參考:Usage: Realtime

應用場景

低延時應用場景包括:

  • 互動式直播:譬如2013年大行其道的美女主播,遊戲直播等等各種主播,流媒體分發給用戶觀看。用戶可以文字聊天和主播互動。
  • 視頻會議:SRS的DEMO就有視頻會議應用,我們要是有同事出差在外地,就用這個視頻會議開內部會議。其實會議1秒延時無所謂,因爲人家講完話後,其他人需要思考,思考的延時也會在1秒左右。當然如果用視頻會議吵架就不行。
  • 其他:監控,直播也有些地方需要對延遲有要求,互聯網上RTMP協議的延遲基本上能夠滿足要求。

RTMP和延時

RTMP的特點如下:

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

HLS低延時

主要有人老是問這個問題,如何降低HLS延遲。

HLS解決延時,就像是爬到楓樹上去捉魚,奇怪的是還有人喊,看那,有魚。你說是怎麼回事。

我只能說你在參與謙哥的魔術表演,錯覺罷了。

如果你真的確信有,請用實際測量的圖片來展示出來,參考下面延遲的測量。

RTMP延遲的測量

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

經過測量發現,在網絡狀況良好時:

  • RTMP延時可以做到0.8秒左右(SRS也可以)。
  • 多級邊緣節點不會影響延遲(和SRS同源的某CDN的邊緣服務器可以做到)
  • Nginx-Rtmp延遲有點大,估計是緩存的處理,多進程通信導致?
  • GOP是個硬指標,不過SRS可以關閉GOP的cache來避免這個影響,參考後面的配置方法。
  • 服務器性能太低,也會導致延遲變大,服務器來不及發送數據。
  • 客戶端的緩衝區長度也影響延遲。譬如flash客戶端的NetStream.bufferTime設置爲10秒,那麼延遲至少10秒以上。

Min-Latency

當開啓最低延遲配置後,SRS會禁用mr(merged-read),並且在consumer隊列中使用超時等待,大約每收到1-2個視頻包就發送給客戶端,達到最低延遲目標。

測試vp6純視頻流能達到0.1秒延遲,參考#257。配置文件:

vhost mrw.srs.com {
    # whether enable min delay mode for vhost.
    # for min latence mode:
    # 1. disable the publish.mr for vhost.
    # 2. use timeout for cond wait for consumer queue.
    # @see https://github.com/ossrs/srs/issues/257
    # default: off
    min_latency     off;
}

部署低延時的實例,參考:[wiki](ENCN).

Merged-Read

RTMP的Read效率非常低,需要先讀一個字節,判斷是哪個chunk,然後讀取header,接着讀取payload。因此上行支持的流的路數大約只有下行的1/3,譬如SRS1.0支持下行2700上行只有1000,SRS2.0支持下行10000上行只有4500。

爲了提高性能,SRS對於上行的read使用merged-read,即SRS在讀寫時一次讀取N毫秒的數據,這個可以配置:

# the MR(merged-read) setting for publisher.
vhost mrw.srs.com {
    # the config for FMLE/Flash publisher, which push RTMP to SRS.
    publish {
        # about MR, read https://github.com/ossrs/srs/issues/241
        # when enabled the mr, SRS will read as large as possible.
        # default: off
        mr          off;
        # the latency in ms for MR(merged-read),
        # the performance+ when latency+, and memory+,
        #       memory(buffer) = latency * kbps / 8
        # for example, latency=500ms, kbps=3000kbps, each publish connection will consume
        #       memory = 500 * 3000 / 8 = 187500B = 183KB
        # when there are 2500 publisher, the total memory of SRS atleast:
        #       183KB * 2500 = 446MB
        # the value recomment is [300, 2000]
        # default: 350
        mr_latency  350;
    }
}

也就是說,當開啓merged-read之後,服務器的接收緩衝區至少會有latency毫秒的數據,延遲也就會有這麼多毫秒。

若需要低延遲配置,關閉merged-read,服務器每次收到1個包就會解析。

Merged-Write

SRS永遠使用Merged-Write,即一次發送N毫秒的包給客戶端。這個算法可以將RTMP下行的效率提升5倍左右,SRS1.0每次writev一個packet支持2700客戶端,SRS2.0一次writev多個packet支持10000客戶端。

用戶可以配置merged-write一次寫入的包的數目,建議不做修改:

# the MW(merged-write) settings for player.
vhost mrw.srs.com {
    # for play client, both RTMP and other stream clients,
    # for instance, the HTTP FLV stream clients.
    play {
        # set the MW(merged-write) latency in ms. 
        # SRS always set mw on, so we just set the latency value.
        # the latency of stream >= mw_latency + mr_latency
        # the value recomment is [300, 1800]
        # default: 350
        mw_latency      350;
    }
}

若需要極低延遲(損失較多性能),可以設置爲100毫秒,SRS大約一次發送幾個包。

GOP-Cache

什麼是GOP?就是視頻流中兩個I幀的時間距離,如果問什麼是I幀就去百度。

GOP有什麼影響?Flash(解碼器)只有拿到GOP才能開始解碼播放。也就是說,服務器一般先給一個I幀給Flash。可惜問題來了,假設GOP是10秒,也就是每隔10秒纔有關鍵幀,如果用戶在第5秒時開始播放,會怎麼樣?

第一種方案:等待下一個I幀,也就是說,再等5秒纔開始給客戶端數據。這樣延遲就很低了,總是實時的流。問題是:等待的這5秒,會黑屏,現象就是播放器卡在那裏,什麼也沒有,有些用戶可能以爲死掉了,就會刷新頁面。總之,某些客戶會認爲等待關鍵幀是個不可饒恕的錯誤,延時有什麼關係?我就希望能快速啓動和播放視頻,最好打開就能放!

第二種方案:馬上開始放,放什麼呢?你肯定知道了,放前一個I幀。也就是說,服務器需要總是cache一個gop,這樣客戶端上來就從前一個I幀開始播放,就可以快速啓動了。問題是:延遲自然就大了。

有沒有好的方案?有!至少有兩種:

  • 編碼器調低GOP,譬如0.5秒一個GOP,這樣延遲也很低,也不用等待。壞處是編碼器壓縮率會降低,圖像質量沒有那麼好。
  • 服務器提供配置,可以選擇前面兩個方案之一:SRS就這麼做,有個gop_cache配置項,on就會馬上播放,off就低延遲。

SRS的配置項:

# the listen ports, split by space.
listen              1935;
vhost __defaultVhost__ {
    # for play client, both RTMP and other stream clients,
    # for instance, the HTTP FLV stream clients.
    play {
        # whether cache the last gop.
        # if on, cache the last gop and dispatch to client,
        #   to enabled fast startup for client, client play immediately.
        # if off, send the latest media data to client,
        #   client need to wait for the next Iframe to decode and show the video.
        # set to off if requires min delay;
        # set to on if requires client fast startup.
        # default: on
        gop_cache       off;
    }
}

備註:參考conf/full.conf的min.delay.com配置。

累積延遲

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

    # the max live queue length in seconds.
    # if the messages in the queue exceed the max length, 
    # drop the old whole gop.
    # default: 30
    queue_length    10;

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

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

處理累積延遲的最好方法,是客戶端檢測到緩衝區有很多數據了,如果可以的話,就重連服務器。當然如果網絡一直不好,那就沒有辦法了。

低延時配置

考慮GOP-Cache和累積延遲,推薦的低延時配置如下(參考min.delay.com):

# the listen ports, split by space.
listen              1935;
vhost __defaultVhost__ {
    tcp_nodelay     on
    min_latency     on;

    play {
        gop_cache       off;
        queue_length    10;
        mw_latency      100;
    }

    publish {
        mr off;
    }
}

當然,服務器的性能也要考慮,不可以讓一個SRS進程跑太高帶寬,一般CPU在80%以下不會影響延遲,連接數參考性能

實測

SRS: 0.9.55

編碼器:FMLE, video(h264, profile=baseline, level=3.1, keyframe-frequency=5seconds), fps=15, input=640x480, output(500kbps, 640x480), 無音頻輸出(FMLE的音頻切片HLS有問題)

網絡:推流爲PC在北京公司內網,觀看爲PC北京公司內網,服務器爲阿里雲青島節點。

服務器配置:

listen              1935;
vhost __defaultVhost__ {
    enabled         on;
    play {
        gop_cache       off;
    }
    hls {
        enabled         on;
        hls_path        ./objs/nginx/html;
        hls_fragment    5;
        hls_window      20;
    }
}

結論:RTMP延遲2秒,HLS延遲24秒。

原地址  https://github.com/ossrs/srs/wiki/v3_CN_LowLatency

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章