doubango/tinyDAV/src/codecs/fec/tdav_codec_ulpfec.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
74ca6d11
 * Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * The original file was part of Open Source Doubango Framework
 * Copyright (C) 2010-2011 Mamadou Diop.
 * Copyright (C) 2012 Doubango Telecom <http://doubango.org>
 *
 * This file is part of Open Source Doubango Framework.
 *
 * DOUBANGO is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DOUBANGO 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with DOUBANGO.
 *
 */
 
 
 /**@file tdav_codec_ulpfec.c
  * @brief Forward Error Correction (FEC) implementation as per RFC 5109
  */
 #include "tinydav/codecs/fec/tdav_codec_ulpfec.h"
 
 #include "tinyrtp/rtp/trtp_rtp_packet.h"
 
 #include "tsk_string.h"
 #include "tsk_memory.h"
 #include "tsk_debug.h"
 
 #define TDAV_FEC_PKT_HDR_SIZE	10
 
 typedef struct tdav_codec_ulpfec_s
 {
 	TMEDIA_DECLARE_CODEC_VIDEO;
 
 	struct{
 		struct tdav_fec_pkt_s* pkt;
 	} encoder;
 }
 tdav_codec_ulpfec_t;
 
 //
 //	FEC LEVEL
 //
 typedef struct tdav_fec_level_s
 {
 	TSK_DECLARE_OBJECT;
 
 	struct{ // 7.4. FEC Level Header for FEC Packets
 		uint16_t length;
 		uint64_t mask;
 		tsk_size_t mask_size; // in bits
 	} hdr;
 	struct{
 		uint8_t* ptr;
 		tsk_size_t size;
 	}payload;
 }tdav_fec_level_t;
 typedef tsk_list_t tdav_fec_levels_L_t;
 static tsk_object_t* tdav_fec_level_ctor(tsk_object_t * self, va_list * app)
 {
 	tdav_fec_level_t *level = self;
 	if (level){
 		level->hdr.mask_size = 16; // L=0
 	}
 	return self;
 }
 static tsk_object_t* tdav_fec_level_dtor(tsk_object_t * self)
 {
 	tdav_fec_level_t *level = self;
 	if (level){
 		TSK_FREE(level->payload.ptr);
 	}
 
 	return self;
 }
 static const tsk_object_def_t tdav_fec_level_def_s =
 {
 	sizeof(tdav_fec_level_t),
 	tdav_fec_level_ctor,
 	tdav_fec_level_dtor,
 	tsk_null,
 };
 const tsk_object_def_t *tdav_fec_level_def_t = &tdav_fec_level_def_s;
 
 
 //
 //	FEC PACKET
 //
 typedef struct tdav_fec_pkt_s
 {
 	TSK_DECLARE_OBJECT;
 
 	struct{ // RFC 5109 - 7.3. FEC Header for FEC Packets
 		unsigned E : 1;
 		unsigned L : 1;
 		unsigned P : 1;
 		unsigned X : 1;
 		unsigned CC : 4;
 		unsigned M : 1;
 		unsigned PT : 7;
 		struct{
 			uint16_t value;
 			unsigned set : 1;
 		}SN_base;
 		uint32_t TS;
 		uint16_t length;
 	}hdr;
 
 	tdav_fec_levels_L_t* levels;
 }
 tdav_fec_pkt_t;
 static tsk_object_t* tdav_fec_pkt_ctor(tsk_object_t * self, va_list * app)
 {
 	tdav_fec_pkt_t *pkt = self;
 	if (pkt){
 		if (!(pkt->levels = tsk_list_create())){
 			TSK_DEBUG_ERROR("Failed to create levels");
 			return tsk_null;
 		}
 	}
 	return self;
 }
 static tsk_object_t* tdav_fec_pkt_dtor(tsk_object_t * self)
 {
 	tdav_fec_pkt_t *pkt = self;
 	if (pkt){
 		TSK_OBJECT_SAFE_FREE(pkt->levels);
 	}
 
 	return self;
 }
 static int tdav_fec_pkt_cmp(const tsk_object_t *_p1, const tsk_object_t *_p2)
 {
 	const tdav_fec_pkt_t *p1 = _p1;
 	const tdav_fec_pkt_t *p2 = _p2;
 
 	if (p1 && p2){
 		return (int)(p1->hdr.SN_base.value - p2->hdr.SN_base.value);
 	}
 	else if (!p1 && !p2) return 0;
 	else return -1;
 }
 static const tsk_object_def_t tdav_fec_pkt_def_s =
 {
 	sizeof(tdav_fec_pkt_t),
 	tdav_fec_pkt_ctor,
 	tdav_fec_pkt_dtor,
 	tdav_fec_pkt_cmp,
 };
 const tsk_object_def_t *tdav_fec_pkt_def_t = &tdav_fec_pkt_def_s;
 
 
 tsk_size_t tdav_codec_ulpfec_guess_serialbuff_size(const tdav_codec_ulpfec_t* self)
 {
 	tsk_size_t size = TDAV_FEC_PKT_HDR_SIZE;
 	tsk_list_item_t *item;
 	tdav_fec_level_t* level;
 
 	if (!self){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return 0;
 	}
 
 	tsk_list_foreach(item, self->encoder.pkt->levels){
 		if (!(level = item->data)){
 			continue;
 		}
 		size += 2 /* Protection length */ + (level->hdr.mask_size >> 3) + level->hdr.length;
 	}
 
 	return size;
 }
 
 int tdav_codec_ulpfec_enc_reset(tdav_codec_ulpfec_t* self)
 {
 	tsk_list_item_t *item;
 	tdav_fec_level_t* level;
 
 	if (!self || !self->encoder.pkt){
 		TSK_DEBUG_ERROR("invalid parameter");
 		return -1;
 	}
 
 	// reset packet
 	memset(&self->encoder.pkt->hdr, 0, sizeof(self->encoder.pkt->hdr));
 
 	// reset levels
 	tsk_list_foreach(item, self->encoder.pkt->levels){
 		if ((level = item->data)){
 			memset(&level->hdr, 0, sizeof(level->hdr));
 			if (level->payload.ptr){
 				memset(level->payload.ptr, 0, level->payload.size);
 			}
 		}
 	}
 	return 0;
 }
 
 int tdav_codec_ulpfec_enc_protect(tdav_codec_ulpfec_t* self, const trtp_rtp_packet_t* rtp_packet)
 {
 	if (!self || !self->encoder.pkt || !rtp_packet || !rtp_packet->header){
 		TSK_DEBUG_ERROR("invalid parameter");
 		return -1;
 	}
 
 	// Packet
 	self->encoder.pkt->hdr.P ^= rtp_packet->header->padding;
 	self->encoder.pkt->hdr.X ^= rtp_packet->header->extension;
 	self->encoder.pkt->hdr.CC ^= rtp_packet->header->csrc_count;
 	self->encoder.pkt->hdr.M ^= rtp_packet->header->marker;
 	self->encoder.pkt->hdr.PT ^= rtp_packet->header->payload_type;
 	if (!self->encoder.pkt->hdr.SN_base.set){
 		self->encoder.pkt->hdr.SN_base.value = rtp_packet->header->seq_num;
 		self->encoder.pkt->hdr.SN_base.set = 1;
 	}
 	else{
 		self->encoder.pkt->hdr.SN_base.value = TSK_MIN(self->encoder.pkt->hdr.SN_base.value, rtp_packet->header->seq_num);
 	}
 	self->encoder.pkt->hdr.TS ^= rtp_packet->header->timestamp;
 	self->encoder.pkt->hdr.length ^= (trtp_rtp_packet_guess_serialbuff_size(rtp_packet) - TRTP_RTP_HEADER_MIN_SIZE);
 
 	// Level
 	// For now, always single-level protection
 	{
 		tdav_fec_level_t* level0 = TSK_LIST_FIRST_DATA(self->encoder.pkt->levels);
 		const uint8_t* rtp_payload = (const uint8_t*)(rtp_packet->payload.data_const ? rtp_packet->payload.data_const : rtp_packet->payload.data);
 		tsk_size_t i;
 		if (!level0){
 			tdav_fec_level_t* _level0;
 			if (!(_level0 = tsk_object_new(tdav_fec_level_def_t))){
 				TSK_DEBUG_ERROR("Failed to create level");
 				return -2;
 			}
 			level0 = _level0;
 			tsk_list_push_back_data(self->encoder.pkt->levels, (void**)&_level0);
 		}
 		if (level0->payload.size < rtp_packet->payload.size){
 			if (!(level0->payload.ptr = tsk_realloc(level0->payload.ptr, rtp_packet->payload.size))){
 				TSK_DEBUG_ERROR("Failed to realloc size %d", rtp_packet->payload.size);
 				level0->payload.size = 0;
 				return -3;
 			}
 			level0->payload.size = rtp_packet->payload.size;
 		}
 		for (i = 0; i < rtp_packet->payload.size; ++i){
 			level0->payload.ptr[i] ^= rtp_payload[i];
 		}
 		level0->hdr.mask_size = self->encoder.pkt->hdr.L ? 48 : 16;
 		level0->hdr.mask |= (uint64_t)((uint64_t)1 << (level0->hdr.mask_size - (rtp_packet->header->seq_num - self->encoder.pkt->hdr.SN_base.value)));
 		level0->hdr.length = (uint16_t)(TSK_MAX(level0->hdr.length, rtp_packet->payload.size));
 	}
 
 	return 0;
 }
 
 tsk_size_t tdav_codec_ulpfec_enc_serialize(const tdav_codec_ulpfec_t* self, void** out_data, tsk_size_t* out_max_size)
 {
 	uint8_t* pdata;
 	tsk_size_t xsize;
 	int32_t i;
 	tsk_list_item_t* item;
 	tdav_fec_level_t* level;
 
 	if (!self || !self->encoder.pkt || !out_data){
 		TSK_DEBUG_ERROR("Invalid parameter");
 		return 0;
 	}
 	xsize = tdav_codec_ulpfec_guess_serialbuff_size(self);
 
 	if (*out_max_size < xsize){
 		if (!(*out_data = tsk_realloc(*out_data, xsize))){
 			TSK_DEBUG_ERROR("Failed to reallocate buffer with size =%d", xsize);
 			*out_max_size = 0;
 			return 0;
 		}
 		*out_max_size = xsize;
 	}
 	pdata = (uint8_t*)*out_data;
 
 	// E(1), L(1), P(1), X(1), CC(4)
 	pdata[0] =
 		(self->encoder.pkt->hdr.E << 7) |
 		(self->encoder.pkt->hdr.L << 6) |
 		(self->encoder.pkt->hdr.P << 5) |
 		(self->encoder.pkt->hdr.X << 4) |
 		(self->encoder.pkt->hdr.CC & 0x0F);
 	// M(1), PT(7)
 	pdata[1] = (self->encoder.pkt->hdr.M << 7) | (self->encoder.pkt->hdr.PT & 0x7F);
 	// SN base (16)
 	pdata[2] = (self->encoder.pkt->hdr.SN_base.value >> 8);
 	pdata[3] = (self->encoder.pkt->hdr.SN_base.value & 0xFF);
 	// TS (32)
 	pdata[4] = self->encoder.pkt->hdr.TS >> 24;
 	pdata[5] = (self->encoder.pkt->hdr.TS >> 16) & 0xFF;
 	pdata[6] = (self->encoder.pkt->hdr.TS >> 8) & 0xFF;
 	pdata[7] = (self->encoder.pkt->hdr.TS & 0xFF);
 	// Length (16)
 	pdata[8] = (self->encoder.pkt->hdr.length >> 8);
 	pdata[9] = (self->encoder.pkt->hdr.length & 0xFF);
 
 	pdata += 10;
 
 	tsk_list_foreach(item, self->encoder.pkt->levels){
 		if (!(level = item->data)){
 			continue;
 		}
 		// Protection length (16)
 		pdata[0] = (level->hdr.length >> 8);
 		pdata[1] = (level->hdr.length & 0xFF);
 		pdata += 2;
 		// mask (16 or 48)
 		for (i = (int32_t)(level->hdr.mask_size - 8); i >= 0; i -= 8){
 			*pdata = ((level->hdr.mask >> i) & 0xFF); ++pdata;
 		}
 		// payload
 		memcpy(pdata, level->payload.ptr, level->hdr.length);
 	}
 
 	return xsize;
 }
 
 
 
 static int tdav_codec_ulpfec_open(tmedia_codec_t* self)
 {
 	return 0;
 }
 
 static int tdav_codec_ulpfec_close(tmedia_codec_t* self)
 {
 	return 0;
 }
 
 static tsk_size_t tdav_codec_ulpfec_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size)
 {
 	TSK_DEBUG_ERROR("Not expected to be called");
 	return 0;
 }
 
 static tsk_size_t tdav_codec_ulpfec_decode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size, const tsk_object_t* proto_hdr)
 {
 	TSK_DEBUG_ERROR("Not expected to be called");
 	return 0;
 }
 
 static tsk_bool_t tdav_codec_ulpfec_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value)
 {
 	return tsk_true;
 }
 
 static char* tdav_codec_ulpfec_sdp_att_get(const tmedia_codec_t* self, const char* att_name)
 {
 	return tsk_null;
 }
 
 
 /* ============ ULPFEC object definition ================= */
 
 /* constructor */
 static tsk_object_t* tdav_codec_ulpfec_ctor(tsk_object_t * self, va_list * app)
 {
 	tdav_codec_ulpfec_t *ulpfec = self;
 	if (ulpfec){
 		/* init base: called by tmedia_codec_create() */
 		/* init self */
 		if (!(ulpfec->encoder.pkt = tsk_object_new(tdav_fec_pkt_def_t))){
 			TSK_DEBUG_ERROR("Failed to create FEC packet");
 			return tsk_null;
 		}
 	}
 	return self;
 }
 /* destructor */
 static tsk_object_t* tdav_codec_ulpfec_dtor(tsk_object_t * self)
 {
 	tdav_codec_ulpfec_t *ulpfec = self;
 	if (ulpfec){
 		/* deinit base */
 		tmedia_codec_video_deinit(ulpfec);
 		/* deinit self */
 		TSK_OBJECT_SAFE_FREE(ulpfec->encoder.pkt);
 	}
 
 	return self;
 }
 /* object definition */
 static const tsk_object_def_t tdav_codec_ulpfec_def_s =
 {
 	sizeof(tdav_codec_ulpfec_t),
 	tdav_codec_ulpfec_ctor,
 	tdav_codec_ulpfec_dtor,
 	tmedia_codec_cmp,
 };
 /* plugin definition*/
 static const tmedia_codec_plugin_def_t tdav_codec_ulpfec_plugin_def_s =
 {
 	&tdav_codec_ulpfec_def_s,
 
 	tmedia_video,
 	tmedia_codec_id_none, // fake codec
 	"ulpfec",
 	"ulpfec codec",
 	TMEDIA_CODEC_FORMAT_ULPFEC,
 	tsk_true,
 	90000, // rate
 
 	/* audio */
 	{ 0 },
 
 	/* video (defaul width,height,fps) */
 	{ 176, 144, 15 },
 
 	tsk_null, // set()
 	tdav_codec_ulpfec_open,
 	tdav_codec_ulpfec_close,
 	tdav_codec_ulpfec_encode,
 	tdav_codec_ulpfec_decode,
 	tdav_codec_ulpfec_sdp_att_match,
 	tdav_codec_ulpfec_sdp_att_get
 };
 const tmedia_codec_plugin_def_t *tdav_codec_ulpfec_plugin_def_t = &tdav_codec_ulpfec_plugin_def_s;