⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtsp.c

📁 一个简单的RTSP客户端实现源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	int bytesRead = 0; // because we've already read the first byte	unsigned bytesReadNow  = 0;	fSocketNum = socketNum;	if (responseBufferSize == 0) return 0; // just in case...	*(responseBuffer) = '\0';	while (bytesRead < (int)responseBufferSize) 	{		lastToCheck = NULL;		if(blockUntilReadable(fSocketNum)<=0)		{			fprintf(stderr,"socket is unreadable\n");			break;		}		bytesReadNow = recv(fSocketNum,(unsigned char*)(responseBuffer+bytesRead),1, 0);		if (bytesReadNow != 1) 		{			fprintf(stderr,"RTSP response was truncated\n");			break;		}		bytesRead++;      		lastToCheck = responseBuffer+bytesRead-4;		if (lastToCheck < responseBuffer) continue;		p = lastToCheck;		if (*p == '\r' && *(p+1) == '\n' &&						*(p+2) == '\r' && *(p+3) == '\n') 		{			*(responseBuffer+bytesRead)= '\0';			// Before returning, trim any \r or \n from the start:			while (*responseBuffer == '\r' || *responseBuffer == '\n'||*responseBuffer!=0x52) 			{				++responseBuffer;				--bytesRead;			}			if(*responseBuffer == 0x52)//&&responseBuffer[1]=='T'&&responseBuffer[2]=='S'&&responseBuffer[3]=='P')				return bytesRead;		}	}	return bytesRead;}/////////////////////char* parseSDPLine(char* inputLine){	char *ptr;	for (ptr = inputLine; *ptr != '\0'; ++ptr) 	{		if (*ptr == '\r' || *ptr == '\n') 		{			++ptr;			while (*ptr == '\r' || *ptr == '\n') ++ptr;			if (ptr[0] == '\0') ptr = NULL; // special case for end			break;		}	}	if (inputLine[0] == '\r' || inputLine[0] == '\n') return ptr;	if (strlen(inputLine) < 2 || inputLine[1] != '='		    || inputLine[0] < 'a' || inputLine[0] > 'z') 	{		fprintf(stderr,"Invalid SDP line \n");		return NULL;	}	return ptr;}char * parseSDPAttribute_rtpmap(char* sdpLine,unsigned* rtpTimestampFrequency,unsigned *fnumChannels) {	unsigned rtpmapPayloadFormat;	unsigned numChannels = 1;	char* codecName = strDupSize(sdpLine); // ensures we have enough space	if (sscanf(sdpLine, "a=rtpmap: %u %[^/]/%u/%u",			&rtpmapPayloadFormat, codecName, rtpTimestampFrequency,			&numChannels) == 4		|| sscanf(sdpLine, "a=rtpmap: %u %[^/]/%u",			&rtpmapPayloadFormat, codecName, rtpTimestampFrequency) == 3		|| sscanf(sdpLine, "a=rtpmap: %u %s",			&rtpmapPayloadFormat, codecName) == 2) 	{		*fnumChannels = numChannels;  		return strDup(codecName);	}	free(codecName);	return NULL;}char * parseSDPAttribute_control(char* sdpLine) {  	char* controlPath = strDupSize(sdpLine); // ensures we have enough space	if (sscanf(sdpLine, "a=control:%s", controlPath) == 1) 	{		return strDup(controlPath);	}	free(controlPath);	return NULL;}int parseSDPAttribute_range(char* sdpLine) {	int parseSuccess = -1;	char playEndTime[32];	char temp[32];	int index = 0;	int j = 0;	unsigned long endtime = 0;	char *endstr;	int k;	int i,num;	if (sscanf(sdpLine, "a=range:npt=0-  %s", playEndTime)==1) 	{		parseSuccess = 0;		for(index = 0;index<strlen(playEndTime);index++)		{			if(playEndTime[index]!='.')			{				temp[j] = playEndTime[index];				j++;			}			else			{				for(k=index+1;k<strlen(playEndTime);k++)				{					temp[j] = playEndTime[k];					j++;					PotPos++;				}				break;			}		}		temp[j] = '\0';						endtime = strtoul(temp,&endstr,10);		if (endtime > fMaxPlayEndTime) 		{			if(PotPos>=3)			{				num = 1;				for(i = 0;i<PotPos-3;i++)				{					num = 10*num;				}				fMaxPlayEndTime = endtime/num;			}			else			{				num = 1;				for(i = 0;i<3-PotPos;i++)				{					num = 10*num;				}				fMaxPlayEndTime = endtime*num;			}			PotPos = 1000;					}		fprintf(stderr,"fMaxPlayEndTime is %lu\n",fMaxPlayEndTime);	}	return parseSuccess;}char * parseSDPAttribute_fmtp(char* sdpLine) {	char* lineCopy;	char* line;	char* valueStr;	char* c;	do 	{		if (strncmp(sdpLine, "a=fmtp:", 7) != 0) break; 		sdpLine += 7;		while (isdigit(*sdpLine)) ++sdpLine;		lineCopy = strDup(sdpLine); 		line = lineCopy;		for (c = line; *c != '\0'; ++c) *c = tolower(*c);    		while (*line != '\0' && *line != '\r' && *line != '\n') 		{			valueStr = strDupSize(line);			if (sscanf(line, " config = %[^; \t\r\n]", valueStr) == 1) 			{				free(lineCopy);								return strDup(valueStr);      			}      			free(valueStr);			while (*line != '\0' && *line != '\r' && *line != '\n'&& *line != ';') ++line;			while (*line == ';') ++line;		}		free(lineCopy);	} while (0);	return NULL;}struct MediaAttribute * GetMediaAttrbute(struct MediaAttribute *Attribute,struct MediaSubsession * subsession,int subsessionNum){	struct MediaSubsession *mediasub;	int len = 0;	mediasub = subsession;	while(subsessionNum>0)	{		if(strcmp(mediasub->fCodecName,"MP4V-ES") == 0)		{				Attribute->fVideoFrequency = mediasub->frtpTimestampFrequency;			Attribute->fVideoPayloadFormat = mediasub->fRTPPayloadFormat;			len = strlen(mediasub->fConfig);			memcpy(Attribute->fConfigAsc,mediasub->fConfig,len);			a_hex(mediasub->fConfig,Attribute->fConfigHex,len);			Attribute->fConfigHexLen = len/2;			parse_vovod(Attribute->fConfigHex,Attribute->fConfigHexLen,&(Attribute->fVideoFrameRate),&(Attribute->fTimeIncBits),&(Attribute->fVideoWidth),&(Attribute->fVideoHeight));						Attribute->fixed_vop_rate = fixed_vop_rate;			VFrameRate = Attribute->fVideoFrameRate;		}		else if(strcmp(mediasub->fCodecName,"MPA") == 0||strcmp(mediasub->fCodecName,"mpeg4-generic") == 0)		{				Attribute->fAudioFrequency = mediasub->frtpTimestampFrequency;			Attribute->fAudioPayloadFormat = mediasub->fRTPPayloadFormat;			Attribute->fTrackNum = mediasub->fNumChannels;		}			mediasub = mediasub->fNext;		subsessionNum--;	}	return Attribute;}struct MediaSubsession * initializeWithSDP(char* sdpDescription,int *SubsessionNum){ 	int Num = 0;	char*  sdpLine = sdpDescription;	char* nextSDPLine = NULL;	struct MediaSubsession *fSubsessionsHead;	struct MediaSubsession *fSubsessionsTail;	struct MediaSubsession* subsession;	char* mediumName;	char * CodecName;	char * ControlPath;	char *Config;	unsigned payloadFormat;	if (sdpDescription == NULL) return NULL;	fSubsessionsHead = fSubsessionsTail = NULL;	while (1) 	{		if ((nextSDPLine = parseSDPLine(sdpLine)) == NULL)		{			return NULL;				}		if (sdpLine[0] == 'm') 		{			Num++;			break;		}		sdpLine = nextSDPLine;		if (sdpLine == NULL) break; // there are no m= lines at all 		if (!parseSDPAttribute_range(sdpLine)) continue;//check a=range:npt=	}    	while (sdpLine != NULL) 	{		subsession = (struct MediaSubsession*)malloc(sizeof(struct MediaSubsession));		if (subsession == NULL) 		{			fprintf(stderr,"Unable to create new MediaSubsession\n");			return NULL;		}		if (fSubsessionsTail == NULL) 		{			fSubsessionsHead = fSubsessionsTail = subsession;		} 		else 		{			fSubsessionsTail->fNext = subsession;			subsession->fNext = NULL;			fSubsessionsTail = subsession;					}		mediumName = strDupSize(sdpLine);    		if (sscanf(sdpLine, "m=%s %hu RTP/AVP %u",mediumName, &subsession->fClientPortNum, &payloadFormat) != 3			|| payloadFormat > 127) 		{			fprintf(stderr,"Bad SDP line\n");			free(mediumName);			return NULL;		}    		subsession->fMediumName = strDup(mediumName);		free(mediumName);		subsession->fRTPPayloadFormat = payloadFormat;				while (1) 		{			sdpLine = nextSDPLine;//a=rtpmap...			if (sdpLine == NULL) break; // we've reached the end			if ((nextSDPLine = parseSDPLine(sdpLine)) == NULL)			{				*SubsessionNum = Num;				return fSubsessionsHead;							//下移一行			}			if (sdpLine[0] == 'm') 			{				Num ++;				break; // we've reached the next subsession			}			// Check for various special SDP lines that we understand:			CodecName = strDupSize(sdpLine);			if ((CodecName = parseSDPAttribute_rtpmap(sdpLine,&(subsession->frtpTimestampFrequency),&(subsession->fNumChannels)))!=NULL)			{				subsession->fCodecName = strDup(CodecName);				if(strcmp(CodecName,"MP4V-ES") == 0)				{						VTimestampFrequency = subsession->frtpTimestampFrequency;					VPayloadType = subsession->fRTPPayloadFormat;				}				else if(strcmp(CodecName,"MPA") == 0||strcmp(CodecName,"mpeg4-generic") == 0)				{						ATimestampFrequency = subsession->frtpTimestampFrequency;					APayloadType = subsession->fRTPPayloadFormat;				}				free(CodecName);				continue;			}			ControlPath = strDupSize(sdpLine);			if ((ControlPath = parseSDPAttribute_control(sdpLine))!=NULL)			{				subsession->fControlPath = strDup(ControlPath);				free(ControlPath);				continue;			}			Config = strDupSize(sdpLine);			if ((Config = parseSDPAttribute_fmtp(sdpLine))!=NULL)			{				subsession->fConfig = strDup(Config);				free(Config);				continue;			}		}	}		*SubsessionNum = Num;	return fSubsessionsHead;  }int blockUntilwriteable(int socket)//, struct timeval* timeout){	int result = -1;	static unsigned numFds;	fd_set wd_set;	do 	{		FD_ZERO(&wd_set);		if (socket < 0) break;		FD_SET((unsigned) socket, &wd_set);		numFds = socket+1;				result = select(numFds, NULL, &wd_set, NULL,0);// timeout);		if (result == 0)		{			break; // this is OK - timeout occurred		}		else if(result <= 0) 		{			fprintf(stderr, "select() error\n ");			break;		}		if (!FD_ISSET(socket, &wd_set)) 		{			fprintf(stderr, "select() error - !FD_ISSET\n");			break;		}	} while (0);	return result;};int blockUntilReadable(int socket)//, struct timeval* timeout) {	fd_set rd_set;	int result = -1;	static unsigned numFds;		do 	{		FD_ZERO(&rd_set);		if (socket < 0) break;		FD_SET((unsigned) socket, &rd_set);		numFds = socket+1;		result = select(numFds, &rd_set, NULL, NULL,0);		if (result == 0) 		{			break; // this is OK - timeout occurred		} 		else if (result <= 0) 		{			fprintf(stderr, "select() error\n ");			break;		}    		if (!FD_ISSET(socket, &rd_set)) 		{			fprintf(stderr, "select() error - !FD_ISSET\n");			break;		}		} while (0);	return result;}int getSDPDescriptionFromURL(int socketNum,char* url,char* Description){	int fSocketNum;	char *readBuffer;//[MAX_READBUFSIZE+1]; 	char* readBuf;	int bytesRead;	char* cmdFmt ="DESCRIBE %s RTSP/1.0\r\nCSeq: %d\r\nAccept: application/sdp\r\n%s\r\n";	unsigned cmdSize = 0;										  	char* cmd = NULL;	char* firstLine;	char* nextLineStart;	unsigned responseCode;	int contentLength = -1;	char* lineStart;  	unsigned numExtraBytesNeeded;	char* ptr;	int bytesRead2;		readBuffer = (char *)malloc((MAX_READBUFSIZE+1)*sizeof(char));	if(readBuffer == NULL)	{		fprintf(stderr,"failed to alloc the memory\n");    		return -1;	}	memset(readBuffer,0,MAX_READBUFSIZE+1);	readBuf =readBuffer;		//fprintf(stderr,"start alloc cmd\n");	cmdSize = strlen(cmdFmt) + strlen(url) + 20 /* max int len */+ strlen(UserAgentHeaderStr);	cmd = (char *)malloc((cmdSize+1)*sizeof(char));	if(cmd ==NULL)	{		fprintf(stderr,"failed to alloc the memory\n");    		free(readBuffer);    		return -1;	}	//fprintf(stderr,"alloc cmd successful\n");	memset(cmd,0,cmdSize+1);	fSocketNum = socketNum;	do 	{   		// Send the DESCRIBE command:		//fprintf(stderr,"Send the DESCRIBE command\n");		sprintf(cmd, cmdFmt,url,++fCSeq,UserAgentHeaderStr);    //发送description 请求				//fprintf(stderr,"start blockUntilwriteable\n");  		if(blockUntilwriteable(fSocketNum)<=0)  		{   			fprintf(stderr,"socket is unwriteable\n");  			break;  		}  		//fprintf(stderr,"start send\n");  		if (send(fSocketNum, cmd, strlen(cmd), 0)<0) 		{			fprintf(stderr,"DESCRIBE send() failed\n ");			break;		}		//fprintf(stderr,"DESCRIBE send() successful\n");			// Get the response from the server:		//fprintf(stderr,"Get the response from the server\n");		bytesRead = getResponse(fSocketNum,readBuf, MAX_READBUFSIZE);		if (bytesRead <= 0) break;				//fprintf(stderr,"DESCRIBE response-%d:\n%s\n",fCSeq,readBuf);		//Received DESCRIBE response    		// Inspect the first line to check whether it's a result code that		// we can handle.		firstLine = readBuf;		nextLineStart = getLine(firstLine);		if (sscanf(firstLine, "%*s%u", &responseCode) != 1) 		{			fprintf(stderr,"no response code in line\n");			break;		}		if (responseCode != 200) 		{			fprintf(stderr,"cannot handle DESCRIBE response\n");			break;		}		// Skip every subsequent header line, until we see a blank line		// The remaining data is assumed to be the SDP descriptor that we want.		// We should really do some checking on the headers here - e.g., to		// check for "Content-type: application/sdp", "Content-base",		// "Content-location", "CSeq", etc. #####		//fprintf(stderr,"start get Content-Length\n");		while (1) 		{			lineStart = nextLineStart;			if (lineStart == NULL||lineStart[0] == '\0') break;			nextLineStart = getLine(lineStart);			if (sscanf(lineStart, "Content-Length: %d", &contentLength) == 1				|| sscanf(lineStart, "Content-length: %d", &contentLength) == 1) 			if(contentLength>0)			{				if (contentLength < 0) 				{					fprintf(stderr,"Bad Content-length\n");					break;				}				// Use the remaining data as the SDP descr, but first, check				// the "Content-length:" header (if any) that we saw.  We may need to				// read more data, or we may have extraneous data in the buffer.				//bodyStart = nextLineStart;				// We saw a "Content-length:" header								//numBodyBytes = &readBuf[bytesRead] - bodyStart;				//if (contentLength > (int)numBodyBytes) 				//{				// We need to read more data.  First, make sure we have enough				// space for it:				numExtraBytesNeeded = contentLength;// - numBodyBytes;							// Keep reading more data until we have enough:				bytesRead = 0;				//fprintf(stderr,"start recv %d\n",contentLength);				while (numExtraBytesNeeded > 0) 				{					if(blockUntilReadable(fSocketNum)<=0)    					{    						fprintf(stderr,"socket is unreadable\n");    						break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -