基于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: 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客户端实现相关推荐
- rtsp协议_Chromium(3/5):rtsp客户端
streamUsingTCP.rtsp协议要传的数据可分为两种,一是用于管理rtsp会话的消息,像DESCRIBE.SETUP.PLAY,它们一定通过TCP,端口号像554.第二种是媒体数据,像视频. ...
- docwizard c++程序文档自动生成工具_如何开发一个基于 TypeScript 的工具库并自动生成文档
为什么用 TypeScript? TypeScript is a typed superset of JavaScript that compiles to plain JavaScript. Any ...
- Boost:基于Boost的HTTP客户端的程序
Boost:基于Boost的HTTP客户端的程序 实现功能 C++实现代码 实现功能 基于Boost的HTTP客户端的程序 C++实现代码 #include <iostream> #inc ...
- RTSP客户端模拟器(TCP方式,Python实现)
由于某种需求,工作中需要自己要开发RTSP客户端模拟器--这里以DarwinStreamingServer(简称DSS)为例进行演示,把思路记录下来,算是开发了一个测试工具,也方便我以后查阅.在我之前 ...
- socket java 客户端_Java基于socket实现的客户端和服务端通信功能完整实例
本文实例讲述了Java基于socket实现的客户端和服务端通信功能.分享给大家供大家参考,具体如下: 以下代码参考马士兵的聊天项目,先运行ChatServer.java实现端口监听,然后再运行Chat ...
- TypeScript算法专题 - blog1.基于TypeScript语言的单链表实现
TypeScript算法专题 - 基于TypeScript语言的单链表实现 李俊才 CSDN:jcLee95 邮箱:291148484@163.com 专题目录:https://blog.csdn.n ...
- 基于FFmpeg接收RTSP的ts流
RTSP用于建立的控制媒体流的传输,通过wireshark抓包可以看到rtsp消息交互的过程: 1. 第一步:查询服务器端可用方法 C->S:OPTION request // 询问S有 ...
- egret与php相连,JavaScript_Mac OS X 系统下安装和部署Egret引擎开发环境, 概述
Egret基于TypeScript开 - phpStudy...
Mac OS X 系统下安装和部署Egret引擎开发环境 概述 Egret基于TypeScript开发的,而TypeScript编译工具tsc是基于Node.js开发的.所以在安装过程中,我们先需要对 ...
- 《基于Android微博整合客户端的设计与实现》毕业设计论文任务书
华 南 理 工 大 学 广 州 学 院 毕 业 设 计 (论文) 任 务 书 兹发给计算机科学与技术专业 1班学生巫文杰毕业设计(论文)任务书,内容如下: 1.毕业设计(论文)题目:基于Android ...
最新文章
- Ruby DSL介绍及其在测试数据构造中的使用(2)
- 学习进度条--第七周
- Java双刃剑之Unsafe类详解
- dubbo 消费者也要暴露端口吗_一文详细解读 Dubbo 中的 http 协议
- Qt图形界面编程入门(7)
- angular2+typescript在asp.net MVC Web项目上的实现
- Mac操作指南:废纸篓里的文件无法清除如何解决?
- mysql有rollup函数,Mysql,Oracle使用rollup函数完成行列统计
- 面向对象课程 第三次博客总结
- CHROME扩展开发文档之·chrome.runtime
- 安全红蓝对抗反制(反捕、画像)
- 转载大牛对Microsoft的认识
- 清华差生10年奋斗经历:各种反省各种彻悟
- android 多线程间通信,android实现线程间通信的四种常见方式
- java 8 lambda 表达式的优缺点总结
- HTML中body相关标签-03
- 5V升压12.6V芯片电路图,三节锂电池充电
- 我的世界java放大化是什么_我的世界:大神们为什么都喜欢“放大化”世界?...
- 51单片机入门——定时器与外部中断
- 《数据结构》(C++)之第一章:绪论