基于typescript的rtsp客户端实现

前言

rtsp(Real Time Streaming Protocol)协议可以实现音视频的实时传输。安防摄像机标配之一就是支持rtsp协议。本文主要从下面几个方面对rtsp协议进行介绍:

1、rtsp协议总览

2、rtsp信令交互流程

3、rtsp鉴权

4、H264的rtp打包

5、tcp如何传输rtp

6、typescript的客户端实现

rtsp协议总览


RTSP相关规范

RFC2326:主要介绍rtsp的信令的交互流程以及鉴权,还包含了TCP/UDP传输rtp包。

RFC3984:主要介绍了H264如何打包到rtp包里面

RFC4566:SDP规范的介绍

RFC3550:RTP头的介绍

rtsp信令交互



最简单的信令交互

前面四步都是信令交互,步骤5是rtp的媒体数据。

步骤一:OPTIONS

请求

OPTIONS rtsp://10.10.14.168:554/Streaming/Channels/101 RTSP/1.0
CSeq: 2
User-Agent: LibVLC/2.2.1 (LIVE555 Streaming Media v2014.07.25)

应答

RTSP/1.0 200 OK
CSeq: 2
Public: OPTIONS, DESCRIBE, PLAY, PAUSE, SETUP, TEARDOWN, SET_PARAMETER, GET_PARAMETER
Date:  Sat, Aug 14 2021 14:54:59 GMT

步骤二:DESCRIBE

请求

DESCRIBE rtsp://10.10.14.168:554/Streaming/Channels/101 RTSP/1.0
CSeq: 3
User-Agent: LibVLC/2.2.1 (LIVE555 Streaming Media v2014.07.25)
Accept: application/sdp

应答

RTSP/1.0 401 Unauthorized
CSeq: 3
WWW-Authenticate: Digest realm="IP Camera(C3459)", nonce="092598ce6a93eb21c740b7cac1acd5aa", stale="FALSE"
WWW-Authenticate: Basic realm="IP Camera(C3459)"
Date:  Sat, Aug 14 2021 14:54:59 GMT

重新请求,携带鉴权

DESCRIBE rtsp://10.10.14.168:554/Streaming/Channels/101 RTSP/1.0
CSeq: 4
Authorization: Digest username="admin", realm="IP Camera(C3459)", nonce="092598ce6a93eb21c740b7cac1acd5aa", uri="rtsp://10.10.14.168:554/Streaming/Channels/101", response="2c5190dceb56f138647aec1613a20e00"
User-Agent: LibVLC/2.2.1 (LIVE555 Streaming Media v2014.07.25)
Accept: application/sdp

应答

RTSP/1.0 200 OK
CSeq: 4
Content-Type: application/sdp
Content-Base: rtsp://10.10.14.168:554/Streaming/Channels/101/
Content-Length: 599


v=0
o=- 1628952899656592 1628952899656592 IN IP4 10.10.14.168
s=Media Presentation
e=NONE
b=AS:5050
t=0 0
a=control:rtsp://10.10.14.168:554/Streaming/Channels/101/
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:5000
a=recvonly
a=x-dimensions:1920,1080
a=control:rtsp://10.10.14.168:554/Streaming/Channels/101/trackID=1
a=rtpmap:96 H264/90000
a=fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z00AKpY1QPAET8s3AQEBQAABwgAAV+QB,aO48gA==
a=Media_header:MEDIAINFO=494D4B48010200000400000100000000000000000000000000000000000000000000000000000000;
a=appversion:1.0

步骤三:SETUP

请求

SETUP rtsp://10.10.14.168:554/Streaming/Channels/101/trackID=1 RTSP/1.0
CSeq: 5
Authorization: Digest username="admin", realm="IP Camera(C3459)", nonce="092598ce6a93eb21c740b7cac1acd5aa", uri="rtsp://10.10.14.168:554/Streaming/Channels/101/", response="cf6da6567716219d8f9585be758d94c7"
User-Agent: LibVLC/2.2.1 (LIVE555 Streaming Media v2014.07.25)
Transport: RTP/AVP/TCP;unicast;interleaved=0-1

应答

RTSP/1.0 200 OK
CSeq: 5
Session:        900278855;timeout=60
Transport: RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=3c7c54df;mode="play"
Date:  Sat, Aug 14 2021 14:54:59 GMT

步骤四:Play

请求

PLAY rtsp://10.10.14.168:554/Streaming/Channels/101/ RTSP/1.0
CSeq: 6
Authorization: Digest username="admin", realm="IP Camera(C3459)", nonce="092598ce6a93eb21c740b7cac1acd5aa", uri="rtsp://10.10.14.168:554/Streaming/Channels/101/", response="92fac6580bec31626a34e2a0222bd856"
User-Agent: LibVLC/2.2.1 (LIVE555 Streaming Media v2014.07.25)
Session: 900278855
Range: npt=0.000-

应答

RTSP/1.0 200 OK
CSeq: 6
Session:        900278855
RTP-Info: url=rtsp://10.10.14.168:554/Streaming/Channels/101/trackID=1;seq=15082;rtptime=2002916762
Date:  Sat, Aug 14 2021 14:54:59 GMT

信令总结:

1、CSeq序号为自增长

2、Play请求的Session为SetUp应答的Session

3、鉴权有两种分别为Basic和Digest,当返回401的时候,需要带上鉴权信息

rtsp鉴权


Basic鉴权

Basic鉴权计算方法

将`用户名:密码`采用base64处理之后的数据携带在rtsp的Authorization里面。

Digest鉴权

Digest鉴权计算方法

在401的应答中,提取出realm和nonce的值,在通过下面公式计算出response

response= md5(md5(username:realm:password):nonce:md5(public_method:url));

H264Rtp打包


rtp的媒体数据为RTP头+H264数据组成,如下图:

rtp数据格式

RTP头

rtp头格式

version (V):2 bits
padding (P):1 bit   当为1时最后一个字节的 padding有一个计数器,
计算数据需要减去最后计算器的数量,计算器数量包含自己
extension (X):1 bit
CSRC count (CC):4 bits
marker (M):1 bit
payload type (PT):7 bits  媒体类型
sequence number:16 bits 每发送一个 RTP 数据报文序列号值加一
timestamp:32 bits  时间戳

RTP解析示例

H264打包

RTP数据包的H264数据第一个字节定义如下:

      +---------------+
      |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+-+
      |F|NRI|  Type   |
      +---------------+

F: 1 个比特.值为0

NRI: 2 个比特

Type: 5 个比特

Type定义如下

  0     没有定义
  1-23  NAL单元   单个 NAL 单元包.
  24    STAP-A   单一时间的组合包
  25    STAP-B   单一时间的组合包
  26    MTAP16   多个时间的组合包
  27    MTAP24   多个时间的组合包
  28    FU-A     分片的单元
  29    FU-B     分片的单元

这里只研究1-23和28的情况,其他不考虑。

NAL单元(1-23)


Nal单元组装

只需要获取到数据加上nal头即可(00 00 00 01)

FU-A(分片单元)


分片单元还需要研究第二个字节

      +---------------+
      |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+-+
      |S|E|R|  Type   |
      +---------------+

S:  开始位  1字节 。当设置成1,指示分片NAL单元的开始。其他为0

E:结束位 1字节。当设置成1,指示分片NAL单元的结束。其他为0

R:预留位 1字节

Type:上面的Nul单元类型 在1-23之间

FU-A数据组成

即在组合的时候,不仅需要增加nal头即可(00 00 00 01),还需要根据H264数据的前面两个字节生成新一个新的单字节F+NRI+Type。另外组成数据还需要去掉前面两个字节。

TCP传输


tcp传输格式

tcp传输rtp包,还需要增加4个字节

$: 0x24 固定值

通道:通道号,一般为0

长度: RTP+H264数据的长度

给一个抓包的截图,直观感受一下:

抓包工具分析

TS客户端实现


实现代码结构图

rtspState:入口类,负责协调信令以及rtp数据处理

rtspTransport:负责发送rtsp的信令以及接收应答和rtp数据

rtpH264Parser:负责从rtp包里面解析出H264数据

这里不介绍代码细节,重点讲一下一个思想的实现。我期望在发送请求的函数里面处理应答过来的数据。

调用逻辑图

以发送Options为例,我的处理如下:

  private sendOption() {
    let params: Map<string, any> = new Map()
    this.sendRequest(
      EnRtspState[EnRtspState.OPTIONS],
      this.RtspUrl,
      params,
      ''
    ).then((value: ResponseStateData) => {
      this.onOption(value)
    })
  }

我直接在请求里面也将应答处理掉了,这样代码是不是一目了然。

我在sendRequest函数里面返回了一个Promise。

    return new Promise<ResponseStateData>((resolve) => {
      this.ResponseStateResolev = resolve
    })

在Promise里面将resolve函数保存起来,当有应答的时候,在调用这个resolve。调用函数如下:

  if (200 == parsed.code) {
      resolevData.state = EnResponseState.state200
      this.ResponseStateResolev(resolevData)
      this.ResponseStateResolev = null
      return
    

写在最后:

可以关注本人公众号:

迷途小书童爱读书

或者扫描如下二维码:

回复tsrtsp

即可获得

1、上述ts代码

2、获得一份抓包

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值