前言

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: 599v=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.state200this.ResponseStateResolev(resolevData)this.ResponseStateResolev = nullreturn

写在最后:

可以关注本人公众号:

迷途小书童爱读书

或者扫描如下二维码:

回复tsrtsp

即可获得

1、上述ts代码

2、获得一份抓包

基于typescript的rtsp客户端实现相关推荐

  1. rtsp协议_Chromium(3/5):rtsp客户端

    streamUsingTCP.rtsp协议要传的数据可分为两种,一是用于管理rtsp会话的消息,像DESCRIBE.SETUP.PLAY,它们一定通过TCP,端口号像554.第二种是媒体数据,像视频. ...

  2. docwizard c++程序文档自动生成工具_如何开发一个基于 TypeScript 的工具库并自动生成文档

    为什么用 TypeScript? TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any ...

  3. Boost:基于Boost的HTTP客户端的程序

    Boost:基于Boost的HTTP客户端的程序 实现功能 C++实现代码 实现功能 基于Boost的HTTP客户端的程序 C++实现代码 #include <iostream> #inc ...

  4. RTSP客户端模拟器(TCP方式,Python实现)

    由于某种需求,工作中需要自己要开发RTSP客户端模拟器--这里以DarwinStreamingServer(简称DSS)为例进行演示,把思路记录下来,算是开发了一个测试工具,也方便我以后查阅.在我之前 ...

  5. socket java 客户端_Java基于socket实现的客户端和服务端通信功能完整实例

    本文实例讲述了Java基于socket实现的客户端和服务端通信功能.分享给大家供大家参考,具体如下: 以下代码参考马士兵的聊天项目,先运行ChatServer.java实现端口监听,然后再运行Chat ...

  6. TypeScript算法专题 - blog1.基于TypeScript语言的单链表实现

    TypeScript算法专题 - 基于TypeScript语言的单链表实现 李俊才 CSDN:jcLee95 邮箱:291148484@163.com 专题目录:https://blog.csdn.n ...

  7. 基于FFmpeg接收RTSP的ts流

    RTSP用于建立的控制媒体流的传输,通过wireshark抓包可以看到rtsp消息交互的过程: 1. 第一步:查询服务器端可用方法 C->S:OPTION request     // 询问S有 ...

  8. egret与php相连,JavaScript_Mac OS X 系统下安装和部署Egret引擎开发环境, 概述 Egret基于TypeScript开 - phpStudy...

    Mac OS X 系统下安装和部署Egret引擎开发环境 概述 Egret基于TypeScript开发的,而TypeScript编译工具tsc是基于Node.js开发的.所以在安装过程中,我们先需要对 ...

  9. 《基于Android微博整合客户端的设计与实现》毕业设计论文任务书

    华 南 理 工 大 学 广 州 学 院 毕 业 设 计 (论文) 任 务 书 兹发给计算机科学与技术专业 1班学生巫文杰毕业设计(论文)任务书,内容如下: 1.毕业设计(论文)题目:基于Android ...

最新文章

  1. Ruby DSL介绍及其在测试数据构造中的使用(2)
  2. 学习进度条--第七周
  3. Java双刃剑之Unsafe类详解
  4. dubbo 消费者也要暴露端口吗_一文详细解读 Dubbo 中的 http 协议
  5. Qt图形界面编程入门(7)
  6. angular2+typescript在asp.net MVC Web项目上的实现
  7. Mac操作指南:废纸篓里的文件无法清除如何解决?
  8. mysql有rollup函数,Mysql,Oracle使用rollup函数完成行列统计
  9. 面向对象课程 第三次博客总结
  10. CHROME扩展开发文档之·chrome.runtime
  11. 安全红蓝对抗反制(反捕、画像)
  12. 转载大牛对Microsoft的认识
  13. 清华差生10年奋斗经历:各种反省各种彻悟
  14. android 多线程间通信,android实现线程间通信的四种常见方式
  15. java 8 lambda 表达式的优缺点总结
  16. HTML中body相关标签-03
  17. 5V升压12.6V芯片电路图,三节锂电池充电
  18. 我的世界java放大化是什么_我的世界:大神们为什么都喜欢“放大化”世界?...
  19. 51单片机入门——定时器与外部中断
  20. 《数据结构》(C++)之第一章:绪论

热门文章

  1. hadoop管理命令——fsck
  2. Scrapy中文乱码
  3. 基于XML操作辅助类
  4. java 数组 存储_Java-将数组存储到内存或从内存上传到磁盘
  5. matlab神经网络不常见问题
  6. Linux学习笔记 -- 定时任务调度/磁盘分区与挂载
  7. python采用函数式编程模式-浅谈Python 函数式编程
  8. 跨设备链路聚合_企业核心经常用到的链路聚合技术,原理与实现
  9. 常用php操作redis命令整理(五)ZSET类型
  10. jQuery 的 ajax