从零编写rtsp-client端

10 篇文章 2 订阅
4 篇文章 0 订阅

目录

简介:

github工程源码:

rtsp协议简介

rtsp相关的一些问题


简介:

使用live555接受rtsp流,发现在 使用udp传输的过程中,h264数据丢帧,播放端花屏,起初以为是网络不好出现udp丢包,可是局域网环境下也不至于如此严重。换低码流的数据倒是ok, 传输 1920x1080 @30fps 码率在600KByte/s 的h264视频流,从live555接受端出来的流丢失严重。  经过在客户端的抓包分析, tcpdum抓到的包提取出来的h264却基本没有丢帧现象,说明live555接受端丢帧。 分析live555可知,live555使用的单线程模式,单个线程,读取到udp数据包后,进行解析组包,读socket过程自然太慢,效率低,导致 udp 丢包。    解决udp丢包,大体可分为
=====20230208====补充说明====
局域网中udp丢包的概率小于乱序,一般优先考虑解决udp的乱序问题,花屏现象会明显改善。live555自带又乱序重拍的部分,可以打开该功能。<二:使用 ,接收端>live555 拉流 udp 重排序_王二の黄金时代的博客-CSDN博客_live555拉流
===========================

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:GitHub - Canok7/canok_rtsp_client: rtsp client for learning rtsp, can get video stream of h264 loaded on rtp-over-udp

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的发送端。

  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值