Linux下RTSPServer程序--HI3516实测通过
源代码是CSDN上一位前辈那里下的[http://download.csdn.net/detail/showmove/6570893],用法和前辈的一样,最大的改动是把所有关于RTSP的代码独立出来,使用者直接调用即可。另外,对程序做了优化,目前在HI3516上测试下来,四个客户端连上,播D1视频,延时约2s。
代码分为两个文件,sample_comm_rtsp.c、rtsp_server.h。用法流程如下:
1.InitRtspServer();
2.udpfd = socket(AF_INET,SOCK_DGRAM,0);//UDP
3.SAMPLE_COMM_VENC_Sentjin(&stStream);
/******************************************************************************
文件名:sample_comm_rtsp.c
源作者:http://download.csdn.net/detail/showmove/6570893
时间:2015.06
******************************************************************************/
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* End of #ifdef __cplusplus */
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#include <linux/if_ether.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "rtsp_server.h"
#include "sample_comm.h"
#define nalu_sent_len 14000
#define RTP_H264 96
#define MAX_CHAN 8
#define RTP_AUDIO 97
#define MAX_RTSP_CLIENT 6
#define RTSP_SERVER_PORT 554
#define RTSP_RECV_SIZE 1024
#define RTSP_MAX_VID (640*1024)
#define RTSP_MAX_AUD (15*1024)
#define AU_HEADER_SIZE 4
#define PARAM_STRING_MAX 100
//static SAMPLE_VENC_GETSTREAM_PARA_S gs_stPara;
//static pthread_t gs_VencPid;
typedef unsigned short u_int16_t;
typedef unsigned char u_int8_t;
typedef u_int16_t portNumBits;
typedef u_int32_t netAddressBits;
typedef long long _int64;
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#define AUDIO_RATE 8000
//#define PACKET_BUFFER_END (unsigned int)0x00000000
typedef struct
{
int startblock;//代表开始文件块号
int endblock;//代表结束文件块号
int BlockFileNum;//代表录像段数
}IDXFILEHEAD_INFO;//.IDX文件的头信息
typedef struct
{
_int64 starttime;//代表开始shijian
_int64 endtime;//代表结束shijian
int startblock;//代表开始文件块号
int endblock;//代表结束文件块号
int stampnum;//代表时间戳数量
}IDXFILEBLOCK_INFO;//.IDX文件段信息
typedef struct
{
int blockindex;//代表所在文件块号
int pos;//代表该时间戳在文件块的位置
_int64 time;//代表时间戳时间戳的时间点
}IDXSTAMP_INFO;//.IDX文件的时间戳信息
typedef struct
{
char filename[150];//代表所在文件块号
int pos;//代表该时间戳在文件块的位置
_int64 time;//代表时间戳时间戳的时间点
}FILESTAMP_INFO;//.IDX文件的时间戳信息
typedef struct
{
char channelid[9];
_int64 starttime;//代表开始shijian
_int64 endtime;//代表结束shijian
_int64 session;
int type; //类型
int encodetype;//编码格式;
}FIND_INFO;//.IDX文件的时间戳信息
typedef enum
{
RTP_UDP,
RTP_TCP,
RAW_UDP
}StreamingMode;
typedef enum
{
RTSP_IDLE = 0,
RTSP_CONNECTED = 1,
RTSP_SENDING = 2,
}RTSP_STATUS;
typedef struct
{
int nVidLen;
int nAudLen;
int bIsIFrm;
int bWaitIFrm;
int bIsFree;
char vidBuf[RTSP_MAX_VID];
char audBuf[RTSP_MAX_AUD];
}RTSP_PACK;
typedef struct
{
int index;
int socket;
int reqchn;
int seqnum;
int seqnum2;
unsigned int tsvid;
unsigned int tsaud;
int status;
int sessionid;
int rtpport[2];
int rtcpport;
char IP[20];
char urlPre[PARAM_STRING_MAX];
}RTSP_CLIENT;
typedef struct
{
int vidLen;
int audLen;
int nFrameID;
char vidBuf[RTSP_MAX_VID];
char audBuf[RTSP_MAX_AUD];
}FRAME_PACK;
typedef struct
{
int startcodeprefix_len; //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)
unsigned len; //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)
unsigned max_size; //! Nal Unit Buffer size
int forbidden_bit; //! should be always FALSE
int nal_reference_idc; //! NALU_PRIORITY_xxxx
int nal_unit_type; //! NALU_TYPE_xxxx
char *buf; //! contains the first byte followed by the EBSP
unsigned short lost_packets; //! true, if packet loss is detected
} NALU_t;
//static bool flag = true;
RTP_FIXED_HEADER *rtp_hdr;
NALU_HEADER *nalu_hdr;
FU_INDICATOR *fu_ind;
FU_HEADER *fu_hdr;
FRAME_PACK g_FrmPack[MAX_CHAN];
RTSP_PACK g_rtpPack[MAX_CHAN];
RTSP_CLIENT g_rtspClients[MAX_RTSP_CLIENT];
int g_nSendDataChn = -1;
pthread_mutex_t g_mutex;
pthread_cond_t g_cond;
pthread_mutex_t g_sendmutex;
pthread_t g_SendDataThreadId = 0;
char g_rtp_playload[20];
int g_audio_rate = 8000;
int g_nframerate;
int exitok = 0;
#if 1
static char const* dateHeader()
{
static char buf[200];
#if !defined(_WIN32_WCE)
time_t tt = time(NULL);
strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt));
#endif
return buf;
}
#endif
static char* GetLocalIP(int sock)
{
struct ifreq ifreq;
struct sockaddr_in *sin;
char * LocalIP = malloc(20);
strcpy(ifreq.ifr_name,"eth0");
if (!(ioctl (sock, SIOCGIFADDR,&ifreq)))
{
sin = (struct sockaddr_in *)&ifreq.ifr_addr;
sin->sin_family = AF_INET;
strcpy(LocalIP,inet_ntoa(sin->sin_addr));
//inet_ntop(AF_INET, &sin->sin_addr,LocalIP, 16);
}
//printf("--------------------------------------------%s\n",LocalIP);
return LocalIP;
}
char* strDupSize(char const* str)
{
if (str == NULL) return NULL;
size_t len = strlen(str) + 1;
char* copy = malloc(len);
return copy;
}
int ParseRequestString( char const* reqStr, unsigned reqStrSize, char* resultCmdName,
unsigned resultCmdNameMaxSize, char* resultURLPreSuffix, unsigned resultURLPreSuffixMaxSize,
char* resultURLSuffix, unsigned resultURLSuffixMaxSize, char* resultCSeq,
unsigned resultCSeqMaxSize)
{
// Read everything up to the first space as the command name:
int parseSucceeded = FALSE;
unsigned i;
for (i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i) {
char c = reqStr[i];
if (c == ' ' || c == '\t') {
parseSucceeded = TRUE;
break;
}
resultCmdName[i] = c;
}
resultCmdName[i] = '\0';
if (!parseSucceeded)
return FALSE;
// Skip over the prefix of any "rtsp://" or "rtsp:/" URL that follows:
unsigned j = i+1;
while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; // skip over any additional white space
//rtsp://192.168.1.5:554
for (j = i+1; j < reqStrSize-8; ++j) {
if ((reqStr[j] == 'r' || reqStr[j] == 'R')
&& (reqStr[j+1] == 't' || reqStr[j+1] == 'T')
&& (reqStr[j+2] == 's' || reqStr[j+2] == 'S')
&& (reqStr[j+3] == 'p' || reqStr[j+3] == 'P')
&& reqStr[j+4] == ':' && reqStr[j+5] == '/') {
j += 6;
//printf("reqStr:%s__\n",&reqStr[j]);
if (reqStr[j] == '/') {
// This is a "rtsp://" URL; skip over the host:port part that follows:
++j;
while (j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ')
++j;
}
else {
// This is a "rtsp:/" URL; back up to the "/":
--j;
}
i = j;
break;
}
}
// Look for the URL suffix (before the following "RTSP/"):
parseSucceeded = FALSE;
unsigned k;
for (k = i+1; k < reqStrSize-5; ++k)
{
if (reqStr[k] == 'R' && \
reqStr[k+1] == 'T' && \
reqStr[k+2] == 'S' && \
reqStr[k+3] == 'P' && \
reqStr[k+4] == '/')
{
while (--k >= i && reqStr[k] == ' '); // go back over all spaces before "RTSP/"
unsigned k1 = k;
while (k1 > i && reqStr[k1] != '/' && reqStr[k1] != ' ') --k1;
// the URL suffix comes from [k1+1,k]
// Copy "resultURLSuffix":
if (k - k1 + 1 > resultURLSuffixMaxSize)
return FALSE; // there's no room
unsigned n = 0, k2 = k1+1;
while (k2 <= k)
resultURLSuffix[n++] = reqStr[k2++];
resultURLSuffix[n] = '\0';
// Also look for the URL 'pre-suffix' before this:
unsigned k3 = --k1;
while (k3 > i && reqStr[k3] != '/' && reqStr[k3] != ' ')
--k3;
// the URL pre-suffix comes from [k3+1,k1]
// Copy "resultURLPreSuffix":
if (k1 - k3 + 1 > resultURLPreSuffixMaxSize)
return FALSE; // there's no room
n = 0;
k2 = k3+1;
while (k2 <= k1)
resultURLPreSuffix[n++] = reqStr[k2++];
resultURLPreSuffix[n] = '\0';
i = k + 7; // to go past " RTSP/"
parseSucceeded = TRUE;
break;
}
}
if (!parseSucceeded)
return FALSE;
#if 1
// Look for "CSeq:", skip whitespace,
// then read everything up to the next \r or \n as 'CSeq':
parseSucceeded = FALSE;
for (j = i; j < reqStrSize-5; ++j) {
if (reqStr[j] == 'C' && reqStr[j+1] == 'S' && reqStr[j+2] == 'e' &&
reqStr[j+3] == 'q' && reqStr[j+4] == ':') {
j += 5;
unsigned n;
while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j;
for (n = 0; n < resultCSeqMaxSize-1 && j < reqStrSize; ++n,++j) {
char c = reqStr[j];
if (c == '\r' || c == '\n') {
parseSucceeded = TRUE;
break;
}
resultCSeq[n] = c;
}
resultCSeq[n] = '\0';
break;
}
}
if (!parseSucceeded)
return FALSE;
#endif
return parseSucceeded;
}
int OptionAnswer(char *cseq, int sock)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n",
cseq,dateHeader(),"OPTIONS,DESCRIBE,SETUP,PLAY,PAUSE,TEARDOWN");
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s\n",buf);
}
return TRUE;
}
return FALSE;
}
int DescribeAnswer(char *cseq,int sock,char * urlSuffix,char* recvbuf)
{
if (sock != 0)
{
char sdpMsg[1024];
char buf[2048];
memset(buf,0,2048);
memset(sdpMsg,0,1024);
char*localip;
localip = GetLocalIP(sock);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n",cseq);
pTemp += sprintf(pTemp,"%s",dateHeader());
pTemp += sprintf(pTemp,"Content-Type: application/sdp\r\n");
//TODO °ÑһЩ¹Ì¶šÖµžÄΪ¶¯Ì¬Öµ
char *pTemp2 = sdpMsg;
pTemp2 += sprintf(pTemp2,"v=0\r\n");
pTemp2 += sprintf(pTemp2,"o=StreamingServer 3331435948 1116907222000 IN IP4 %s\r\n",localip);
pTemp2 += sprintf(pTemp2,"s=H.264\r\n");
pTemp2 += sprintf(pTemp2,"c=IN IP4 0.0.0.0\r\n");
pTemp2 += sprintf(pTemp2,"t=0 0\r\n");
pTemp2 += sprintf(pTemp2,"a=control:*\r\n");
/*ÊÓÆµÃœÌåÃèÊö*/
/*H264 TrackID=0 RTP_PT 96*/
pTemp2 += sprintf(pTemp2,"m=video 0 RTP/AVP 96\r\n");
pTemp2 += sprintf(pTemp2,"a=control:trackID=0\r\n");
pTemp2 += sprintf(pTemp2,"a=rtpmap:96 H264/90000\r\n");
pTemp2 += sprintf(pTemp2,"a=fmtp:96 packetization-mode=1; sprop-parameter-sets=%s\r\n", "AAABBCCC");
#if 1
/*ÒôƵÜÌåÃèÊö*/
/*G726*/
/*TODO 񙮵*/
pTemp2 += sprintf(pTemp2,"m=audio 0 RTP/AVP 97\r\n");
pTemp2 += sprintf(pTemp2,"a=control:trackID=1\r\n");
if(strcmp(g_rtp_playload,"AAC")==0)
{
pTemp2 += sprintf(pTemp2,"a=rtpmap:97 MPEG4-GENERIC/%d/2\r\n",16000);
pTemp2 += sprintf(pTemp2,"a=fmtp:97 streamtype=5;profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;config=1410\r\n");
}
else
{
pTemp2 += sprintf(pTemp2,"a=rtpmap:97 G726-32/%d/1\r\n",8000);
pTemp2 += sprintf(pTemp2,"a=fmtp:97 packetization-mode=1\r\n");
}
#endif
pTemp += sprintf(pTemp,"Content-length: %d\r\n", strlen(sdpMsg));
pTemp += sprintf(pTemp,"Content-Base: rtsp://%s/%s/\r\n\r\n",localip,urlSuffix);
//printf("mem ready\n");
strcat(pTemp, sdpMsg);
free(localip);
//printf("Describe ready sent\n");
int re = send(sock, buf, strlen(buf),0);
if(re <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s\n",buf);
}
}
return TRUE;
}
void ParseTransportHeader(char const* buf,
StreamingMode* streamingMode,
char**streamingModeString,
char**destinationAddressStr,
u_int8_t* destinationTTL,
portNumBits* clientRTPPortNum, // if UDP
portNumBits* clientRTCPPortNum, // if UDP
unsigned char* rtpChannelId, // if TCP
unsigned char* rtcpChannelId // if TCP
)
{
// Initialize the result parameters to default values:
*streamingMode = RTP_UDP;
*streamingModeString = NULL;
*destinationAddressStr = NULL;
*destinationTTL = 255;
*clientRTPPortNum = 0;
*clientRTCPPortNum = 1;
*rtpChannelId = *rtcpChannelId = 0xFF;
portNumBits p1, p2;
unsigned ttl, rtpCid, rtcpCid;
// First, find "Transport:"
while (1) {
if (*buf == '\0')
return; // not found
if (strncasecmp(buf, "Transport: ", 11) == 0)
break;
++buf;
}
// Then, run through each of the fields, looking for ones we handle:
char const* fields = buf + 11;
char* field = strDupSize(fields);
while (sscanf(fields, "%[^;]", field) == 1) {
if (strcmp(field, "RTP/AVP/TCP") == 0) {
*streamingMode = RTP_TCP;
} else if (strcmp(field, "RAW/RAW/UDP") == 0 ||
strcmp(field, "MP2T/H2221/UDP") == 0) {
*streamingMode = RAW_UDP;
} else if (strncasecmp(field, "destination=", 12) == 0)
{
free(destinationAddressStr);
} else if (sscanf(field, "ttl%u", &ttl) == 1) {
destinationTTL = (u_int8_t)ttl;
} else if (sscanf(field, "client_port=%hu-%hu", &p1, &p2) == 2) {
*clientRTPPortNum = p1;
*clientRTCPPortNum = p2;
} else if (sscanf(field, "client_port=%hu", &p1) == 1) {
*clientRTPPortNum = p1;
*clientRTCPPortNum = streamingMode == RAW_UDP ? 0 : p1 + 1;
} else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) {
*rtpChannelId = (unsigned char)rtpCid;
*rtcpChannelId = (unsigned char)rtcpCid;
}
fields += strlen(field);
while (*fields == ';')
++fields; // skip over separating ';' chars
if (*fields == '\0' || *fields == '\r' || *fields == '\n')
break;
}
free(field);
}
int SetupAnswer(char *cseq,int sock,int SessionId,char * urlSuffix,char* recvbuf,int* rtpport, int* rtcpport)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
StreamingMode streamingMode;
char* streamingModeString; // set when RAW_UDP streaming is specified
char* clientsDestinationAddressStr;
u_int8_t clientsDestinationTTL;
portNumBits clientRTPPortNum, clientRTCPPortNum;
unsigned char rtpChannelId, rtcpChannelId;
ParseTransportHeader(recvbuf,&streamingMode, &streamingModeString,
&clientsDestinationAddressStr, &clientsDestinationTTL,
&clientRTPPortNum, &clientRTCPPortNum,
&rtpChannelId, &rtcpChannelId);
*rtpport = clientRTPPortNum;
*rtcpport = clientRTCPPortNum;
char *pTemp = buf;
char*localip;
localip = GetLocalIP(sock);
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sTransport: RTP/AVP;unicast;destination=%s;client_port=%d-%d;server_port=%d-%d\r\nSession: %d\r\n\r\n",
cseq,dateHeader(),localip,
ntohs(htons(clientRTPPortNum)),
ntohs(htons(clientRTCPPortNum)),
ntohs(2000),
ntohs(2001),
SessionId);
free(localip);
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s",buf);
}
return TRUE;
}
return FALSE;
}
int PlayAnswer(char *cseq, int sock,int SessionId,char* urlPre,char* recvbuf)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
char*localip;
localip = GetLocalIP(sock);
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sRange: npt=0.000-\r\nSession: %d\r\nRTP-Info: url=rtsp://%s/%s;seq=0\r\n\r\n",
cseq,dateHeader(),SessionId,localip,urlPre);
free(localip);
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s",buf);
}
return TRUE;
}
return FALSE;
}
int PauseAnswer(char *cseq,int sock,char *recvbuf)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%s\r\n\r\n",
cseq,dateHeader());
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s",buf);
}
return TRUE;
}
return FALSE;
}
int TeardownAnswer(char *cseq,int sock,int SessionId,char *recvbuf)
{
if (sock != 0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n",
cseq,dateHeader(),SessionId);
int reg = send(sock, buf,strlen(buf),0);
if(reg <= 0)
{
return FALSE;
}
else
{
printf(">>>>>%s",buf);
}
return TRUE;
}
return FALSE;
}
void * RtspClientMsg(void*pParam)
{
pthread_detach(pthread_self());
char strIp[255]; //192.168.001.001
int srcIP[4];
int strPort;
char strOther[255];
int nRes,Ret;
char pRecvBuf[RTSP_RECV_SIZE];
RTSP_CLIENT * pClient = (RTSP_CLIENT*)pParam;
memset(pRecvBuf,0,sizeof(pRecvBuf));
printf("RTSP:-----Create Client %s\n",pClient->IP);
while(pClient->status != RTSP_IDLE)
{
nRes = recv(pClient->socket, pRecvBuf, RTSP_RECV_SIZE,0);
if(nRes < 1)
{
printf("RTSP:Recv Error--- %d\n",nRes);
g_rtspClients[pClient->index].status = RTSP_IDLE;
g_rtspClients[pClient->index].seqnum = 0;
g_rtspClients[pClient->index].tsvid = 0;
g_rtspClients[pClient->index].tsaud = 0;
close(pClient->socket);
break;
}
{
sscanf(pRecvBuf, "%*[^:]://%[^:]:%d/%s", strIp, &strPort, strOther);
sscanf(strIp,"%d.%d.%d.%d",&srcIP[0],&srcIP[1],&srcIP[2],&srcIP[3]);
printf("%d\t%d\t%d\t%d\t\n",srcIP[0],srcIP[1],srcIP[2],srcIP[3]);
printf("%s\t%d\t%s\t\n",strIp,strPort,strOther);
}
char cmdName[PARAM_STRING_MAX];
char urlPreSuffix[PARAM_STRING_MAX];
char urlSuffix[PARAM_STRING_MAX];
char cseq[PARAM_STRING_MAX];
Ret = ParseRequestString(pRecvBuf,nRes,cmdName,sizeof(cmdName),urlPreSuffix,sizeof(urlPreSuffix),
urlSuffix,sizeof(urlSuffix),cseq,sizeof(cseq));
if(Ret==FALSE)
{
printf("ParseRequestString error[%s]\n",pRecvBuf);
break;
}
char *p = pRecvBuf;
printf("<<<<<%s\n",p);
if(strstr(cmdName, "OPTIONS"))
{
OptionAnswer(cseq,pClient->socket);
}
else if(strstr(cmdName, "DESCRIBE"))
{
DescribeAnswer(cseq,pClient->socket,urlSuffix,p);
}
else if(strstr(cmdName, "SETUP"))
{
int rtpport,rtcpport;
int trackID=0;
SetupAnswer(cseq,pClient->socket,pClient->sessionid,urlPreSuffix,p,&rtpport,&rtcpport);
sscanf(urlSuffix, "trackID=%u", &trackID);
if(trackID<0 || trackID>=2)
trackID=0;
g_rtspClients[pClient->index].rtpport[trackID] = rtpport;
g_rtspClients[pClient->index].rtcpport= rtcpport;
g_rtspClients[pClient->index].reqchn = atoi(urlPreSuffix);
if(strlen(urlPreSuffix)<100)
strcpy(g_rtspClients[pClient->index].urlPre,urlPreSuffix);
}
else if(strstr(cmdName, "PLAY"))
{
PlayAnswer(cseq,pClient->socket,pClient->sessionid,g_rtspClients[pClient->index].urlPre,p);
g_rtspClients[pClient->index].status = RTSP_SENDING;
}
else if(strstr(cmdName, "PAUSE"))
{
PauseAnswer(cseq,pClient->socket,p);
}
else if(strstr(cmdName, "TEARDOWN"))
{
TeardownAnswer(cseq,pClient->socket,pClient->sessionid,p);
g_rtspClients[pClient->index].status = RTSP_IDLE;
g_rtspClients[pClient->index].seqnum = 0;
g_rtspClients[pClient->index].tsvid = 0;
g_rtspClients[pClient->index].tsaud = 0;
close(pClient->socket);
}
if(exitok)
{
exitok++;
return NULL;
}
}
printf("RTSP:-----Exit Client %s\n",pClient->IP);
return NULL;
}
void * RtspServerListen(void*pParam)
{
int s32Socket;
struct sockaddr_in servaddr;
int s32CSocket;
int s32Rtn;
int s32Socket_opt_value = 1;
int nAddrLen;
struct sockaddr_in addrAccept;
//int bResult;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(RTSP_SERVER_PORT);
s32Socket = socket(AF_INET, SOCK_STREAM, 0);
if (setsockopt(s32Socket ,SOL_SOCKET,SO_REUSEADDR,&s32Socket_opt_value,sizeof(int)) == -1)
{
return (void *)(-1);
}
s32Rtn = bind(s32Socket, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));
if(s32Rtn < 0)
{
return (void *)(-2);
}
s32Rtn = listen(s32Socket, 50); /*50,×îŽóµÄÁ¬œÓÊý*/
if(s32Rtn < 0)
{
return (void *)(-2);
}
nAddrLen = sizeof(struct sockaddr_in);
int nSessionId = 1000;
while ((s32CSocket = accept(s32Socket,(struct sockaddr*)&addrAccept,(socklen_t *)&nAddrLen)) >= 0)
{
printf("<<<<RTSP Client %s Connected...\n", inet_ntoa(addrAccept.sin_addr));
int nMaxBuf = 10 * 1024; // ϵͳœ«»á·ÖÅä 2 x nMaxBuf µÄ»º³åŽóС
if(setsockopt(s32CSocket, SOL_SOCKET, SO_SNDBUF, (char*)&nMaxBuf, sizeof(nMaxBuf)) == -1)
printf("RTSP:!!!!!! Enalarge socket sending buffer error !!!!!!\n");
int i;
int bAdd=FALSE;
for(i=0;i<MAX_RTSP_CLIENT;i++)
{
if(g_rtspClients[i].status == RTSP_IDLE)
{
memset(&g_rtspClients[i],0,sizeof(RTSP_CLIENT));
g_rtspClients[i].index = i;
g_rtspClients[i].socket = s32CSocket;
g_rtspClients[i].status = RTSP_CONNECTED ;//RTSP_SENDING;
g_rtspClients[i].sessionid = nSessionId++;
strcpy(g_rtspClients[i].IP,inet_ntoa(addrAccept.sin_addr));
pthread_t threadIdlsn = 0;
struct sched_param sched;
sched.sched_priority = 1;
//to return ACKecho
pthread_create(&threadIdlsn, NULL, RtspClientMsg, &g_rtspClients[i]);
pthread_setschedparam(threadIdlsn,SCHED_RR,&sched);
bAdd = TRUE;
break;
}
}
if(bAdd==FALSE)
{
memset(&g_rtspClients[0],0,sizeof(RTSP_CLIENT));
g_rtspClients[0].index = 0;
g_rtspClients[0].socket = s32CSocket;
g_rtspClients[0].status = RTSP_CONNECTED ;//RTSP_SENDING;
g_rtspClients[0].sessionid = nSessionId++;
strcpy(g_rtspClients[0].IP,inet_ntoa(addrAccept.sin_addr));
pthread_t threadIdlsn = 0;
struct sched_param sched;
sched.sched_priority = 1;
//to return ACKecho
pthread_create(&threadIdlsn, NULL, RtspClientMsg, &g_rtspClients[0]);
pthread_setschedparam(threadIdlsn,SCHED_RR,&sched);
bAdd = TRUE;
}
if(exitok)
{
exitok++;
return NULL;
}
}
printf("----- INIT_RTSP_Listen() Exit !! \n");
return NULL;
}
HI_S32 framenum=0;
HI_S32 VENC_Sent(char *buffer,int buflen)
{
//HI_S32 i;
VIDEO_NORM_E gs_enNorm = VIDEO_ENCODING_MODE_NTSC;//30fps
//--------------------------------------------------------
int is=0;
int nChanNum=0;
#if 0
FILE *fp;
fp = fopen("test_rtsp.264", "ab");
if (!fp)
{
SAMPLE_PRT("open file failed!\n");
return 0;
}
#endif
framenum++;
for(is=0;is<MAX_RTSP_CLIENT;is++)
{
if(g_rtspClients[is].status!=RTSP_SENDING)
{
continue;
}
int heart = g_rtspClients[is].seqnum % 1000;
if(heart==0 && g_rtspClients[is].seqnum!=0)
{
char buf[1024];
memset(buf,0,1024);
char *pTemp = buf;
pTemp += sprintf(pTemp,"RTSP/1.0 200 OK\r\nCSeq: %s\r\nPublic: %s\r\n\r\n", \
"","OPTIONS,DESCRIBE,SETUP,PLAY,PAUSE,TEARDOWN");
int reg = send(g_rtspClients[is].socket, buf,strlen(buf),0);
if(reg <= 0)
{
//printf("RTSP:Send Error---- %d\n",reg);
g_rtspClients[is].status = RTSP_IDLE;
g_rtspClients[is].seqnum = 0;
g_rtspClients[is].tsvid = 0;
g_rtspClients[is].tsaud = 0;
close(g_rtspClients[is].socket);
continue;
}
else
{
unsigned char Time[20];
GetSysTime(Time);
printf("%s\tHeart:%d----------------------------------\n",Time,reg);
}
}
char* nalu_payload;
int nAvFrmLen = 0;
int nIsIFrm = 0;
int nNaluType = 0;
char sendbuf[320*1024+32];
nChanNum = g_rtspClients[is].reqchn;
if(nChanNum<0 || nChanNum>=MAX_CHAN )
{
continue;
}
nAvFrmLen = buflen;
struct sockaddr_in server;
server.sin_family=AF_INET;
server.sin_port=htons(g_rtspClients[is].rtpport[0]);
server.sin_addr.s_addr=inet_addr(g_rtspClients[is].IP);
int bytes=0;
unsigned int timestamp_increse=0;
if(VIDEO_ENCODING_MODE_PAL == gs_enNorm)
g_nframerate = 15;
else if(VIDEO_ENCODING_MODE_NTSC == gs_enNorm)
g_nframerate = 30;
timestamp_increse=(unsigned int)(90000.0 / g_nframerate);
rtp_hdr =(RTP_FIXED_HEADER*)&sendbuf[0];
rtp_hdr->payload = RTP_H264; //¸ºÔØÀàÐͺţ¬
rtp_hdr->version = 2; //°æ±¾ºÅ£¬´Ë°æ±¾¹Ì¶¨Îª2
rtp_hdr->marker = 0; //±ê־룬ÓɾßÌåЭÒ鹿¶¨ÆäÖµ¡£
rtp_hdr->ssrc = htonl(10); //Ëæ»úÖ¸¶¨Îª10£¬²¢ÇÒÔÚ±¾RTP»á»°ÖÐÈ«¾ÖΨһ
s32RtspFrmRate++;
if(nAvFrmLen<=nalu_sent_len)
{
//ÉèÖÃrtp M λ£»
//printf("a");
rtp_hdr->marker=1;
rtp_hdr->seq_no = htons(g_rtspClients[is].seqnum++); //ÐòÁкţ¬Ã¿·¢ËÍÒ»¸öRTP°üÔö1
nalu_hdr =(NALU_HEADER*)&sendbuf[12];
nalu_hdr->F=0;
nalu_hdr->NRI= nIsIFrm;
nalu_hdr->TYPE= nNaluType;
nalu_payload=&sendbuf[13];//ͬÀí½«sendbuf[13]¸³¸ønalu_payload
memcpy(nalu_payload,buffer,nAvFrmLen);
//memcpy(nalu_payload,buffer+4,nAvFrmLen-4);
g_rtspClients[is].tsvid = g_rtspClients[is].tsvid+timestamp_increse;
rtp_hdr->timestamp=htonl(g_rtspClients[is].tsvid);
bytes=nAvFrmLen+ 13 ;
sendto(udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
//fwrite(nalu_payload,nAvFrmLen, 1, fp);
//fwrite(sendbuf,bytes, 1, fp);
}
else if(nAvFrmLen>nalu_sent_len)
{
//printf("b");
//µÃµ½¸ÃnaluÐèÒªÓöàÉÙ³¤¶ÈΪ1400×Ö½ÚµÄRTP°üÀ´·¢ËÍ
int k=0,l=0;
k=nAvFrmLen/nalu_sent_len;//ÐèÒªk¸ö1400×Ö½ÚµÄRTP°ü
l=nAvFrmLen%nalu_sent_len;//×îºóÒ»¸öRTP°üµÄÐèÒª×°ÔØµÄ×Ö½ÚÊý
int t=0; //ÓÃÓÚָʾµ±Ç°·¢Ë͵ÄÊǵڼ¸¸ö·ÖƬRTP°ü
g_rtspClients[is].tsvid = g_rtspClients[is].tsvid+timestamp_increse;
//rtp_hdr->timestamp=htonl(g_rtspClients[is].tsvid);
while(t<=k)
{
rtp_hdr->seq_no = htons(g_rtspClients[is].seqnum++);
if(t==0)
{
//ÉèÖÃrtp M λ£»
rtp_hdr->marker=0;
fu_ind =(FU_INDICATOR*)&sendbuf[12];
fu_ind->F= 0;
fu_ind->NRI= nIsIFrm;
fu_ind->TYPE=28;
//ÉèÖÃFU HEADER,²¢½«Õâ¸öHEADERÌîÈësendbuf[13]
fu_hdr =(FU_HEADER*)&sendbuf[13];
fu_hdr->E=0;
fu_hdr->R=0;
fu_hdr->S=1;
fu_hdr->TYPE=nNaluType;
nalu_payload=&sendbuf[14];
memcpy(nalu_payload,buffer,nalu_sent_len);
//memcpy(nalu_payload,buffer+4,nalu_sent_len);
bytes=nalu_sent_len+14;
sendto( udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
//fwrite(nalu_payload,nalu_sent_len, 1, fp);
//fwrite(sendbuf,bytes, 1, fp);
t++;
}
else if(k==t)
{
//ÉèÖÃrtp M λ£»µ±Ç°´«ÊäµÄÊÇ×îºóÒ»¸ö·ÖƬʱ¸ÃλÖÃ1
rtp_hdr->marker=1;
fu_ind =(FU_INDICATOR*)&sendbuf[12];
fu_ind->F= 0 ;
fu_ind->NRI= nIsIFrm ;
fu_ind->TYPE=28;
//ÉèÖÃFU HEADER,²¢½«Õâ¸öHEADERÌîÈësendbuf[13]
fu_hdr =(FU_HEADER*)&sendbuf[13];
fu_hdr->R=0;
fu_hdr->S=0;
fu_hdr->TYPE= nNaluType;
fu_hdr->E=1;
nalu_payload=&sendbuf[14];
memcpy(nalu_payload,buffer+t*nalu_sent_len,l);
//memcpy(nalu_payload,buffer+4+t*nalu_sent_len,l);
bytes=l+14;
sendto(udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
//fwrite(nalu_payload,l, 1, fp);
//fwrite(sendbuf,bytes, 1, fp);
t++;
}
else if(t<k && t!=0)
{
//ÉèÖÃrtp M λ£»
rtp_hdr->marker=0;
//ÉèÖÃFU INDICATOR,²¢½«Õâ¸öHEADERÌîÈësendbuf[12]
fu_ind =(FU_INDICATOR*)&sendbuf[12];
fu_ind->F=0;
fu_ind->NRI=nIsIFrm;
fu_ind->TYPE=28;
fu_hdr =(FU_HEADER*)&sendbuf[13];
//fu_hdr->E=0;
fu_hdr->R=0;
fu_hdr->S=0;
fu_hdr->E=0;
fu_hdr->TYPE=nNaluType;
nalu_payload=&sendbuf[14];
memcpy(nalu_payload,buffer+t*nalu_sent_len,nalu_sent_len);
//memcpy(nalu_payload,buffer+4+t*nalu_sent_len,nalu_sent_len);
bytes=nalu_sent_len+14;
sendto(udpfd, sendbuf, bytes, 0, (struct sockaddr *)&server,sizeof(server));
//fwrite(sendbuf,bytes, 1, fp);
t++;
}
}
}
#if 0
{
unsigned char testdat[20];
int i;
memcpy(testdat,sendbuf,20);
printf("[%d]--------------------------------------------------->\n",nAvFrmLen);
for(i=0;i<14;i++)
{
printf("%#.2x\t",testdat[i]);
if(i==11)
printf("-->\n");
}
printf("\n");
printf("<---------------------------------------------------\n\n");
}
#endif
{
#if 0
FILE *fp;
unsigned char filename[20];
sprintf(filename, "frame%d.264", framenum);
fp = fopen(filename, "ab");
if (!fp)
{
SAMPLE_PRT("open file failed!\n");
return NULL;
}
fwrite(buffer,buflen, 1, fp);
//fwrite(buffer,buflen, 1, fp);
fclose(fp);
#endif
//fclose(fp);
}
}
return 0;
}
/******************************************************************************
* funciton : sent H264 stream
******************************************************************************/
HI_S32 SAMPLE_COMM_VENC_Sentjin(VENC_STREAM_S *pstStream)
{
HI_S32 i,flag=0;
for(i=0;i<MAX_RTSP_CLIENT;i++)//have atleast a connect
{
if(g_rtspClients[i].status == RTSP_SENDING)
{
flag = 1;
break;
}
}
if(flag)
{
//printf("a");
for (i = 0; i < pstStream->u32PackCount; i++)
{
HI_S32 lens=0;
//HI_S32 j;
//HI_S32 lastadd=0;
//HI_S32 newadd=0;
HI_S32 showflap=0;
char sendbuf[320*1024];
//char tmp[640*1024];
lens = pstStream->pstPack[i].u32Len[0];
memcpy(&sendbuf[0],pstStream->pstPack[i].pu8Addr[0],lens);
if (pstStream->pstPack[i].u32Len[1] > 0)
{
memcpy(&sendbuf[lens],pstStream->pstPack[i].pu8Addr[1],lens+pstStream->pstPack[i].u32Len[1]);
lens = lens+pstStream->pstPack[i].u32Len[1];
showflap=1;
}
VENC_Sent(sendbuf,lens);
lens = 0;
}
}
return HI_SUCCESS;
}
void InitRtspServer(void)
{
int i;
pthread_t threadId = 0;
for(i=0;i<MAX_CHAN;i++)
{
memset(&g_rtpPack[i],0,sizeof(RTSP_PACK));
g_rtpPack[i].bIsFree = TRUE;
memset(&g_FrmPack[i],0,sizeof(FRAME_PACK));
}
memset(g_rtp_playload,0,sizeof(g_rtp_playload));
strcpy(g_rtp_playload,"G726-32");
g_audio_rate = 8000;
pthread_mutex_init(&g_sendmutex,NULL);
pthread_mutex_init(&g_mutex,NULL);
pthread_cond_init(&g_cond,NULL);
memset(g_rtspClients,0,sizeof(RTSP_CLIENT)*MAX_RTSP_CLIENT);
struct sched_param thdsched;
thdsched.sched_priority = 2;
//to listen visiting
pthread_create(&threadId, NULL, RtspServerListen, NULL);
pthread_setschedparam(threadId,SCHED_RR,&thdsched);
printf("RTSP:-----Init Rtsp server\n");
#if 0
HI_S32 s32Ret;
s32Ret = SAMPLE_VENC_720P_CLASSIC();
//exit
if (HI_SUCCESS == s32Ret)
printf("program exit normally!\n");
else
printf("program exit abnormally!\n");
exitok++;
#endif
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus *//******************************************************************************
文件名:rtsp_server.h
源作者:http://download.csdn.net/detail/showmove/6570893
时间:2015.06
******************************************************************************/
#ifndef RTSP_SERVER_H
#define RTSP_SERVER_H
//#include "rtsp_cmd.h"
#if !defined(WIN32)
#define __PACKED__ __attribute__ ((__packed__))
#else
#define __PACKED__
#endif
typedef enum
{
RTSP_VIDEO=0,
RTSP_VIDEOSUB=1,
RTSP_AUDIO=2,
RTSP_YUV422=3,
RTSP_RGB=4,
RTSP_VIDEOPS=5,
RTSP_VIDEOSUBPS=6
}enRTSP_MonBlockType;
struct _RTP_FIXED_HEADER
{
/**//* byte 0 */
unsigned char csrc_len:4; /**//* expect 0 */
unsigned char extension:1; /**//* expect 1, see RTP_OP below */
unsigned char padding:1; /**//* expect 0 */
unsigned char version:2; /**//* expect 2 */
/**//* byte 1 */
unsigned char payload:7; /**//* RTP_PAYLOAD_RTSP */
unsigned char marker:1; /**//* expect 1 */
/**//* bytes 2, 3 */
unsigned short seq_no;
/**//* bytes 4-7 */
unsigned long timestamp;
/**//* bytes 8-11 */
unsigned long ssrc; /**//* stream number is used here. */
} __PACKED__;
typedef struct _RTP_FIXED_HEADER RTP_FIXED_HEADER;
struct _NALU_HEADER
{
//byte 0
unsigned char TYPE:5;
unsigned char NRI:2;
unsigned char F:1;
}__PACKED__; /**//* 1 BYTES */
typedef struct _NALU_HEADER NALU_HEADER;
struct _FU_INDICATOR
{
//byte 0
unsigned char TYPE:5;
unsigned char NRI:2;
unsigned char F:1;
}__PACKED__; /**//* 1 BYTES */
typedef struct _FU_INDICATOR FU_INDICATOR;
struct _FU_HEADER
{
//byte 0
unsigned char TYPE:5;
unsigned char R:1;
unsigned char E:1;
unsigned char S:1;
} __PACKED__; /**//* 1 BYTES */
typedef struct _FU_HEADER FU_HEADER;
struct _AU_HEADER
{
//byte 0, 1
unsigned short au_len;
//byte 2,3
unsigned short frm_len:13;
unsigned char au_index:3;
} __PACKED__; /**//* 1 BYTES */
typedef struct _AU_HEADER AU_HEADER;
#endif凯特网版权声明:以上内容允许转载,但请注明出处,谢谢!
