前言:

网上对于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. Python——第三章:函数的定义

    函数的定义: 对某一个特定的功能或者代码块进行封装. 在需要使用该功能的时候直接调用即可 格式: def 函数的名字(): 被封装的功能或者代码块->函数体 调用: 函数的名字() 使用函数的好 ...

  2. Pytest07-pytest.ini配置文件

    1.pytest配置文件 固定名称:pytest.ini 作用域:当前目录及子目录 具体配置功能见下: [pytest] # 01 把命令行参数自动添加到这里 addopts = -s -v --ht ...

  3. springboot整合hibernate(非JPA)(一)

    springboot整合hibernate(非JPA)(一) springboot整合hibernate,非jpa,若是jpa就简单了,但是公司项目只有hibernate,并要求支持多数据库,因此记录 ...

  4. NoClassDefFoundError: javax/el/ELManager

    Caused by: java.lang.NoClassDefFoundError: javax/el/ELManager at org.hibernate.validator.messageinte ...

  5. maven系列:多环境配置与应用

    目录 一.多环境配置步骤 定义多环境 使用多环境(构建过程) 二.跳过测试(了解) 应用场景 跳过测试命令 2.3 细粒度控制跳过测试 多环境配置有什么好处? maven提供配置多种环境的设定,帮助开 ...

  6. WMTS地图服务每一层级分辨率

    目录 1. 概述 2. 详论 2.1. Web墨卡托 2.2. 大地经纬度 3. 参考 1. 概述 WMTS地图服务每一层级的分辨率是多少?关于这个问题以前推算过,但总是忘记了.网上查询又是一堆废话, ...

  7. 仿微信语音聊天webrtc

    主要技术 MediaRecorder 录音 webrtc 获取麦克风 URL.createObjectURL 转换为url(实际生产中,通过后端转换blob为mp3网址) 实现elementui+vu ...

  8. MySQL进阶篇:详解索引概述

    2.1 MySQL进阶篇:第二章_二.一_索引概述 2.1.1 介绍 索引(index)是帮助MySQL高效获取数据的数据结构(有序).在数据之外,数据库系统还维护着满足 特定查找算法的数据结构,这些 ...

  9. Spark-submit执行流程,了解一下

    摘要:本文主要是通过Spark代码走读来了解spark-submit的流程. 1.任务命令提交 我们在进行Spark任务提交时,会使用"spark-submit -class .....&q ...

  10. 30亿参数,华为云发布全球最大预训练模型,开启工业化AI开发新模式

    摘要: 4月25日,华为云发布盘古系列超大规模预训练模型,包括30亿参数的全球最大视觉(CV)预训练模型,以及与循环智能.鹏城实验室联合开发的千亿参数.40TB训练数据的全球最大中文语言(NLP)预训 ...