287 lines
7.5 KiB
C
287 lines
7.5 KiB
C
/*
|
|
* 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_speex.c
|
|
* @brief Speex codecs
|
|
*
|
|
* @author Mamadou Diop <diopmamadou(at)doubango.org>
|
|
*
|
|
|
|
*/
|
|
#include "tinydav/codecs/speex/tdav_codec_speex.h"
|
|
|
|
#if HAVE_LIB_SPEEX
|
|
|
|
#include "tsk_memory.h"
|
|
#include "tsk_debug.h"
|
|
|
|
#define SPEEX_BUFFER_MAX_SIZE 1024
|
|
#define SPEEX_DEFAULT_QUALITY 6
|
|
|
|
/* ============ Common ================= */
|
|
int tdav_codec_speex_init(tdav_codec_speex_t* self, tdav_codec_speex_type_t type);
|
|
int tdav_codec_speex_deinit(tdav_codec_speex_t* self);
|
|
|
|
/* ============ Speex Plugin interface ================= */
|
|
|
|
int tdav_codec_speex_open(tmedia_codec_t* self)
|
|
{
|
|
static int quality = SPEEX_DEFAULT_QUALITY;
|
|
tdav_codec_speex_t* speex = (tdav_codec_speex_t*)self;
|
|
|
|
switch(speex->type){
|
|
case tdav_codec_speex_type_nb:
|
|
speex->encoder.state = speex_encoder_init(&speex_nb_mode);
|
|
speex->decoder.state = speex_decoder_init(&speex_nb_mode);
|
|
break;
|
|
case tdav_codec_speex_type_wb:
|
|
speex->encoder.state = speex_encoder_init(&speex_wb_mode);
|
|
speex->decoder.state = speex_decoder_init(&speex_wb_mode);
|
|
break;
|
|
case tdav_codec_speex_type_uwb:
|
|
speex->encoder.state = speex_encoder_init(&speex_uwb_mode);
|
|
speex->decoder.state = speex_decoder_init(&speex_uwb_mode);
|
|
break;
|
|
default:
|
|
TSK_DEBUG_ERROR("Not implemented");
|
|
return -2;
|
|
}
|
|
|
|
speex_decoder_ctl(speex->decoder.state, SPEEX_GET_FRAME_SIZE, &speex->decoder.size);
|
|
speex->decoder.size *= sizeof(spx_int16_t);
|
|
if(!(speex->decoder.buffer = tsk_calloc(speex->decoder.size, 1))){
|
|
speex->decoder.size = speex->decoder.size = 0;
|
|
TSK_DEBUG_ERROR("Failed to allocate new buffer");
|
|
return -3;
|
|
}
|
|
|
|
speex_encoder_ctl(speex->encoder.state, SPEEX_SET_QUALITY, &quality);
|
|
speex_encoder_ctl(speex->encoder.state, SPEEX_GET_FRAME_SIZE, &speex->encoder.size);
|
|
|
|
speex_bits_init(&speex->encoder.bits);
|
|
speex_bits_init(&speex->decoder.bits);
|
|
speex_bits_reset(&speex->encoder.bits);
|
|
speex_bits_reset(&speex->decoder.bits);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tdav_codec_speex_close(tmedia_codec_t* self)
|
|
{
|
|
tdav_codec_speex_t* speex = (tdav_codec_speex_t*)self;
|
|
|
|
(void)(speex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
tsk_size_t tdav_codec_speex_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_speex_t* speex = (tdav_codec_speex_t*)self;
|
|
tsk_size_t outsize = 0;
|
|
|
|
if(!self || !in_data || !in_size || !out_data){
|
|
TSK_DEBUG_ERROR("Invalid parameter");
|
|
return 0;
|
|
}
|
|
|
|
speex_bits_reset(&speex->encoder.bits);
|
|
speex_encode_int(speex->encoder.state, (spx_int16_t*)in_data, &speex->encoder.bits);
|
|
|
|
if(*out_max_size <speex->encoder.size){
|
|
if((*out_data = tsk_realloc(*out_data, speex->encoder.size))){
|
|
*out_max_size = speex->encoder.size;
|
|
}
|
|
else{
|
|
*out_max_size = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
outsize = speex_bits_write(&speex->encoder.bits, *out_data, (speex->encoder.size >> 1));
|
|
|
|
return outsize;
|
|
}
|
|
|
|
tsk_size_t tdav_codec_speex_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)
|
|
{
|
|
int ret;
|
|
tsk_size_t out_size = 0;
|
|
tdav_codec_speex_t* speex = (tdav_codec_speex_t*)self;
|
|
|
|
if(!self || !in_data || !in_size || !out_data){
|
|
TSK_DEBUG_ERROR("Invalid parameter");
|
|
return 0;
|
|
}
|
|
|
|
// initializes the bit-stream
|
|
speex_bits_read_from(&speex->decoder.bits, (char*)in_data, in_size);
|
|
|
|
do{
|
|
// performs decode()
|
|
if((ret = speex_decode_int(speex->decoder.state, &speex->decoder.bits, speex->decoder.buffer))){
|
|
TSK_DEBUG_ERROR("Failed to decode the buffer. retcode=%d", ret);
|
|
break;
|
|
}
|
|
|
|
if(*out_max_size <(out_size + speex->decoder.size)){
|
|
if((*out_data = tsk_realloc(*out_data, (out_size + speex->decoder.size)))){
|
|
*out_max_size = (out_size + speex->decoder.size);
|
|
}
|
|
else{
|
|
*out_max_size = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// copy output buffer
|
|
memcpy(&((uint8_t*)*out_data)[out_size], speex->decoder.buffer, speex->decoder.size);
|
|
out_size += speex->decoder.size;
|
|
}
|
|
while(speex_bits_remaining(&speex->decoder.bits) >= 5);
|
|
|
|
|
|
return out_size;
|
|
}
|
|
|
|
char* tdav_codec_speex_sdp_att_get(const tmedia_codec_t* codec, const char* att_name)
|
|
{
|
|
return tsk_null;
|
|
}
|
|
|
|
tsk_bool_t tdav_codec_speex_sdp_att_match(const tmedia_codec_t* codec, const char* att_name, const char* att_value)
|
|
{
|
|
return tsk_true;
|
|
}
|
|
|
|
|
|
//
|
|
// Speex Codec Object definition
|
|
//
|
|
#define SPEEX_OBJECT_DEFINITION(mode,name,description,format,rate) \
|
|
static tsk_object_t* tdav_codec_speex_##mode##_ctor(tsk_object_t * self, va_list * app) \
|
|
{ \
|
|
tdav_codec_speex_t *speex = self; \
|
|
if(speex){ \
|
|
tdav_codec_speex_init(speex, tdav_codec_speex_type_##mode); \
|
|
} \
|
|
return self; \
|
|
} \
|
|
static tsk_object_t* tdav_codec_speex_##mode##_dtor(tsk_object_t * self) \
|
|
{ \
|
|
tdav_codec_speex_t *speex = self; \
|
|
if(speex){ \
|
|
/* deinit base */ \
|
|
tmedia_codec_audio_deinit(speex); \
|
|
/* deinit self */ \
|
|
tdav_codec_speex_deinit(speex); \
|
|
} \
|
|
\
|
|
return self; \
|
|
} \
|
|
static const tsk_object_def_t tdav_codec_speex_##mode##_def_s = \
|
|
{ \
|
|
sizeof(tdav_codec_speex_t), \
|
|
tdav_codec_speex_##mode##_ctor, \
|
|
tdav_codec_speex_##mode##_dtor, \
|
|
tmedia_codec_cmp, \
|
|
}; \
|
|
static const tmedia_codec_plugin_def_t tdav_codec_speex_##mode##_plugin_def_s = \
|
|
{ \
|
|
&tdav_codec_speex_##mode##_def_s, \
|
|
\
|
|
tmedia_audio, \
|
|
tmedia_codec_id_speex_##mode, \
|
|
name, \
|
|
description, \
|
|
format, \
|
|
tsk_true, \
|
|
rate, /* rate*/ \
|
|
\
|
|
{ /* audio */ \
|
|
1, /* channels*/ \
|
|
0 /* ptime @deprecated*/ \
|
|
}, \
|
|
\
|
|
/* video */ \
|
|
{0}, \
|
|
\
|
|
tsk_null, /* set()*/ \
|
|
tdav_codec_speex_open, \
|
|
tdav_codec_speex_close, \
|
|
tdav_codec_speex_encode, \
|
|
tdav_codec_speex_decode, \
|
|
tdav_codec_speex_sdp_att_match, \
|
|
tdav_codec_speex_sdp_att_get \
|
|
}; \
|
|
const tmedia_codec_plugin_def_t *tdav_codec_speex_##mode##_plugin_def_t = &tdav_codec_speex_##mode##_plugin_def_s;
|
|
|
|
|
|
SPEEX_OBJECT_DEFINITION(nb,"SPEEX","Speex-NB Codec",TMEDIA_CODEC_FORMAT_SPEEX_NB,8000);
|
|
SPEEX_OBJECT_DEFINITION(wb,"SPEEX","Speex-WB Codec",TMEDIA_CODEC_FORMAT_SPEEX_WB,16000);
|
|
SPEEX_OBJECT_DEFINITION(uwb,"SPEEX","Speex-UWB Codec",TMEDIA_CODEC_FORMAT_SPEEX_UWB,32000);
|
|
|
|
//
|
|
// Common functions
|
|
//
|
|
int tdav_codec_speex_init(tdav_codec_speex_t* self, tdav_codec_speex_type_t type)
|
|
{
|
|
if(self){
|
|
self->type = type;
|
|
return 0;
|
|
}
|
|
else{
|
|
TSK_DEBUG_ERROR("Invalid parameter");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int tdav_codec_speex_deinit(tdav_codec_speex_t* self)
|
|
{
|
|
if(self){
|
|
if(self->decoder.state){
|
|
speex_decoder_destroy(self->decoder.state);
|
|
self->decoder.state = tsk_null;
|
|
}
|
|
speex_bits_destroy(&self->decoder.bits);
|
|
if(self->decoder.buffer){
|
|
TSK_FREE(self->decoder.buffer);
|
|
self->decoder.size = 0;
|
|
}
|
|
|
|
if(self->encoder.state){
|
|
speex_encoder_destroy(self->encoder.state);
|
|
self->encoder.state = tsk_null;
|
|
}
|
|
speex_bits_destroy(&self->encoder.bits);
|
|
self->encoder.size = 0;
|
|
|
|
return 0;
|
|
}
|
|
else{
|
|
TSK_DEBUG_ERROR("Invalid parameter");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
#endif /* HAVE_LIB_SPEEX */
|