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

发布时间 2023-04-20 19:38:33作者: liwen01

前言:

网上对于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 公众号