GF_Err gp_rtp_builder_do_latm(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration)
{
	u32 size, latm_hdr_size, i, data_offset;
	Bool fragmented;

	if (!data) {
		latm_flush(builder);
		return GF_OK;
	}

	if ((builder->flags & GP_RTP_PCK_USE_MULTI) && builder->max_ptime) {
		if ((u32) builder->sl_header.compositionTimeStamp + duration >= builder->rtp_header.TimeStamp + builder->max_ptime)
			latm_flush(builder);
	}
	/*compute max size for frame, flush current if this doesn't fit*/
	latm_hdr_size = (data_size / 255) + 1;
	if (latm_hdr_size+data_size > builder->Path_MTU - builder->bytesInPacket) {
		latm_flush(builder);
	}

	data_offset = 0;
	fragmented = GF_FALSE;
	while (data_size > 0) {
		u8 *latm_hdr;
		latm_hdr_size = (data_size / 255) + 1;
		/*fragmenting*/
		if (latm_hdr_size + data_size > builder->Path_MTU) {
			assert(!builder->bytesInPacket);
			fragmented = GF_TRUE;
			latm_hdr_size = (builder->Path_MTU / 255) + 1;
			size = builder->Path_MTU - latm_hdr_size;
			builder->rtp_header.Marker = 0;
		}
		/*last fragment or full AU*/
		else {
			fragmented = GF_FALSE;
			size = data_size;
			builder->rtp_header.Marker = 1;
		}
		data_size -= size;

		/*create new RTP Packet if needed*/
		if (!builder->bytesInPacket) {
			builder->rtp_header.SequenceNumber += 1;
			builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
			builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
		}

		/* compute AudioMuxUnit header */
		latm_hdr_size = (size / 255) + 1;
		latm_hdr = (unsigned char *)gf_malloc( sizeof(char) * latm_hdr_size);
		for (i=0; i<latm_hdr_size-1; i++)  latm_hdr[i] = 255;
		latm_hdr[latm_hdr_size-1] = size % 255;

		/*add LATM header IN ORDER in case we aggregate audioMuxElements in RTP*/
		builder->OnData(builder->cbk_obj, (char*) latm_hdr, latm_hdr_size, GF_FALSE);
		builder->bytesInPacket += latm_hdr_size;
		gf_free(latm_hdr);

		/*add payload*/
		if (builder->OnDataReference) {
			builder->OnDataReference(builder->cbk_obj, size, data_offset);
		} else
			builder->OnData(builder->cbk_obj, data, size, GF_FALSE);

		builder->bytesInPacket += size;

		data_offset += size;

		/*fragmented AU, always flush packet*/
		if (!builder->rtp_header.Marker) latm_flush(builder);
	}
	/*if the AU has been fragmented or we don't use RTP aggregation, flush*/
	if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) fragmented = GF_TRUE;
	if (fragmented) latm_flush(builder);

	return GF_OK;
}
GF_Err gp_rtp_builder_do_latm(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration)
{
	u32 size, latm_hdr_size, i, data_offset;
	Bool fragmented;

	if (!data) {
		latm_flush(builder);
		return GF_OK;
	}

	if ((builder->flags & GP_RTP_PCK_USE_MULTI) && builder->max_ptime) {
		if ((u32) builder->sl_header.compositionTimeStamp + duration >= builder->rtp_header.TimeStamp + builder->max_ptime)
			latm_flush(builder);
	}
	 
	latm_hdr_size = (data_size / 255) + 1;
	if (latm_hdr_size+data_size > builder->Path_MTU - builder->bytesInPacket) {
		latm_flush(builder);
	}

	data_offset = 0;
	fragmented = GF_FALSE;
	while (data_size > 0) {
		u8 *latm_hdr;
		latm_hdr_size = (data_size / 255) + 1;
		 
		if (latm_hdr_size + data_size > builder->Path_MTU) {
			assert(!builder->bytesInPacket);
			fragmented = GF_TRUE;
			latm_hdr_size = (builder->Path_MTU / 255) + 1;
			size = builder->Path_MTU - latm_hdr_size;
			builder->rtp_header.Marker = 0;
		}
		 
		else {
			fragmented = GF_FALSE;
			size = data_size;
			builder->rtp_header.Marker = 1;
		}
		data_size -= size;

		 
		if (!builder->bytesInPacket) {
			builder->rtp_header.SequenceNumber += 1;
			builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
			builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
		}

		 
		latm_hdr_size = (size / 255) + 1;
		latm_hdr = (unsigned char *)gf_malloc( sizeof(char) * latm_hdr_size);
		for (i=0; i<latm_hdr_size-1; i++)  latm_hdr[i] = 255;
		latm_hdr[latm_hdr_size-1] = size % 255;

		 
		builder->OnData(builder->cbk_obj, (char*) latm_hdr, latm_hdr_size, GF_FALSE);
		builder->bytesInPacket += latm_hdr_size;
		gf_free(latm_hdr);

		 
		if (builder->OnDataReference) {
			builder->OnDataReference(builder->cbk_obj, size, data_offset);
		} else
			builder->OnData(builder->cbk_obj, data, size, GF_FALSE);

		builder->bytesInPacket += size;

		data_offset += size;

		 
		if (!builder->rtp_header.Marker) latm_flush(builder);
	}
	 
	if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) fragmented = GF_TRUE;
	if (fragmented) latm_flush(builder);

	return GF_OK;
}