summaryrefslogtreecommitdiffstats
path: root/tinyDAV/src/codecs/g729/tdav_codec_g729.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinyDAV/src/codecs/g729/tdav_codec_g729.c')
-rw-r--r--tinyDAV/src/codecs/g729/tdav_codec_g729.c454
1 files changed, 454 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..3ca6fc7
--- /dev/null
+++ b/tinyDAV/src/codecs/g729/tdav_codec_g729.c
@@ -0,0 +1,454 @@
+/*
+* Copyright (C) 2009-2010 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>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tinydav/codecs/g729/tdav_codec_g729.h"
+
+#if HAVE_G729
+
+#include "g729b/dtx.h"
+#include "g729b/octet.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+
+#if defined(_MSC_VER)
+# pragma comment(lib, "../thirdparties/win32/lib/g729b/g729b.a")
+#endif
+
+Word16 bad_lsf; /* bad LSF indicator */
+
+#ifndef G729_ENABLE_VAD
+# define G729_ENABLE_VAD 1
+#endif
+
+static Word16 bin2int(Word16 no_of_bits, const Word16 *bitstream);
+static void int2bin(Word16 value, Word16 no_of_bits, Word16 *bitstream);
+
+static void unpack_G729(const uint8_t bitstream[], Word16 bits[], int len);
+static void unpack_SID(const uint8_t bitstream[], Word16 bits[]);
+
+static void pack_G729(const Word16 ituBits[], uint8_t bitstream[]);
+static void pack_SID(const Word16 ituBits[], uint8_t bitstream[]);
+
+/* ============ G.729ab Plugin interface ================= */
+
+#define tdav_codec_g729ab_fmtp_set tsk_null
+
+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;
+}
+
+int tdav_codec_g729ab_close(tmedia_codec_t* self)
+{
+ tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)self;
+
+ return 0;
+}
+
+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 Word16 *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(Word16)], sizeof(Word16)*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");
+ return 0;
+ }
+ }
+
+ return out_size;
+}
+
+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;
+}
+
+tsk_bool_t tdav_codec_g729ab_fmtp_match(const tmedia_codec_t* codec, const char* fmtp)
+{
+ tsk_params_L_t* params = tsk_null;
+ const char* val_str;
+
+ tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)codec;
+
+ if((params = tsk_params_fromstring(fmtp, ";", tsk_true))){
+ if((val_str = tsk_params_get_param_value(params, "annexb"))){
+ g729a->encoder.vad_enable = tsk_strequals(val_str, "yes");
+ }
+
+ TSK_OBJECT_SAFE_FREE(params);
+ }
+
+ return tsk_true;
+}
+
+char* tdav_codec_g729ab_fmtp_get(const tmedia_codec_t* codec)
+{
+ tdav_codec_g729ab_t* g729a = (tdav_codec_g729ab_t*)codec;
+
+ if(g729a->encoder.vad_enable){
+ return tsk_strdup("annexb=yes");
+ }
+ else{
+ return tsk_strdup("annexb=no");
+ }
+}
+
+
+
+
+
+
+/* ============ Internal functions ================= */
+
+
+/**
+* Converts from bitstream (ITU bits) to word16 value
+* @param no_of_bits number of bits to read
+* @param bitstream array containing bits
+* @retval decimal value of bit pattern
+*/
+static Word16 bin2int(Word16 no_of_bits, const Word16 *bitstream)
+{
+ Word16 value, i;
+ Word16 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 Word16 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(Word16 value, Word16 no_of_bits, Word16 *bitstream)
+{
+ Word16 *pt_bitstream;
+ Word16 i, bit;
+
+ pt_bitstream = bitstream + no_of_bits;
+
+ for (i = 0; i < no_of_bits; i++){
+ bit = value & (Word16)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[], Word16 bits[], int len)
+{
+ Word16 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[], Word16 bits[])
+{
+ *bits++ = SYNC_WORD;
+ *bits++ = RATE_SID_OCTET;
+ int2bin((Word16)bitstream[0], 8, &bits[0]);
+ int2bin((Word16)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 Word16 ituBits[], uint8_t bitstream[])
+{
+ Word16 word16, i;
+ for(i=0; i<5; i++){
+ word16 = bin2int(16, (Word16*)&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 Word16 ituBits[], uint8_t bitstream[])
+{
+ Word16 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,
+ "g729",
+ "g729ab Codec",
+ TMEDIA_CODEC_FORMAT_G729,
+ tsk_false,
+ 8000, // rate
+
+ { /* audio */
+ 1, // channels
+ 20 // ptime
+ },
+
+ /* video */
+ {0},
+
+ tdav_codec_g729ab_open,
+ tdav_codec_g729ab_close,
+ tdav_codec_g729ab_encode,
+ tdav_codec_g729ab_decode,
+ tdav_codec_g729ab_fmtp_match,
+ tdav_codec_g729ab_fmtp_get,
+ tdav_codec_g729ab_fmtp_set
+};
+const tmedia_codec_plugin_def_t *tdav_codec_g729ab_plugin_def_t = &tdav_codec_g729ab_plugin_def_s;
+
+#endif /* HAVE_G729 */ \ No newline at end of file
OpenPOWER on IntegriCloud