前言:

网上对于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客户端的请求格式:

method url vesion\r\n
CSeq: x\r\n
xxx\r\n
...
\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服务端响应格式

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

2.RTSP请求的常用方法

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

3.交互过程实例

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

OPTIONS rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
CSeq: 1
User-Agent: Caibiao_Lee RTSP/1.0 401 Unauthorized
CSeq: 1
WWW-Authenticate: Digest realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e" OPTIONS rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
CSeq: 2
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" RTSP/1.0 200 OK
CSeq: 2
Public: OPTIONS, DESCRIBE, ANNOUNCE, SETUP, PLAY, PAUSE, TEARDOWN, GET_PARAMETER, SET_PARAMETER, REDIRECT, RECORD
Server: Rtsp Server/3.0 DESCRIBE rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
CSeq: 3
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"
User-Agent: Caibiao_Lee
Accept: application/sdp RTSP/1.0 200 OK
CSeq: 3
Content-Base: rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/
Content-Type: application/sdp
x-Accept-Dynamic-Rate: 1
Cache-Control: must-revalidate
Content-Length: 566 v=0
o=- 2229913047 2229913047 IN IP4 0.0.0.0
s=Media Server
c=IN IP4 0.0.0.0
t=0 0
a=control:*
a=packetization-supported:DH
a=rtppayload-supported:DH
a=range:npt=now-
m=video 0 RTP/AVP 96
a=control:trackID=0
a=framerate:25.000000
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=64002A;sprop-parameter-sets=Z2QAKqwsaoHgCJ+WbgICAgQA,aO48sAA=
a=recvonly
m=audio 0 RTP/AVP 8
a=control:trackID=1
a=rtpmap:8 PCMA/8000
a=recvonly
m=application 0 RTP/AVP 107
a=control:trackID=4
a=rtpmap:107 vnd.onvif.metadata/90000
a=recvonly
SETUP rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/trackID=0 RTSP/1.0
CSeq: 4
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"
User-Agent: Caibiao_Lee
Transport:RTP/AVP;unicast;client_port=32766-32767 RTSP/1.0 200 OK
CSeq: 4
Session: 2666913996
Transport: RTP/AVP;unicast;client_port=32766-32767;server_port=2000-2001;ssrc=d6198a00
x-Dynamic-Rate: 1 PLAY rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/ RTSP/1.0
CSeq: 5
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"
User-Agent: Caibiao_Lee
Session: 2666913996
Range: npt=0.000- RTSP/1.0 200 OK
CSeq: 5
Session: 2666913996
Range: npt=0.000-
RTP-Info: url=trackID=0;seq=1;rtptime=0 TEARDOWN rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/ RTSP/1.0
CSeq: 6
User-Agent: Caibiao_Lee
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"
User-Agent: Caibiao_Lee
Session: 2666913996 RTSP/1.0 200 OK
CSeq: 6
Session: 2666913996

3.1SDP格式分析

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

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

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

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

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

代码实现:

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

/************************************************************
*Copyright (C),lcb0281at163.com lcb0281atgmail.com
*FileName: rtsp_client.c
*BlogAddr: https://blog.csdn.net/li_wen01
*Description: RTSP 协议
*Date: 2019-06-22
*Author: Caibiao Lee
*Version: V1.0
*Others:
*History:
***********************************************************/
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rtsp_client.h" #define BUF_LEN_1024_BYTE 1024
#define RTSP_DEFAULT_PORT 554
static int gs_s32CseqCount = 1; static unsigned short IPC_RTSP_GetPort(const char *const ps8Rtsp)
{
char l_as8RTSP[128] = {0};
char *l_ps8Buf = NULL;
int i =0;
unsigned int l_u16RtspPort = 0; if(NULL == ps8Rtsp)
{
printf("[%s,%d] psTIPCDEV is NULL error\n ",__FILE__,__LINE__);
return 0;
}
memcpy(l_as8RTSP,ps8Rtsp,strlen(ps8Rtsp)); printf("[%s,%d]l_ps8Buf=%s\n",__FUNCTION__,__LINE__,l_as8RTSP);
l_ps8Buf = strtok(l_as8RTSP,"//"); printf("[%s,%d]l_ps8Buf=%s\n",__FUNCTION__,__LINE__,l_ps8Buf); if(NULL != l_ps8Buf)
{
l_ps8Buf = strtok(NULL,":");
}
if(NULL != l_ps8Buf)
{
l_ps8Buf = strtok(NULL,"/");
}
if(NULL != l_ps8Buf)
{
for(i = 0;i < 6 && l_ps8Buf[i] - '0' >= 0 && l_ps8Buf[i] - '0' <= 9;i++)
{
l_u16RtspPort *= 10;
l_u16RtspPort += l_ps8Buf[i] - '0';
}
}
return l_u16RtspPort;
} static int IPC_RTSP_RecvSelect(int s32RtspFd,char *ps8buf,int s32Len)
{
int l_s32Ret;
fd_set l_s4Fdset;
struct timeval l_stTimeout; FD_ZERO(&l_s4Fdset);
FD_SET(s32RtspFd,&l_s4Fdset);
l_stTimeout.tv_sec = 2;
l_stTimeout.tv_usec = 0; l_s32Ret = select(s32RtspFd + 1,&l_s4Fdset,NULL,NULL,&l_stTimeout);
if(l_s32Ret < 0)
{
printf("[%s,%d]slect error\n",__FUNCTION__,__LINE__);
}
else if(0 == l_s32Ret)
{
printf("[%s,%d] slect timeout\n",__FUNCTION__,__LINE__);
}
else
{
l_s32Ret = NET_SocketRecvData(s32RtspFd,ps8buf,s32Len);
}
return l_s32Ret;
} static int IPC_RTSP_CheckReply(char *ps8buf)
{
char *p = NULL;
p = strstr(ps8buf,"OK");
if(NULL == p)
{
return -1;
}
return 0;
} static int IPC_RTSP_HandleRTSPStr(RTSP_STATUS_S *pstRTSPClient)
{
char l_arrs8Buf[256]={0};
int l_s32Len; memcpy(l_arrs8Buf,pstRTSPClient->arrs8RTSPUrl,strlen(pstRTSPClient->arrs8RTSPUrl));
l_s32Len = strlen(l_arrs8Buf)-1;
while(l_s32Len >20)
{
if(' ' == l_arrs8Buf[l_s32Len] || '&' == l_arrs8Buf[l_s32Len])
{
l_arrs8Buf[l_s32Len] = '\0';
bzero(pstRTSPClient->arrs8RTSPUrl,strlen(pstRTSPClient->arrs8RTSPUrl));
memcpy(pstRTSPClient->arrs8RTSPUrl,l_arrs8Buf,strlen(l_arrs8Buf));
break;
}
l_s32Len--;
}
return 0;
} static void IPC_RTSP_SDPAnalyze(RTSP_STATUS_S *pstRTSPClient,char *ps8Buf)
{
char *p = ps8Buf;
char *tmp;
int i,j; /*********************step 1:control***********************/
for(i = 0;i< 3;i++)
{
/**取出control的内容**/
p = strstr(p,"a=control:");
if(NULL == p)
break; /**去掉*的行继续下行检测**/
if(0 == strncmp(p,"a=control:*",11))
{
p++;
continue;
}
/**检测control中是否存在rtsp**/
else if(NULL != (tmp = strstr(p,"rtsp")))
{
while('\n' != *tmp && '\r' != *tmp && '\0' != *tmp)
{
tmp++;
}
*tmp = '\0';
if(NULL != strstr(p,"track"))
{
j=0;
p+=10;
bzero(pstRTSPClient->stSDPPara.arrs8RTSPUrl,sizeof(pstRTSPClient->stSDPPara.arrs8RTSPUrl));
while('\n' != *p && '\r' != *p && '\0' != *p)
{
pstRTSPClient->arrs8RTSPUrl[j] = *(p++);
j++;
}
pstRTSPClient->stSDPPara.arrs8Control[0]='\0';
bzero(pstRTSPClient->arrs8RTSPUrl,128);
memcpy(pstRTSPClient->arrs8RTSPUrl,pstRTSPClient->stSDPPara.arrs8RTSPUrl,
strlen(pstRTSPClient->stSDPPara.arrs8RTSPUrl));
return ; }
p = tmp +1;
continue;
}
else
{ j=0;
p+=10;
while('\n' != *p && '\r' != *p && '\0' != *p)
{
pstRTSPClient->stSDPPara.arrs8Control[j] = *(p++);
j++;
}
pstRTSPClient->stSDPPara.arrs8Control[j]='\0';
break;
}
}
p = ps8Buf; /********************************step 2:rtspurl******************************/
p = strstr(p,"rtsp:"); /**出去rtsp**/
if(NULL != p)
{
tmp = p;
while(NULL != p && '\r' != *p && '\n' != *p && '\0' != *p)
{
p++;
}
if(NULL != p)
*p = '\0';
p--;
while(' ' == *p)
{
p--;
}
if('/' == *p)
*p = '\0';
bzero(pstRTSPClient->stSDPPara.arrs8RTSPUrl,sizeof(pstRTSPClient->stSDPPara.arrs8RTSPUrl));
memcpy(pstRTSPClient->stSDPPara.arrs8RTSPUrl,tmp,strlen(tmp));
} } static int IPC_RTSP_ERRHandle(RTSP_STATUS_S *pstRTSPClient,char *ps8Buf)
{
char *p;
char *tmp;
int i;
if(NULL == strstr(ps8Buf,"401"))
{
return 0;
}
p = strstr(ps8Buf,"realm=");
if(NULL == p)
{
return -1;
}
tmp = p+7;
for(i = 0;NULL != tmp && '"' != tmp[i] && i < 32;i++)
{
pstRTSPClient->stSDPPara.arrs8Realm[i] = tmp[i];
}
p = strstr(ps8Buf,"nonce=");
if(NULL == p)
{
return -1;
}
tmp = p+7;
for(i = 0;NULL != tmp && '"' != tmp[i] && i < 128;i++)
{
pstRTSPClient->stSDPPara.arrs8Nonce[i] = tmp[i];
}
return 0;
} static char *IPC_RTSP_StreamHandle(char *ps8Buf,int s32StreamType)
{
char *sub = NULL;
sub = strstr(ps8Buf,"subtype=");
if(NULL != sub)
{
if(SUBSTREAM == s32StreamType)
{
*(sub + 8) = '1';
}
else if(MAINSTREAM == s32StreamType){
*(sub + 8) = '0';
}
return ps8Buf;
}
sub = strstr(ps8Buf,"stream=");
if(NULL != sub)
{
if(SUBSTREAM == s32StreamType)
{
*(sub + 7) = '1';
}
else if(MAINSTREAM == s32StreamType){
*(sub + 7) = '0';
}
return ps8Buf;
}
else if(NULL != (sub = strstr(ps8Buf,"Channels/")) || NULL != (sub = strstr(ps8Buf,"channels/")))
{
sub += 9;
while('/' != *sub && '\0' != *sub)
{
sub++;
}
if(SUBSTREAM == s32StreamType)
{
*(--sub) +=1;
}
}
else if(NULL != (sub = strstr(ps8Buf,"stream")))
{
if((*(sub + 6) >= '0') && (*(sub + 6) <= '9'))
{
if(SUBSTREAM == s32StreamType)
{
*(sub + 6) = '2';
}
else if(MAINSTREAM == s32StreamType)
{
*(sub + 6) = '1';
}
}
return ps8Buf;
}
else if(NULL != (sub = strstr(ps8Buf,"/1/1")))
{
if(SUBSTREAM == s32StreamType)
{
sub+=3;
*sub +=1;
}
} return ps8Buf;
} static int IPC_RTSP_DESCRIBEHandle(RTSP_STATUS_S *stRTSPClient,char *ps8Buf,int s32Type)
{
char l_arrs8Author[32]={0};
unsigned char l_arru8Response[33]={0}; bzero(ps8Buf,BUF_LEN_1024_BYTE); switch(s32Type)
{
case 0:
{
sprintf(ps8Buf,"DESCRIBE %s RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\nAccept: application/h264\r\n\r\n",\
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount);
break;
} case 1:
{
COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,
stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_arru8Response,"DESCRIBE",
stRTSPClient->arrs8RTSPUrl,NULL,0);
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",\
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,\
stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,l_arru8Response);
break;
} case 2:
{
sprintf(ps8Buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
COM_base64_bits_to_64((unsigned char *)l_arrs8Author,(unsigned char *)ps8Buf,strlen(ps8Buf));
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",\
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,l_arrs8Author);
break;
} default:
s32Type = -1;
break;
} return s32Type;
} static int IPC_RTSP_OPTIONSHandle(RTSP_STATUS_S *stRTSPClient,char *ps8buf,int s32Type)
{
char l_s32Author[32] = {0};
unsigned char l_s32Response[33] = {0}; bzero(ps8buf,BUF_LEN_1024_BYTE); printf("s32Type = %d \n",s32Type); switch(s32Type)
{
case 0:
{
sprintf(ps8buf,"OPTIONS %s RTSP/1.0\r\nCSeq: %d\r\nUser-Agent: Caibiao_Lee\r\n\r\n",\
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount);
break;
} case 1:
{
COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,\
stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_s32Response,"OPTIONS",\
stRTSPClient->arrs8RTSPUrl,NULL,0);
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",\
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,l_s32Response);
break;
} case 2:
{
sprintf(ps8buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
printf("name = %s password = %s buf = %s \n",
stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,ps8buf);
COM_base64_bits_to_64((unsigned char *)l_s32Author,(unsigned char *)ps8buf,strlen(ps8buf));
sprintf(ps8buf,"OPTIONS %s RTSP/1.0\r\nCSeq: %d\r\nAuthorization: Basic %s\r\n\r\n",stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,l_s32Author);
break;
} default:
s32Type = -1;
break;
}
return s32Type; } static int IPC_RTSP_TEARDOWNHandle(RTSP_STATUS_S *stRTSPClient,char *ps8Buf,int s32tmp,char *pRTSPSessionId)
{
char l_s32author[32] = {0};
unsigned char l_arru8Response[33]={0}; bzero(ps8Buf,BUF_LEN_1024_BYTE); switch(s32tmp)
{
case 0:
{
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);
break;
} case 1:
{
COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_arru8Response,"TEARDOWN",stRTSPClient->arrs8RTSPUrl,NULL,0);
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",\
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,\
stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,\
l_arru8Response,pRTSPSessionId);
break;
} case 2:
{
sprintf(ps8Buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
COM_base64_bits_to_64((unsigned char *)l_s32author,(unsigned char *)ps8Buf,strlen(ps8Buf));
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",
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,pRTSPSessionId,l_s32author);
break; } default:
{
printf("%s,%d,switch is default\n",__FUNCTION__,__LINE__);
break;
s32tmp = -1;
}
}
return s32tmp;
} static int IPC_RTSP_SETUPHandle(RTSP_STATUS_S *stRTSPClient,char *ps8Buf,int s32Type,int localport)
{
char l_arrs8Author[32] = {0};
unsigned char l_arru8Response[33]={0}; bzero(ps8Buf,BUF_LEN_1024_BYTE); switch(s32Type)
{
case 0:
{
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",\
stRTSPClient->arrs8RTSPUrl,stRTSPClient->stSDPPara.arrs8Control,\
gs_s32CseqCount,localport,localport+1);
break;
} case 1:
{
COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_arru8Response,"SETUP",stRTSPClient->arrs8RTSPUrl,NULL,0);
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",
stRTSPClient->arrs8RTSPUrl,stRTSPClient->stSDPPara.arrs8Control,\
gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stSDPPara.arrs8Realm,\
stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,\
l_arru8Response,localport,localport+1); break;
} case 2:
{
sprintf(ps8Buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
COM_base64_bits_to_64((unsigned char *)l_arrs8Author,(unsigned char *)ps8Buf,strlen(ps8Buf));
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",\
stRTSPClient->arrs8RTSPUrl,stRTSPClient->stSDPPara.arrs8Control,\
gs_s32CseqCount,localport,localport+1,l_arrs8Author); break;
}
default:
{
s32Type = -1;
break;
}
} return s32Type;
} static int IPC_RTSP_PLAYHandle(RTSP_STATUS_S *stRTSPClient,char *ps8Buf,int s32Type,char *RTSPSessionId)
{
bzero(ps8Buf,BUF_LEN_1024_BYTE);
char l_arrs8Author[32] = {0};
unsigned char l_arru8Response[33]={0};
switch(s32Type)
{
case 0:
{
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",\
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,RTSPSessionId);
break; }
case 1:
{
COM_authorization_digest(stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord,stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,l_arru8Response,"PLAY",stRTSPClient->arrs8RTSPUrl,NULL,0);
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",\
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,stRTSPClient->stClientUser.arrs8Name,\
stRTSPClient->stSDPPara.arrs8Realm,stRTSPClient->stSDPPara.arrs8Nonce,stRTSPClient->arrs8RTSPUrl,\
l_arru8Response,RTSPSessionId);
break;
}
case 2:
{
sprintf(ps8Buf,"%s:%s",stRTSPClient->stClientUser.arrs8Name,stRTSPClient->stClientUser.arrs8PassWord);
COM_base64_bits_to_64((unsigned char *)l_arrs8Author,(unsigned char *)ps8Buf,strlen(ps8Buf));
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",\
stRTSPClient->arrs8RTSPUrl,gs_s32CseqCount,RTSPSessionId,l_arrs8Author);
break;
}
default:
{
s32Type = -1;
break;
}
} return s32Type;
} int RTSP_Client_Init(RTSP_STATUS_S * stRTSPClient)
{
memset((unsigned char*)stRTSPClient,0,sizeof(RTSP_STATUS_S));
stRTSPClient->bRTPState = false;
return 0;
} int RTSP_Client_Release(RTSP_STATUS_S * stRTSPClient)
{
if(NULL==stRTSPClient)
{
printf("%s %d input para error\n",__FUNCTION__,__LINE__);
return -1;
} if(stRTSPClient->s32SockFd > 0)
{
close(stRTSPClient->s32SockFd);
stRTSPClient->s32SockFd = -1;
}
return 0;
} int RTSP_Client_Session(RTSP_STATUS_S *stRTSPClient)
{
bool l_bRTSPState;
unsigned short l_u16Port = 0;
int l_s32Ret = 0;
int l_s32RtspSockfd = -1; if(NULL==stRTSPClient)
{
printf("%s %d input para error\n",__FUNCTION__,__LINE__);
return -1;
} l_bRTSPState = stRTSPClient->bRTPState;
l_s32RtspSockfd = stRTSPClient->s32SockFd; if(true==stRTSPClient->bRTPState)
{
printf("%s %d RTSP is already init error \n",__FUNCTION__,__LINE__);
return -1;
} if(l_s32RtspSockfd > 0)
{
close(l_s32RtspSockfd);
}
l_s32RtspSockfd = NET_SocketCreate(SOCK_STREAM);
if(l_s32RtspSockfd < 0)
{
printf("%s %d:create socket is error \n",__FUNCTION__,__LINE__);
return -3;
} l_u16Port = IPC_RTSP_GetPort(stRTSPClient->arrs8RTSPUrl);
l_u16Port = (l_u16Port>0)?(l_u16Port):(RTSP_DEFAULT_PORT);
printf("RTSP Server IP=%s,ServerPort=%d \n",stRTSPClient->arrs8ServerIP,l_u16Port); l_s32Ret = NET_SocketConnect(l_s32RtspSockfd,stRTSPClient->arrs8ServerIP,l_u16Port);
if(l_s32Ret < 0)
{
printf("%s %d :connect to Server error \n",__FUNCTION__,__LINE__);
return -4;
} stRTSPClient->s32SockFd = l_s32RtspSockfd; return 0;
} int RTSP_Client_OPTIONS(RTSP_STATUS_S *pstRTSPClient)
{
int i;
int l_s32Ret;
int l_s32RtspSocketFd;
bool l_bRTSPState;
char l_arrs8Buf[BUF_LEN_1024_BYTE]; if(NULL==pstRTSPClient)
{
printf("%s %d input para error\n",__FUNCTION__,__LINE__);
return -1;
} if(true==pstRTSPClient->bRTPState)
{
printf("%s %d RTSP is already start error \n",__FUNCTION__,__LINE__);
return -1;
} l_bRTSPState = pstRTSPClient->bRTPState;
l_s32RtspSocketFd = pstRTSPClient->s32SockFd; pstRTSPClient->stSDPPara.s32AuthorType = 0;
bzero(l_arrs8Buf,BUF_LEN_1024_BYTE); for(i=0;i< 2;i++)
{
IPC_RTSP_OPTIONSHandle(pstRTSPClient,l_arrs8Buf,i);
l_s32Ret = NET_SocketSendData(l_s32RtspSocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
if(l_s32Ret < 0)
{
printf("%s,%d :Send Data error \n",__FUNCTION__,__LINE__);
return -2;
} printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret); bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspSocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
if(l_s32Ret <= 0)
{
printf("[%s %d:] RTSP recv data error \n",__FUNCTION__,__LINE__);
gs_s32CseqCount++;
continue; }else
{
printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
} l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
if(0 != l_s32Ret)
{
printf("biao debug [%s %d:] l_s32Ret = %d \n",__FUNCTION__,__LINE__,l_s32Ret);
IPC_RTSP_ERRHandle(pstRTSPClient,l_arrs8Buf);
gs_s32CseqCount++;
continue;
}else
{
printf("biao debug [%s %d:] recv OK \n",__FUNCTION__,__LINE__);
}
gs_s32CseqCount++;
pstRTSPClient->stSDPPara.s32AuthorType = i;
return 0;
}
return -1; } int RTSP_Client_DESCRIBE(RTSP_STATUS_S *pstRTSPClient)
{
bool l_bRTSPState;
char *l_ps8Sub;
char l_arrs8Buf[BUF_LEN_1024_BYTE];
int i;
int l_s32Ret;
int l_s32RtspsocketFd; if(NULL==pstRTSPClient)
{
printf("%s %d input para error\n",__FUNCTION__,__LINE__);
return -1;
} if(true==pstRTSPClient->bRTPState)
{
printf("%s %d RTSP is already start error \n",__FUNCTION__,__LINE__);
return -1;
} l_bRTSPState = pstRTSPClient->bRTPState;
l_s32RtspsocketFd = pstRTSPClient->s32SockFd; for(i=pstRTSPClient->stSDPPara.s32AuthorType;i < 2;i++)
{
IPC_RTSP_DESCRIBEHandle(pstRTSPClient,l_arrs8Buf,i);
l_ps8Sub = COM_get_substringstart(l_arrs8Buf,"subtype=");
if(NULL != l_ps8Sub)
{
l_ps8Sub += 8;
} if(SUBSTREAM==pstRTSPClient->s32StreamType)
{
*l_ps8Sub = '1';
}
else if(MAINSTREAM== pstRTSPClient->s32StreamType)
{
*l_ps8Sub = '0';
} l_s32Ret = NET_SocketSendData(l_s32RtspsocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
if(l_s32Ret < 0)
{
printf("%s %d: Send Data Error \n",__FUNCTION__,__LINE__);
return -2;
} printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret); bzero(l_arrs8Buf,BUF_LEN_1024_BYTE); l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspsocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
if(l_s32Ret <= 0)
{
printf("%s %d : Recv Data Error \n",__FUNCTION__,__LINE__);
gs_s32CseqCount++;
return -3;
}else
{
printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
} l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
if(0 != l_s32Ret)
{
IPC_RTSP_ERRHandle(pstRTSPClient,l_arrs8Buf);
gs_s32CseqCount++;
return -4;
}
else
{
printf("biao debug [%s %d:] recv OK \n",__FUNCTION__,__LINE__);
}
IPC_RTSP_SDPAnalyze(pstRTSPClient,l_arrs8Buf);
gs_s32CseqCount++;
pstRTSPClient->stSDPPara.s32AuthorType = i;
return 0;
} return -5;
} int RTSP_Client_SETUP(RTSP_STATUS_S *pstRTSPClient)
{
bool l_bRTSPState;
char l_arrs8RTSPSessionId[16];
char l_arrs8RTPPort[12];
char l_arrs8Buf[BUF_LEN_1024_BYTE];
char *l_ps8Sub;
char l_s8Flag = ';';
char l_arrs8SPFlagStr[] = "server_port=";
int i;
int l_s32Len;
int localport;
int l_s32Ret;
int l_s32RtspsocketFd;
char *l_ps8RTSPSessionId; if(NULL==pstRTSPClient)
{
printf("%s %d input para error\n",__FUNCTION__,__LINE__);
return -1;
} if(true==pstRTSPClient->bRTPState)
{
printf("%s %d RTSP is already start error \n",__FUNCTION__,__LINE__);
return -1;
} l_bRTSPState = pstRTSPClient->bRTPState;
l_s32RtspsocketFd = pstRTSPClient->s32SockFd;
l_ps8RTSPSessionId = pstRTSPClient->arrs8SessionId; for(i=pstRTSPClient->stSDPPara.s32AuthorType;i <3;i++)
{
IPC_RTSP_StreamHandle(pstRTSPClient->arrs8RTSPUrl,pstRTSPClient->s32StreamType);
IPC_RTSP_SETUPHandle(pstRTSPClient,l_arrs8Buf,i,localport); l_s32Ret = NET_SocketSendData(l_s32RtspsocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
if(l_s32Ret < 0)
{
printf("%s %d: Send Data Error \n",__FUNCTION__,__LINE__);
return -2;
} printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret);
bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspsocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
if(l_s32Ret <= 0)
{
printf("%s %d : Recv Data Error \n",__FUNCTION__,__LINE__);
gs_s32CseqCount++;
return -3;
}else
{
printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
} l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
if(0 != l_s32Ret)
{
gs_s32CseqCount++;
return -4;
}
else
{
printf("biao debug [%s %d:] recv OK \n",__FUNCTION__,__LINE__);
}
l_ps8Sub = COM_get_substringstart(l_arrs8Buf,"Session:");
if(NULL != l_ps8Sub)
{
l_ps8Sub += 8;
}
while(NULL != l_ps8Sub && ' ' == *l_ps8Sub)
{
l_ps8Sub++;
} bzero(l_arrs8RTSPSessionId,16); COM_get_begingstring(l_ps8Sub,l_arrs8RTSPSessionId,l_s8Flag);
l_ps8Sub = COM_get_substringstart(l_arrs8Buf,l_arrs8SPFlagStr);
if(NULL != l_ps8Sub)
{
l_ps8Sub += 12;
}
bzero(l_arrs8RTPPort,12);
COM_get_begingstring(l_ps8Sub,l_arrs8RTPPort,'-'); bzero(pstRTSPClient->arrs8SessionId,16);
sprintf(pstRTSPClient->arrs8SessionId,"%s",l_arrs8RTSPSessionId);
bzero(pstRTSPClient->arrs8SerRTPPort,12);
sprintf(pstRTSPClient->arrs8SerRTPPort,"%s",l_arrs8RTPPort);
l_s32Len = strlen(pstRTSPClient->arrs8SerRTPPort);
l_s32Len = l_s32Len -1;
pstRTSPClient->arrs8SerRTPPort[l_s32Len] = pstRTSPClient->arrs8SerRTPPort[l_s32Len]+1; gs_s32CseqCount++;
return 0;
}
return -5; }
int RTSP_Client_PLAY(RTSP_STATUS_S *pstRTSPClient)
{
char l_arrs8Buf[BUF_LEN_1024_BYTE];
char *l_ps8RTSPSessionId;
int i;
int l_s32Ret;
int l_s32RtspsocketFd;
bool l_bRTSPState; if(NULL==pstRTSPClient)
{
printf("%s %d input para error\n",__FUNCTION__,__LINE__);
return -1;
} if(true==pstRTSPClient->bRTPState)
{
printf("%s %d RTSP is already start error \n",__FUNCTION__,__LINE__);
return -2;
} l_bRTSPState = pstRTSPClient->bRTPState;
l_s32RtspsocketFd = pstRTSPClient->s32SockFd;
l_ps8RTSPSessionId = pstRTSPClient->arrs8SessionId; for(i=pstRTSPClient->stSDPPara.s32AuthorType;i < 3;i++)
{
IPC_RTSP_StreamHandle(pstRTSPClient->arrs8RTSPUrl,pstRTSPClient->s32StreamType);
IPC_RTSP_PLAYHandle(pstRTSPClient,l_arrs8Buf,i,l_ps8RTSPSessionId);
l_s32Ret = NET_SocketSendData(l_s32RtspsocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
if(l_s32Ret < 0)
{
printf("%s %d:Send Data Error \n",__FUNCTION__,__LINE__);
return -3;
} printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret); bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspsocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
if(l_s32Ret <= 0)
{
printf("%s %d Recv Select Error\n",__FUNCTION__,__LINE__); gs_s32CseqCount++;
return -4;
}else
{
printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
} l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
if(0 != l_s32Ret)
{
gs_s32CseqCount++;
return -5;
}
else
{
printf("biao debug [%s %d:] recv OK \n",__FUNCTION__,__LINE__);
} gs_s32CseqCount++; pstRTSPClient->bRTPState = true; return 0;
}
return -1; } int RTSP_Client_TEARDOWN(RTSP_STATUS_S *pstRTSPClient)
{
char l_arrs8Buf[BUF_LEN_1024_BYTE];
int l_s32Ret;
int i;
int l_s32RtspsocketFd;
char *l_ps8RTSPSessionId; if(NULL==pstRTSPClient)
{
printf("%s %d input para error\n",__FUNCTION__,__LINE__);
return -1;
} l_s32RtspsocketFd = pstRTSPClient->s32SockFd;
l_ps8RTSPSessionId = pstRTSPClient->arrs8SessionId; bzero(l_arrs8Buf,BUF_LEN_1024_BYTE); for(i=pstRTSPClient->stSDPPara.s32AuthorType;i<3;i++)
{
IPC_RTSP_StreamHandle(pstRTSPClient->arrs8RTSPUrl,pstRTSPClient->s32StreamType);
IPC_RTSP_TEARDOWNHandle(pstRTSPClient,l_arrs8Buf,i,l_ps8RTSPSessionId);
l_s32Ret = NET_SocketSendData(l_s32RtspsocketFd,l_arrs8Buf,strlen(l_arrs8Buf));
if(l_s32Ret < 0)
{
printf("%s %d:Send Data Error \n",__FUNCTION__,__LINE__);
return -2;
} printf("[%s %d:] Send data:\n%s\nl_s32Ret=%d\n",__FUNCTION__,__LINE__,l_arrs8Buf,l_s32Ret); bzero(l_arrs8Buf,BUF_LEN_1024_BYTE);
l_s32Ret = IPC_RTSP_RecvSelect(l_s32RtspsocketFd,l_arrs8Buf,BUF_LEN_1024_BYTE);
if(l_s32Ret <= 0)
{
printf("%s %d: Recv Select Error\n",__FUNCTION__,__LINE__);
return -3;
}else
{
printf("[%s %d:] Recv Data: %s \n",__FUNCTION__,__LINE__,l_arrs8Buf);
} l_s32Ret = IPC_RTSP_CheckReply(l_arrs8Buf);
if(0 != l_s32Ret)
{
printf("%s %d Check Replay Error \n",__FUNCTION__,__LINE__);
return -4;
}
gs_s32CseqCount++; pstRTSPClient->bRTPState = true;
return 0;
} return -1;
}

程序运行结果如下:

biao@ubuntu:~/test/vlc_camara$ sudo ./test
[IPC_RTSP_GetPort,39]l_ps8Buf=rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif
[IPC_RTSP_GetPort,42]l_ps8Buf=rtsp:
RTSP Server IP=192.168.1.120,ServerPort=554
s32Type = 0
[RTSP_Client_OPTIONS 645:] Send data:
OPTIONS rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
CSeq: 1
User-Agent: Caibiao_Lee l_s32Ret=140
[RTSP_Client_OPTIONS 657:] Recv Data: RTSP/1.0 401 Unauthorized
CSeq: 1
WWW-Authenticate: Digest realm="Login to F8990C5E0599500D",nonce="4e6ea17f-789f-4d89-a1be-aba7340a3b8e" biao debug [RTSP_Client_OPTIONS 663:] l_s32Ret = -1
s32Type = 1
[RTSP_Client_OPTIONS 645:] Send data:
OPTIONS rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
CSeq: 2
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" l_s32Ret=371
[RTSP_Client_OPTIONS 657:] Recv Data: RTSP/1.0 200 OK
CSeq: 2
Public: OPTIONS, DESCRIBE, ANNOUNCE, SETUP, PLAY, PAUSE, TEARDOWN, GET_PARAMETER, SET_PARAMETER, REDIRECT, RECORD
Server: Rtsp Server/3.0 biao debug [RTSP_Client_OPTIONS 669:] recv OK
[RTSP_Client_DESCRIBE 728:] Send data:
DESCRIBE rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif RTSP/1.0
CSeq: 3
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"
User-Agent: Caibiao_Lee
Accept: application/sdp l_s32Ret=422
[RTSP_Client_DESCRIBE 740:] Recv Data: RTSP/1.0 200 OK
CSeq: 3
Content-Base: rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/
Content-Type: application/sdp
x-Accept-Dynamic-Rate: 1
Cache-Control: must-revalidate
Content-Length: 566 v=0
o=- 2229913047 2229913047 IN IP4 0.0.0.0
s=Media Server
c=IN IP4 0.0.0.0
t=0 0
a=control:*
a=packetization-supported:DH
a=rtppayload-supported:DH
a=range:npt=now-
m=video 0 RTP/AVP 96
a=control:trackID=0
a=framerate:25.000000
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=64002A;sprop-parameter-sets=Z2QAKqwsaoHgCJ+WbgICAgQA,aO48sAA=
a=recvonly
m=audio 0 RTP/AVP 8
a=control:trackID=1
a=rtpmap:8 PCMA/8000
a=recvonly
m=application 0 RTP/AVP 107
a=control:trackID=4
a=rtpmap:107 vnd.onvif.metadata/90000
a=recvonly biao debug [RTSP_Client_DESCRIBE 752:] recv OK
[RTSP_Client_SETUP 807:] Send data:
SETUP rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/trackID=0 RTSP/1.0
CSeq: 4
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"
User-Agent: Caibiao_Lee
Transport:RTP/AVP;unicast;client_port=32766-32767 l_s32Ret=455
[RTSP_Client_SETUP 817:] Recv Data: RTSP/1.0 200 OK
CSeq: 4
Session: 2666913996
Transport: RTP/AVP;unicast;client_port=32766-32767;server_port=2000-2001;ssrc=d6198a00
x-Dynamic-Rate: 1 biao debug [RTSP_Client_SETUP 828:] recv OK
[RTSP_Client_PLAY 902:] Send data:
PLAY rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/ RTSP/1.0
CSeq: 5
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"
User-Agent: Caibiao_Lee
Session: 2666913996
Range: npt=0.000- l_s32Ret=437
[RTSP_Client_PLAY 914:] Recv Data: RTSP/1.0 200 OK
CSeq: 5
Session: 2666913996
Range: npt=0.000-
RTP-Info: url=trackID=0;seq=1;rtptime=0 biao debug [RTSP_Client_PLAY 925:] recv OK
[RTSP_Client_TEARDOWN 969:] Send data:
TEARDOWN rtsp://192.168.1.120:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif/ RTSP/1.0
CSeq: 6
User-Agent: Caibiao_Lee
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"
User-Agent: Caibiao_Lee
Session: 2666913996 l_s32Ret=444
[RTSP_Client_TEARDOWN 979:] Recv Data: RTSP/1.0 200 OK
CSeq: 6
Session: 2666913996 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 中被加以規範。将数据(如一段文字)运算变为另一固定长度值,是雜湊算法的基础原理。

工程目录:

完整工程文件结构:

biao@ubuntu:~/test/rtsp_client$ tree
.
├── include
│   ├── common.h
│   └── rtsp_client.h
├── lib
│   ├── libcrypto.a
│   ├── libcrypto.so
│   ├── libssl.a
│   └── libssl.so
├── Makefile
└── src
├── common.c
├── main.c
└── rtsp_client.c 3 directories, 10 files
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. ElasticSearch之Search settings

    相关参数 indices.query.bool.max_clause_count 本参数当前已失效. search.max_buckets 本参数用于控制在单个响应中返回的聚合的桶的数量. 默认值为6 ...

  2. Python——第五章:Traceback模块

    traceback 模块提供了在程序中处理和分析异常时的工具,帮助开发人员更好地理解程序出现问题的原因. 使用 traceback.format_exc() 函数可以获取当前异常的堆栈信息.可以把错误 ...

  3. RocketMQ 的基本使用

    RocketMQwiki是一个分布式消息和流数据平台,具有低延迟.高性能.高可靠性.万亿级容量和灵活的可扩展性.RocketMQ是2012年阿里巴巴开源的第三代分布式消息中间件,2016年11月21日 ...

  4. Java 中常见类型的判空方式

    引用类型(Reference Types): 使用 == 运算符判断是否为 null. 使用 != 运算符判断是否不为 null. 使用 Objects.isNull() 方法判断是否为 null. ...

  5. Boost Your Strategy With The Content Marketing Tools

    Boost Your Strategy With The Content Marketing Tools In today's digital landscape, content marketing ...

  6. 一图看懂华为云CodeArts Link六大特性

    本文分享自华为云社区<一图看懂华为云CodeArts Link六大特性,带你体验一站式跨平台数据互联>,作者:华为云PaaS服务小智 . 能够打破不同研发工具之间的壁垒,实现数据的无缝集成 ...

  7. 【玩转鲲鹏 DevKit系列】如何快速迁移无源码应用?

    本文分享自华为云社区<[玩转鲲鹏 DevKit系列]如何快速迁移无源码应用?>,作者: 华为云社区精选. 为了帮助广大用户和开发者快速将无源码应用从 x86 迁移到鲲鹏,鲲鹏 DevKit ...

  8. 浅谈DWS函数出参方式

    摘要:DWS的PL/pgSQL函数/存储过程中有一个特殊的语法PERFORM语法,用于执行语句但是丢弃执行结果的场景,常用于一些状态判断的场景. 本文分享自华为云社区<GassDB(DWS)功能 ...

  9. 掌握ROMA Compose,报表清单不秃头

    摘要:在没有ROMA Compose之前,完成一个跨数据源的关联查询是一个十分艰巨的任务. 1. ROMA Compose为何诞生 试想这样一个场景,主管让刚入职的小沛明天下班前给他发一份报表.小沛兴 ...

  10. 基于GaussDB(DWS)的全文检索特性,了解一下?

    摘要:全文检索是在互联网场景下应用非常广泛的特性,搜索引擎.站内搜索.电商搜索等场景下都会使用到,GaussDB(DWS)同样也支持全文检索功能,是基于GIN索引实现的,下面给大家详细介绍一下Gaus ...