static GF_Err gf_rtp_payt_setup()

in src/ietf/rtp_depacketizer.c [1199:1666]


static GF_Err gf_rtp_payt_setup(GF_RTPDepacketizer *rtp, GF_RTPMap *map, GF_SDPMedia *media)
{
	u32 i, j;
	GF_SDP_FMTP *fmtp;

	/*reset sl map*/
	memset(&rtp->sl_map, 0, sizeof(GP_RTPSLMap));

	if (!stricmp(map->payload_name, "enc-mpeg4-generic")) rtp->flags |= GF_RTP_HAS_ISMACRYP;


	/*then process all FMTPs*/
	i=0;
	while ((fmtp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &i))) {
		GF_X_Attribute *att;
		//we work with only one PayloadType for now
		if (fmtp->PayloadType != map->PayloadType) continue;
		j=0;
		while ((att = (GF_X_Attribute *)gf_list_enum(fmtp->Attributes, &j))) {
			payt_set_param(rtp, att->Name, att->Value);
		}
	}

	switch (rtp->payt) {
#ifndef GPAC_DISABLE_AV_PARSERS
	case GF_RTP_PAYT_LATM:
	{
		u32 AudioMuxVersion, AllStreamsSameTime, numSubFrames, numPrograms, numLayers, ch_cfg;
		GF_M4ADecSpecInfo cfg;
		char *latm_dsi = rtp->sl_map.config;
		GF_BitStream *bs = gf_bs_new(latm_dsi, rtp->sl_map.configSize, GF_BITSTREAM_READ);
		AudioMuxVersion = gf_bs_read_int(bs, 1);
		AllStreamsSameTime = gf_bs_read_int(bs, 1);
		numSubFrames = gf_bs_read_int(bs, 6);
		numPrograms = gf_bs_read_int(bs, 4);
		numLayers = gf_bs_read_int(bs, 3);

		if (AudioMuxVersion || !AllStreamsSameTime || numSubFrames || numPrograms || numLayers) {
			gf_bs_del(bs);
			return GF_NOT_SUPPORTED;
		}
		memset(&cfg, 0, sizeof(cfg));
		cfg.base_object_type = gf_bs_read_int(bs, 5);
		cfg.base_sr_index = gf_bs_read_int(bs, 4);
		if (cfg.base_sr_index == 0x0F) {
			cfg.base_sr = gf_bs_read_int(bs, 24);
		} else {
			cfg.base_sr = GF_M4ASampleRates[cfg.base_sr_index];
		}
		ch_cfg = gf_bs_read_int(bs, 4);
		if (cfg.base_object_type==5 || cfg.base_object_type==29) {
			if (cfg.base_object_type==29) {
				cfg.has_ps = 1;
				cfg.nb_chan = 1;
			}
			cfg.has_sbr = 1;
			cfg.sbr_sr_index = gf_bs_read_int(bs, 4);
			if (cfg.sbr_sr_index == 0x0F) {
				cfg.sbr_sr = gf_bs_read_int(bs, 24);
			} else {
				cfg.sbr_sr = GF_M4ASampleRates[cfg.sbr_sr_index];
			}
			cfg.sbr_object_type = gf_bs_read_int(bs, 5);
		}
		gf_bs_del(bs);
		gf_free(rtp->sl_map.config);
		bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
		/*write as regular AAC*/
		gf_bs_write_int(bs, cfg.base_object_type, 5);
		gf_bs_write_int(bs, cfg.base_sr_index, 4);

		gf_bs_write_int(bs, ch_cfg, 4);
		gf_bs_align(bs);
		gf_bs_get_content(bs, &rtp->sl_map.config, &rtp->sl_map.configSize);
		gf_bs_del(bs);
		rtp->sl_map.StreamType = GF_STREAM_AUDIO;
		rtp->sl_map.ObjectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4;

		/*assign depacketizer*/
		rtp->depacketize = gf_rtp_parse_latm;
	}
	break;
#endif
	case GF_RTP_PAYT_MPEG4:
		/*mark if AU header is present*/
		rtp->sl_map.auh_first_min_len = 0;
		if (rtp->flags & GF_RTP_HAS_ISMACRYP) {
			if (!rtp->isma_scheme) rtp->isma_scheme = GF_4CC('i','A','E','C');
			if (!rtp->sl_map.IV_length) rtp->sl_map.IV_length = 4;

			if (rtp->flags & GF_RTP_ISMA_SEL_ENC) rtp->sl_map.auh_first_min_len += 8;
			else rtp->sl_map.auh_first_min_len += 8*(rtp->sl_map.IV_length + rtp->sl_map.KI_length);
		}
		rtp->sl_map.auh_first_min_len += rtp->sl_map.CTSDeltaLength;
		rtp->sl_map.auh_first_min_len += rtp->sl_map.DTSDeltaLength;
		rtp->sl_map.auh_first_min_len += rtp->sl_map.SizeLength;
		rtp->sl_map.auh_first_min_len += rtp->sl_map.RandomAccessIndication;
		rtp->sl_map.auh_first_min_len += rtp->sl_map.StreamStateIndication;
		rtp->sl_map.auh_min_len = rtp->sl_map.auh_first_min_len;
		rtp->sl_map.auh_first_min_len += rtp->sl_map.IndexLength;
		rtp->sl_map.auh_min_len += rtp->sl_map.IndexDeltaLength;
		/*RFC3016 flags*/
		if (!stricmp(map->payload_name, "MP4V-ES")) {
			rtp->sl_map.StreamType = GF_STREAM_VISUAL;
			rtp->sl_map.ObjectTypeIndication = GPAC_OTI_VIDEO_MPEG4_PART2;
		}
		else if (!strnicmp(map->payload_name, "AAC", 3)) {
			rtp->sl_map.StreamType = GF_STREAM_AUDIO;
			rtp->sl_map.ObjectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4;
		}
		else if (!stricmp(map->payload_name, "MP4A-LATM")) {
			rtp->sl_map.StreamType = GF_STREAM_AUDIO;
			rtp->sl_map.ObjectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4;
		}
		/*MPEG-4 video, check RAPs if not indicated*/
		if ((rtp->sl_map.StreamType == GF_STREAM_VISUAL) && (rtp->sl_map.ObjectTypeIndication == GPAC_OTI_VIDEO_MPEG4_PART2) && !rtp->sl_map.RandomAccessIndication) {
			rtp->flags |= GF_RTP_M4V_CHECK_RAP;
		}
#ifndef GPAC_DISABLE_AV_PARSERS
		if ((rtp->sl_map.ObjectTypeIndication == GPAC_OTI_AUDIO_AAC_MPEG4) && !rtp->sl_map.config) {
			GF_M4ADecSpecInfo cfg;
			GF_RTPMap*map = (GF_RTPMap*)gf_list_get(media->RTPMaps, 0);

			memset(&cfg, 0, sizeof(GF_M4ADecSpecInfo));
			cfg.audioPL = rtp->sl_map.PL_ID;
			cfg.nb_chan = map->AudioChannels;
			cfg.nb_chan = 1;
			cfg.base_sr = map->ClockRate/2;
			cfg.sbr_sr = map->ClockRate;
			cfg.base_object_type = GF_M4A_AAC_LC;
			cfg.base_object_type = 5;
			cfg.sbr_object_type = GF_M4A_AAC_MAIN;
			gf_m4a_write_config(&cfg, &rtp->sl_map.config, &rtp->sl_map.configSize);
		}
#endif
		/*assign depacketizer*/
		rtp->depacketize = gf_rtp_parse_mpeg4;
		break;
#ifndef GPAC_DISABLE_AV_PARSERS
	case GF_RTP_PAYT_MPEG12_AUDIO:
		rtp->sl_map.StreamType = GF_STREAM_AUDIO;
		rtp->sl_map.ObjectTypeIndication = GPAC_OTI_AUDIO_MPEG2_PART3;
		/*assign depacketizer*/
		rtp->depacketize = gf_rtp_parse_mpeg12_audio;
		break;
#endif /*GPAC_DISABLE_AV_PARSERS*/

	case GF_RTP_PAYT_MPEG12_VIDEO:
		/*we signal RAPs*/
		rtp->sl_map.RandomAccessIndication = GF_TRUE;
		rtp->sl_map.StreamType = GF_STREAM_VISUAL;
		/*FIXME: how to differentiate MPEG1 from MPEG2 video before any frame is received??*/
		rtp->sl_map.ObjectTypeIndication = GPAC_OTI_VIDEO_MPEG1;
		/*assign depacketizer*/
		rtp->depacketize = gf_rtp_parse_mpeg12_video;
		break;
	case GF_RTP_PAYT_AMR:
	case GF_RTP_PAYT_AMR_WB:
	{
		GF_BitStream *bs;
		rtp->sl_map.StreamType = GF_STREAM_AUDIO;
		rtp->sl_map.ObjectTypeIndication = GPAC_OTI_MEDIA_GENERIC;
		/*create DSI*/
		bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
		if (rtp->payt == GF_RTP_PAYT_AMR) {
			gf_bs_write_u32(bs, GF_4CC('s', 'a', 'm', 'r'));
			gf_bs_write_u32(bs, 8000);
			gf_bs_write_u16(bs, 1);
			gf_bs_write_u16(bs, 160);
		} else {
			gf_bs_write_u32(bs, GF_4CC('s', 'a', 'w', 'b'));
			gf_bs_write_u32(bs, 16000);
			gf_bs_write_u16(bs, 1);
			gf_bs_write_u16(bs, 320);
		}
		gf_bs_write_u8(bs, 16);
		gf_bs_write_u8(bs, 1);
		gf_bs_get_content(bs, &rtp->sl_map.config, &rtp->sl_map.configSize);
		gf_bs_del(bs);
		/*assign depacketizer*/
		rtp->depacketize = gf_rtp_parse_amr;
	}
	break;
	case GF_RTP_PAYT_H263:
	{
		u32 x, y, w, h;
		GF_X_Attribute *att;
		GF_BitStream *bs;
		x = y = w = h = 0;
		j=0;
		while ((att = (GF_X_Attribute *)gf_list_enum(media->Attributes, &j))) {
			if (stricmp(att->Name, "cliprect")) continue;
			/*only get the display area*/
			sscanf(att->Value, "%u,%u,%u,%u", &y, &x, &h, &w);
		}

		rtp->sl_map.StreamType = GF_STREAM_VISUAL;
		rtp->sl_map.ObjectTypeIndication = GPAC_OTI_MEDIA_GENERIC;
		/*create DSI*/
		bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
		gf_bs_write_u32(bs, GF_4CC('h', '2', '6', '3'));
		gf_bs_write_u16(bs, w);
		gf_bs_write_u16(bs, h);
		gf_bs_get_content(bs, &rtp->sl_map.config, &rtp->sl_map.configSize);
		gf_bs_del(bs);
		/*we signal RAPs*/
		rtp->sl_map.RandomAccessIndication = GF_TRUE;
		/*assign depacketizer*/
		rtp->depacketize = gf_rtp_parse_h263;
	}
	break;
	case GF_RTP_PAYT_3GPP_TEXT:
	{
		char *tx3g, *a_tx3g;
		GF_BitStream *bs;
		u32 nb_desc;
		GF_SDP_FMTP *fmtp;
		GF_TextConfig tcfg;
		memset(&tcfg, 0, sizeof(GF_TextConfig));
		tcfg.tag = GF_ODF_TEXT_CFG_TAG;
		tcfg.Base3GPPFormat = 0x10;
		tcfg.MPEGExtendedFormat = 0x10;
		tcfg.profileLevel = 0x10;
		tcfg.timescale = map->ClockRate;
		tcfg.sampleDescriptionFlags = 1;
		tx3g = NULL;

		i=0;
		while ((fmtp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &i))) {
			GF_X_Attribute *att;
			if (fmtp->PayloadType != map->PayloadType) continue;
			j=0;
			while ((att = (GF_X_Attribute *)gf_list_enum(fmtp->Attributes, &j))) {

				if (!stricmp(att->Name, "width")) tcfg.text_width = atoi(att->Value);
				else if (!stricmp(att->Name, "height")) tcfg.text_height = atoi(att->Value);
				else if (!stricmp(att->Name, "tx")) tcfg.horiz_offset = atoi(att->Value);
				else if (!stricmp(att->Name, "ty")) tcfg.vert_offset = atoi(att->Value);
				else if (!stricmp(att->Name, "layer")) tcfg.layer = atoi(att->Value);
				else if (!stricmp(att->Name, "max-w")) tcfg.video_width = atoi(att->Value);
				else if (!stricmp(att->Name, "max-h")) tcfg.video_height = atoi(att->Value);
				else if (!stricmp(att->Name, "tx3g")) tx3g = att->Value;
			}
		}
		if (!tx3g) return GF_NON_COMPLIANT_BITSTREAM;

		bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
		gf_bs_write_u8(bs, tcfg.Base3GPPFormat);
		gf_bs_write_u8(bs, tcfg.MPEGExtendedFormat); /*MPEGExtendedFormat*/
		gf_bs_write_u8(bs, tcfg.profileLevel); /*profileLevel*/
		gf_bs_write_u24(bs, tcfg.timescale);
		gf_bs_write_int(bs, 0, 1);	/*no alt formats*/
		gf_bs_write_int(bs, tcfg.sampleDescriptionFlags, 2);
		gf_bs_write_int(bs, 1, 1);	/*we will write sample desc*/
		gf_bs_write_int(bs, 1, 1);	/*video info*/
		gf_bs_write_int(bs, 0, 3);	/*reserved, spec doesn't say the values*/
		gf_bs_write_u8(bs, tcfg.layer);
		gf_bs_write_u16(bs, tcfg.text_width);
		gf_bs_write_u16(bs, tcfg.text_height);
		/*get all tx3g (comma separated)*/
		nb_desc = 1;
		a_tx3g = tx3g;
		while ((a_tx3g = strchr(a_tx3g, ',')) ) {
			a_tx3g ++;
			nb_desc ++;
		}
		a_tx3g = tx3g;
		gf_bs_write_u8(bs, nb_desc);
		while (1) {
			char *next_tx3g, szOut[1000];
			u32 len;
			strcpy(a_tx3g, tx3g);
			next_tx3g = strchr(a_tx3g, ',');
			if (next_tx3g) next_tx3g[0] = 0;
			len = gf_base64_decode(a_tx3g, (u32) strlen(a_tx3g), szOut, 1000);
			gf_bs_write_data(bs, szOut, len);
			tx3g = strchr(tx3g, ',');
			if (!tx3g) break;
			tx3g += 1;
			while (tx3g[0] == ' ') tx3g += 1;
		}

		/*write video cfg*/
		gf_bs_write_u16(bs, tcfg.video_width);
		gf_bs_write_u16(bs, tcfg.video_height);
		gf_bs_write_u16(bs, tcfg.horiz_offset);
		gf_bs_write_u16(bs, tcfg.vert_offset);
		gf_bs_get_content(bs, &rtp->sl_map.config, &rtp->sl_map.configSize);
		rtp->sl_map.StreamType = GF_STREAM_TEXT;
		rtp->sl_map.ObjectTypeIndication = 0x08;
		gf_bs_del(bs);
		/*assign depacketizer*/
		rtp->depacketize = gf_rtp_parse_ttxt;
	}
	break;
#ifndef GPAC_DISABLE_AV_PARSERS
	case GF_RTP_PAYT_H264_AVC:
	case GF_RTP_PAYT_H264_SVC:
	{
		GF_SDP_FMTP *fmtp;
		GF_AVCConfig *avcc = gf_odf_avc_cfg_new();
		avcc->AVCProfileIndication = (rtp->sl_map.PL_ID>>16) & 0xFF;
		avcc->profile_compatibility = (rtp->sl_map.PL_ID>>8) & 0xFF;
		avcc->AVCLevelIndication = rtp->sl_map.PL_ID & 0xFF;
		avcc->configurationVersion = 1;
		avcc->nal_unit_size = 4;
		rtp->sl_map.StreamType = 4;
		rtp->sl_map.ObjectTypeIndication = GPAC_OTI_VIDEO_AVC;
		/*we will signal RAPs*/
		rtp->sl_map.RandomAccessIndication = GF_TRUE;
		/*rewrite sps and pps*/
		i=0;
		while ((fmtp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &i))) {
			GF_X_Attribute *att;
			if (fmtp->PayloadType != map->PayloadType) continue;
			j=0;
			while ((att = (GF_X_Attribute *)gf_list_enum(fmtp->Attributes, &j))) {
				char *nal_ptr, *sep;
				if (stricmp(att->Name, "sprop-parameter-sets")) continue;

				nal_ptr = att->Value;
				while (nal_ptr) {
					u32 nalt, b64size, ret;
					char *b64_d;

					sep = strchr(nal_ptr, ',');
					if (sep) sep[0] = 0;

					b64size = (u32) strlen(nal_ptr);
					b64_d = (char*)gf_malloc(sizeof(char)*b64size);
					ret = gf_base64_decode(nal_ptr, b64size, b64_d, b64size);
					b64_d[ret] = 0;

					nalt = b64_d[0] & 0x1F;
					if (/*SPS*/(nalt==0x07) || /*PPS*/(nalt==0x08) || /*SSPS*/(nalt==0x0F)) {
						GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *)gf_malloc(sizeof(GF_AVCConfigSlot));
						sl->size = ret;
						sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
						memcpy(sl->data, b64_d, sizeof(char)*sl->size);
						if (nalt==0x07 || nalt==0x0F) {
							gf_list_add(avcc->sequenceParameterSets, sl);
						} else {
							gf_list_add(avcc->pictureParameterSets, sl);
						}
					}
					gf_free(b64_d);

					if (sep) {
						sep[0] = ',';
						nal_ptr = sep+1;
					} else {
						break;
					}
				}
			}
		}
		gf_odf_avc_cfg_write(avcc, &rtp->sl_map.config, &rtp->sl_map.configSize);
		gf_odf_avc_cfg_del(avcc);
	}
		/*assign depacketizer*/
	rtp->depacketize = gf_rtp_parse_h264;
	break;
	case GF_RTP_PAYT_HEVC:
	case GF_RTP_PAYT_SHVC:
#ifndef GPAC_DISABLE_HEVC
	{
		GF_SDP_FMTP *fmtp;
		GF_HEVCConfig *hevcc = gf_odf_hevc_cfg_new();
		hevcc->configurationVersion = 1;
		hevcc->nal_unit_size = 4;
		rtp->sl_map.StreamType = 4;
		rtp->sl_map.ObjectTypeIndication = GPAC_OTI_VIDEO_HEVC;
		/*we will signal RAPs*/
		rtp->sl_map.RandomAccessIndication = GF_TRUE;
		i=0;
		while ((fmtp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &i))) {
			GF_X_Attribute *att;
			if (fmtp->PayloadType != map->PayloadType) continue;
			j=0;
			while ((att = (GF_X_Attribute *)gf_list_enum(fmtp->Attributes, &j))) {
				char *nal_ptr, *sep;
				GF_HEVCParamArray *ar;
				if (!stricmp(att->Name, "sprop-vps")) {
					GF_SAFEALLOC(ar, GF_HEVCParamArray);
					ar->nalus = gf_list_new();
					ar->type = GF_HEVC_NALU_VID_PARAM;
				}
				else if (!stricmp(att->Name, "sprop-sps")) {
					GF_SAFEALLOC(ar, GF_HEVCParamArray);
					ar->nalus = gf_list_new();
					ar->type = GF_HEVC_NALU_SEQ_PARAM;
				}
				else if (!stricmp(att->Name, "sprop-pps")) {
					GF_SAFEALLOC(ar, GF_HEVCParamArray);
					ar->nalus = gf_list_new();
					ar->type = GF_HEVC_NALU_PIC_PARAM;
				}
				else
					continue;
				nal_ptr = att->Value;
				while (nal_ptr) {
					u32 b64size, ret;
					char *b64_d;
					GF_AVCConfigSlot *sl;

					sep = strchr(nal_ptr, ',');
					if (sep) sep[0] = 0;

					b64size = (u32) strlen(nal_ptr);
					b64_d = (char*)gf_malloc(sizeof(char)*b64size);
					ret = gf_base64_decode(nal_ptr, b64size, b64_d, b64size);
					b64_d[ret] = 0;

					sl = (GF_AVCConfigSlot *)gf_malloc(sizeof(GF_AVCConfigSlot));
					sl->size = ret;
					sl->data = (char*)gf_malloc(sizeof(char)*sl->size);
					memcpy(sl->data, b64_d, sizeof(char)*sl->size);
					gf_list_add(ar->nalus, sl);

					gf_free(b64_d);

					if (sep) {
						sep[0] = ',';
						nal_ptr = sep+1;
					} else {
						break;
					}
				}
				if (!hevcc->param_array) hevcc->param_array = gf_list_new();
				gf_list_add(hevcc->param_array, ar);
			}
		}
		gf_odf_hevc_cfg_write(hevcc, &rtp->sl_map.config, &rtp->sl_map.configSize);
		gf_odf_hevc_cfg_del(hevcc);
	}
	rtp->depacketize = gf_rtp_parse_hevc;
#else
	return GF_NOT_SUPPORTED;
#endif
	break;
#endif /*GPAC_DISABLE_AV_PARSERS*/

	/*todo - rewrite DIMS config*/
	case GF_RTP_PAYT_3GPP_DIMS:
		rtp->sl_map.StreamType = GF_STREAM_SCENE;
		rtp->sl_map.ObjectTypeIndication = GPAC_OTI_SCENE_DIMS;
		/*we will signal RAPs*/
		rtp->sl_map.RandomAccessIndication = GF_TRUE;
		/*we map DIMS CTR to AU seq num, hence 3 bits*/
		rtp->sl_map.StreamStateIndication = 3;
		rtp->sl_map.IndexLength = 3;
		/*assign depacketizer*/
		rtp->depacketize = gf_rtp_parse_3gpp_dims;
		break;
#ifndef GPAC_DISABLE_AV_PARSERS
	case GF_RTP_PAYT_AC3:
		rtp->sl_map.StreamType = GF_STREAM_AUDIO;
		rtp->sl_map.ObjectTypeIndication = 0xA5;
		rtp->sl_map.RandomAccessIndication = GF_TRUE;
		/*assign depacketizer*/
		rtp->depacketize = gf_rtp_parse_ac3;
		break;
#endif /*GPAC_DISABLE_AV_PARSERS*/
	default:
		return GF_NOT_SUPPORTED;
	}
	return GF_OK;
}