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

📄 rtp.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *			GPAC - Multimedia Framework C SDK * *			Copyright (c) Jean Le Feuvre 2000-2005  *					All rights reserved * *  This file is part of GPAC / IETF RTP/RTSP/SDP sub-project * *  GPAC is free software; you can redistribute it and/or modify *  it under the terms of the GNU Lesser General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *    *  GPAC is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU Lesser General Public License for more details. *    *  You should have received a copy of the GNU Lesser General Public *  License along with this library; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  * */#include <gpac/internal/ietf_dev.h>#include <gpac/bitstream.h>#define MAX_RTP_SN	0x10000GF_EXPORTGF_RTPChannel *gf_rtp_new(){	GF_RTPChannel *tmp;	GF_SAFEALLOC(tmp, GF_RTPChannel);	tmp->first_SR = 1;	tmp->SSRC = gf_rand();		return tmp;}GF_EXPORTvoid gf_rtp_del(GF_RTPChannel *ch){	if (!ch) return;	if (ch->rtp) gf_sk_del(ch->rtp);	if (ch->rtcp) gf_sk_del(ch->rtcp);	if (ch->net_info.source) free(ch->net_info.source);	if (ch->net_info.destination) free(ch->net_info.destination);	if (ch->net_info.Profile) free(ch->net_info.Profile);	if (ch->po) gf_rtp_reorderer_del(ch->po);	if (ch->send_buffer) free(ch->send_buffer);	if (ch->CName) free(ch->CName);	if (ch->s_name) free(ch->s_name);	if (ch->s_email) free(ch->s_email);	if (ch->s_location) free(ch->s_location);	if (ch->s_phone) free(ch->s_phone);	if (ch->s_tool) free(ch->s_tool);	if (ch->s_note) free(ch->s_note);	if (ch->s_priv) free(ch->s_priv);	free(ch);}GF_EXPORTGF_Err gf_rtp_setup_transport(GF_RTPChannel *ch, GF_RTSPTransport *trans_info, char *remote_address){	if (!ch || !trans_info) return GF_BAD_PARAM;	//assert we have at least ONE source ID	if (!trans_info->source && !remote_address) return GF_BAD_PARAM;	if (ch->net_info.destination) free(ch->net_info.destination);	if (ch->net_info.Profile) free(ch->net_info.Profile);	if (ch->net_info.source) free(ch->net_info.source);	memcpy(&ch->net_info, trans_info, sizeof(GF_RTSPTransport));	if (trans_info->destination) 		ch->net_info.destination = strdup(trans_info->destination);	if (trans_info->Profile) 		ch->net_info.Profile = strdup(trans_info->Profile);	if (trans_info->source) {		ch->net_info.source = strdup(trans_info->source);	} else if (!ch->net_info.IsUnicast && trans_info->destination) {		ch->net_info.source = strdup(trans_info->destination);	} else {		ch->net_info.source = strdup(remote_address);	}	if (trans_info->SSRC) ch->SenderSSRC = trans_info->SSRC;	//check we REALLY have unicast or multicast	if (gf_sk_is_multicast_address(ch->net_info.source) && ch->net_info.IsUnicast) return GF_SERVICE_ERROR;	return GF_OK;}GF_EXPORTvoid gf_rtp_reset_buffers(GF_RTPChannel *ch){	if (ch->rtp) gf_sk_reset(ch->rtp);	if (ch->rtcp) gf_sk_reset(ch->rtcp);	if (ch->po) gf_rtp_reorderer_reset(ch->po);	/*also reset ssrc*/	//ch->SenderSSRC = 0;	ch->first_SR = 1;}GF_EXPORTvoid gf_rtp_enable_nat_keepalive(GF_RTPChannel *ch, u32 nat_timeout){	if (ch) {		ch->nat_keepalive_time_period = nat_timeout;		ch->last_nat_keepalive_time = 0;	}}GF_EXPORTGF_Err gf_rtp_set_info_rtp(GF_RTPChannel *ch, u32 seq_num, u32 rtp_time, u32 ssrc){	if (!ch) return GF_BAD_PARAM;	ch->rtp_time = rtp_time;	ch->last_pck_sn = 0;	ch->rtp_first_SN = seq_num;	ch->num_sn_loops = 0;	//reset RTCP	ch->ntp_init = 0;	ch->first_SR = 1;	if (ssrc) ch->SenderSSRC = ssrc;	ch->total_pck = ch->total_bytes = ch->last_num_pck_rcv = ch->last_num_pck_expected = ch->last_num_pck_loss = ch->tot_num_pck_rcv = ch->tot_num_pck_expected = ch->rtcp_bytes_sent = 0;	return GF_OK;}GF_EXPORTGF_Err gf_rtp_initialize(GF_RTPChannel *ch, u32 UDPBufferSize, Bool IsSource, u32 PathMTU, u32 ReorederingSize, u32 MaxReorderDelay, char *local_interface_ip){	GF_Err e;	if (IsSource && !PathMTU) return GF_BAD_PARAM;	if (ch->rtp) gf_sk_del(ch->rtp);	if (ch->rtcp) gf_sk_del(ch->rtcp);	if (ch->po) gf_rtp_reorderer_del(ch->po);	ch->CurrentTime = 0;	ch->rtp_time = 0;	//create sockets for RTP/AVP profile only	if (ch->net_info.Profile && 		( !stricmp(ch->net_info.Profile, GF_RTSP_PROFILE_RTP_AVP) 		|| !stricmp(ch->net_info.Profile, "RTP/AVP/UDP")		|| !stricmp(ch->net_info.Profile, "RTP/SAVP")		)		) {		//destination MUST be specified for unicast		if (IsSource && ch->net_info.IsUnicast && !ch->net_info.destination) return GF_BAD_PARAM;		//		//	RTP		//		ch->rtp = gf_sk_new(GF_SOCK_TYPE_UDP);		if (!ch->rtp) return GF_IP_NETWORK_FAILURE;		if (ch->net_info.IsUnicast) {			//if client, bind and connect the socket			if (!IsSource) {				e = gf_sk_bind(ch->rtp, ch->net_info.client_port_first, ch->net_info.source, ch->net_info.port_first, GF_SOCK_REUSE_PORT);				if (e) return e;			}			//else bind and set remote destination			else {				if (!ch->net_info.port_first) ch->net_info.port_first = ch->net_info.client_port_first;				e = gf_sk_bind(ch->rtp, ch->net_info.port_first, ch->net_info.destination, ch->net_info.client_port_first, GF_SOCK_REUSE_PORT);				if (e) return e;			}		} else {			//Bind to multicast (auto-join the group). 			//we do not bind the socket if this is a source-only channel because some servers			//don't like that on local loop ...			e = gf_sk_setup_multicast(ch->rtp, ch->net_info.source, ch->net_info.port_first, ch->net_info.TTL, (IsSource==2), local_interface_ip);			if (e) return e;					//destination is used for multicast interface addressing - TO DO		}		if (UDPBufferSize) gf_sk_set_buffer_size(ch->rtp, IsSource, UDPBufferSize);		if (IsSource) {			if (ch->send_buffer) free(ch->send_buffer);			ch->send_buffer = (char *) malloc(sizeof(char) * PathMTU);			ch->send_buffer_size = PathMTU;		}				//create re-ordering queue for UDP only, and recieve		if (ReorederingSize && !IsSource) {			if (!MaxReorderDelay) MaxReorderDelay = 200;			ch->po = gf_rtp_reorderer_new(ReorederingSize, MaxReorderDelay);		}		//		//	RTCP		//		ch->rtcp = gf_sk_new(GF_SOCK_TYPE_UDP);		if (!ch->rtcp) return GF_IP_NETWORK_FAILURE;		if (ch->net_info.IsUnicast) {			if (!IsSource) {				e = gf_sk_bind(ch->rtcp, ch->net_info.client_port_last, ch->net_info.source, ch->net_info.port_last, GF_SOCK_REUSE_PORT);				if (e) return e;			} else {				e = gf_sk_bind(ch->rtcp, ch->net_info.port_last, ch->net_info.destination, ch->net_info.client_port_last, GF_SOCK_REUSE_PORT);				if (e) return e;			}		} else {			if (!ch->net_info.port_last) ch->net_info.port_last = ch->net_info.client_port_last;			//Bind to multicast (auto-join the group)			e = gf_sk_setup_multicast(ch->rtcp, ch->net_info.source, ch->net_info.port_last, ch->net_info.TTL, (IsSource==2), local_interface_ip);			if (e) return e;			//destination is used for multicast interface addressing - TO DO		}	}			//format CNAME if not done yet	if (!ch->CName) {		//this is the real CName setup		if (!ch->rtp) {			ch->CName = strdup("mpeg4rtp");		} else {			char name[GF_MAX_IP_NAME_LEN];			s32 start;			gf_get_user_name(name, 1024);			if (strlen(name)) strcat(name, "@");			start = strlen(name);			//get host IP or loopback if error			if (gf_sk_get_local_ip(ch->rtp, name+start) != GF_OK) strcpy(name+start, "127.0.0.1");			ch->CName = strdup(name);		}	}	#ifndef GPAC_DISABLE_LOG	if ((gf_log_get_level() >= (GF_LOG_DEBUG)) && (gf_log_get_tools() & (GF_LOG_RTP)))  {		GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Packet Log Format: SSRC SequenceNumber TimeStamp NTP@recvTime deviance, Jiter, PckLost PckTotal BytesTotal\n"));	}#endif		return GF_OK;}/*get the UTC time expressed in RTP timescale*/u32 gf_rtp_channel_time(GF_RTPChannel *ch){	u32 sec, frac, res;	gf_net_get_ntp(&sec, &frac);	res = ( (u32) ( (frac>>26)*ch->TimeScale) ) >> 6;	res += ch->TimeScale*(sec - ch->ntp_init);	return (u32) res;}u32 gf_rtp_get_report_time(){	u32 sec, frac;	gf_net_get_ntp(&sec, &frac);	/*in units of 1/65536 seconds*/	return (u32) ( (frac>>16) + 0x10000L*sec );}void gf_rtp_get_next_report_time(GF_RTPChannel *ch){	Double d;	/*offset between .5 and 1.5 sec*/	d = 0.5 + ((Double) gf_rand()) / ((Double) RAND_MAX);	/*of a minimal 5sec interval expressed in 1/65536 of a sec*/	d = 5.0 * d * 65536;	/*we should estimate bandwidth sharing too, but as we only support one sender*/	ch->next_report_time = gf_rtp_get_report_time() + (u32) d;}GF_EXPORTu32 gf_rtp_read_rtp(GF_RTPChannel *ch, char *buffer, u32 buffer_size){	GF_Err e;	u32 seq_num, res;	char *pck;	//only if the socket exist (otherwise RTSP interleaved channel)	if (!ch || !ch->rtp) return 0;	e = gf_sk_receive(ch->rtp, buffer, buffer_size, 0, &res);	if (!res || e || (res < 12)) res = 0;	//add the packet to our Queue if any	if (ch->po) {		if (res) {			seq_num = ((buffer[2] << 8) & 0xFF00) | (buffer[3] & 0xFF);			gf_rtp_reorderer_add(ch->po, (void *) buffer, res, seq_num);		}		//pck queue may need to be flushed		pck = (char *) gf_rtp_reorderer_get(ch->po, &res);		if (pck) {			memcpy(buffer, pck, res);			free(pck);		}	}	/*monitor keep-alive period*/	if (ch->nat_keepalive_time_period) {		u32 now = gf_sys_clock();		if (res) {			ch->last_nat_keepalive_time = now; 		} else {			if (now - ch->last_nat_keepalive_time >= ch->nat_keepalive_time_period) {				char rtp_nat[12];				rtp_nat[0] = (u8) 0xC0;				rtp_nat[1] = ch->PayloadType;				rtp_nat[2] = (ch->last_pck_sn>>8)&0xFF;				rtp_nat[3] = (ch->last_pck_sn)&0xFF;				rtp_nat[4] = (ch->last_pck_ts>>24)&0xFF;				rtp_nat[5] = (ch->last_pck_ts>>16)&0xFF;				rtp_nat[6] = (ch->last_pck_ts>>8)&0xFF;				rtp_nat[7] = (ch->last_pck_ts)&0xFF;				rtp_nat[8] = (ch->SenderSSRC>>24)&0xFF;				rtp_nat[9] = (ch->SenderSSRC>>16)&0xFF;				rtp_nat[10] = (ch->SenderSSRC>>8)&0xFF;				rtp_nat[11] = (ch->SenderSSRC)&0xFF;				e = gf_sk_send(ch->rtp, buffer, 12);				if (e) {					GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP] Error sending NAT keep-alive packet: %s - disabling NAT\n", gf_error_to_string(e) ));					ch->nat_keepalive_time_period = 0;				} else {					GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Sending NAT keep-alive packet - response %s\n", gf_error_to_string(e) ));				}				ch->last_nat_keepalive_time = now;			}		}	}	return res;}GF_EXPORTGF_Err gf_rtp_decode_rtp(GF_RTPChannel *ch, char *pck, u32 pck_size, GF_RTPHeader *rtp_hdr, u32 *PayloadStart){	GF_Err e;	s32 deviance, delta;	u32 CurrSeq, LastSeq;	u32 ntp, lost, low16;	if (!rtp_hdr) return GF_BAD_PARAM;	e = GF_OK;	//we need to uncompress the RTP header	rtp_hdr->Version = (pck[0] & 0xC0 ) >> 6;	if (rtp_hdr->Version != 2) return GF_NOT_SUPPORTED;	rtp_hdr->Padding = ( pck[0] & 0x20 ) >> 5;	rtp_hdr->Extension = ( pck[0] & 0x10 ) >> 4;	rtp_hdr->CSRCCount = pck[0] & 0x0F;	rtp_hdr->Marker = ( pck[1] & 0x80 ) >> 7;	rtp_hdr->PayloadType = pck[1] & 0x7F;	/*we don't support multiple CSRC now. Only one source (the server) is allowed*/	if (rtp_hdr->CSRCCount) return GF_NOT_SUPPORTED;	/*SeqNum*/	rtp_hdr->SequenceNumber = ((pck[2] << 8) & 0xFF00) | (pck[3] & 0xFF);	/*TS*/	rtp_hdr->TimeStamp = (u32) ((pck[4]<<24) &0xFF000000) | ((pck[5]<<16) & 0xFF0000) | ((pck[6]<<8) & 0xFF00) | ((pck[7]) & 0xFF);	/*SSRC*/	rtp_hdr->SSRC = ((pck[8]<<24) &0xFF000000) | ((pck[9]<<16) & 0xFF0000) | ((pck[10]<<8) & 0xFF00) | ((pck[11]) & 0xFF);	/*first we only work with one payload type...*/	if (rtp_hdr->PayloadType != ch->PayloadType) return GF_NOT_SUPPORTED;	/*update RTP time if we didn't get the info*/	if (!ch->rtp_time) {		ch->rtp_time = rtp_hdr->TimeStamp;		ch->rtp_first_SN = rtp_hdr->SequenceNumber;		ch->num_sn_loops = 0;	}	if (!ch->ntp_init && ch->SenderSSRC && (ch->SenderSSRC != rtp_hdr->SSRC) ) {		GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTP] SSRC mismatch: %d vs %d\n", rtp_hdr->SSRC, ch->SenderSSRC));		return GF_IP_NETWORK_EMPTY;	}	/*RTP specs annexe A.8*/	if (!ch->ntp_init) {		gf_net_get_ntp(&ch->ntp_init, &lost);		ch->last_pck_sn = (u32) rtp_hdr->SequenceNumber-1;	}	/*this is a loop in SN - add it*/	if ( (ch->last_pck_sn + 1 > rtp_hdr->SequenceNumber) 		&& (rtp_hdr->SequenceNumber >= ch->last_pck_sn + MAX_RTP_SN/2)) {		ch->num_sn_loops += 1;	}		ntp = gf_rtp_channel_time(ch);	deviance = ntp - rtp_hdr->TimeStamp;	delta = deviance - ch->last_deviance;	ch->last_deviance = deviance;	if (delta < 0) delta = -delta;	ch->Jitter += delta - ( (ch->Jitter + 8) >> 4);	lost = 0;	LastSeq = ch->last_pck_sn;	CurrSeq = (u32) rtp_hdr->SequenceNumber;	/*next sequential pck*/	if ( ( (LastSeq + 1) & 0xffff ) == CurrSeq ) {			ch->last_num_pck_rcv += 1;		ch->last_num_pck_expected += 1;	}	/*repeated pck*/	else if ( (LastSeq & 0xffff ) == CurrSeq ) {		ch->last_num_pck_rcv += 1;	}	/*drop pck*/	else {		low16 = LastSeq & 0xffff;		if ( CurrSeq > low16 )			lost = CurrSeq - low16;		else			lost = 0xffff - low16 + CurrSeq + 1;		ch->last_num_pck_expected += lost;		ch->last_num_pck_rcv += 1;		ch->last_num_pck_loss += lost;	}	ch->last_pck_sn = CurrSeq;#ifndef GPAC_DISABLE_LOG	if ((gf_log_get_level() >= (GF_LOG_DEBUG)) && (gf_log_get_tools() & (GF_LOG_RTP)))  {		ch->total_pck++;		ch->total_bytes += pck_size-12;		GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP]\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", 									ch->SenderSSRC,									rtp_hdr->SequenceNumber,									rtp_hdr->TimeStamp,									ntp,

⌨️ 快捷键说明

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