diff options
Diffstat (limited to 'tinyDAV/src/codecs/g729/tdav_codec_g729.c')
-rw-r--r-- | tinyDAV/src/codecs/g729/tdav_codec_g729.c | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/tinyDAV/src/codecs/g729/tdav_codec_g729.c b/tinyDAV/src/codecs/g729/tdav_codec_g729.c new file mode 100644 index 0000000..8981687 --- /dev/null +++ b/tinyDAV/src/codecs/g729/tdav_codec_g729.c @@ -0,0 +1,466 @@ +/* +* Copyright (C) 2010-2011 Mamadou Diop. +* +* Contact: Mamadou Diop <diopmamadou(at)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_g729.c + * @brief G729ab codec. + * Source from: http://www.itu.int/rec/T-REC-G.729-199610-S!AnnB/en + * + * @author Mamadou Diop <diopmamadou(at)doubango.org> + * + */ +#include "tinydav/codecs/g729/tdav_codec_g729.h" + +#if HAVE_G729 + +#include "g729b/dtx.h" +#include "g729b/octet.h" + +#include "tsk_string.h" +#include "tsk_params.h" +#include "tsk_memory.h" +#include "tsk_debug.h" + + +#if defined(_MSC_VER) +# pragma comment(lib, "../thirdparties/win32/lib/g729b/g729b.a") +#endif + +int16_t bad_lsf; /* bad LSF indicator */ + +#ifndef G729_ENABLE_VAD +# define G729_ENABLE_VAD 0 // FIXME: speexJB not prepared for such feature +#endif + +static int16_t bin2int(int16_t no_of_bits, const int16_t *bitstream); +static void int2bin(int16_t value, int16_t no_of_bits, int16_t *bitstream); + +static void unpack_G729(const uint8_t bitstream[], int16_t bits[], int len); +static void unpack_SID(const uint8_t bitstream[], int16_t bits[]); + +static void pack_G729(const int16_t ituBits[], uint8_t bitstream[]); +static void pack_SID(const int16_t ituBits[], uint8_t bitstream[]); + +/* ============ G.729ab Plugin interface ================= */ + +#define tdav_codec_g729ab_set tsk_null + +static int tdav_codec_g729ab_open(tmedia_codec_t* self) +{ + tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self; + + // Initialize the decoder + bad_lsf = 0; + g729a->decoder.synth = (g729a->decoder.synth_buf + M); + + Init_Decod_ld8a(); + Init_Post_Filter(); + Init_Post_Process(); + /* for G.729B */ + Init_Dec_cng(); + + // Initialize the encoder + Init_Pre_Process(); + Init_Coder_ld8a(); + Set_zero(g729a->encoder.prm, PRM_SIZE + 1); + /* for G.729B */ + Init_Cod_cng(); + + + return 0; +} + +static int tdav_codec_g729ab_close(tmedia_codec_t* self) +{ + tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self; + + (void)(g729a); + + /* resources will be freed by the dctor() */ + + return 0; +} + +static tsk_size_t tdav_codec_g729ab_encode(tmedia_codec_t* self, const void* in_data, tsk_size_t in_size, void** out_data, tsk_size_t* out_max_size) +{ + tsk_size_t ex_size, out_size = 0; + tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self; + int i, frame_count = (in_size / 160); + + + if(!self || !in_data || !in_size || !out_data || (in_size % 160)){ + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + ex_size = (frame_count * 10); + + // allocate new buffer if needed + if(*out_max_size <ex_size){ + if(!(*out_data = tsk_realloc(*out_data, ex_size))){ + TSK_DEBUG_ERROR("Failed to allocate new buffer"); + *out_max_size = 0; + return 0; + } + *out_max_size = ex_size; + } + + for(i=0; i<frame_count; i++){ + extern int16_t *new_speech; + + if(g729a->encoder.frame == 32767){ + g729a->encoder.frame = 256; + } + else{ + g729a->encoder.frame++; + } + + memcpy(new_speech, &((uint8_t*)in_data)[i*L_FRAME*sizeof(int16_t)], sizeof(int16_t)*L_FRAME); + + Pre_Process(new_speech, L_FRAME); + Coder_ld8a(g729a->encoder.prm, g729a->encoder.frame, g729a->encoder.vad_enable); + prm2bits_ld8k(g729a->encoder.prm, g729a->encoder.serial); + + if(g729a->encoder.serial[1] == RATE_8000){ + pack_G729(&g729a->encoder.serial[2], &((uint8_t*)(*out_data))[out_size]); + out_size += 10; + } + else if(g729a->encoder.serial[1] == RATE_SID_OCTET){ + pack_SID(&g729a->encoder.serial[2], &((uint8_t*)(*out_data))[out_size]); + out_size += 2; + } + else{ // RATE_0 + //TSK_DEBUG_INFO("G729_RATE_0 - Not transmitted"); + if (!g729a->encoder.vad_enable) { + // silence + memset(&((uint8_t*)(*out_data))[out_size], 0, 10); + out_size += 10; + } + } + } + + return out_size; +} + +static tsk_size_t tdav_codec_g729ab_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_size_t out_size = 0; + int i, frame_count; + const uint8_t* data_start = (const uint8_t*)in_data; + const uint8_t* data_end; + tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self; + + if(!self || !in_data || !in_size || !out_data || ((in_size % 10) && (in_size % 10 != 2))){ + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + data_end = (data_start + in_size); + + frame_count = (in_size/10) + ((in_size % 10) ? 1 : 0); + + out_size = 160*frame_count; + + /* allocate new buffer if needed */ + if(*out_max_size <out_size){ + if(!(*out_data = tsk_realloc(*out_data, out_size))){ + TSK_DEBUG_ERROR("Failed to allocate new buffer"); + *out_max_size = 0; + return 0; + } + *out_max_size = out_size; + } + + for(i=0; i<frame_count; i++){ + memset(g729a->decoder.synth_buf, 0, M); + g729a->decoder.synth = g729a->decoder.synth_buf + M; + + if((data_end - data_start) == 2){ + unpack_SID(data_start, g729a->decoder.serial); + data_start += 2; + } + else{ + unpack_G729(data_start, g729a->decoder.serial, 10); + data_start += 10; + } + + bits2prm_ld8k(&g729a->decoder.serial[1], g729a->decoder.parm); + + /* This part was modified for version V1.3 */ + /* for speech and SID frames, the hardware detects frame erasures + by checking if all bits are set to zero */ + /* for untransmitted frames, the hardware detects frame erasures + by testing serial[0] */ + + g729a->decoder.parm[0] = 0; /* No frame erasure */ + if(g729a->decoder.serial[1] != 0) { + int j; + for (j=0; j < g729a->decoder.serial[1]; j++){ + if (g729a->decoder.serial[j+2] == 0){ + g729a->decoder.parm[0] = 1; /* frame erased */ + break; + } + } + } + else if(g729a->decoder.serial[0] != SYNC_WORD){ + g729a->decoder.parm[0] = 1; + } + if(g729a->decoder.parm[1] == 1) { + /* check parity and put 1 in parm[5] if parity error */ + g729a->decoder.parm[5] = Check_Parity_Pitch(g729a->decoder.parm[4], g729a->decoder.parm[5]); + } + + Decod_ld8a(g729a->decoder.parm, g729a->decoder.synth, g729a->decoder.Az_dec, g729a->decoder.T2, &g729a->decoder.Vad); + Post_Filter(g729a->decoder.synth, g729a->decoder.Az_dec, g729a->decoder.T2, g729a->decoder.Vad); /* Post-filter */ + Post_Process(g729a->decoder.synth, L_FRAME); + + memcpy(&((uint8_t*)*out_data)[160*i], g729a->decoder.synth, 160); + } + + + return out_size; +} + +static tsk_bool_t tdav_codec_g729ab_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value) +{ + tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)codec; + + if(tsk_striequals(att_name, "fmtp")){ + tsk_params_L_t* params = tsk_null; + const char* val_str; + if((params = tsk_params_fromstring(att_value, ";", tsk_true))){ + if((val_str = tsk_params_get_param_value(params, "annexb"))){ + g729a->encoder.vad_enable &= tsk_strequals(val_str, "yes") ? 1 : 0; + } + TSK_OBJECT_SAFE_FREE(params); + } + } + return tsk_true; +} + +static char* tdav_codec_g729ab_sdp_att_get(const tmedia_codec_t* codec, const char* att_name) +{ + tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)codec; + + if(tsk_striequals(att_name, "fmtp")){ + if(g729a->encoder.vad_enable){ + return tsk_strdup("annexb=yes"); + } + else{ + return tsk_strdup("annexb=no"); + } + } + return tsk_null; +} + + + + + + +/* ============ Internal functions ================= */ + + +/** +* Converts from bitstream (ITU bits) to int16_t value +* @param no_of_bits number of bits to read +* @param bitstream array containing bits +* @retval decimal value of bit pattern +*/ +static int16_t bin2int(int16_t no_of_bits, const int16_t *bitstream) +{ + int16_t value, i; + int16_t bit; + + value = 0; + for(i = 0; i < no_of_bits; i++){ + value <<= 1; + bit = *bitstream++; + if (bit == BIT_1){ + value += 1; + } + } + return(value); +} + +/*---------------------------------------------------------------------------- + * int2bin convert integer to binary and write the bits bitstream array + *---------------------------------------------------------------------------- + */ + +/** +* Writes int16_t value to bitstream +* @param value decimal value to write +* @param no_of_bits number of bits from value to write +* @param bitstream pointer to the destination stream (ITU bits) +*/ +static void int2bin(int16_t value, int16_t no_of_bits, int16_t *bitstream) +{ + int16_t *pt_bitstream; + int16_t i, bit; + + pt_bitstream = bitstream + no_of_bits; + + for (i = 0; i < no_of_bits; i++){ + bit = value & (int16_t)0x0001; /* get lsb */ + if (bit == 0){ + *--pt_bitstream = BIT_0; + } + else{ + *--pt_bitstream = BIT_1; + } + value >>= 1; + } +} + +/** +* UnPack RTP bitstream as unpacked ITU stream +* @param bitstream RTP bitstream to unpack +* @param bits ITU bitstream used as destination (0 - BIT_0, 1 - BIT_1) +* @param len length of the RTP bitstream +*/ +static void unpack_G729(const uint8_t bitstream[], int16_t bits[], int len) +{ + int16_t i; + *bits++ = SYNC_WORD; /* bit[0], at receiver this bits indicates BFI */ + switch(len){ + case 10: + *bits++ = SIZE_WORD; + break; + case 8: // RATE_6400 + case 15: //RATE_11800 + default: + TSK_DEBUG_ERROR("%d is an invalid lenght value", len); + return; + } + + for(i=0; i<len; i++){ + int2bin(bitstream[i], 8, &bits[i*8]); + } +} + +/** +* UnPack RTP bitstream containing SID frame as unpacked ITU stream +* @param bitstream RTP bitstream to unpack +* @param bits ITU bitstream used as destination (0 - BIT_0, 1 - BIT_1) +*/ +static void unpack_SID(const uint8_t bitstream[], int16_t bits[]) +{ + *bits++ = SYNC_WORD; + *bits++ = RATE_SID_OCTET; + int2bin((int16_t)bitstream[0], 8, &bits[0]); + int2bin((int16_t)bitstream[1], 8, &bits[8]); +} + +/** +* Pack ITU bits into RTP stream +* @param ituBits ITU stream to pack (80 shorts) +* @param bitstream RTP bitstream (80 bits, 5 shorts, 10 bytes) +*/ +static void pack_G729(const int16_t ituBits[], uint8_t bitstream[]) +{ + int16_t word16, i; + for(i=0; i<5; i++){ + word16 = bin2int(16, (int16_t*)&ituBits[i*16]); + bitstream[i*2] = word16>>8, bitstream[(i*2)+1] = (word16 & 0xFF); + } +} + +/** +* Pack ITU bits containing SID frame as RTP stream +* @param ituBits ITU stream to pack +* @param bitstream RTP bitstream (15 bits, 1 short, 2 bytes) +*/ +static void pack_SID(const int16_t ituBits[], uint8_t bitstream[]) +{ + int16_t word16 = bin2int(16, ituBits); + bitstream[0] = word16>>8, bitstream[1] = (word16 & 0xFF); +} + + +// +// g729ab Plugin definition +// + +/* constructor */ +static tsk_object_t* tdav_codec_g729ab_ctor(tsk_object_t * self, va_list * app) +{ + tdav_codec_g729ab_t *g729a = self; + if(g729a){ + /* init base: called by tmedia_codec_create() */ + /* init self */ + g729a->encoder.vad_enable = G729_ENABLE_VAD; // AnnexB + } + return self; +} +/* destructor */ +static tsk_object_t* tdav_codec_g729ab_dtor(tsk_object_t * self) +{ + tdav_codec_g729ab_t *g729a = self; + if(g729a){ + /* deinit base */ + tmedia_codec_audio_deinit(g729a); + /* deinit self */ + + } + + return self; +} +/* object definition */ +static const tsk_object_def_t tdav_codec_g729ab_def_s = +{ + sizeof(tdav_codec_g729ab_t), + tdav_codec_g729ab_ctor, + tdav_codec_g729ab_dtor, + tmedia_codec_cmp, +}; +/* plugin definition*/ +static const tmedia_codec_plugin_def_t tdav_codec_g729ab_plugin_def_s = +{ + &tdav_codec_g729ab_def_s, + + tmedia_audio, + tmedia_codec_id_g729ab, + "g729", + "g729ab Codec (libg729)", + TMEDIA_CODEC_FORMAT_G729, + tsk_false, + 8000, // rate + + { /* audio */ + 1, // channels + 0 // ptime @deprecated + }, + + /* video */ + {0}, + + tdav_codec_g729ab_set, + tdav_codec_g729ab_open, + tdav_codec_g729ab_close, + tdav_codec_g729ab_encode, + tdav_codec_g729ab_decode, + tdav_codec_g729ab_sdp_att_match, + tdav_codec_g729ab_sdp_att_get +}; +const tmedia_codec_plugin_def_t *tdav_codec_g729ab_plugin_def_t = &tdav_codec_g729ab_plugin_def_s; + +#endif /* HAVE_G729 */ |