從零編寫rtsp-client端

目錄

 

簡介:

github工程源碼:

rtsp協議簡介

rtsp相關的一些問題


簡介:

使用live555接受rtsp流,發現在 使用udp傳輸的過程中,h264數據丟幀,播放端花屏,起初以爲是網絡不好出現udp丟包,可是局域網環境下也不至於如此嚴重。換低碼流的數據倒是ok, 傳輸 1920x1080 @30fps 碼率在600KByte/s 的h264視頻流,從live555接受端出來的流丟失嚴重。  經過在客戶端的抓包分析, tcpdum抓到的包提取出來的h264卻基本沒有丟幀現象,說明live555接受端丟幀。 分析live555可知,live555使用的單線程模式,單個線程,讀取到udp數據包後,進行解析組包,讀socket過程自然太慢,效率低,導致 udp 丟包。    解決udp丟包,大體可分爲

1.0 發送端丟包,降低發送端頻率,增加發送端socket緩衝區。

2.0 網絡傳輸過程丟包,這個只能添加重發的機制了

3.0 接受端丟包,加快接受端讀取速度,增加接受端socket緩衝區。

live庫有相關接口可以增加socket的接受緩衝區,vlc在使用live555接受rtp流的模塊中,也有調用live555這一函數擴大接受緩衝區。對應vlc源碼文件在/modules/access/live555.cpp::

SessionsSetup()

 /* Increase the buffer size */
 if( i_receive_buffer > 0 )
     increaseReceiveBufferTo( *p_sys->env, fd, i_receive_buffer );

擴大緩衝區之後有所緩解,但是有些時候還是不頂用,畢竟live555使用單線程,優化修改live555也是很麻煩,所以爲一探究竟從零寫了rtsp-client端。使用多線程,單獨一個線程負責讀rtp 的socket,不做其他事,確保數據不丟失。

github工程源碼:

github:https://github.com/Canok7/canok_rtsp_client

rtp協議:https://en.wikipedia.org/wiki/Real-time_Transport_Protocol

rtsp協議:https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol

rtsp協議簡介

以下實際運行過程中的rtsp交互信息,使用的vlc作爲服務端。

程序記錄的實際 log
c->s:::::::
OPTIONS rtsp://127.0.0.1:8989/stream RTSP/1.0
CSeq:1

s->c========RTSP/1.0 200 OK
Server: VLC/3.0.6
Content-Length: 0
Cseq: 1
Public: DESCRIBE,SETUP,TEARDOWN,PLAY,PAUSE,GET_PARAMETER

c->s:::::::
DESCRIBE rtsp://127.0.0.1:8989/stream RTSP/1.0
CSeq:2

s->c========RTSP/1.0 200 OK
Server: VLC/3.0.6
Date: Wed, 23 Oct 2019 03:53:47 GMT
Content-Type: application/sdp
Content-Base: rtsp://127.0.0.1:8989/stream
Content-Length: 710
Cache-Control: no-cache
Cseq: 2

v=0
o=- 16238376392436828344 16238376392436828344 IN IP4 can-virtual-machine
s=Unnamed
i=N/A
c=IN IP4 0.0.0.0
t=0 0
a=tool:vlc 3.0.6
a=recvonly
a=type:broadcast
a=charset:UTF-8
a=control:rtsp://127.0.0.1:8989/stream
m=audio 0 RTP/AVP 96
b=RR:0
a=rtpmap:96 mpeg4-generic/44100/2
a=fmtp:96 streamtype=5; profile-level-id=15; mode=AAC-hbr; config=121056e500; SizeLength=13; IndexLength=3; IndexDeltaLength=3; Profile=1;
a=control:rtsp://127.0.0.1:8989/stream/trackID=0
m=video 0 RTP/AVP 96
b=RR:0
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=64001f;sprop-parameter-sets=Z2QAH6zZAFAFuwEQAAADABAAAAMDwPGDGWA=,aOrvLA==;
a=control:rtsp://127.0.0.1:8989/stream/trackID=1
c->s:::::::
SETUP rtsp://127.0.0.1:8989/stream/trackID=1 RTSP/1.0
CSeq:3
Transport:RTP/AVP;unicast;client_port=8554-8555

s->c========RTSP/1.0 200 OK
Server: VLC/3.0.6
Date: Wed, 23 Oct 2019 03:53:47 GMT
Transport: RTP/AVP/UDP;unicast;client_port=8554-8555;server_port=57506-57507;ssrc=0BEA5821;mode=play
Session: 4180841055d9ef16
Content-Length: 0
Cache-Control: no-cache
Cseq: 3

c->s:::::::
PLAY rtsp://127.0.0.1:8989/stream RTSP/1.0
CSeq:4
nRange:npt=0.000-
Session:4180841055d9ef16

s->c========RTSP/1.0 200 OK
Server: VLC/3.0.6
Date: Wed, 23 Oct 2019 03:53:47 GMT
RTP-Info: url=rtsp://127.0.0.1:8989/stream/trackID=1;seq=31374;rtptime=593147628
Range: npt=4.056605-
Session: 4180841055d9ef16
Content-Length: 0
Cache-Control: no-cache
Cseq: 4

rtsp相關的一些問題

FQ:1.0 rtp 單獨使用udp傳輸,單播模式下,怎麼確定雙方使用的端口? 

在客戶端發送SETUP 指令時,其中就需要告訴服務端,自己客戶端的所使用的udp端口。服務端響應SETUP返回信息中包含有服務端的udp端口,這其中包括 rtp端口和rtcp端口。 Transport:RTP/AVP;unicast;client_port=8554-8555    Transport: RTP/AVP/UDP;unicast;client_port=8554-8555;server_port=57506-57507;ssrc=0BEA5821;mode=play

FQ:2.0 怎麼確定是使用 tcp 傳輸還是udp傳輸?

這個取決於客戶端發起的請求,SETUP 信息中指定要求是使用tcp還是udp,如果服務器不支持使用tcp來傳輸,會返回失敗,客戶端需要重新發起請求切換爲使用udp來傳輸。

FQ:3.0 rtp-over-tcp

如果是使用udp來傳輸rtp流,那麼整個會話的組成是,有一個建立好的 tcp連接,只用於傳輸rtsp協議的文本內容。另外有多個udp socket (udp畢竟不是面向連接的) ,一路視頻數據,一個udp socket,對應一個rtp流。 同時相應的會有一個rtcp來 反應這個rtp流的收發情況,rtcp的數據可以服用當前的udp socket,也可以另開一個 udp socket, 具體是否複用是服務端在DESCRIBE返回的信息中說明。  

如果是使用tcp傳輸,那麼整個會話的組成,只有一個 建立好的tcp連接,即只有一個socket, 傳輸rtp數據的時候,有一個額外的表示符,來區分rtp數據和rtsp數據。RTP和RTCP數據會以$符號+1個字節的通道編號+2個字節的數據長度,共4個字節的前綴開始,RTSP數據是沒有前綴數據$ 的。https://blog.csdn.net/machh/article/details/52171997

| magic number | channel number | data length | data  |magic number - 

magic number:   RTP數據標識符,"$" 一個字節
channel number: 信道數字 - 1個字節,用來指示信道
data length :   數據長度 - 2個字節,用來指示插入數據長度
data :          數據 - ,比如說RTP包,總長度與上面的數據長度相同

個人理解,要深入理解,建議得看看tcp/ip協議棧的實現。

《《《 爲什麼要有data length ,而udp傳輸的rtp數據沒有數據長度的描述?
tcp 流式套接字,傳輸層從socket讀出來的數據都是剝離了 ip tcp等協議的頭的,他的數據能夠確保是發送端發過來的不丟失,有順序的數據,read 5個字節,下次讀還可以從5個字節的後面讀取,其socket緩衝區存儲的是整個連續的數據。

而UDP,其socket 緩衝區存儲的是一個一個的數據包。讀也是按照數據包一個包一個包地讀,讀一次不會給你返回兩個包,所以沒必要擔心粘包,不用自己去區分包邊界。 故而也是其叫做SOCK_DGRAM 數據包套接字的原因吧

FQ:4.0 服務端由多個流,音頻和視頻,怎麼確定具體哪一個流。

在客戶端發送SETUP的時候,自己指定。在從服務器返回的DESCRIBE信息中,有使用SDP 協議包含的一大串信息,詳細描述媒體信息,其中的一段比如:

m=video 0 RTP/AVP 96
b=RR:0
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=64001f;sprop-parameter-sets=Z2QAH6zZAFAFuwEQAAADABAAAAMDwPGDGWA=,aOrvLA==;
a=control:rtsp://127.0.0.1:8989/stream/trackID=1

即video 視頻信息,負載類型爲96, h264, a=control:rtsp://127.0.0.1:8989/stream/trackID=1 這個control是客戶端發送SETUP信息需要制定的,表示要拉取這一個流,所以有些抓到的包中可以看到兩個SETUP請求,因爲需要setup 音頻流一次,setup視頻流一次,如果只需要視頻,可以只發送這個視頻的setup請求,至於後續的PLAY,沒有單獨播放一個媒體的操作,是針對整個RTSP的,所以是沒有帶 tarckID這些信息的。

FQ:5.0 rtp 負載內容,怎麼確定是h264?

rtp可以負載多種格式的媒體數據,有些對應格式是和PT(rtp 協議頭 中PT域) 值固定的,有些是動態分配的.參考:

https://en.wikipedia.org/wiki/RTP_payload_formats

FQ: 6.0 發送完PLAY,都ok,但是讀不到流數據

發送PLAY時,需要加上 setup命令返回的 Session:4180841055d9ef16, 這是服務器端用來確定會話的一個數據,個人在實際開發中發現vlc 作爲服務端,接受到PLAY命令會對Session進行檢查,Session不匹配的情況下也沒有返回錯誤碼,但是不會啓動rtp的發送端。

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