前言:

网上对于RTSP协议客户端的表述和实现非常不清晰,在实际使用中,FFMPEG和live555这些软件已经实现了RTSP客户端和服务端的所有功能,但是它们并没有将RTSP协议独立出来,通过看live555或是FFMPEG这些第三方库的源码来学习rtsp协议还是非常吃力。这里根据协议自己现实一个RTSP客户端程序,以便可以更好的应用RTSP协议。系列博客包括:

《ONVIF网络摄像头(IPC)客户端开发—ONVIF介绍》

《ONVIF网络摄像头(IPC)客户端开发—最简RTSP客户端实现》

《ONVIF网络摄像头(IPC)客户端开发—RTSP RTCP RTP加载H264视频流》

《ONVIF网络摄像头(IPC)客户端开发—RTSP RTCP RTP加载AAC音频流》

说明:

(1)大华IPC作为RTSP服务端

(2)在ubuntu16.04中编译实现RTSP客户端

(3)服务端IP: 192.168.1.120

(4)客户端IP: 192.168.1.112

RTSP协议:

RTSP是一个实时传输流协议,是一个应用层的协议。通常说的RTSP包括RTSP协议、RTP协议、RTCP协议。对于这些协议的作用简单的理解如下:

  • RTSP:负责服务器与客户端之间的请求与响应
  • RTP: 负责传输媒体数据
  • RTCP:在RTP传输过程中提供传输信息

rtsp承载在rtp和rtcp之上,rtsp并不会发送媒体数据,而是使用rtp协议传输,rtp并没有规定发送方式,可以选择udp发送或者tcp发送。

1. RTSP数据格式:

RTSP的交互过程就是客户端请求,服务端相应,协议格式与HTTP协议类似。

(1.1)RTSP客户端的请求格式:

  1. method url vesion\r\n
  2. CSeq: x\r\n
  3. xxx\r\n
  4. ...
  5. \r\n
  • method:方法,表明这次请求的方法,rtsp定义了很多方法,稍后介绍
  • url:格式一般为rtsp://ip:port/session,ip表主机ip,port表端口好,如果不写那么就是默认端口,rtsp的默认端口为554,session表明请求哪一个会话
  • version:表示rtsp的版本,现在为RTSP/1.0
  • CSeq:序列号,每个RTSP请求和响应都对应一个序列号,序列号是递增的

(1.2)RTSP服务端响应格式

  1. vesion 200 OK\r\n
  2. CSeq: x\r\n
  3. xxx\r\n
  4. ...
  5. \r\n
  • version:表示rtsp的版本,现在为RTSP/1.0
  • CSeq:序列号,这个必须与对应请求的序列号相同

2.RTSP请求的常用方法

  1. 方法 描述
  2. OPTIONS 获取服务端提供的可用方法
  3. DESCRIBE向服务端获取对应会话的媒体描述信息
  4. SETUP  向服务端发起建立请求,建立连接会话
  5. PLAY 向服务端发起播放请求
  6. TEARDOWN向服务端发起关闭连接会话请求

3.交互过程实例

使用Wireshark抓包工具抓取一个实际RTSP会话过程的数据流,使用ip.addr==192.168.1.120 && rtsp过滤RTSP协议内容,数据如下:

  1. OPTIONS rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
  2. CSeq: 1
  3. User-Agent: Caibiao_Lee
  4. RTSP/1.0 401 Unauthorized
  5. CSeq: 1
  6. WWW-Authenticate: Digest realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e"
  7. OPTIONS rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
  8. CSeq: 2
  9. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e",uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif",response="59a6120145ee2c5adad4552f20a3bad2"
  10. RTSP/1.0 200 OK
  11. CSeq: 2
  12. Public: OPTIONS, DESCRIBE, ANNOUNCE, SETUP, PLAY, PAUSE, TEARDOWN, GET_PARAMETER, SET_PARAMETER, REDIRECT, RECORD
  13. Server: Rtsp Server/3.0
  14. DESCRIBE rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
  15. CSeq: 3
  16. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e",uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif",response="0fefc97b4a497566ce815e2f9f48ff4a"
  17. User-Agent: Caibiao_Lee
  18. Accept: application/sdp
  19. RTSP/1.0 200 OK
  20. CSeq: 3
  21. Content-Base: rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/
  22. Content-Type: application/sdp
  23. x-Accept-Dynamic-Rate: 1
  24. Cache-Control: must-revalidate
  25. Content-Length: 566
  26. v=0
  27. o=- 2229913047 2229913047 IN IP4 0.0.0.0
  28. s=Media Server
  29. c=IN IP4 0.0.0.0
  30. t=0 0
  31. a=control:*
  32. a=packetization-supported:DH
  33. a=rtppayload-supported:DH
  34. a=range:npt=now-
  35. m=video 0 RTP/AVP 96
  36. a=control:trackID=0
  37. a=framerate:25.000000
  38. a=rtpmap:96 H264/90000
  39. a=fmtp:96 packetization-mode=1;profile-level-id=64002A;sprop-parameter-sets=Z2QAKqwsaoHgCJ+WbgICAgQA,aO48sAA=
  40. a=recvonly
  41. m=audio 0 RTP/AVP 8
  42. a=control:trackID=1
  43. a=rtpmap:8 PCMA/8000
  44. a=recvonly
  45. m=application 0 RTP/AVP 107
  46. a=control:trackID=4
  47. a=rtpmap:107 vnd.onvif.metadata/90000
  48. a=recvonly
  49. SETUP rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/trackID=0 RTSP/1.0
  50. CSeq: 4
  51. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e",uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif",response="c650887dd112d10e0a868510d64088f6"
  52. User-Agent: Caibiao_Lee
  53. Transport:RTP/AVP;unicast;client_port=32766-32767
  54. RTSP/1.0 200 OK
  55. CSeq: 4
  56. Session: 2666913996
  57. Transport: RTP/AVP;unicast;client_port=32766-32767;server_port=2000-2001;ssrc=d6198a00
  58. x-Dynamic-Rate: 1
  59. PLAY rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/ RTSP/1.0
  60. CSeq: 5
  61. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D", nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e", uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif", response="bc9b1026a0ce64b963da457d4e87b6a5"
  62. User-Agent: Caibiao_Lee
  63. Session: 2666913996
  64. Range: npt=0.000-
  65. RTSP/1.0 200 OK
  66. CSeq: 5
  67. Session: 2666913996
  68. Range: npt=0.000-
  69. RTP-Info: url=trackID=0;seq=1;rtptime=0
  70. TEARDOWN rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/ RTSP/1.0
  71. CSeq: 6
  72. User-Agent: Caibiao_Lee
  73. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e",uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif",response="68f5346f3fea36b7c69be9e8184abc5b"
  74. User-Agent: Caibiao_Lee
  75. Session: 2666913996
  76. RTSP/1.0 200 OK
  77. CSeq: 6
  78. Session: 2666913996

3.1SDP格式分析

sdp格式由多行的type=value组成

sdp会话描述由一个会话级描述和多个媒体级描述组成。会话级描述的作用域是整个会话,媒体级描述描述的是一个视频流或者音频流

会话级描述由v=开始到第一个媒体级描述结束

媒体级描述由m=开始到下一个媒体级描述结束

SDP的具体格式网上有很多,这里不做具体分析。

代码实现:

使用C语言实现RTSP客户端对服务端的请求的功能,实现代码如下:

  1. /************************************************************
  2. *Copyright (C),lcb0281at163.com lcb0281atgmail.com
  3. *FileName: rtsp_client.c
  4. *BlogAddr: https://blog.csdn.net/li_wen01
  5. *Description: RTSP 协议
  6. *Date: 2019-06-22
  7. *Author: Caibiao Lee
  8. *Version: V1.0
  9. *Others:
  10. *History:
  11. ***********************************************************/
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <unistd.h>
  15. #include <fcntl.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include "rtsp_client.h"
  19. #define BUF_LEN_1024_BYTE 1024
  20. #define RTSP_DEFAULT_PORT 554
  21. static int gs_s32CseqCount = 1;
  22. static unsigned short IPC_RTSP_GetPort(const char *const ps8Rtsp)
  23. {
  24. char l_as8RTSP[128] = {0};
  25. char *l_ps8Buf = NULL;
  26. int i =0;
  27. unsigned int l_u16RtspPort = 0;
  28. if(NULL == ps8Rtsp)
  29. {
  30. printf("[%s,%d] psTIPCDEV is NULL error\n ",__FILE__,__LINE__);
  31. return 0;
  32. }
  33. memcpy(l_as8RTSP,ps8Rtsp,strlen(ps8Rtsp));
  34. printf("[%s,%d]l_ps8Buf=%s\n",__FUNCTION__,__LINE__,l_as8RTSP);
  35. l_ps8Buf = strtok(l_as8RTSP,"//");
  36. printf("[%s,%d]l_ps8Buf=%s\n",__FUNCTION__,__LINE__,l_ps8Buf);
  37. if(NULL != l_ps8Buf)
  38. {
  39. l_ps8Buf = strtok(NULL,":");
  40. }
  41. if(NULL != l_ps8Buf)
  42. {
  43. l_ps8Buf = strtok(NULL,"/");
  44. }
  45. if(NULL != l_ps8Buf)
  46. {
  47. for(i = 0;i < 6 && l_ps8Buf[i] - '0' >= 0 && l_ps8Buf[i] - '0' <= 9;i++)
  48. {
  49. l_u16RtspPort *= 10;
  50. l_u16RtspPort += l_ps8Buf[i] - '0';
  51. }
  52. }
  53. return l_u16RtspPort;
  54. }
  55. static int IPC_RTSP_RecvSelect(int s32RtspFd,char *ps8buf,int s32Len)
  56. {
  57. int l_s32Ret;
  58. fd_set l_s4Fdset;
  59. struct timeval l_stTimeout;
  60. FD_ZERO(&l_s4Fdset);
  61. FD_SET(s32RtspFd,&l_s4Fdset);
  62. l_stTimeout.tv_sec = 2;
  63. l_stTimeout.tv_usec = 0;
  64. l_s32Ret = select(s32RtspFd + 1,&l_s4Fdset,NULL,NULL,&l_stTimeout);
  65. if(l_s32Ret < 0)
  66. {
  67. printf("[%s,%d]slect error\n",__FUNCTION__,__LINE__);
  68. }
  69. else if(0 == l_s32Ret)
  70. {
  71. printf("[%s,%d] slect timeout\n",__FUNCTION__,__LINE__);
  72. }
  73. else
  74. {
  75. l_s32Ret = NET_SocketRecvData(s32RtspFd,ps8buf,s32Len);
  76. }
  77. return l_s32Ret;
  78. }
  79. static int IPC_RTSP_CheckReply(char *ps8buf)
  80. {
  81. char *p = NULL;
  82. p = strstr(ps8buf,"OK");
  83. if(NULL == p)
  84. {
  85. return -1;
  86. }
  87. return 0;
  88. }
  89. static int IPC_RTSP_HandleRTSPStr(RTSP_STATUS_S *pstRTSPClient)
  90. {
  91. char l_arrs8Buf[256]={0};
  92. int l_s32Len;
  93. memcpy(l_arrs8Buf,pstRTSPClient->arrs8RTSPUrl,strlen(pstRTSPClient->arrs8RTSPUrl));
  94. l_s32Len = strlen(l_arrs8Buf)-1;
  95. while(l_s32Len >20)
  96. {
  97. if(' ' == l_arrs8Buf[l_s32Len] || '&' == l_arrs8Buf[l_s32Len])
  98. {
  99. l_arrs8Buf[l_s32Len] = '\0';
  100. bzero(pstRTSPClient->arrs8RTSPUrl,strlen(pstRTSPClient->arrs8RTSPUrl));
  101. memcpy(pstRTSPClient->arrs8RTSPUrl,l_arrs8Buf,strlen(l_arrs8Buf));
  102. break;
  103. }
  104. l_s32Len--;
  105. }
  106. return 0;
  107. }
  108. static void IPC_RTSP_SDPAnalyze(RTSP_STATUS_S *pstRTSPClient,char *ps8Buf)
  109. {
  110. char *p = ps8Buf;
  111. char *tmp;
  112. int i,j;
  113. /*********************step 1:control***********************/
  114. for(i = 0;i< 3;i++)
  115. {
  116. /**取出control的内容**/
  117. p = strstr(p,"a=control:");
  118. if(NULL == p)
  119. break;
  120. /**去掉*的行继续下行检测**/
  121. if(0 == strncmp(p,"a=control:*",11))
  122. {
  123. p++;
  124. continue;
  125. }
  126. /**检测control中是否存在rtsp**/
  127. else if(NULL != (tmp = strstr(p,"rtsp")))
  128. {
  129. while('\n' != *tmp && '\r' != *tmp && '\0' != *tmp)
  130. {
  131. tmp++;
  132. }
  133. *tmp = '\0';
  134. if(NULL != strstr(p,"track"))
  135. {
  136. j=0;
  137. p+=10;
  138. bzero(pstRTSPClient->stSDPPara.arrs8RTSPUrl,sizeof(pstRTSPClient->stSDPPara.arrs8RTSPUrl));
  139. while('\n' != *p && '\r' != *p && '\0' != *p)
  140. {
  141. pstRTSPClient->arrs8RTSPUrl[j] = *(p++);
  142. j++;
  143. }
  144. pstRTSPClient->stSDPPara.arrs8Control[0]='\0';
  145. bzero(pstRTSPClient->arrs8RTSPUrl,128);
  146. memcpy(pstRTSPClient->arrs8RTSPUrl,pstRTSPClient->stSDPPara.arrs8RTSPUrl,
  147. strlen(pstRTSPClient->stSDPPara.arrs8RTSPUrl));
  148. return ;
  149. }
  150. p = tmp +1;
  151. continue;
  152. }
  153. else
  154. {
  155. j=0;
  156. p+=10;
  157. while('\n' != *p && '\r' != *p && '\0' != *p)
  158. {
  159. pstRTSPClient->stSDPPara.arrs8Control[j] = *(p++);
  160. j++;
  161. }
  162. pstRTSPClient->stSDPPara.arrs8Control[j]='\0';
  163. break;
  164. }
  165. }
  166. p = ps8Buf;
  167. /********************************step 2:rtspurl******************************/
  168. p = strstr(p,"rtsp:"); /**出去rtsp**/
  169. if(NULL != p)
  170. {
  171. tmp = p;
  172. while(NULL != p && '\r' != *p && '\n' != *p && '\0' != *p)
  173. {
  174. p++;
  175. }
  176. if(NULL != p)
  177. *p = '\0';
  178. p--;
  179. while(' ' == *p)
  180. {
  181. p--;
  182. }
  183. if('/' == *p)
  184. *p = '\0';
  185. bzero(pstRTSPClient->stSDPPara.arrs8RTSPUrl,sizeof(pstRTSPClient->stSDPPara.arrs8RTSPUrl));
  186. memcpy(pstRTSPClient->stSDPPara.arrs8RTSPUrl,tmp,strlen(tmp));
  187. }
  188. }
  189. static int IPC_RTSP_ERRHandle(RTSP_STATUS_S *pstRTSPClient,char *ps8Buf)
  190. {
  191. char *p;
  192. char *tmp;
  193. int i;
  194. if(NULL == strstr(ps8Buf,"401"))
  195. {
  196. return 0;
  197. }
  198. p = strstr(ps8Buf,"realm=");
  199. if(NULL == p)
  200. {
  201. return -1;
  202. }
  203. tmp = p+7;
  204. for(i = 0;NULL != tmp && '"' != tmp[i] && i < 32;i++)
  205. {
  206. pstRTSPClient->stSDPPara.arrs8Realm[i] = tmp[i];
  207. }
  208. p = strstr(ps8Buf,"nonce=");
  209. if(NULL == p)
  210. {
  211. return -1;
  212. }
  213. tmp = p+7;
  214. for(i = 0;NULL != tmp && '"' != tmp[i] && i < 128;i++)
  215. {
  216. pstRTSPClient->stSDPPara.arrs8Nonce[i] = tmp[i];
  217. }
  218. return 0;
  219. }
  220. static char *IPC_RTSP_StreamHandle(char *ps8Buf,int s32StreamType)
  221. {
  222. char *sub = NULL;
  223. sub = strstr(ps8Buf,"subtype=");
  224. if(NULL != sub)
  225. {
  226. if(SUBSTREAM == s32StreamType)
  227. {
  228. *(sub + 8) = '1';
  229. }
  230. else if(MAINSTREAM == s32StreamType){
  231. *(sub + 8) = '0';
  232. }
  233. return ps8Buf;
  234. }
  235. sub = strstr(ps8Buf,"stream=");
  236. if(NULL != sub)
  237. {
  238. if(SUBSTREAM == s32StreamType)
  239. {
  240. *(sub + 7) = '1';
  241. }
  242. else if(MAINSTREAM == s32StreamType){
  243. *(sub + 7) = '0';
  244. }
  245. return ps8Buf;
  246. }
  247. else if(NULL != (sub = strstr(ps8Buf,"Channels/")) || NULL != (sub = strstr(ps8Buf,"channels/")))
  248. {
  249. sub += 9;
  250. while('/' != *sub && '\0' != *sub)
  251. {
  252. sub++;
  253. }
  254. if(SUBSTREAM == s32StreamType)
  255. {
  256. *(--sub) +=1;
  257. }
  258. }
  259. else if(NULL != (sub = strstr(ps8Buf,"stream")))
  260. {
  261. if((*(sub + 6) >= '0') && (*(sub + 6) <= '9'))
  262. {
  263. if(SUBSTREAM == s32StreamType)
  264. {
  265. *(sub + 6) = '2';
  266. }
  267. else if(MAINSTREAM == s32StreamType)
  268. {
  269. *(sub + 6) = '1';
  270. }
  271. }
  272. return ps8Buf;
  273. }
  274. else if(NULL != (sub = strstr(ps8Buf,"/1/1")))
  275. {
  276. if(SUBSTREAM == s32StreamType)
  277. {
  278. sub+=3;
  279. *sub +=1;
  280. }
  281. }
  282. return ps8Buf;
  283. }
  284. static int IPC_RTSP_DESCRIBEHandle(RTSP_STATUS_S *stRTSPClient,char *ps8Buf,int s32Type)
  285. {
  286. char l_arrs8Author[32]={0};
  287. unsigned char l_arru8Response[33]={0};
  288. bzero(ps8Buf,BUF_LEN_1024_BYTE);
  289. switch(s32Type)
  290. {
  291. case 0:
  292. {
  293. sprintf(ps8Buf,"DESCRIBE %s RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nAccept: application/h264\r\n\r\n",\
  294. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount);
  295. break;
  296. }
  297. case 1:
  298. {
  299. COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,
  300. stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_arru8Response,"DESCRIBE",
  301. stRTSPClient->arrs8RTSPUrl,NULL,0);
  302. sprintf(ps8Buf,"DESCRIBE %s RTSP/1.0\r\nCSeq: %d\r\nAuthorization: Digest username=\"%s\", realm=\"%s\",nonce=\"%s\",uri=\"%s\",response=\"%s\"\r\nUser-Agent: Caibiao_Lee\r\nAccept: application/sdp\r\n\r\n",\
  303. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,\
  304. stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,l_arru8Response);
  305. break;
  306. }
  307. case 2:
  308. {
  309. sprintf(ps8Buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
  310. COM_base64_bits_to_64((unsigned char *)l_arrs8Author,(unsigned char *)ps8Buf,strlen(ps8Buf));
  311. sprintf(ps8Buf,"DESCRIBE %s RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nAccept: application/sdp\r\nAuthorization: Basic %s\r\n\r\n",\
  312. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,l_arrs8Author);
  313. break;
  314. }
  315. default:
  316. s32Type = -1;
  317. break;
  318. }
  319. return s32Type;
  320. }
  321. static int IPC_RTSP_OPTIONSHandle(RTSP_STATUS_S *stRTSPClient,char *ps8buf,int s32Type)
  322. {
  323. char l_s32Author[32] = {0};
  324. unsigned char l_s32Response[33] = {0};
  325. bzero(ps8buf,BUF_LEN_1024_BYTE);
  326. printf("s32Type = %d \n",s32Type);
  327. switch(s32Type)
  328. {
  329. case 0:
  330. {
  331. sprintf(ps8buf,"OPTIONS %s RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\n\r\n",\
  332. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount);
  333. break;
  334. }
  335. case 1:
  336. {
  337. COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,\
  338. stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_s32Response,"OPTIONS",\
  339. stRTSPClient->arrs8RTSPUrl,NULL,0);
  340. sprintf(ps8buf,"OPTIONS %s RTSP/1.0\r\nCSeq: %d\r\nAuthorization: Digest username=\"%s\", realm=\"%s\",nonce=\"%s\",uri=\"%s\",response=\"%s\"\r\n\r\n",\
  341. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,l_s32Response);
  342. break;
  343. }
  344. case 2:
  345. {
  346. sprintf(ps8buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
  347. printf("name = %s password = %s buf = %s \n",
  348. stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,ps8buf);
  349. COM_base64_bits_to_64((unsigned char *)l_s32Author,(unsigned char *)ps8buf,strlen(ps8buf));
  350. sprintf(ps8buf,"OPTIONS %s RTSP/1.0\r\nCSeq: %d\r\nAuthorization: Basic %s\r\n\r\n",stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,l_s32Author);
  351. break;
  352. }
  353. default:
  354. s32Type = -1;
  355. break;
  356. }
  357. return s32Type;
  358. }
  359. static int IPC_RTSP_TEARDOWNHandle(RTSP_STATUS_S *stRTSPClient,char *ps8Buf,int s32tmp,char *pRTSPSessionId)
  360. {
  361. char l_s32author[32] = {0};
  362. unsigned char l_arru8Response[33]={0};
  363. bzero(ps8Buf,BUF_LEN_1024_BYTE);
  364. switch(s32tmp)
  365. {
  366. case 0:
  367. {
  368. sprintf(ps8Buf,"TEARDOWN %s/ RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nSession: %s\r\nRange: npt=0.000-\r\n\r\n",stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,pRTSPSessionId);
  369. break;
  370. }
  371. case 1:
  372. {
  373. COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_arru8Response,"TEARDOWN",stRTSPClient->arrs8RTSPUrl,NULL,0);
  374. sprintf(ps8Buf,"TEARDOWN %s/ RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nAuthorization: Digest username=\"%s\", realm=\"%s\",nonce=\"%s\",uri=\"%s\",response=\"%s\"\r\nUser-Agent: Caibiao_Lee\r\nSession: %s\n\r\n",\
  375. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,\
  376. stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,\
  377. l_arru8Response,pRTSPSessionId);
  378. break;
  379. }
  380. case 2:
  381. {
  382. sprintf(ps8Buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
  383. COM_base64_bits_to_64((unsigned char *)l_s32author,(unsigned char *)ps8Buf,strlen(ps8Buf));
  384. sprintf(ps8Buf,"TEARDOWN %s/ RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nSession: %s\r\nRange: npt=0.000-\r\nAuthorization: Basic %s\r\n\r\n",
  385. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,pRTSPSessionId,l_s32author);
  386. break;
  387. }
  388. default:
  389. {
  390. printf("%s,%d,switch is default\n",__FUNCTION__,__LINE__);
  391. break;
  392. s32tmp = -1;
  393. }
  394. }
  395. return s32tmp;
  396. }
  397. static int IPC_RTSP_SETUPHandle(RTSP_STATUS_S *stRTSPClient,char *ps8Buf,int s32Type,int localport)
  398. {
  399. char l_arrs8Author[32] = {0};
  400. unsigned char l_arru8Response[33]={0};
  401. bzero(ps8Buf,BUF_LEN_1024_BYTE);
  402. switch(s32Type)
  403. {
  404. case 0:
  405. {
  406. sprintf(ps8Buf,"SETUP %s/%s RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nTransport:RTP/AVP;unicast;client_port=%d-%d\r\n\r\n",\
  407. stRTSPClient->arrs8RTSPUrl,stRTSPClient->stSDPPara.arrs8Control,\
  408. gs_s32CseqCount,localport,localport+1);
  409. break;
  410. }
  411. case 1:
  412. {
  413. COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_arru8Response,"SETUP",stRTSPClient->arrs8RTSPUrl,NULL,0);
  414. sprintf(ps8Buf,"SETUP %s/%s RTSP/1.0\r\nCSeq: %d\r\nAuthorization: Digest username=\"%s\", realm=\"%s\",nonce=\"%s\",uri=\"%s\",response=\"%s\"\r\nUser-Agent: Caibiao_Lee\r\nTransport:RTP/AVP;unicast;client_port=%d-%d\r\n\r\n",
  415. stRTSPClient->arrs8RTSPUrl,stRTSPClient->stSDPPara.arrs8Control,\
  416. gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stSDPPara.arrs8Realm,\
  417. stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,\
  418. l_arru8Response,localport,localport+1);
  419. break;
  420. }
  421. case 2:
  422. {
  423. sprintf(ps8Buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
  424. COM_base64_bits_to_64((unsigned char *)l_arrs8Author,(unsigned char *)ps8Buf,strlen(ps8Buf));
  425. sprintf(ps8Buf,"SETUP %s/%s RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nTransport:RTP/AVP;unicast;client_port=%d-%d\r\nAuthorization: Basic %s\r\n\r\n",\
  426. stRTSPClient->arrs8RTSPUrl,stRTSPClient->stSDPPara.arrs8Control,\
  427. gs_s32CseqCount,localport,localport+1,l_arrs8Author);
  428. break;
  429. }
  430. default:
  431. {
  432. s32Type = -1;
  433. break;
  434. }
  435. }
  436. return s32Type;
  437. }
  438. static int IPC_RTSP_PLAYHandle(RTSP_STATUS_S *stRTSPClient,char *ps8Buf,int s32Type,char *RTSPSessionId)
  439. {
  440. bzero(ps8Buf,BUF_LEN_1024_BYTE);
  441. char l_arrs8Author[32] = {0};
  442. unsigned char l_arru8Response[33]={0};
  443. switch(s32Type)
  444. {
  445. case 0:
  446. {
  447. sprintf(ps8Buf,"PLAY %s/ RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nSession: %s\r\nRange: npt=0.000-\r\n\r\n",\
  448. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,RTSPSessionId);
  449. break;
  450. }
  451. case 1:
  452. {
  453. COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_arru8Response,"PLAY",stRTSPClient->arrs8RTSPUrl,NULL,0);
  454. sprintf(ps8Buf,"PLAY %s/ RTSP/1.0\r\nCSeq: %d\r\nAuthorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"\r\nUser-Agent: Caibiao_Lee\r\nSession: %s\nRange: npt=0.000-\r\n\r\n",\
  455. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,\
  456. stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,\
  457. l_arru8Response,RTSPSessionId);
  458. break;
  459. }
  460. case 2:
  461. {
  462. sprintf(ps8Buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
  463. COM_base64_bits_to_64((unsigned char *)l_arrs8Author,(unsigned char *)ps8Buf,strlen(ps8Buf));
  464. sprintf(ps8Buf,"PLAY %s/ RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nSession: %s\r\nRange: npt=0.000-\r\nAuthorization: Basic %s\r\n\r\n",\
  465. stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,RTSPSessionId,l_arrs8Author);
  466. break;
  467. }
  468. default:
  469. {
  470. s32Type = -1;
  471. break;
  472. }
  473. }
  474. return s32Type;
  475. }
  476. int RTSP_Client_Init(RTSP_STATUS_S * stRTSPClient)
  477. {
  478. memset((unsigned char*)stRTSPClient,0,sizeof(RTSP_STATUS_S));
  479. stRTSPClient->bRTPState = false;
  480. return 0;
  481. }
  482. int RTSP_Client_Release(RTSP_STATUS_S * stRTSPClient)
  483. {
  484. if(NULL==stRTSPClient)
  485. {
  486. printf("%s %d input para error\n",__FUNCTION__,__LINE__);
  487. return -1;
  488. }
  489. if(stRTSPClient->s32SockFd > 0)
  490. {
  491. close(stRTSPClient->s32SockFd);
  492. stRTSPClient->s32SockFd = -1;
  493. }
  494. return 0;
  495. }
  496. int RTSP_Client_Session(RTSP_STATUS_S *stRTSPClient)
  497. {
  498. bool l_bRTSPState;
  499. unsigned short l_u16Port = 0;
  500. int l_s32Ret = 0;
  501. int l_s32RtspSockfd = -1;
  502. if(NULL==stRTSPClient)
  503. {
  504. printf("%s %d input para error\n",__FUNCTION__,__LINE__);
  505. return -1;
  506. }
  507. l_bRTSPState = stRTSPClient->bRTPState;
  508. l_s32RtspSockfd = stRTSPClient->s32SockFd;
  509. if(true==stRTSPClient->bRTPState)
  510. {
  511. printf("%s %d RTSP is already init error \n",__FUNCTION__,__LINE__);
  512. return -1;
  513. }
  514. if(l_s32RtspSockfd > 0)
  515. {
  516. close(l_s32RtspSockfd);
  517. }
  518. l_s32RtspSockfd = NET_SocketCreate(SOCK_STREAM);
  519. if(l_s32RtspSockfd < 0)
  520. {
  521. printf("%s %d:create socket is error \n",__FUNCTION__,__LINE__);
  522. return -3;
  523. }
  524. l_u16Port = IPC_RTSP_GetPort(stRTSPClient->arrs8RTSPUrl);
  525. l_u16Port = (l_u16Port>0)?(l_u16Port):(RTSP_DEFAULT_PORT);
  526. printf("RTSP Server IP=%s,ServerPort=%d \n",stRTSPClient->arrs8ServerIP,l_u16Port);
  527. l_s32Ret = NET_SocketConnect(l_s32RtspSockfd,stRTSPClient->arrs8ServerIP,l_u16Port);
  528. if(l_s32Ret < 0)
  529. {
  530. printf("%s %d :connect to Server error \n",__FUNCTION__,__LINE__);
  531. return -4;
  532. }
  533. stRTSPClient->s32SockFd = l_s32RtspSockfd;
  534. return 0;
  535. }
  536. int RTSP_Client_OPTIONS(RTSP_STATUS_S *pstRTSPClient)
  537. {
  538. int i;
  539. int l_s32Ret;
  540. int l_s32RtspSocketFd;
  541. bool l_bRTSPState;
  542. char l_arrs8Buf[BUF_LEN_1024_BYTE];
  543. if(NULL==pstRTSPClient)
  544. {
  545. printf("%s %d input para error\n",__FUNCTION__,__LINE__);
  546. return -1;
  547. }
  548. if(true==pstRTSPClient->bRTPState)
  549. {
  550. printf("%s %d RTSP is already start error \n",__FUNCTION__,__LINE__);
  551. return -1;
  552. }
  553. l_bRTSPState = pstRTSPClient->bRTPState;
  554. l_s32RtspSocketFd = pstRTSPClient->s32SockFd;
  555. pstRTSPClient->stSDPPara.s32AuthorType = 0;
  556. bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
  557. for(i=0;i< 2;i++)
  558. {
  559. IPC_RTSP_OPTIONSHandle(pstRTSPClient,l_arrs8Buf,i);
  560. l_s32Ret = NET_SocketSendData(l_s32RtspSocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
  561. if(l_s32Ret < 0)
  562. {
  563. printf("%s,%d :Send Data error \n",__FUNCTION__,__LINE__);
  564. return -2;
  565. }
  566. printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret);
  567. bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
  568. l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspSocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
  569. if(l_s32Ret <= 0)
  570. {
  571. printf("[%s %d:] RTSP recv data error \n",__FUNCTION__,__LINE__);
  572. gs_s32CseqCount++;
  573. continue;
  574. }else
  575. {
  576. printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
  577. }
  578. l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
  579. if(0 != l_s32Ret)
  580. {
  581. printf("biao debug [%s %d:] l_s32Ret = %d \n",__FUNCTION__,__LINE__,l_s32Ret);
  582. IPC_RTSP_ERRHandle(pstRTSPClient,l_arrs8Buf);
  583. gs_s32CseqCount++;
  584. continue;
  585. }else
  586. {
  587. printf("biao debug [%s %d:] recv OK \n",__FUNCTION__,__LINE__);
  588. }
  589. gs_s32CseqCount++;
  590. pstRTSPClient->stSDPPara.s32AuthorType = i;
  591. return 0;
  592. }
  593. return -1;
  594. }
  595. int RTSP_Client_DESCRIBE(RTSP_STATUS_S *pstRTSPClient)
  596. {
  597. bool l_bRTSPState;
  598. char *l_ps8Sub;
  599. char l_arrs8Buf[BUF_LEN_1024_BYTE];
  600. int i;
  601. int l_s32Ret;
  602. int l_s32RtspsocketFd;
  603. if(NULL==pstRTSPClient)
  604. {
  605. printf("%s %d input para error\n",__FUNCTION__,__LINE__);
  606. return -1;
  607. }
  608. if(true==pstRTSPClient->bRTPState)
  609. {
  610. printf("%s %d RTSP is already start error \n",__FUNCTION__,__LINE__);
  611. return -1;
  612. }
  613. l_bRTSPState = pstRTSPClient->bRTPState;
  614. l_s32RtspsocketFd = pstRTSPClient->s32SockFd;
  615. for(i=pstRTSPClient->stSDPPara.s32AuthorType;i < 2;i++)
  616. {
  617. IPC_RTSP_DESCRIBEHandle(pstRTSPClient,l_arrs8Buf,i);
  618. l_ps8Sub = COM_get_substringstart(l_arrs8Buf,"subtype=");
  619. if(NULL != l_ps8Sub)
  620. {
  621. l_ps8Sub += 8;
  622. }
  623. if(SUBSTREAM==pstRTSPClient->s32StreamType)
  624. {
  625. *l_ps8Sub = '1';
  626. }
  627. else if(MAINSTREAM== pstRTSPClient->s32StreamType)
  628. {
  629. *l_ps8Sub = '0';
  630. }
  631. l_s32Ret = NET_SocketSendData(l_s32RtspsocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
  632. if(l_s32Ret < 0)
  633. {
  634. printf("%s %d: Send Data Error \n",__FUNCTION__,__LINE__);
  635. return -2;
  636. }
  637. printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret);
  638. bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
  639. l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspsocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
  640. if(l_s32Ret <= 0)
  641. {
  642. printf("%s %d : Recv Data Error \n",__FUNCTION__,__LINE__);
  643. gs_s32CseqCount++;
  644. return -3;
  645. }else
  646. {
  647. printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
  648. }
  649. l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
  650. if(0 != l_s32Ret)
  651. {
  652. IPC_RTSP_ERRHandle(pstRTSPClient,l_arrs8Buf);
  653. gs_s32CseqCount++;
  654. return -4;
  655. }
  656. else
  657. {
  658. printf("biao debug [%s %d:] recv OK \n",__FUNCTION__,__LINE__);
  659. }
  660. IPC_RTSP_SDPAnalyze(pstRTSPClient,l_arrs8Buf);
  661. gs_s32CseqCount++;
  662. pstRTSPClient->stSDPPara.s32AuthorType = i;
  663. return 0;
  664. }
  665. return -5;
  666. }
  667. int RTSP_Client_SETUP(RTSP_STATUS_S *pstRTSPClient)
  668. {
  669. bool l_bRTSPState;
  670. char l_arrs8RTSPSessionId[16];
  671. char l_arrs8RTPPort[12];
  672. char l_arrs8Buf[BUF_LEN_1024_BYTE];
  673. char *l_ps8Sub;
  674. char l_s8Flag = ';';
  675. char l_arrs8SPFlagStr[] = "server_port=";
  676. int i;
  677. int l_s32Len;
  678. int localport;
  679. int l_s32Ret;
  680. int l_s32RtspsocketFd;
  681. char *l_ps8RTSPSessionId;
  682. if(NULL==pstRTSPClient)
  683. {
  684. printf("%s %d input para error\n",__FUNCTION__,__LINE__);
  685. return -1;
  686. }
  687. if(true==pstRTSPClient->bRTPState)
  688. {
  689. printf("%s %d RTSP is already start error \n",__FUNCTION__,__LINE__);
  690. return -1;
  691. }
  692. l_bRTSPState = pstRTSPClient->bRTPState;
  693. l_s32RtspsocketFd = pstRTSPClient->s32SockFd;
  694. l_ps8RTSPSessionId = pstRTSPClient->arrs8SessionId;
  695. for(i=pstRTSPClient->stSDPPara.s32AuthorType;i <3;i++)
  696. {
  697. IPC_RTSP_StreamHandle(pstRTSPClient->arrs8RTSPUrl,pstRTSPClient->s32StreamType);
  698. IPC_RTSP_SETUPHandle(pstRTSPClient,l_arrs8Buf,i,localport);
  699. l_s32Ret = NET_SocketSendData(l_s32RtspsocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
  700. if(l_s32Ret < 0)
  701. {
  702. printf("%s %d: Send Data Error \n",__FUNCTION__,__LINE__);
  703. return -2;
  704. }
  705. printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret);
  706. bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
  707. l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspsocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
  708. if(l_s32Ret <= 0)
  709. {
  710. printf("%s %d : Recv Data Error \n",__FUNCTION__,__LINE__);
  711. gs_s32CseqCount++;
  712. return -3;
  713. }else
  714. {
  715. printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
  716. }
  717. l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
  718. if(0 != l_s32Ret)
  719. {
  720. gs_s32CseqCount++;
  721. return -4;
  722. }
  723. else
  724. {
  725. printf("biao debug [%s %d:] recv OK \n",__FUNCTION__,__LINE__);
  726. }
  727. l_ps8Sub = COM_get_substringstart(l_arrs8Buf,"Session:");
  728. if(NULL != l_ps8Sub)
  729. {
  730. l_ps8Sub += 8;
  731. }
  732. while(NULL != l_ps8Sub && ' ' == *l_ps8Sub)
  733. {
  734. l_ps8Sub++;
  735. }
  736. bzero(l_arrs8RTSPSessionId,16);
  737. COM_get_begingstring(l_ps8Sub,l_arrs8RTSPSessionId,l_s8Flag);
  738. l_ps8Sub = COM_get_substringstart(l_arrs8Buf,l_arrs8SPFlagStr);
  739. if(NULL != l_ps8Sub)
  740. {
  741. l_ps8Sub += 12;
  742. }
  743. bzero(l_arrs8RTPPort,12);
  744. COM_get_begingstring(l_ps8Sub,l_arrs8RTPPort,'-');
  745. bzero(pstRTSPClient->arrs8SessionId,16);
  746. sprintf(pstRTSPClient->arrs8SessionId,"%s",l_arrs8RTSPSessionId);
  747. bzero(pstRTSPClient->arrs8SerRTPPort,12);
  748. sprintf(pstRTSPClient->arrs8SerRTPPort,"%s",l_arrs8RTPPort);
  749. l_s32Len = strlen(pstRTSPClient->arrs8SerRTPPort);
  750. l_s32Len = l_s32Len -1;
  751. pstRTSPClient->arrs8SerRTPPort[l_s32Len] = pstRTSPClient->arrs8SerRTPPort[l_s32Len]+1;
  752. gs_s32CseqCount++;
  753. return 0;
  754. }
  755. return -5;
  756. }
  757. int RTSP_Client_PLAY(RTSP_STATUS_S *pstRTSPClient)
  758. {
  759. char l_arrs8Buf[BUF_LEN_1024_BYTE];
  760. char *l_ps8RTSPSessionId;
  761. int i;
  762. int l_s32Ret;
  763. int l_s32RtspsocketFd;
  764. bool l_bRTSPState;
  765. if(NULL==pstRTSPClient)
  766. {
  767. printf("%s %d input para error\n",__FUNCTION__,__LINE__);
  768. return -1;
  769. }
  770. if(true==pstRTSPClient->bRTPState)
  771. {
  772. printf("%s %d RTSP is already start error \n",__FUNCTION__,__LINE__);
  773. return -2;
  774. }
  775. l_bRTSPState = pstRTSPClient->bRTPState;
  776. l_s32RtspsocketFd = pstRTSPClient->s32SockFd;
  777. l_ps8RTSPSessionId = pstRTSPClient->arrs8SessionId;
  778. for(i=pstRTSPClient->stSDPPara.s32AuthorType;i < 3;i++)
  779. {
  780. IPC_RTSP_StreamHandle(pstRTSPClient->arrs8RTSPUrl,pstRTSPClient->s32StreamType);
  781. IPC_RTSP_PLAYHandle(pstRTSPClient,l_arrs8Buf,i,l_ps8RTSPSessionId);
  782. l_s32Ret = NET_SocketSendData(l_s32RtspsocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
  783. if(l_s32Ret < 0)
  784. {
  785. printf("%s %d:Send Data Error \n",__FUNCTION__,__LINE__);
  786. return -3;
  787. }
  788. printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret);
  789. bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
  790. l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspsocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
  791. if(l_s32Ret <= 0)
  792. {
  793. printf("%s %d Recv Select Error\n",__FUNCTION__,__LINE__);
  794. gs_s32CseqCount++;
  795. return -4;
  796. }else
  797. {
  798. printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
  799. }
  800. l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
  801. if(0 != l_s32Ret)
  802. {
  803. gs_s32CseqCount++;
  804. return -5;
  805. }
  806. else
  807. {
  808. printf("biao debug [%s %d:] recv OK \n",__FUNCTION__,__LINE__);
  809. }
  810. gs_s32CseqCount++;
  811. pstRTSPClient->bRTPState = true;
  812. return 0;
  813. }
  814. return -1;
  815. }
  816. int RTSP_Client_TEARDOWN(RTSP_STATUS_S *pstRTSPClient)
  817. {
  818. char l_arrs8Buf[BUF_LEN_1024_BYTE];
  819. int l_s32Ret;
  820. int i;
  821. int l_s32RtspsocketFd;
  822. char *l_ps8RTSPSessionId;
  823. if(NULL==pstRTSPClient)
  824. {
  825. printf("%s %d input para error\n",__FUNCTION__,__LINE__);
  826. return -1;
  827. }
  828. l_s32RtspsocketFd = pstRTSPClient->s32SockFd;
  829. l_ps8RTSPSessionId = pstRTSPClient->arrs8SessionId;
  830. bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
  831. for(i=pstRTSPClient->stSDPPara.s32AuthorType;i<3;i++)
  832. {
  833. IPC_RTSP_StreamHandle(pstRTSPClient->arrs8RTSPUrl,pstRTSPClient->s32StreamType);
  834. IPC_RTSP_TEARDOWNHandle(pstRTSPClient,l_arrs8Buf,i,l_ps8RTSPSessionId);
  835. l_s32Ret = NET_SocketSendData(l_s32RtspsocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
  836. if(l_s32Ret < 0)
  837. {
  838. printf("%s %d:Send Data Error \n",__FUNCTION__,__LINE__);
  839. return -2;
  840. }
  841. printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret);
  842. bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
  843. l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspsocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
  844. if(l_s32Ret <= 0)
  845. {
  846. printf("%s %d: Recv Select Error\n",__FUNCTION__,__LINE__);
  847. return -3;
  848. }else
  849. {
  850. printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
  851. }
  852. l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
  853. if(0 != l_s32Ret)
  854. {
  855. printf("%s %d Check Replay Error \n",__FUNCTION__,__LINE__);
  856. return -4;
  857. }
  858. gs_s32CseqCount++;
  859. pstRTSPClient->bRTPState = true;
  860. return 0;
  861. }
  862. return -1;
  863. }

程序运行结果如下:

  1. biao@ubuntu:~/test/vlc_camara$ sudo ./test
  2. [IPC_RTSP_GetPort,39]l_ps8Buf=rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif
  3. [IPC_RTSP_GetPort,42]l_ps8Buf=rtsp:
  4. RTSP Server IP=192.168.1.120,ServerPort=554
  5. s32Type = 0
  6. [RTSP_Client_OPTIONS 645:] Send data:
  7. OPTIONS rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
  8. CSeq: 1
  9. User-Agent: Caibiao_Lee
  10. l_s32Ret=140
  11. [RTSP_Client_OPTIONS 657:] Recv Data: RTSP/1.0 401 Unauthorized
  12. CSeq: 1
  13. WWW-Authenticate: Digest realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e"
  14. biao debug [RTSP_Client_OPTIONS 663:] l_s32Ret = -1
  15. s32Type = 1
  16. [RTSP_Client_OPTIONS 645:] Send data:
  17. OPTIONS rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
  18. CSeq: 2
  19. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e",uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif",response="59a6120145ee2c5adad4552f20a3bad2"
  20. l_s32Ret=371
  21. [RTSP_Client_OPTIONS 657:] Recv Data: RTSP/1.0 200 OK
  22. CSeq: 2
  23. Public: OPTIONS, DESCRIBE, ANNOUNCE, SETUP, PLAY, PAUSE, TEARDOWN, GET_PARAMETER, SET_PARAMETER, REDIRECT, RECORD
  24. Server: Rtsp Server/3.0
  25. biao debug [RTSP_Client_OPTIONS 669:] recv OK
  26. [RTSP_Client_DESCRIBE 728:] Send data:
  27. DESCRIBE rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
  28. CSeq: 3
  29. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e",uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif",response="0fefc97b4a497566ce815e2f9f48ff4a"
  30. User-Agent: Caibiao_Lee
  31. Accept: application/sdp
  32. l_s32Ret=422
  33. [RTSP_Client_DESCRIBE 740:] Recv Data: RTSP/1.0 200 OK
  34. CSeq: 3
  35. Content-Base: rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/
  36. Content-Type: application/sdp
  37. x-Accept-Dynamic-Rate: 1
  38. Cache-Control: must-revalidate
  39. Content-Length: 566
  40. v=0
  41. o=- 2229913047 2229913047 IN IP4 0.0.0.0
  42. s=Media Server
  43. c=IN IP4 0.0.0.0
  44. t=0 0
  45. a=control:*
  46. a=packetization-supported:DH
  47. a=rtppayload-supported:DH
  48. a=range:npt=now-
  49. m=video 0 RTP/AVP 96
  50. a=control:trackID=0
  51. a=framerate:25.000000
  52. a=rtpmap:96 H264/90000
  53. a=fmtp:96 packetization-mode=1;profile-level-id=64002A;sprop-parameter-sets=Z2QAKqwsaoHgCJ+WbgICAgQA,aO48sAA=
  54. a=recvonly
  55. m=audio 0 RTP/AVP 8
  56. a=control:trackID=1
  57. a=rtpmap:8 PCMA/8000
  58. a=recvonly
  59. m=application 0 RTP/AVP 107
  60. a=control:trackID=4
  61. a=rtpmap:107 vnd.onvif.metadata/90000
  62. a=recvonly
  63. biao debug [RTSP_Client_DESCRIBE 752:] recv OK
  64. [RTSP_Client_SETUP 807:] Send data:
  65. SETUP rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/trackID=0 RTSP/1.0
  66. CSeq: 4
  67. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e",uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif",response="c650887dd112d10e0a868510d64088f6"
  68. User-Agent: Caibiao_Lee
  69. Transport:RTP/AVP;unicast;client_port=32766-32767
  70. l_s32Ret=455
  71. [RTSP_Client_SETUP 817:] Recv Data: RTSP/1.0 200 OK
  72. CSeq: 4
  73. Session: 2666913996
  74. Transport: RTP/AVP;unicast;client_port=32766-32767;server_port=2000-2001;ssrc=d6198a00
  75. x-Dynamic-Rate: 1
  76. biao debug [RTSP_Client_SETUP 828:] recv OK
  77. [RTSP_Client_PLAY 902:] Send data:
  78. PLAY rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/ RTSP/1.0
  79. CSeq: 5
  80. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D", nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e", uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif", response="bc9b1026a0ce64b963da457d4e87b6a5"
  81. User-Agent: Caibiao_Lee
  82. Session: 2666913996
  83. Range: npt=0.000-
  84. l_s32Ret=437
  85. [RTSP_Client_PLAY 914:] Recv Data: RTSP/1.0 200 OK
  86. CSeq: 5
  87. Session: 2666913996
  88. Range: npt=0.000-
  89. RTP-Info: url=trackID=0;seq=1;rtptime=0
  90. biao debug [RTSP_Client_PLAY 925:] recv OK
  91. [RTSP_Client_TEARDOWN 969:] Send data:
  92. TEARDOWN rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/ RTSP/1.0
  93. CSeq: 6
  94. User-Agent: Caibiao_Lee
  95. Authorization: Digest username="admin", realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e",uri="rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif",response="68f5346f3fea36b7c69be9e8184abc5b"
  96. User-Agent: Caibiao_Lee
  97. Session: 2666913996
  98. l_s32Ret=444
  99. [RTSP_Client_TEARDOWN 979:] Recv Data: RTSP/1.0 200 OK
  100. CSeq: 6
  101. Session: 2666913996
  102. biao@ubuntu:~/test/vlc_camara$

用户密码与加解密

RTSP请求的时候,一般有三种情况,(a)不需要用户密码,直接访问。(b)使用BASE64加密访问。(c)使用MD5加密访问。上面运行的测试程序,因为使用的是大华的IPC摄像头,所以使用的是MD5用户加密交互。

  • BASE64的维基百科解析是:Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于 {\displaystyle 2^{6}=64} {\displaystyle 2^{6}=64},所以每6个位元为一个单元,对应某个可打印字符。3个字节有24个位元,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后BinHex的版本使用不同的64字符集来代表6个二进制数字,但是不被稱為Base64。Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。
  • MD5在维基百科中解释是:MD5訊息摘要演算法(英語:MD5 Message-Digest Algorithm),一種被廣泛使用的密碼雜湊函數,可以產生出一個128位元(16位元組)的散列值(hash value),用于确保信息传输完整一致。MD5由美國密碼學家罗纳德·李维斯特(Ronald Linn Rivest)設計,於1992年公開,用以取代MD4演算法。這套演算法的程序在 RFC 1321 中被加以規範。将数据(如一段文字)运算变为另一固定长度值,是雜湊算法的基础原理。

工程目录:

完整工程文件结构:

  1. biao@ubuntu:~/test/rtsp_client$ tree
  2. .
  3. ├── include
  4.    ├── common.h
  5.    └── rtsp_client.h
  6. ├── lib
  7.    ├── libcrypto.a
  8.    ├── libcrypto.so
  9.    ├── libssl.a
  10.    └── libssl.so
  11. ├── Makefile
  12. └── src
  13. ├── common.c
  14. ├── main.c
  15. └── rtsp_client.c
  16. 3 directories, 10 files
  17. biao@ubuntu:~/test/rtsp_client$

liwen01 公众号中回复 网络编程 获取工程代码,本章代码工程名为:rtsp_client_20190922.tar.gz

---------------------------End---------------------------
长按识别二维码
关注 liwen01 公众号

ONVIF网络摄像头(IPC)客户端开发—最简RTSP客户端实现的更多相关文章

  1. Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  2. ONVIF客户端搜索设备获取rtsp地址开发笔记(精华篇)

    原文  http://blog.csdn.net/gubenpeiyuan/article/details/25618177   概要: 目前ONVIF协议家族设备已占据数字监控行业半壁江山以上,亲, ...

  3. 【视频开发】ONVIF客户端搜索设备获取rtsp地址开发笔记(精华篇)

    转载地址:http://blog.csdn.net/gubenpeiyuan/article/details/25618177 概要:           目前ONVIF协议家族设备已占据数字监控行业 ...

  4. Android IOS WebRTC 音视频开发总结(八十三)-- 使用WebRTC广播网络摄像头视频(上)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  5. 1、简述在java网络编程中,服务端程序与客户端程序的具体开发步骤?

    网络编程分为UDP通信和TCP通信 UDP协议: 发送端:1.创建DatagramSocket对象.2.创建DatagramPacket对象,并封装数据.3.发送数据.4.释放 资源. 接收端:1.创 ...

  6. 网络编程之TCP客户端开发和TCP服务端开发

    开发 TCP 客户端程序开发步骤 创建客户端套接字对象 和服务端套接字建立连接 发送数据 接收数据 关闭客户端套接字 import socket if __name__ == '__main__': ...

  7. onvif获取摄像头的流媒体地址完整流程

    linux设备上的Onvif 实现6:获取摄像头的流媒体地址完整流程 整体流程: Probe: 发现网络摄像头,获取webserver地址 http://192.168.15.240/onvif/de ...

  8. python 网络编程之socket开发和socketserver模块

    一 客户端/服务器架构 1.硬件C/S架构(打印机) 2.软件C/S架构 互联网中处处是C/S架构 如黄色网站是服务端,你的浏览器是客户端(B/S架构也是C/S架构的一种) 腾讯作为服务端为你提供视频 ...

  9. [原创]上海好买基金招高级Java技术经理/运维主管/高级无线客户端开发等职位(内推)

    [原创]上海好买基金招高级Java技术经理/运维主管/高级无线客户端开发等职位(内推) 内部推荐职位 高级JAVA技术经理: 岗位职责: 负责项目管理(技术方向),按照产品开发流 ,带领研发团队,制定 ...

  10. TVideoGrabber如何将网络摄像头影像实时发布到网络

    在TVideoGrabber中如何将网络摄像头影像实时发布到网络?如何设置正在运行TVideoGrabber的一台电脑,同时通过另一台电脑在网络中实时的观看在线视频呢? 在这里称发送视频流的电脑为“m ...

随机推荐

  1. javacv实现屏幕录制(一)

    javacv实现屏幕录制(一) javacv从入门到入土系列,发现了个好玩的东西,视频处理,于是我想搞个屏幕录屏,我百度了一下,copy那些代码我没有实现过,那些代码也没有说明,只好去官网看文档找资料 ...

  2. 文心一言 VS 讯飞星火 VS chatgpt (176)-- 算法导论13.3 5题

    五.用go语言,考虑一棵用 RB-INSERT 插人 n 个结点而成的红黑树.证明:如果 n>1,则该树至少有一个红结点. 文心一言: 要证明这个问题,我们首先需要理解红黑树的性质.红黑树是一种 ...

  3. ClickHouse(21)ClickHouse集成Kafka表引擎详细解析

    目录 Kafka表集成引擎 配置 Kerberos 支持 虚拟列 资料分享 参考文章 Kafka表集成引擎 此引擎与Apache Kafka结合使用. Kafka 特性: 发布或者订阅数据流. 容错存 ...

  4. 如何在IIS上部署docsify以及404问题

    操作步骤 创建一个文件夹,在文件夹中新建2个文件 index.html:入口文件,整个网站只需要这个html文件,其他文件都是md文件 README.md:主页内容,如果没有这个文件,访问时提示404 ...

  5. CodeForces 1105D 嵌套BFS

    CodeForces 1105D 嵌套BFS 题意 - 给我们一个n*m的阵列,一个格子如果是#则为障碍,若为.则为空,若为数字,则代表这个格子属于该数字代表的玩家. - 给我们每个玩家(不到十个)的 ...

  6. Spring系列:基于注解的方式构建IOC

    目录 一.搭建子模块spring6-ioc-annotation 二.添加配置类 三.使用注解定义 Bean 四.@Autowired注入 五.@Resource注入 六.全部代码 从 Java 5 ...

  7. 当GaussDB遇上了毕昇编译器

    摘要:当应用软件及硬件确定后,编译器对应用的自动优化将成为应用性能的关键. 从应用优化说起 一个应用的优化通常有架构级优化.模块级优化和函数级优化,高性能作为云数据库GaussDB主打特性之一,其在这 ...

  8. 数据库面试要点:关于MySQL数据库千万级数据查询和存储

    摘要:百万级.千万级数据处理,核心关键在于数据存储方案设计,存储方案设计的是否合理,直接影响到数据CRUD操作.总体设计可以考虑一下几个方面进行设计考虑: 数据存储结构设计:索引设计:数据主键设计:查 ...

  9. 论文解读丨无参数的注意力模块SimAm

    摘要:本文提出了一个概念简单但对卷积神经网络非常有效的注意力模块. 本文分享自华为云社区<论文解读系列三十:无参数的注意力模块SimAm论文解读>,作者:谷雨润一麦. 摘要 本文提出了一个 ...

  10. 提速 10 倍!深度解读字节跳动新型云原生 Spark History Server

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 前不久,在 6月29日 Databricks 举办的 Data + AI Summit 上,火山引擎向大家首次介绍 ...