rtsp学习----海康RTSP客户端连接深入分析

摘要:
554/MPEG-4/ch2/main/av_Stream](3)几秒钟后单击停止播放:554/MPEG4/ch2/main/av_Stream/trackID=1RTSP/1.0RTSP【S4】回复:554/MPEG-4/ch2/main/av_Stream/trackID=2RTSP/1.0RTS【S5】回复:

转载于:http://blog.csdn.net/zhouyongku/article/details/41546789

海康相机RTSP连接代码分析

最近在做海康相机rtsp连接获取音视频的工作,现在介绍一下分析过程和源码。

【源码在我上传的共享资料中:http://download.csdn.net/detail/zhouyongku/8203521

   一、基本原理

 RTSP客户端去连接服务器的最基本步骤如下:   

(1)分析url中的端口号,创建一个与服务器[S-PORT]端口号的TCP连接用于RTSP命令交互 (2)执行RTSP命令请求,告诉服务器可以连接到本地的端口[C-PORT]进行数据发送 (3)客户端从本地[C-PORT]读取数据

rtsp学习----海康RTSP客户端连接深入分析第1张

  

   二、研究步骤

 来研究一下海康相机的RTSP数据是怎么交互的

(1)打开Wireshark,选择"抓包"->"网络接口"->选择网卡->“开始”,在"过滤“栏输入"rtsp",屏蔽不相关信息。

 

rtsp学习----海康RTSP客户端连接深入分析第2张

(2)打开VLC播放器,输入海康相机RTSP地址

例如:【rtsp://admin:12345@192.168.1.145:554/MPEG-4/ch2/main/av_stream】

rtsp学习----海康RTSP客户端连接深入分析第3张

rtsp学习----海康RTSP客户端连接深入分析第4张

(3)播放几秒后再点击停止播放,退出VLC播放器。 (4)分析Wireshark数据

rtsp学习----海康RTSP客户端连接深入分析第5张

三、RTSP协议过程分析

1、RTSP协议梗概

就这几个简单的交互命令就能实现RTSP对接,C代表Client S代表Server

        例如:C1-客户端发的第一个命令 S1-服务器响应的第一个回复

【C1】OPTIONS rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream RTSP/1.0RTSP

【S1】Reply: RTSP/1.0 200 OKRTSP 【C2】DESCRIBE rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream RTSP/1.0RTSP 【S2】Reply: RTSP/1.0 401 Unauthorized RTSP 【C3】DESCRIBE rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream RTSP/1.0RTSP 【S3】Reply: RTSP/1.0 200 OK, with session descriptionRTSP/SDP 【C4】SETUP rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/trackID=1 RTSP/1.0RTSP 【S4】Reply: RTSP/1.0 200 OK RTSP 【C5】SETUP rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/trackID=2 RTSP/1.0RTSP 【S5】Reply: RTSP/1.0 200 OK RTSP 【C6】PLAY rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/ RTSP/1.0RTSP 【S6】Reply: RTSP/1.0 200 OK RTSP 【C7】GET_PARAMETER rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/ RTSP/1.0RTSP 【S7】Reply: RTSP/1.0 200 OK RTSP 【C8】TEARDOWN rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/ RTSP/1.0RTSP 【S8】Reply: RTSP/1.0 200 OK RTSP

2、请求OPTION

【C1-OPTION】

 Request: OPTIONS rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream RTSP/1.0
CSeq: 2
User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21)

询问RTSP服务器有哪些命令可以使用

【S1-REPLY】

Response: RTSP/1.0 200 OK
CSeq: 2
Public: OPTIONS, DESCRIBE, PLAY, PAUSE, SETUP, TEARDOWN, SET_PARAMETER, GET_PARAMETER
Date:  Thu, Nov 27 2014 11:59:41 GMT  

服务器回应客户端的请求。这个回应第一行为OK,则表明服务器接受查询命令,并且反馈给客户端信息,可以使用的命令有:OPTIONS, DESCRIBE, PLAY, PAUSE, SETUP, TEARDOWN, SET_PARAMETER, GET_PARAMETER,则下一步就可以向服务器发送这些命令,如果没有,则服务器不接收这些命令。

3、无验证请求资源描述DESCRIBE

【C2-DESCRIBE】

  Request: DESCRIBE rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream RTSP/1.0
  CSeq: 3
  User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21)

 Accept: application/sdp

 

请求RTSP服务器描述自身有哪些音视频资源

【S2-REPLY】

Response: RTSP/1.0 401 Unauthorized CSeq: 3 WWW-Authenticate: Digest realm="4419b727ab09", nonce="66bb9f0bf5ac93a909ac8e88877ae727", stale="FALSE" WWW-Authenticate: Basic realm="4419b727ab09"

Date:  Thu, Nov 27 2014 11:59:41 GMT

服务器回应客户端的请求。第一行为Unauthorized,表明认证不成功服务器拒绝给出拥有的资源,因此我们需要再次发送认证的请求到服务器,则服务器才能给出拥有的资源

4、认证请求资源描述DESCRIBE

【C3-DESCRIBE】

Request: DESCRIBE rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream RTSP/1.0
CSeq: 4
Authorization: Digest username="admin", realm="4419b727ab09", nonce="66bb9f0bf5ac93a909ac8e88877ae727", uri="rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream", response="108084646408d21aa255664781c886fc"
User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21)
Accept: application/sdp
发送具有认证标识的信息到服务器,去获取服务器的资源列表。怎样的格式算正确认证的信息?这个关键在于response字段。[S2-REPLY]中反馈了两个信息realm="4419b727ab09", nonce="66bb9f0bf5ac93a909ac8e88877ae727",

**************************************response区域的计算规则如下***********************************

(1)当password为MD5编码,则
response = md5(<password>:<nonce>:md5(<cmd>:<url>));
(2)当password为ANSI字符串,则
response = md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<uri>));

***********************************************************************************************************

其中 password=密码,nonce=服务器返回的nonce,cmd=当前命令(DESCRIBE、SETUP等),realm=服务器返回的reaml,uri=请求的uri地址.当服务器接收到response为108084646408d21aa255664781c886fc的时候,服务器也会用这一套公式去计算,当发现计算出的值与客户端提供的值吻合的时候,则表明用户名和密码校验成功

  1. void RtspRequest::SendRegisterRequest(string requestType)  
  2. {  
  3.     string requestCmd;  
  4.     char cseq[256];  
  5.     char session[256];  
  6.     char author[500] = { 0 };  
  7.     char acc[200] = { 0 };  
  8.     char szInput[200] = { "" };  
  9.     char szOutput[200] = { 0 };  
  10.     char szMd5Pwd[200] = { 0 };  
  11.     char szmd5methorduri[200] = { 0 };  
  12.       
  13.     m_CSeq++;  
  14.   
  15.     if (m_SetupName.length())  
  16.     {  
  17.         requestCmd = requestType;  
  18.         requestCmd += " ";  
  19.         requestCmd += m_RequestsMrl;  
  20.         requestCmd += "/";  
  21.         requestCmd += m_SetupName;  
  22.         requestCmd += " RTSP/1.0";  
  23.   
  24.         m_SetupName = "";  
  25.     }  
  26.     else  
  27.     {  
  28.         requestCmd = requestType;  
  29.         requestCmd += " ";  
  30.         requestCmd += m_RequestsMrl;  
  31.         requestCmd += " RTSP/1.0";  
  32.     }  
  33.   
  34.   
  35.     //当password为ANSI字符串 response = md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<uri>));  
  36.       
  37.     //md5(<username>:<realm>:<password>)=md5(admin:4419b727ab09:12345)=fa47d934c754db5ebebd9b42a4412073  
  38.     sprintf_s(szInput, 200, "%s:%s:%s", m_uername.c_str(), m_realm.c_str(), m_password.c_str());  
  39.     md5_hash(szInput, strlen(szInput), szMd5Pwd);  
  40.       
  41.     //md5(<cmd>:<uri>)=md5(DESCRIBE:rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream) =0b0a4e77e852876bdfdf6ecb72ba3900  
  42.     sprintf_s(szInput, 200, "DESCRIBE:%s", m_RequestsMrl.c_str());  
  43.     md5_hash(szInput, strlen(szInput), szmd5methorduri);  
  44.       
  45.     //md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<uri>));  
  46.     //=md5(fa47d934c754db5ebebd9b42a4412073:66bb9f0bf5ac93a909ac8e88877ae727:0b0a4e77e852876bdfdf6ecb72ba3900)=108084646408d21aa255664781c886fc  
  47.     //关于这一条,http://www.3464.com/Tools/MD5/index.asp 网站给出的结论则不一致:98f90a583e5c436f83da956c9b00767b   
void RtspRequest::SendRegisterRequest(string requestType)
{
	string requestCmd;
	char cseq[256];
	char session[256];
	char author[500] = { 0 };
	char acc[200] = { 0 };
	char szInput[200] = { "" };
	char szOutput[200] = { 0 };
	char szMd5Pwd[200] = { 0 };
	char szmd5methorduri[200] = { 0 };
	
	m_CSeq++;

	if (m_SetupName.length())
	{
		requestCmd = requestType;
		requestCmd += " ";
		requestCmd += m_RequestsMrl;
		requestCmd += "/";
		requestCmd += m_SetupName;
		requestCmd += " RTSP/1.0";

		m_SetupName = "";
	}
	else
	{
		requestCmd = requestType;
		requestCmd += " ";
		requestCmd += m_RequestsMrl;
		requestCmd += " RTSP/1.0";
	}


	//当password为ANSI字符串 response = md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<uri>));
	
	//md5(<username>:<realm>:<password>)=md5(admin:4419b727ab09:12345)=fa47d934c754db5ebebd9b42a4412073
	sprintf_s(szInput, 200, "%s:%s:%s", m_uername.c_str(), m_realm.c_str(), m_password.c_str());
	md5_hash(szInput, strlen(szInput), szMd5Pwd);
	
	//md5(<cmd>:<uri>)=md5(DESCRIBE:rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream) =0b0a4e77e852876bdfdf6ecb72ba3900
	sprintf_s(szInput, 200, "DESCRIBE:%s", m_RequestsMrl.c_str());
	md5_hash(szInput, strlen(szInput), szmd5methorduri);
	
	//md5(md5(<username>:<realm>:<password>):<nonce>:md5(<cmd>:<uri>));
	//=md5(fa47d934c754db5ebebd9b42a4412073:66bb9f0bf5ac93a909ac8e88877ae727:0b0a4e77e852876bdfdf6ecb72ba3900)=108084646408d21aa255664781c886fc
	//关于这一条,http://www.3464.com/Tools/MD5/index.asp 网站给出的结论则不一致:98f90a583e5c436f83da956c9b00767b 
  1. <span style="white-space:pre">    </span>//我的代码给出的值与VLC和其它工具给出的值完全匹配  
  2.     sprintf_s(szInput, 200, "%s:%s:%s", szMd5Pwd, m_nonce.c_str(), szmd5methorduri);  
  3.     md5_hash(szInput, strlen(szInput), szOutput);  
  4.     m_response = szOutput;  
  5.   
  6.     _snprintf(cseq, 256, "CSeq: %u", m_CSeq);  
  7.     _snprintf(author, 500, "Authorization: Digest username="%s", realm="%s", nonce="%s", uri="%s", response="%s"",  
  8.         m_uername.c_str(), m_realm.c_str(), m_nonce.c_str(), m_RequestsMrl.c_str(), m_response.c_str());  
  9.     _snprintf(acc, 500, "Accept: application/sdp");  
  10.   
  11.     if (requestType.compare("TEARDOWN") == 0)  
  12.         m_Session = 0;  
  13.     _snprintf(session, 256, "Session: %I64u", m_Session);  
  14.   
  15.     Write(requestCmd.c_str());  
  16.     Write(cseq);  
  17.     Write(author);  
  18.     Write("User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21)");  
  19.     Write(acc);  
  20.     if (m_Session > 0)  
  21.         Write(session);  
  22.   
  23.     WriteFields();  
  24.     Write("");  
  25. }  
<span style="white-space:pre">	</span>//我的代码给出的值与VLC和其它工具给出的值完全匹配
	sprintf_s(szInput, 200, "%s:%s:%s", szMd5Pwd, m_nonce.c_str(), szmd5methorduri);
	md5_hash(szInput, strlen(szInput), szOutput);
	m_response = szOutput;

	_snprintf(cseq, 256, "CSeq: %u", m_CSeq);
	_snprintf(author, 500, "Authorization: Digest username="%s", realm="%s", nonce="%s", uri="%s", response="%s"",
		m_uername.c_str(), m_realm.c_str(), m_nonce.c_str(), m_RequestsMrl.c_str(), m_response.c_str());
	_snprintf(acc, 500, "Accept: application/sdp");

	if (requestType.compare("TEARDOWN") == 0)
		m_Session = 0;
	_snprintf(session, 256, "Session: %I64u", m_Session);

	Write(requestCmd.c_str());
	Write(cseq);
	Write(author);
	Write("User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21)");
	Write(acc);
	if (m_Session > 0)
		Write(session);

	WriteFields();
	Write("");
}

【S3-REPLY】

Response: RTSP/1.0 200 OK
CSeq: 4
Content-type: application/sdp
Content-Base: rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/
Content-length: 672
Session Description Protocol
Session Description Protocol Version (v): 0
Owner/Creator, Session Id (o): - 1417089581269778 1417089581269778 IN IP4 192.168.1.145
Session Name (s): Media Presentation
E-mail Address (e): NONE
Bandwidth Information (b): AS:5100
Time Description, active time (t): 0 0
Session Attribute (a): control:rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/
Media Description, name and address (m): video 0 RTP/AVP 96
Bandwidth Information (b): AS:5000
Media Attribute (a): control:rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/trackID=1
Media Attribute (a): rtpmap:96 H264/90000
Media Attribute (a): fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z0KAH4iLUCgC3QgAADhAAAr8gCA=,aM44gA==
Media Description, name and address (m): audio 0 RTP/AVP 0
Bandwidth Information (b): AS:50
Media Attribute (a): control:rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/trackID=2
Media Attribute (a): rtpmap:0 PCMU/8000
Media Attribute (a): Media_header:MEDIAINFO=494D4B48010100000400010010710110401F000000FA000000000000000000000000000000000000;
Media Attribute (a): appversion:1.0
首先第一行给了OK,表明上一个命令成功--DESCRIBE成功得到服务器认证
其次,给出了服务器的媒体信息-具有两路码流--音频(audio)和视频(video) 并给出了请求两路数据的地址


5、请求视频资源

【C4-SETUP】

Request: SETUP rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/trackID=1 RTSP/1.0
CSeq: 5
Authorization: Digest username="admin", realm="4419b727ab09", nonce="66bb9f0bf5ac93a909ac8e88877ae727", uri="rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/", response="dfd7cfc85819d15d622e4491ad12217d"
User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21)
Transport: RTP/AVP;unicast;client_port=56732-56733

请求获取流媒体服务器上的视频资源 并告知服务器可以往客户端56732端口发送视频数据,56733为RTCP接收端口,发送方式为单播。传输方式为UDP 

**********************传输方式与Transport string的对应关系**********************

UDP传输:Transport:RTP/AVP

TCP传输:Transport:RTP/AVP/TCP

RAW UDP传输:Transport:RAW/RAW/UDP

****************************************************************************************

【S4-REPLY】

Response: RTSP/1.0 200 OK
CSeq: 5
Session: 1350856257;timeout=60
Transport: RTP/AVP;unicast;client_port=56732-56733;server_port=8208-8209;ssrc=4a3a67d5;mode="play"
Date:  Thu, Nov 27 2014 11:59:41 GMT

服务器同意发送视频数据给客户端 56732为视频接收端,56733为RTCP接收端口,发送方式为单播。传输方式为UDP 

6、请求音频资源

【C5-SETUP】

Request: SETUP rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/trackID=2 RTSP/1.0
CSeq: 6
Authorization: Digest username="admin", realm="4419b727ab09", nonce="66bb9f0bf5ac93a909ac8e88877ae727", uri="rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/", response="dfd7cfc85819d15d622e4491ad12217d"
User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21)
Transport: RTP/AVP;unicast;client_port=56734-56735
Session: 1350856257

请求获取服务器上的音频资源 并告知服务器可以往客户端56734端口发送视频数据,56735为RTCP接收端口,发送方式为单播。传输方式为UDP 

【S5-REPLY】

Response: RTSP/1.0 200 OK
CSeq: 6
Session: 1350856257;timeout=60
Transport: RTP/AVP;unicast;client_port=56734-56735;server_port=8226-8227;ssrc=232306b5;mode="play"
Date:  Thu, Nov 27 2014 11:59:41 GMT

服务器同意发送音频数据给客户端 56734为视频接收端,56735为RTCP接收端口,发送方式为单播。传输方式为UDP 

7、开始数据接收

【C6-PLAY】

Request: PLAY rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/ RTSP/1.0
CSeq: 7
Authorization: Digest username="admin", realm="4419b727ab09", nonce="66bb9f0bf5ac93a909ac8e88877ae727", uri="rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/", response="4c4e89a5894d2b208489fde1aeaf9e44"
User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21)
Session: 1350856257
Range: npt=0.000-

告知服务器一切准备就绪,数据可以发过来了!come on baby!

【S6-REPLY】

Response: RTSP/1.0 200 OK
CSeq: 7
Session: 1350856257
RTP-Info: url=rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/trackID=1;seq=31283;rtptime=1712470431,url=rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/trackID=2;seq=3370;rtptime=1846536290
Date:  Thu, Nov 27 2014 11:59:41 GMT

服务器告知客户端,朋友我已经送数据过来了,你可以接收了!
这个时候我们打开Wireshark,在过滤栏输入rtp,可以看到如下数据,表明服务器已经向客户端的56732、56734端口发送数据
rtsp学习----海康RTSP客户端连接深入分析第6张

RTP拆包到图像显示和音频播放,会在我的下一篇博客中详细解释

8、关闭播放

【C7-TEARDOWN】

Request: TEARDOWN rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/ RTSP/1.0
Method: TEARDOWN
URL: rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/
CSeq: 9
Authorization: Digest username="admin", realm="4419b727ab09", nonce="66bb9f0bf5ac93a909ac8e88877ae727", uri="rtsp://192.168.1.145:554/MPEG-4/ch2/main/av_stream/", response="af15346442151a51f1478da1858778d5"
User-Agent: LibVLC/2.1.3 (LIVE555 Streaming Media v2014.01.21)
Session: 1350856257

关闭数据传输 释放服务器资源 如果需要重新获取码流 则需要从1~6再来一次

【S7-REPLY】

Response: RTSP/1.0 200 OK
Status: 200
CSeq: 9
Session: 1350856257
Date:  Thu, Nov 27 2014 11:59:42 GMT

 服务器已经成功关闭当前链接

本文引用:http://blog.163.com/seek_for/blog/static/1116353920116154386537/

免责声明:文章转载自《rtsp学习----海康RTSP客户端连接深入分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇iOS UIBezierPath简单实用用node.js(socket.io)实现数据实时推送下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

第五课:部署Ingress服务

14 部署Ingress (master01) 服务反向代理 部署Traefik 2.0版本 14.1 创建traefik-crd.yaml文件 全局生效,不局限于ns,定义kind类型,用于ingress-route.yaml里的kind使用。 mkdir /root/traefik && cd /root/traefik cat >...

Linux 安装 docker 后的步骤

预计阅读时间: 16分钟 本节包含用于配置 Linux 主机以使其与 Docker 配合使用的可选过程。 以非 root 用户管理 Docker Docker 守护程序绑定到 Unix 套接字而不是 TCP 端口。默认情况下, Unix 套接字由用户拥有 root ,其他用户只能使用来访问它 sudo 。 Docker 守护程序始终以 root 用户身份运...

memcached-tool 工具

perl memcached-tool server_ip:port stats   输出说明: pid memcache服务器的进程ID uptime 服务器已经运行的秒数 time 服务器当前的unix时间戳 version  memcache 版本 pointer_size  当前操作系统的指针大小(32位系统一般是32bit...

集群Cluster介绍

来源:http://www.ibm.com/developerworks/cn/linux/cluster/lw-clustering.html简单的说,集群(cluster)就是一组计算机,它们作为一个整体向用户提供一组网络资源。这些单个的计算机系统就是集群的节点(node)。一个理想的集群是,用户从来不会意识到集群系统底层的节点,在他/她们看来,集群是一...

LINUX下简单的编译和使用动态链接库[compile .so use c++ in linux]

对动态链接库的概念其实还很模糊,自己的理解是:把一些常用的代码,如函数,类等,编译成一个"包"即DLL(WINDOWS下)或者SO(LINUX下)文件,然后供其它程序使用时直接调用里面封闭的函数即可,实现的代码的重用,也节省了硬盘空间(这点可能是次要的吧).在WIDOWS下利用VC++可方便的生成DLL,在LINUX下则需要通过各种编译命令来实现,对于像我...

Java分布式锁的三种实现方案(redis)

方案一:数据库乐观锁 乐观锁通常实现基于数据版本(version)的记录机制实现的,比如有一张红包表(t_bonus),有一个字段(left_count)记录礼物的剩余个数,用户每领取一个奖品,对应的left_count减1,在并发的情况下如何要保证left_count不为负数,乐观锁的实现方式为在红包表上添加一个版本号字段(version),默认为0。...