Example #1
0
GF_EXPORT
GF_RTPHinter *gf_hinter_track_new(GF_ISOFile *file, u32 TrackNum, 
							u32 Path_MTU, u32 max_ptime, u32 default_rtp_rate, u32 flags, u8 PayloadID, 
							Bool copy_media, u32 InterleaveGroupID, u8 InterleaveGroupPriority, GF_Err *e)
{

	GF_SLConfig my_sl;
	u32 descIndex, MinSize, MaxSize, avgTS, streamType, oti, const_dur, nb_ch, maxDTSDelta;
	u8 OfficialPayloadID;
	u32 TrackMediaSubType, TrackMediaType, hintType, nbEdts, required_rate, force_dts_delta, avc_nalu_size, PL_ID, bandwidth, IV_length, KI_length;
	const char *url, *urn;
	char *mpeg4mode;
	Bool is_crypted, has_mpeg4_mapping;
	GF_RTPHinter *tmp;
	GF_ESD *esd;

	*e = GF_BAD_PARAM;
	if (!file || !TrackNum || !gf_isom_get_track_id(file, TrackNum)) return NULL;

	if (!gf_isom_get_sample_count(file, TrackNum)) {
		*e = GF_OK;
		return NULL;
	}
	*e = GF_NOT_SUPPORTED;
	nbEdts = gf_isom_get_edit_segment_count(file, TrackNum);
	if (nbEdts>1) {
		u64 et, sd, mt;
		u8 em;
		gf_isom_get_edit_segment(file, TrackNum, 1, &et, &sd, &mt, &em);
		if ((nbEdts>2) || (em!=GF_ISOM_EDIT_EMPTY)) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[rtp hinter] Cannot hint track whith EditList\n"));
			return NULL;
		}
	}
	if (nbEdts) gf_isom_remove_edit_segments(file, TrackNum);

	if (!gf_isom_is_track_enabled(file, TrackNum)) return NULL;

	/*by default NO PL signaled*/
	PL_ID = 0;
	OfficialPayloadID = 0;
	force_dts_delta = 0;
	streamType = oti = 0;
	mpeg4mode = NULL;
	required_rate = 0;
	is_crypted = 0;
	IV_length = KI_length = 0;
	oti = 0;
	nb_ch = 0;
	avc_nalu_size = 0;
	has_mpeg4_mapping = 1;
	TrackMediaType = gf_isom_get_media_type(file, TrackNum);
	TrackMediaSubType = gf_isom_get_media_subtype(file, TrackNum, 1);
	
	/*for max compatibility with QT*/
	if (!default_rtp_rate) default_rtp_rate = 90000;

	/*timed-text is a bit special, we support multiple stream descriptions & co*/
	if ( (TrackMediaType==GF_ISOM_MEDIA_TEXT) || (TrackMediaType==GF_ISOM_MEDIA_SUBT)) {
		hintType = GF_RTP_PAYT_3GPP_TEXT;
		oti = GPAC_OTI_TEXT_MPEG4;
		streamType = GF_STREAM_TEXT;
		/*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/
		PL_ID = 0x10;
	} else {
		if (gf_isom_get_sample_description_count(file, TrackNum) > 1) return NULL;

		TrackMediaSubType = gf_isom_get_media_subtype(file, TrackNum, 1);
		switch (TrackMediaSubType) {
		case GF_ISOM_SUBTYPE_MPEG4_CRYP: 
			is_crypted = 1;
		case GF_ISOM_SUBTYPE_MPEG4:
			esd = gf_isom_get_esd(file, TrackNum, 1);
			hintType = GF_RTP_PAYT_MPEG4;
			if (esd) {
				streamType = esd->decoderConfig->streamType;
				oti = esd->decoderConfig->objectTypeIndication;
				if (esd->URLString) hintType = 0;
				/*AAC*/
				if ((streamType==GF_STREAM_AUDIO) && esd->decoderConfig->decoderSpecificInfo
				/*(nb: we use mpeg4 for MPEG-2 AAC)*/
				&& ((oti==GPAC_OTI_AUDIO_AAC_MPEG4) || (oti==GPAC_OTI_AUDIO_AAC_MPEG4) || (oti==GPAC_OTI_AUDIO_AAC_MPEG2_MP) || (oti==GPAC_OTI_AUDIO_AAC_MPEG2_LCP) || (oti==GPAC_OTI_AUDIO_AAC_MPEG2_SSRP)) ) {

					u32 sample_rate;
					GF_M4ADecSpecInfo a_cfg;
					gf_m4a_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &a_cfg);
					nb_ch = a_cfg.nb_chan;
					sample_rate = a_cfg.base_sr;
					PL_ID = a_cfg.audioPL;
					switch (a_cfg.base_object_type) {
					case GF_M4A_AAC_MAIN:
					case GF_M4A_AAC_LC:
						if (flags & GP_RTP_PCK_USE_LATM_AAC) {
							hintType = GF_RTP_PAYT_LATM;
							break;
						}
					case GF_M4A_AAC_SBR:
					case GF_M4A_AAC_PS:
					case GF_M4A_AAC_LTP:
					case GF_M4A_AAC_SCALABLE:
					case GF_M4A_ER_AAC_LC:
					case GF_M4A_ER_AAC_LTP:
					case GF_M4A_ER_AAC_SCALABLE:
						mpeg4mode = "AAC";
						break;
					case GF_M4A_CELP:
					case GF_M4A_ER_CELP:
						mpeg4mode = "CELP";
						break;
					}
					required_rate = sample_rate;
				}
				/*MPEG1/2 audio*/
				else if ((streamType==GF_STREAM_AUDIO) && ((oti==GPAC_OTI_AUDIO_MPEG2_PART3) || (oti==GPAC_OTI_AUDIO_MPEG1))) {
					u32 sample_rate;
					if (!is_crypted) {
						GF_ISOSample *samp = gf_isom_get_sample(file, TrackNum, 1, NULL);
						u32 hdr = GF_4CC((u8)samp->data[0], (u8)samp->data[1], (u8)samp->data[2], (u8)samp->data[3]);
						nb_ch = gf_mp3_num_channels(hdr);
						sample_rate = gf_mp3_sampling_rate(hdr);
						gf_isom_sample_del(&samp);
						hintType = GF_RTP_PAYT_MPEG12_AUDIO;
						/*use official RTP/AVP payload type*/
						OfficialPayloadID = 14;
						required_rate = 90000;
					}
					/*encrypted MP3 must be sent through MPEG-4 generic to signal all ISMACryp stuff*/
					else {
						u8 bps;
						gf_isom_get_audio_info(file, TrackNum, 1, &sample_rate, &nb_ch, &bps);
						required_rate = sample_rate;
					}
				}
				/*QCELP audio*/
				else if ((streamType==GF_STREAM_AUDIO) && (oti==GPAC_OTI_AUDIO_13K_VOICE)) {
					hintType = GF_RTP_PAYT_QCELP;
					OfficialPayloadID = 12;
					required_rate = 8000;
					streamType = GF_STREAM_AUDIO;
					nb_ch = 1;
				}
				/*EVRC/SVM audio*/
				else if ((streamType==GF_STREAM_AUDIO) && ((oti==GPAC_OTI_AUDIO_EVRC_VOICE) || (oti==GPAC_OTI_AUDIO_SMV_VOICE)) ) {
					hintType = GF_RTP_PAYT_EVRC_SMV;
					required_rate = 8000;
					streamType = GF_STREAM_AUDIO;
					nb_ch = 1;
				}
				/*visual streams*/
				else if (streamType==GF_STREAM_VISUAL) {
					if (oti==GPAC_OTI_VIDEO_MPEG4_PART2) {
						GF_M4VDecSpecInfo dsi;
						gf_m4v_get_config(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi);
						PL_ID = dsi.VideoPL;
					}
					/*MPEG1/2 video*/
					if ( ((oti>=GPAC_OTI_VIDEO_MPEG2_SIMPLE) && (oti<=GPAC_OTI_VIDEO_MPEG2_422)) || (oti==GPAC_OTI_VIDEO_MPEG1)) {
						if (!is_crypted) {
							hintType = GF_RTP_PAYT_MPEG12_VIDEO;
							OfficialPayloadID = 32;
						}
					}
					/*for ISMA*/
					if (is_crypted) {
						/*that's another pain with ISMACryp, even if no B-frames the DTS is signaled...*/
						if (oti==GPAC_OTI_VIDEO_MPEG4_PART2) force_dts_delta = 22;
						else if (oti==GPAC_OTI_VIDEO_AVC) {
							flags &= ~GP_RTP_PCK_USE_MULTI;
							force_dts_delta = 22;
						}
						flags |= GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_SIGNAL_TS;
					}

					required_rate = default_rtp_rate;
				}
				/*systems streams*/
				else if (gf_isom_has_sync_shadows(file, TrackNum) || gf_isom_has_sample_dependency(file, TrackNum)) {
					flags |= GP_RTP_PCK_SYSTEMS_CAROUSEL;
				}
				gf_odf_desc_del((GF_Descriptor*)esd);
			}
			break;
		case GF_ISOM_SUBTYPE_3GP_H263:
			hintType = GF_RTP_PAYT_H263;
			required_rate = 90000;
			streamType = GF_STREAM_VISUAL;
			OfficialPayloadID = 34;
			/*not 100% compliant (short header is missing) but should still work*/
			oti = GPAC_OTI_VIDEO_MPEG4_PART2;
			PL_ID = 0x01;
			break;
		case GF_ISOM_SUBTYPE_3GP_AMR:
			required_rate = 8000;
			hintType = GF_RTP_PAYT_AMR;
			streamType = GF_STREAM_AUDIO;
			has_mpeg4_mapping = 0;
			nb_ch = 1;
			break;
		case GF_ISOM_SUBTYPE_3GP_AMR_WB:
			required_rate = 16000;
			hintType = GF_RTP_PAYT_AMR_WB;
			streamType = GF_STREAM_AUDIO;
			has_mpeg4_mapping = 0;
			nb_ch = 1;
			break;
		case GF_ISOM_SUBTYPE_AVC_H264:
		case GF_ISOM_SUBTYPE_AVC2_H264:
		case GF_ISOM_SUBTYPE_SVC_H264:
		{
			GF_AVCConfig *avcc = gf_isom_avc_config_get(file, TrackNum, 1);
			required_rate = 90000;	/* "90 kHz clock rate MUST be used"*/
			hintType = GF_RTP_PAYT_H264_AVC;
			streamType = GF_STREAM_VISUAL;
			avc_nalu_size = avcc->nal_unit_size;
			oti = GPAC_OTI_VIDEO_AVC;
			PL_ID = 0x0F;
			gf_odf_avc_cfg_del(avcc);
		}
			break;
		case GF_ISOM_SUBTYPE_3GP_QCELP:
			required_rate = 8000;
			hintType = GF_RTP_PAYT_QCELP;
			streamType = GF_STREAM_AUDIO;
			oti = GPAC_OTI_AUDIO_13K_VOICE;
			OfficialPayloadID = 12;
			nb_ch = 1;
			break;
		case GF_ISOM_SUBTYPE_3GP_EVRC:
		case GF_ISOM_SUBTYPE_3GP_SMV:
			required_rate = 8000;
			hintType = GF_RTP_PAYT_EVRC_SMV;
			streamType = GF_STREAM_AUDIO;
			oti = (TrackMediaSubType==GF_ISOM_SUBTYPE_3GP_EVRC) ? GPAC_OTI_AUDIO_EVRC_VOICE : GPAC_OTI_AUDIO_SMV_VOICE;
			nb_ch = 1;
			break;
		case GF_ISOM_SUBTYPE_3GP_DIMS:
			hintType = GF_RTP_PAYT_3GPP_DIMS;
			streamType = GF_STREAM_SCENE;
			break;
		case GF_ISOM_SUBTYPE_AC3:
			hintType = GF_RTP_PAYT_AC3;
			streamType = GF_STREAM_AUDIO;
			gf_isom_get_audio_info(file, TrackNum, 1, NULL, &nb_ch, NULL);
			break;
		default:
			/*ERROR*/
			hintType = 0;
			break;
		}
	}

	/*not hintable*/
	if (!hintType) return NULL;
	/*we only support self-contained files for hinting*/
	gf_isom_get_data_reference(file, TrackNum, 1, &url, &urn);
	if (url || urn) return NULL;
	
	*e = GF_OUT_OF_MEM;
	GF_SAFEALLOC(tmp, GF_RTPHinter);
	if (!tmp) return NULL;

	/*override hinter type if requested and possible*/
	if (has_mpeg4_mapping && (flags & GP_RTP_PCK_FORCE_MPEG4)) {
		hintType = GF_RTP_PAYT_MPEG4;
		avc_nalu_size = 0;
	}
	/*use static payload ID if enabled*/
	else if (OfficialPayloadID && (flags & GP_RTP_PCK_USE_STATIC_ID) ) {
		PayloadID = OfficialPayloadID;
	}

	tmp->file = file;
	tmp->TrackNum = TrackNum;
	tmp->avc_nalu_size = avc_nalu_size;
	tmp->nb_chan = nb_ch;

	/*spatial scalability check*/
	tmp->has_ctts = gf_isom_has_time_offset(file, TrackNum);

	/*get sample info*/
	gf_media_get_sample_average_infos(file, TrackNum, &MinSize, &MaxSize, &avgTS, &maxDTSDelta, &const_dur, &bandwidth);

	/*systems carousel: we need at least IDX and RAP signaling*/
	if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) {
		flags |= GP_RTP_PCK_SIGNAL_RAP;
	}

	/*update flags in MultiSL*/
	if (flags & GP_RTP_PCK_USE_MULTI) {
		if (MinSize != MaxSize) flags |= GP_RTP_PCK_SIGNAL_SIZE;
		if (!const_dur) flags |= GP_RTP_PCK_SIGNAL_TS;
	}
	if (tmp->has_ctts) flags |= GP_RTP_PCK_SIGNAL_TS;

	/*default SL for RTP */
	InitSL_RTP(&my_sl);

	my_sl.timestampResolution = gf_isom_get_media_timescale(file, TrackNum);
	/*override clockrate if set*/
	if (required_rate) {
		Double sc = required_rate;
		sc /= my_sl.timestampResolution;
		maxDTSDelta = (u32) (maxDTSDelta*sc);
		my_sl.timestampResolution = required_rate;
	}
	/*switch to RTP TS*/
	max_ptime = (u32) (max_ptime * my_sl.timestampResolution / 1000);

	my_sl.AUSeqNumLength = gf_get_bit_size(gf_isom_get_sample_count(file, TrackNum));
	my_sl.CUDuration = const_dur;

	if (gf_isom_has_sync_points(file, TrackNum)) {
		my_sl.useRandomAccessPointFlag = 1;
	} else {
		my_sl.useRandomAccessPointFlag = 0;
		my_sl.hasRandomAccessUnitsOnlyFlag = 1;
	}

	if (is_crypted) {
		Bool use_sel_enc;
		gf_isom_get_ismacryp_info(file, TrackNum, 1, NULL, NULL, NULL, NULL, NULL, &use_sel_enc, &IV_length, &KI_length);
		if (use_sel_enc) flags |= GP_RTP_PCK_SELECTIVE_ENCRYPTION;
	}

	// in case a different timescale was provided
	tmp->OrigTimeScale = gf_isom_get_media_timescale(file, TrackNum);
	tmp->rtp_p = gf_rtp_builder_new(hintType, &my_sl, flags, tmp, 
								MP4T_OnNewPacket, MP4T_OnPacketDone, 
								/*if copy, no data ref*/
								copy_media ? NULL : MP4T_OnDataRef, 
								MP4T_OnData);

	//init the builder
	gf_rtp_builder_init(tmp->rtp_p, PayloadID, Path_MTU, max_ptime,
					   streamType, oti, PL_ID, MinSize, MaxSize, avgTS, maxDTSDelta, IV_length, KI_length, mpeg4mode);

	/*ISMA compliance is a pain...*/
	if (force_dts_delta) tmp->rtp_p->slMap.DTSDeltaLength = force_dts_delta;


	/*		Hint Track Setup	*/
	tmp->TrackID = gf_isom_get_track_id(file, TrackNum);
	tmp->HintID = tmp->TrackID + 65535;
	while (gf_isom_get_track_by_id(file, tmp->HintID)) tmp->HintID++;

	tmp->HintTrack = gf_isom_new_track(file, tmp->HintID, GF_ISOM_MEDIA_HINT, my_sl.timestampResolution);
	gf_isom_setup_hint_track(file, tmp->HintTrack, GF_ISOM_HINT_RTP);
	/*create a hint description*/
	gf_isom_new_hint_description(file, tmp->HintTrack, -1, -1, 0, &descIndex);
	gf_isom_rtp_set_timescale(file, tmp->HintTrack, descIndex, my_sl.timestampResolution);

	if (hintType==GF_RTP_PAYT_MPEG4) {
		tmp->rtp_p->slMap.ObjectTypeIndication = oti;
		/*set this SL for extraction.*/
		gf_isom_set_extraction_slc(file, TrackNum, 1, &my_sl);
	}
	tmp->bandwidth = bandwidth;

	/*set interleaving*/
	gf_isom_set_track_group(file, TrackNum, InterleaveGroupID);
	if (!copy_media) {
		/*if we don't copy data set hint track and media track in the same group*/
		gf_isom_set_track_group(file, tmp->HintTrack, InterleaveGroupID);
	} else {
		gf_isom_set_track_group(file, tmp->HintTrack, InterleaveGroupID + OFFSET_HINT_GROUP_ID);
	}
	/*use user-secified priority*/
	InterleaveGroupPriority*=2;
	gf_isom_set_track_priority_in_group(file, TrackNum, InterleaveGroupPriority+1);
	gf_isom_set_track_priority_in_group(file, tmp->HintTrack, InterleaveGroupPriority);

#if 0
	/*QT FF: not setting these flags = server uses a random offset*/
	gf_isom_rtp_set_time_offset(file, tmp->HintTrack, 1, 0);
	/*we don't use seq offset for maintainance pruposes*/
	gf_isom_rtp_set_time_sequence_offset(file, tmp->HintTrack, 1, 0);
#endif
	*e = GF_OK;
	return tmp;
}
Example #2
0
GF_EXPORT
GF_RTPStreamer *gf_rtp_streamer_new_extended(u32 streamType, u32 oti, u32 timeScale, 
								const char *ip_dest, u16 port, u32 MTU, u8 TTL, const char *ifce_addr, 
								 u32 flags, char *dsi, u32 dsi_len, 
								 
								 u32 PayloadType, u32 sample_rate, u32 nb_ch,
								 Bool is_crypted, u32 IV_length, u32 KI_length,
								 u32 MinSize, u32 MaxSize, u32 avgTS, u32 maxDTSDelta, u32 const_dur, u32 bandwidth, u32 max_ptime, 
								 u32 au_sn_len
								 )
{
	GF_SLConfig slc;
	GF_RTPStreamer *stream;
	u32 rtp_type, default_rtp_rate;
	u8 OfficialPayloadType;
	u32 required_rate, force_dts_delta, PL_ID;
	char *mpeg4mode;
	Bool has_mpeg4_mapping;
	GF_Err e;

	if (!timeScale) timeScale = 1000;

	GF_SAFEALLOC(stream, GF_RTPStreamer);


	/*by default NO PL signaled*/
	PL_ID = 0;
	OfficialPayloadType = 0;
	force_dts_delta = 0;
	mpeg4mode = NULL;
	required_rate = 0;
	nb_ch = 0;
	has_mpeg4_mapping = 1;
	rtp_type = 0;

	/*for max compatibility with QT*/
	default_rtp_rate = 90000;

	/*timed-text is a bit special, we support multiple stream descriptions & co*/
	switch (streamType) {
	case GF_STREAM_TEXT:
		if (oti!=GPAC_OTI_TEXT_MPEG4)
			return NULL;

		rtp_type = GF_RTP_PAYT_3GPP_TEXT;
		/*fixme - this works cos there's only one PL for text in mpeg4 at the current time*/
		PL_ID = 0x10;
		break;
	case GF_STREAM_AUDIO:
		required_rate = sample_rate;
		switch (oti) {
		/*AAC*/
		case GPAC_OTI_AUDIO_AAC_MPEG4:
		case GPAC_OTI_AUDIO_AAC_MPEG2_MP:
		case GPAC_OTI_AUDIO_AAC_MPEG2_LCP:
		case GPAC_OTI_AUDIO_AAC_MPEG2_SSRP:
			PL_ID = 0x01;
			mpeg4mode = "AAC";
			rtp_type = GF_RTP_PAYT_MPEG4;
			required_rate = sample_rate;

#ifndef GPAC_DISABLE_AV_PARSERS
			if (dsi) {
				GF_M4ADecSpecInfo a_cfg;
				gf_m4a_get_config(dsi, dsi_len, &a_cfg);
				nb_ch = a_cfg.nb_chan;
				sample_rate = a_cfg.base_sr;
				PL_ID = a_cfg.audioPL;
				switch (a_cfg.base_object_type) {
				case GF_M4A_AAC_MAIN:
				case GF_M4A_AAC_LC:
					if (flags & GP_RTP_PCK_USE_LATM_AAC) {
						rtp_type = GF_RTP_PAYT_LATM;
						break;
					}
				case GF_M4A_AAC_SBR:
				case GF_M4A_AAC_PS:
				case GF_M4A_AAC_LTP:
				case GF_M4A_AAC_SCALABLE:
				case GF_M4A_ER_AAC_LC:
				case GF_M4A_ER_AAC_LTP:
				case GF_M4A_ER_AAC_SCALABLE:
					mpeg4mode = "AAC";
					break;
				case GF_M4A_CELP:
				case GF_M4A_ER_CELP:
					mpeg4mode = "CELP";
					break;
				}
			} 
#endif
			break;

			/*MPEG1/2 audio*/
		case GPAC_OTI_AUDIO_MPEG2_PART3:
		case GPAC_OTI_AUDIO_MPEG1:
			if (!is_crypted) {
				rtp_type = GF_RTP_PAYT_MPEG12_AUDIO;
				/*use official RTP/AVP payload type*/
				OfficialPayloadType = 14;
				required_rate = 90000;
			}
			/*encrypted MP3 must be sent through MPEG-4 generic to signal all ISMACryp stuff*/
			else {
				rtp_type = GF_RTP_PAYT_MPEG4;
			}
			break;

		/*QCELP audio*/
		case GPAC_OTI_AUDIO_13K_VOICE:
			rtp_type = GF_RTP_PAYT_QCELP;
			OfficialPayloadType = 12;
			required_rate = 8000;
			nb_ch = 1;
			break;

		/*EVRC/SVM audio*/
		case GPAC_OTI_AUDIO_EVRC_VOICE:
		case GPAC_OTI_AUDIO_SMV_VOICE:
			rtp_type = GF_RTP_PAYT_EVRC_SMV;
			required_rate = 8000;
			nb_ch = 1;
		}

		break;

	case GF_STREAM_VISUAL:
		rtp_type = GF_RTP_PAYT_MPEG4;
		required_rate = default_rtp_rate;
		if (is_crypted) {
			/*that's another pain with ISMACryp, even if no B-frames the DTS is signaled...*/
			if (oti==GPAC_OTI_VIDEO_MPEG4_PART2) force_dts_delta = 22;
			flags |= GP_RTP_PCK_SIGNAL_RAP | GP_RTP_PCK_SIGNAL_TS;
		}

		switch (oti) {
		/*ISO/IEC 14496-2*/
		case GPAC_OTI_VIDEO_MPEG4_PART2:
			PL_ID = 1;
#ifndef GPAC_DISABLE_AV_PARSERS
			if (dsi) {
				GF_M4VDecSpecInfo vhdr;
				gf_m4v_get_config(dsi, dsi_len, &vhdr);
				PL_ID = vhdr.VideoPL;
			}
#endif
			break;

		/*MPEG1/2 video*/
		case GPAC_OTI_VIDEO_MPEG1:
		case GPAC_OTI_VIDEO_MPEG2_SIMPLE:
		case GPAC_OTI_VIDEO_MPEG2_MAIN:
		case GPAC_OTI_VIDEO_MPEG2_SNR:
		case GPAC_OTI_VIDEO_MPEG2_SPATIAL:
		case GPAC_OTI_VIDEO_MPEG2_HIGH:
		case GPAC_OTI_VIDEO_MPEG2_422:
			if (!is_crypted) {
				rtp_type = GF_RTP_PAYT_MPEG12_VIDEO;
				OfficialPayloadType = 32;
			}
			break;
		/*AVC/H.264*/
		case GPAC_OTI_VIDEO_AVC:
			required_rate = 90000;	/* "90 kHz clock rate MUST be used"*/
			rtp_type = GF_RTP_PAYT_H264_AVC;
			PL_ID = 0x0F;
			break;
		/*H264-SVC*/
		case GPAC_OTI_VIDEO_SVC:
			required_rate = 90000;	/* "90 kHz clock rate MUST be used"*/
			rtp_type = GF_RTP_PAYT_H264_SVC;
			PL_ID = 0x0F;
			break;
		/*HEVC*/
		case GPAC_OTI_VIDEO_HEVC:
			required_rate = 90000;	/* "90 kHz clock rate MUST be used"*/
			rtp_type = GF_RTP_PAYT_HEVC;
			PL_ID = 0x0F;
			break;
		}
		break;

	case GF_STREAM_SCENE:
	case GF_STREAM_OD:
        if (oti == GPAC_OTI_SCENE_DIMS) {
            rtp_type = GF_RTP_PAYT_3GPP_DIMS;
            has_mpeg4_mapping = 0;
        } else {
            rtp_type = GF_RTP_PAYT_MPEG4;
        }
		break;


	case GF_STREAM_4CC:
		switch (oti) {
		case GF_ISOM_SUBTYPE_3GP_H263:
			rtp_type = GF_RTP_PAYT_H263;
			required_rate = 90000;
			streamType = GF_STREAM_VISUAL;
			OfficialPayloadType = 34;
			/*not 100% compliant (short header is missing) but should still work*/
			oti = GPAC_OTI_VIDEO_MPEG4_PART2;
			PL_ID = 0x01;
			break;
		case GF_ISOM_SUBTYPE_3GP_AMR:
			required_rate = 8000;
			rtp_type = GF_RTP_PAYT_AMR;
			streamType = GF_STREAM_AUDIO;
			has_mpeg4_mapping = 0;
			nb_ch = 1;
			break;
		case GF_ISOM_SUBTYPE_3GP_AMR_WB:
			required_rate = 16000;
			rtp_type = GF_RTP_PAYT_AMR_WB;
			streamType = GF_STREAM_AUDIO;
			has_mpeg4_mapping = 0;
			nb_ch = 1;
			break;
		case GF_ISOM_SUBTYPE_AC3:
			rtp_type = GF_RTP_PAYT_AC3;
			streamType = GF_STREAM_AUDIO;
			has_mpeg4_mapping = 1;
			nb_ch = 1;
			break;
		case GF_ISOM_SUBTYPE_AVC_H264:
		case GF_ISOM_SUBTYPE_AVC2_H264:
		case GF_ISOM_SUBTYPE_AVC3_H264:
		case GF_ISOM_SUBTYPE_AVC4_H264:
		case GF_ISOM_SUBTYPE_SVC_H264:
		{
			required_rate = 90000;	/* "90 kHz clock rate MUST be used"*/
			rtp_type = GF_RTP_PAYT_H264_AVC;
			streamType = GF_STREAM_VISUAL;
			oti = GPAC_OTI_VIDEO_AVC;
			PL_ID = 0x0F;
		}
			break;
		case GF_ISOM_SUBTYPE_3GP_QCELP:
			required_rate = 8000;
			rtp_type = GF_RTP_PAYT_QCELP;
			streamType = GF_STREAM_AUDIO;
			oti = GPAC_OTI_AUDIO_13K_VOICE;
			OfficialPayloadType = 12;
			nb_ch = 1;
			break;
		case GF_ISOM_SUBTYPE_3GP_EVRC:
		case GF_ISOM_SUBTYPE_3GP_SMV:
			required_rate = 8000;
			rtp_type = GF_RTP_PAYT_EVRC_SMV;
			streamType = GF_STREAM_AUDIO;
			oti = (oti==GF_ISOM_SUBTYPE_3GP_EVRC) ? GPAC_OTI_AUDIO_EVRC_VOICE : GPAC_OTI_AUDIO_SMV_VOICE;
			nb_ch = 1;
			break;
		}
		break;

	default:
		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Unsupported stream type %x\n", streamType));
		return NULL;
	}

	/*not supported*/
	if (!rtp_type) return NULL;
	
	/*override hinter type if requested and possible*/
	if (has_mpeg4_mapping && (flags & GP_RTP_PCK_FORCE_MPEG4)) {
		rtp_type = GF_RTP_PAYT_MPEG4;
	}
	/*use static payload ID if enabled*/
	else if (OfficialPayloadType && (flags & GP_RTP_PCK_USE_STATIC_ID) ) {
		PayloadType = OfficialPayloadType;
	}

	/*systems carousel: we need at least IDX and RAP signaling*/
	if (flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) {
		flags |= GP_RTP_PCK_SIGNAL_RAP;
	}

	/*update flags in MultiSL*/
	if (flags & GP_RTP_PCK_USE_MULTI) {
		if (MinSize != MaxSize) flags |= GP_RTP_PCK_SIGNAL_SIZE;
		if (!const_dur) flags |= GP_RTP_PCK_SIGNAL_TS;
	}

	/*default SL for RTP */
	memset(&slc, 0, sizeof(GF_SLConfig));
	slc.tag = GF_ODF_SLC_TAG;
	slc.useTimestampsFlag = 1;
	slc.timestampLength = 32;
	slc.timestampResolution = timeScale;

	/*override clockrate if set*/
	if (required_rate) {
		Double sc = required_rate;
		sc /= slc.timestampResolution;
		maxDTSDelta = (u32) (maxDTSDelta*sc);
		slc.timestampResolution = required_rate;
	}
	/*switch to RTP TS*/
	max_ptime = (u32) (max_ptime * slc.timestampResolution / 1000);

	slc.AUSeqNumLength = au_sn_len;
	slc.CUDuration = const_dur;

	if (flags & GP_RTP_PCK_SIGNAL_RAP) {
		slc.useRandomAccessPointFlag = 1;
	} else {
		slc.useRandomAccessPointFlag = 0;
		slc.hasRandomAccessUnitsOnlyFlag = 1;
	}

	stream->packetizer = gf_rtp_builder_new(rtp_type, &slc, flags, 
								stream, 
								rtp_stream_on_new_packet, rtp_stream_on_packet_done, 
								NULL, rtp_stream_on_data);
	
	if (!stream->packetizer) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Failed to create packetizer\n"));
		gf_free(stream);
		return NULL;
	}
	
	gf_rtp_builder_init(stream->packetizer, PayloadType, MTU, max_ptime,
					   streamType, oti, PL_ID, MinSize, MaxSize, avgTS, maxDTSDelta, IV_length, KI_length, mpeg4mode);


	if (force_dts_delta) stream->packetizer->slMap.DTSDeltaLength = force_dts_delta;

	e = rtp_stream_init_channel(stream, MTU + 12, ip_dest, port, TTL, ifce_addr);
	if (e) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[RTP Packetizer] Failed to create RTP channel - error %s\n", gf_error_to_string(e) ));
		gf_free(stream);
		return NULL;
	}
	stream->ts_scale = slc.timestampResolution;
	stream->ts_scale /= timeScale;

	stream->buffer_alloc = MTU+12;
	stream->buffer = gf_malloc(sizeof(char) * stream->buffer_alloc);

	return stream;
}
Example #3
0
//Compute the #params of the slMap
GF_EXPORT
void gf_rtp_builder_init(GP_RTPPacketizer *builder, u8 PayloadType, u32 PathMTU, u32 max_ptime, 
					   u32 StreamType, u32 OTI, u32 PL_ID,
					   u32 avgSize, u32 maxSize, 
					   u32 avgTS, u32 maxDTS,
					   u32 IV_length, u32 KI_length,
					   char *pref_mode) 
{
	u32 k, ismacrypt_flags;

	memset(&builder->slMap, 0, sizeof(GP_RTPSLMap));
	builder->Path_MTU = PathMTU;
	builder->PayloadType = PayloadType;
	builder->slMap.StreamType = StreamType;
	builder->slMap.ObjectTypeIndication = OTI;
	builder->slMap.PL_ID = PL_ID;
	builder->max_ptime = max_ptime;
	if (pref_mode) strcpy(builder->slMap.mode, pref_mode);


	//some cst vars
	builder->rtp_header.Version = 2;
	builder->rtp_header.PayloadType = builder->PayloadType;

	/*our max config is with 1 packet only (SingleSL)*/
	builder->first_sl_in_rtp = 1;
	/*no AUX data*/
	builder->slMap.AuxiliaryDataSizeLength= 0;


	/*just compute max aggregation size*/
	switch (builder->rtp_payt) {
	case GF_RTP_PAYT_QCELP:
	case GF_RTP_PAYT_EVRC_SMV:
	case GF_RTP_PAYT_AMR:
	case GF_RTP_PAYT_AMR_WB:
	{
		u32 nb_pck = 1;
		u32 block_size = 160;
		/*compute max frames per packet - if no avg size, use max size per codec*/
		if (builder->flags & GP_RTP_PCK_USE_MULTI) {
			if (builder->rtp_payt == GF_RTP_PAYT_QCELP) {
				if (!avgSize) avgSize = 35;
				nb_pck = (PathMTU-1) / avgSize;	/*one-byte header*/
				if (nb_pck>10) nb_pck=10;	/*cf RFC2658*/
			} else if (builder->rtp_payt == GF_RTP_PAYT_EVRC_SMV) {
				if (!avgSize) avgSize = 23;
				nb_pck = (PathMTU) / avgSize;
				if (nb_pck>32) nb_pck=32;	/*cf RFC3558*/
			} else if (builder->rtp_payt == GF_RTP_PAYT_AMR_WB) {
				if (!avgSize) avgSize = 61;
				nb_pck = (PathMTU-1) / avgSize;
				block_size = 320;
			} else {
				if (!avgSize) avgSize = 32;
				nb_pck = (PathMTU-1) / avgSize;
			}
			if (max_ptime) {
				u32 max_pck = max_ptime / block_size;
				if (nb_pck > max_pck) nb_pck = max_pck;
			}
		}
		if (nb_pck<=1) {
			builder->flags &= ~(GP_RTP_PCK_USE_MULTI|GP_RTP_PCK_USE_INTERLEAVING);
			builder->auh_size = 1;
		} else {
			builder->auh_size = nb_pck;
		}
		/*remove all MPEG-4 and ISMA flags */
		builder->flags &= 0x07;
	}
		return;
	case GF_RTP_PAYT_LATM: 
	case GF_RTP_PAYT_MPEG4:
		break;
	default:
		/*remove all MPEG-4 and ISMA flags */
		builder->flags &= 0x07;
		/*disable aggregation for visual streams, except for AVC where STAP/MTAP can be used*/
		if (StreamType==GF_STREAM_VISUAL) {
			if (OTI != GPAC_OTI_VIDEO_AVC) {
				builder->flags &= ~GP_RTP_PCK_USE_MULTI;
			}
		}
		else if (avgSize && (PathMTU <= avgSize) ) {
			builder->flags &= ~GP_RTP_PCK_USE_MULTI;
		}
		return;
	} 

	builder->slMap.IV_length = IV_length;
	builder->slMap.KI_length = KI_length;

	ismacrypt_flags = 0;
	if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) ismacrypt_flags |= GP_RTP_PCK_SELECTIVE_ENCRYPTION;
	if (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU) ismacrypt_flags |= GP_RTP_PCK_KEY_IDX_PER_AU;

	/*mode setup*/
	if (!strnicmp(builder->slMap.mode, "AAC", 3)) {
		builder->flags = GP_RTP_PCK_USE_MULTI | GP_RTP_PCK_SIGNAL_SIZE | GP_RTP_PCK_SIGNAL_AU_IDX | ismacrypt_flags;
		/*if (builder->flags & GP_RTP_PCK_USE_INTERLEAVING) */
		builder->slMap.ConstantDuration = avgTS;

		/*AAC LBR*/
		if (maxSize < 63) {
			strcpy(builder->slMap.mode, "AAC-lbr");
			builder->slMap.IndexLength = builder->slMap.IndexDeltaLength = 2;
			builder->slMap.SizeLength = 6;
		}
		/*AAC HBR*/
		else {
			strcpy(builder->slMap.mode, "AAC-hbr");
			builder->slMap.IndexLength = builder->slMap.IndexDeltaLength = 3;
			builder->slMap.SizeLength = 13;
		}
		goto check_header;
	}
	if (!strnicmp(builder->slMap.mode, "CELP", 4)) {
		/*CELP-cbr*/
		if (maxSize == avgSize) {
			/*reset flags (interleaving forbidden)*/
			builder->flags = GP_RTP_PCK_USE_MULTI | ismacrypt_flags;
			strcpy(builder->slMap.mode, "CELP-cbr");
			builder->slMap.ConstantSize = avgSize;
			builder->slMap.ConstantDuration = avgTS;
		}
		/*CELP VBR*/
		else {
			strcpy(builder->slMap.mode, "CELP-vbr");
			builder->slMap.IndexLength = builder->slMap.IndexDeltaLength = 2;
			builder->slMap.SizeLength = 6;
			/*if (builder->flags & GP_RTP_PCK_USE_INTERLEAVING) */builder->slMap.ConstantDuration = avgTS;
			builder->flags = GP_RTP_PCK_USE_MULTI | GP_RTP_PCK_SIGNAL_SIZE | GP_RTP_PCK_SIGNAL_AU_IDX | ismacrypt_flags;
		}
		goto check_header;
	}

	/*generic setup by flags*/
	
	/*size*/
	if (builder->flags & GP_RTP_PCK_SIGNAL_SIZE) {
		if (avgSize==maxSize) {
			builder->slMap.SizeLength = 0;
			builder->slMap.ConstantSize = maxSize;
		} else {
			builder->slMap.SizeLength = gf_get_bit_size(maxSize ? maxSize : PathMTU);
			builder->slMap.ConstantSize = 0;
		}
	} else {
		builder->slMap.SizeLength = 0;
		if (builder->flags & GP_RTP_PCK_USE_MULTI)
			builder->slMap.ConstantSize = (avgSize==maxSize) ? maxSize : 0;
		else
			builder->slMap.ConstantSize = 0;
	}

	/*single SL per RTP*/
	if (!(builder->flags & GP_RTP_PCK_USE_MULTI)) {
		if ( builder->sl_config.AUSeqNumLength && (builder->flags & GP_RTP_PCK_SIGNAL_AU_IDX)) {
			builder->slMap.IndexLength = builder->sl_config.AUSeqNumLength;
		} else {
			builder->slMap.IndexLength = 0;
		}
		/*one packet per RTP so no delta*/
		builder->slMap.IndexDeltaLength = 0;
		builder->slMap.IV_delta_length = 0;

		/*CTS Delta is always 0 since we have one SL packet per RTP*/
		builder->slMap.CTSDeltaLength = 0;

		/*DTS Delta depends on the video type*/
		if ((builder->flags & GP_RTP_PCK_SIGNAL_TS) && maxDTS ) 
			builder->slMap.DTSDeltaLength = gf_get_bit_size(maxDTS);
		else
			builder->slMap.DTSDeltaLength = 0;

		/*RAP*/
		if (builder->sl_config.useRandomAccessPointFlag && (builder->flags & GP_RTP_PCK_SIGNAL_RAP)) {
			builder->slMap.RandomAccessIndication = 1;
		} else {
			builder->slMap.RandomAccessIndication = 0;
		}

		/*stream state*/
		if (builder->flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) {
			if (!builder->sl_config.AUSeqNumLength) builder->sl_config.AUSeqNumLength = 4;
			builder->slMap.StreamStateIndication = builder->sl_config.AUSeqNumLength;
		}
		goto check_header;
	}

	/*this is the avg samples we can store per RTP packet*/
	k = PathMTU / avgSize;
	if (k<=1) {
		builder->flags &= ~GP_RTP_PCK_USE_MULTI;
		/*keep TS signaling for B-frames (eg never default to M4V-ES when B-frames are present)*/
		//builder->flags &= ~GP_RTP_PCK_SIGNAL_TS;
		builder->flags &= ~GP_RTP_PCK_SIGNAL_SIZE;
		builder->flags &= ~GP_RTP_PCK_SIGNAL_AU_IDX;
		builder->flags &= ~GP_RTP_PCK_USE_INTERLEAVING;
		builder->flags &= ~GP_RTP_PCK_KEY_IDX_PER_AU;
		gf_rtp_builder_init(builder, PayloadType, PathMTU, max_ptime, StreamType, OTI, PL_ID, avgSize, maxSize, avgTS, maxDTS, IV_length, KI_length, pref_mode);
		return;
	}

	/*multiple SL per RTP - check if we have to send TS*/
	builder->slMap.ConstantDuration = builder->sl_config.CUDuration;
	if (!builder->slMap.ConstantDuration) {
		builder->flags |= GP_RTP_PCK_SIGNAL_TS;
	}
	/*if we have a constant duration and are not writting TSs, make sure we write AU IDX when interleaving*/
	else if (! (builder->flags & GP_RTP_PCK_SIGNAL_TS) && (builder->flags & GP_RTP_PCK_USE_INTERLEAVING)) {
		builder->flags |= GP_RTP_PCK_SIGNAL_AU_IDX;
	}

	if (builder->flags & GP_RTP_PCK_SIGNAL_TS) {
		/*compute CTS delta*/
		builder->slMap.CTSDeltaLength = gf_get_bit_size(k*avgTS);

		/*compute DTS delta. Delta is ALWAYS from the CTS of the same sample*/ 
		if (maxDTS) 
			builder->slMap.DTSDeltaLength = gf_get_bit_size(maxDTS);
		else
			builder->slMap.DTSDeltaLength = 0;
	}

	if ((builder->flags & GP_RTP_PCK_SIGNAL_AU_IDX) && builder->sl_config.AUSeqNumLength) {
		builder->slMap.IndexLength = builder->sl_config.AUSeqNumLength;
		/*and k-1 AUs in Delta*/
		builder->slMap.IndexDeltaLength = (builder->flags & GP_RTP_PCK_USE_INTERLEAVING) ? gf_get_bit_size(k-1) : 0;
	}
	else if (builder->flags & GP_RTP_PCK_SYSTEMS_CAROUSEL) {
		if (!builder->sl_config.AUSeqNumLength) builder->sl_config.AUSeqNumLength = 4;
		builder->slMap.StreamStateIndication = builder->sl_config.AUSeqNumLength;
	}

	/*RAP*/
	if (builder->sl_config.useRandomAccessPointFlag && (builder->flags & GP_RTP_PCK_SIGNAL_RAP)) {
		builder->slMap.RandomAccessIndication = 1;
	} else {
		builder->slMap.RandomAccessIndication = 0;
	}

check_header:

	/*IV delta only if interleaving (otherwise reconstruction from IV is trivial)*/
	if (IV_length && (builder->flags & GP_RTP_PCK_USE_INTERLEAVING)) {
		builder->slMap.IV_delta_length = gf_get_bit_size(maxSize);
	}
	/*ISMACryp video mode*/
	if ((builder->slMap.StreamType==GF_STREAM_VISUAL) && (builder->slMap.ObjectTypeIndication==GPAC_OTI_VIDEO_MPEG4_PART2)
		&& (builder->flags & GP_RTP_PCK_SIGNAL_RAP) && builder->slMap.IV_length 
		&& !(builder->flags & GP_RTP_PCK_SIGNAL_AU_IDX) && !(builder->flags & GP_RTP_PCK_SIGNAL_SIZE)
		/*shall have SignalTS*/
		&& (builder->flags & GP_RTP_PCK_SIGNAL_TS) && !(builder->flags & GP_RTP_PCK_USE_MULTI)
	) {
		strcpy(builder->slMap.mode, "mpeg4-video");
	}
	/*ISMACryp AVC video mode*/
	else if ((builder->slMap.StreamType==GF_STREAM_VISUAL) && (builder->slMap.ObjectTypeIndication==GPAC_OTI_VIDEO_AVC)
		&& (builder->flags & GP_RTP_PCK_SIGNAL_RAP) && builder->slMap.IV_length 
		&& !(builder->flags & GP_RTP_PCK_SIGNAL_AU_IDX) && !(builder->flags & GP_RTP_PCK_SIGNAL_SIZE)
		/*shall have SignalTS*/
		&& (builder->flags & GP_RTP_PCK_SIGNAL_TS) && !(builder->flags & GP_RTP_PCK_USE_MULTI)
	) {
		strcpy(builder->slMap.mode, "avc-video");
	}

	/*check if we use AU header or not*/
	if (!builder->slMap.SizeLength 
		&& !builder->slMap.IndexLength 
		&& !builder->slMap.IndexDeltaLength
		&& !builder->slMap.DTSDeltaLength  
		&& !builder->slMap.CTSDeltaLength
		&& !builder->slMap.RandomAccessIndication
		&& !builder->slMap.IV_length
		&& !builder->slMap.KI_length
	) {
		builder->has_AU_header= 0;
	} else {
		builder->has_AU_header = 1;
	}
}