From 631fffee8a28b1bec5ed1f1d26a20e0135967f99 Mon Sep 17 00:00:00 2001 From: Mamadou DIOP Date: Mon, 17 Aug 2015 01:56:35 +0200 Subject: - --- tinyDAV/src/codecs/fec/tdav_codec_red.c | 263 ++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 tinyDAV/src/codecs/fec/tdav_codec_red.c (limited to 'tinyDAV/src/codecs/fec/tdav_codec_red.c') diff --git a/tinyDAV/src/codecs/fec/tdav_codec_red.c b/tinyDAV/src/codecs/fec/tdav_codec_red.c new file mode 100644 index 0000000..2fb6f27 --- /dev/null +++ b/tinyDAV/src/codecs/fec/tdav_codec_red.c @@ -0,0 +1,263 @@ +/* +* Copyright (C) 2012 Doubango Telecom +* +* Contact: Mamadou Diop +* +* 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_red.c + * @brief RTP Payload for Redundant Audio Data as per RFC 2198 + */ +#include "tinydav/codecs/fec/tdav_codec_red.h" + +#include "tinyrtp/rtp/trtp_rtp_packet.h" + +#include "tsk_memory.h" +#include "tsk_time.h" +#include "tsk_debug.h" + +typedef struct tdav_codec_red_s +{ + TMEDIA_DECLARE_CODEC_VIDEO; + + tdav_codec_red_rtppacket_cb_f callback; + const void* callback_data; +} +tdav_codec_red_t; + +int tdav_codec_red_set_callback(tdav_codec_red_t *self, tdav_codec_red_rtppacket_cb_f callback, const void* callback_data) +{ + if(!self){ + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + self->callback = callback; + self->callback_data = callback_data; + + return 0; +} + +static int tdav_codec_red_open(tmedia_codec_t* self) +{ + return 0; +} + +static int tdav_codec_red_close(tmedia_codec_t* self) +{ + return 0; +} + +static tsk_size_t tdav_codec_red_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size) +{ + tdav_codec_red_t *red = (tdav_codec_red_t *)self; + tsk_size_t xsize = (in_size + 1); + static const uint8_t __first_octet = 0x00; // F=1, PT=0. Up to the caller to update this first octet with the right PT. + + if(!red || !in_data || !in_size || !out_data || !out_max_size){ + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + if(*out_max_size < xsize){ + if(!(*out_data = tsk_realloc(*out_data, xsize))){ + TSK_DEBUG_ERROR("Failed to realloc data"); + *out_max_size = 0; + } + *out_max_size = xsize; + } + + ((uint8_t*)*out_data)[0] = __first_octet; + memcpy(&((uint8_t*)*out_data)[1], in_data, in_size); + + return xsize; +} + +static tsk_size_t tdav_codec_red_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) +{ + tdav_codec_red_t* red = (tdav_codec_red_t*)self; + const trtp_rtp_header_t* rtp_hdr = proto_hdr; + trtp_rtp_packet_t* red_rtp_pkt = tsk_null; + const uint8_t* pdata = in_data; + const uint8_t* red_hdr = in_data; + tsk_size_t red_hdrs_count, i; + tsk_bool_t last; + uint8_t F; + uint16_t timestamp_offset, block_length; + + if(!red || !in_data || (in_size < TDAV_CODEC_RED_MIN_PKT_SIZE)|| !out_data){ + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + if(!red->callback){ + TSK_DEBUG_WARN("Not callback installed for RED data"); + return 0; + } + + if((F = (pdata[0] & 0x80)) == 0){ + i = 1; + red_hdrs_count = 1; + } + else{ + for(i = 0, red_hdrs_count = 0; i < in_size; i+= 4, ++red_hdrs_count){ + if((F = (pdata[i] & 0x80)) == 0){ ++i; ++red_hdrs_count; break; } + } + } + + if(i >= in_size){ + TSK_DEBUG_ERROR("Invalid data"); + return 0; + } + + pdata += i; + in_size -= i; + + for(i = 0; i < red_hdrs_count && in_size > 0; ++i){ + TSK_OBJECT_SAFE_FREE(red_rtp_pkt); + if(!(red_rtp_pkt = trtp_rtp_packet_create_null())){ + TSK_DEBUG_ERROR("Failed to create RTP packet"); + continue; + } + if(!(red_rtp_pkt->header = trtp_rtp_header_create(rtp_hdr->ssrc, rtp_hdr->seq_num, rtp_hdr->timestamp, rtp_hdr->payload_type, rtp_hdr->marker))){ + TSK_DEBUG_ERROR("Failed to create RTP header"); + continue; + } + + // Must create an RTP packet for each RED chunck as they will be saved in the JB + last = (i == (red_hdrs_count - 1)); + F = (red_hdr[0] & 0x80); + red_rtp_pkt->header->payload_type = (red_hdr[0] & 0x7F); + + if(last || !F){ + /* + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |0| Block PT | + +-+-+-+-+-+-+-+-+ + */ + block_length = (uint16_t)in_size; + } + else{ + /* + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |1| block PT=7 | timestamp offset | block length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + timestamp_offset = ((red_hdr[1] << 8) | red_hdr[2]) >> 2; + block_length = ((red_hdr[2] & 0x03) << 8) | red_hdr[3]; + if(block_length > in_size){ + TSK_DEBUG_ERROR("Invalid 'block length'"); + break; + } + red_rtp_pkt->header->timestamp += timestamp_offset; + red_hdr += 4; + } + + // decode + if(red->callback){ + // do not use "data_const" as payload will be saved in the jitter buffer and decoded later (async) + if((red_rtp_pkt->payload.data = tsk_malloc(block_length))){ + memcpy(red_rtp_pkt->payload.data, pdata, block_length); + red_rtp_pkt->payload.size = block_length; + red->callback(red->callback_data, red_rtp_pkt); + } + } + + pdata += block_length; + in_size -= block_length; + } + + TSK_OBJECT_SAFE_FREE(red_rtp_pkt); + + return 0; // must be always zero +} + +static tsk_bool_t tdav_codec_red_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value) +{ + return tsk_true; +} + +static char* tdav_codec_red_sdp_att_get(const tmedia_codec_t* self, const char* att_name) +{ + return tsk_null; +} + + +/* ============ red object definition ================= */ + +/* constructor */ +static tsk_object_t* tdav_codec_red_ctor(tsk_object_t * self, va_list * app) +{ + tdav_codec_red_t *red = self; + if(red){ + /* init base: called by tmedia_codec_create() */ + /* init self */ + + } + return self; +} +/* destructor */ +static tsk_object_t* tdav_codec_red_dtor(tsk_object_t * self) +{ + tdav_codec_red_t *red = self; + if(red){ + /* deinit base */ + tmedia_codec_video_deinit(red); + /* deinit self */ + + } + + return self; +} +/* object definition */ +static const tsk_object_def_t tdav_codec_red_def_s = +{ + sizeof(tdav_codec_red_t), + tdav_codec_red_ctor, + tdav_codec_red_dtor, + tmedia_codec_cmp, +}; +/* plugin definition*/ +static const tmedia_codec_plugin_def_t tdav_codec_red_plugin_def_s = +{ + &tdav_codec_red_def_s, + + (/* tmedia_video | tmedia_audio | */tmedia_t140), // FIXME: for now is only supported with T.140 + tmedia_codec_id_red, + "red", + "red codec", + TMEDIA_CODEC_FORMAT_RED, + tsk_true, + 1000, // rate: FIXME: for now it's only for T.140 + + /* audio */ + { 0 }, + + /* video (defaul width,height,fps) */ + {176, 144, 15}, + + tsk_null, // set() + tdav_codec_red_open, + tdav_codec_red_close, + tdav_codec_red_encode, + tdav_codec_red_decode, + tdav_codec_red_sdp_att_match, + tdav_codec_red_sdp_att_get +}; +const tmedia_codec_plugin_def_t *tdav_codec_red_plugin_def_t = &tdav_codec_red_plugin_def_s; -- cgit v1.1