ONVIF网络摄像头(IPC)客户端开发—最简RTSP客户端实现
前言:
网上对于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