Commit 200a9744 authored by François Grisez's avatar François Grisez
Browse files

iLBC codec filter based on WebRtc's implementation

parent 02cd3c00
......@@ -36,6 +36,7 @@ set(VERSION "${PACKAGE_VERSION}")
option(ENABLE_AECM "Enable the WebRTC echo canceller for mobile support." YES)
option(ENABLE_ISAC "Enable the ISAC audio codec support." YES)
option(ENABLE_ILBC "Build iLBC codec filter" YES)
set(ISAC_FLAVOUR "fix" CACHE STRING "ISAC audio codec flavour.")
set_property(CACHE ISAC_FLAVOUR PROPERTY STRINGS "fix" "main")
option(ENABLE_STATIC "Build static library (default is shared library)." NO)
......@@ -59,6 +60,9 @@ endif()
if(ENABLE_ISAC)
set(BUILD_ISAC 1)
endif()
if(ENABLE_ILBC)
set(BUILD_ILBC 1)
endif()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
......@@ -67,6 +71,7 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}
webrtc
webrtc/common_audio/signal_processing/include
webrtc/modules/audio_coding/codecs/ilbc/interface
)
add_definitions(-DHAVE_CONFIG_H)
......@@ -204,6 +209,81 @@ if(ENABLE_ISAC)
${ISAC_SRC_DIR}/interface
)
endif()
if(ENABLE_ILBC)
set(ILBC_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/webrtc/modules/audio_coding/codecs/ilbc)
set(ILBC_SRCS
ilbc.c
${ILBC_SRC_DIR}/abs_quant.c
${ILBC_SRC_DIR}/abs_quant_loop.c
${ILBC_SRC_DIR}/augmented_cb_corr.c
${ILBC_SRC_DIR}/bw_expand.c
${ILBC_SRC_DIR}/cb_construct.c
${ILBC_SRC_DIR}/cb_mem_energy_augmentation.c
${ILBC_SRC_DIR}/cb_mem_energy.c
${ILBC_SRC_DIR}/cb_mem_energy_calc.c
${ILBC_SRC_DIR}/cb_search.c
${ILBC_SRC_DIR}/cb_search_core.c
${ILBC_SRC_DIR}/cb_update_best_index.c
${ILBC_SRC_DIR}/chebyshev.c
${ILBC_SRC_DIR}/comp_corr.c
${ILBC_SRC_DIR}/constants.c
${ILBC_SRC_DIR}/create_augmented_vec.c
${ILBC_SRC_DIR}/decode.c
${ILBC_SRC_DIR}/decode_residual.c
${ILBC_SRC_DIR}/decoder_interpolate_lsf.c
${ILBC_SRC_DIR}/do_plc.c
${ILBC_SRC_DIR}/encode.c
${ILBC_SRC_DIR}/energy_inverse.c
${ILBC_SRC_DIR}/enhancer.c
${ILBC_SRC_DIR}/enhancer_interface.c
${ILBC_SRC_DIR}/enh_upsample.c
${ILBC_SRC_DIR}/filtered_cb_vecs.c
${ILBC_SRC_DIR}/frame_classify.c
${ILBC_SRC_DIR}/gain_dequant.c
${ILBC_SRC_DIR}/gain_quant.c
${ILBC_SRC_DIR}/get_cd_vec.c
${ILBC_SRC_DIR}/get_lsp_poly.c
${ILBC_SRC_DIR}/get_sync_seq.c
${ILBC_SRC_DIR}/hp_input.c
${ILBC_SRC_DIR}/hp_output.c
${ILBC_SRC_DIR}/ilbc.c
${ILBC_SRC_DIR}/index_conv_dec.c
${ILBC_SRC_DIR}/index_conv_enc.c
${ILBC_SRC_DIR}/init_decode.c
${ILBC_SRC_DIR}/init_encode.c
${ILBC_SRC_DIR}/interpolate.c
${ILBC_SRC_DIR}/interpolate_samples.c
${ILBC_SRC_DIR}/lpc_encode.c
${ILBC_SRC_DIR}/lsf_check.c
${ILBC_SRC_DIR}/lsf_interpolate_to_poly_dec.c
${ILBC_SRC_DIR}/lsf_interpolate_to_poly_enc.c
${ILBC_SRC_DIR}/lsf_to_lsp.c
${ILBC_SRC_DIR}/lsf_to_poly.c
${ILBC_SRC_DIR}/lsp_to_lsf.c
${ILBC_SRC_DIR}/my_corr.c
${ILBC_SRC_DIR}/nearest_neighbor.c
${ILBC_SRC_DIR}/pack_bits.c
${ILBC_SRC_DIR}/poly_to_lsf.c
${ILBC_SRC_DIR}/poly_to_lsp.c
${ILBC_SRC_DIR}/refiner.c
${ILBC_SRC_DIR}/simple_interpolate_lsf.c
${ILBC_SRC_DIR}/simple_lpc_analysis.c
${ILBC_SRC_DIR}/simple_lsf_dequant.c
${ILBC_SRC_DIR}/simple_lsf_quant.c
${ILBC_SRC_DIR}/smooth.c
${ILBC_SRC_DIR}/smooth_out_data.c
${ILBC_SRC_DIR}/sort_sq.c
${ILBC_SRC_DIR}/split_vq.c
${ILBC_SRC_DIR}/state_construct.c
${ILBC_SRC_DIR}/state_search.c
${ILBC_SRC_DIR}/swap_bytes.c
${ILBC_SRC_DIR}/unpack_bits.c
${ILBC_SRC_DIR}/vq3.c
${ILBC_SRC_DIR}/vq4.c
${ILBC_SRC_DIR}/window32_w32.c
${ILBC_SRC_DIR}/xcorr_coef.c
)
endif()
set(SOURCE_FILES
mswebrtc.c
......@@ -215,6 +295,9 @@ endif()
if(ENABLE_ISAC)
list(APPEND SOURCE_FILES ${ISAC_SRCS})
endif()
if(ENABLE_ILBC)
list(APPEND SOURCE_FILES ${ILBC_SRCS})
endif()
set(LIBS ${MEDIASTREAMER2_LIBRARIES})
......
......@@ -33,3 +33,4 @@
#cmakedefine BUILD_AEC
#cmakedefine BUILD_ISAC
#cmakedefine BUILD_ILBC
/*
ilbc.c
Copyright (C) 2015 Belledonne Communications, Grenoble, France
This program 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 2
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "ilbc.h"
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/mscodecutils.h"
#include "mediastreamer2/msticker.h"
#ifdef HAVE_ms_bufferizer_fill_current_metas
#define ms_bufferizer_fill_current_metas(b,m) ms_bufferizer_fill_current_metas(b,m)
#else
#define ms_bufferizer_fill_current_metas(b,m)
#endif
#define BLOCKL_20MS 160
#define BLOCKL_30MS 240
#define BLOCKL_MAX 240
#define NO_OF_BYTES_20MS 38
#define NO_OF_BYTES_30MS 50
typedef struct EncState{
int nsamples;
int nbytes;
int ms_per_frame;
int ptime;
uint32_t ts;
MSBufferizer *bufferizer;
iLBC_encinst_t *ilbc_enc;
}EncState;
static void enc_init(MSFilter *f){
EncState *s=ms_new0(EncState,1);
#ifdef USE_20MS_FRAMES
s->nsamples=BLOCKL_20MS;
s->nbytes=NO_OF_BYTES_20MS;
s->ms_per_frame=20;
#else
s->nsamples=BLOCKL_30MS;
s->nbytes=NO_OF_BYTES_30MS;
s->ms_per_frame=30;
#endif
s->ts = 0;
s->bufferizer=ms_bufferizer_new();
WebRtcIlbcfix_EncoderCreate(&s->ilbc_enc);
f->data=s;
}
static void enc_uninit(MSFilter *f){
EncState *s=(EncState*)f->data;
ms_bufferizer_destroy(s->bufferizer);
WebRtcIlbcfix_EncoderFree(s->ilbc_enc);
ms_free(f->data);
}
static void enc_preprocess(MSFilter *f){
EncState *s=(EncState*)f->data;
WebRtcIlbcfix_EncoderInit(s->ilbc_enc, s->ms_per_frame);
}
static int enc_add_fmtp(MSFilter *f, void *arg){
char buf[64];
const char *fmtp=(const char *)arg;
EncState *s=(EncState*)f->data;
memset(buf, '\0', sizeof(buf));
if (fmtp_get_value(fmtp, "mode", buf, sizeof(buf))){
if (buf[0]=='\0'){
ms_warning("unsupported fmtp parameter (%s)!", fmtp);
return 0;
}
ms_message("iLBC encoder got mode=%s",buf);
if (strstr(buf,"20")!=NULL){
s->nsamples=BLOCKL_20MS;
s->nbytes=NO_OF_BYTES_20MS;
s->ms_per_frame=20;
}else if (strstr(buf,"30")!=NULL){
s->nsamples=BLOCKL_30MS;
s->nbytes=NO_OF_BYTES_30MS;
s->ms_per_frame=30;
}
}
if (fmtp_get_value(fmtp,"ptime",buf,sizeof(buf))){
int ptime;
if (buf[0]=='\0'){
ms_warning("unsupported fmtp parameter (%s)!", fmtp);
return 0;
}
ms_message("iLBC encoder got ptime=%s",buf);
ptime=atoi(buf);
if (ptime>=20 && ptime<=140){
s->ptime=ptime;
}
}
return 0;
}
static int enc_add_attr(MSFilter *f, void *arg){
const char *fmtp=(const char *)arg;
EncState *s=(EncState*)f->data;
if (strstr(fmtp,"ptime:20")!=NULL){
s->ptime=20;
}else if (strstr(fmtp,"ptime:30")!=NULL){
s->ptime=30;
}else if (strstr(fmtp,"ptime:40")!=NULL){
s->ptime=40;
}else if (strstr(fmtp,"ptime:60")!=NULL){
s->ptime=60;
}else if (strstr(fmtp,"ptime:80")!=NULL){
s->ptime=80;
}else if (strstr(fmtp,"ptime:90")!=NULL){
s->ptime=90;
}else if (strstr(fmtp,"ptime:100")!=NULL){
s->ptime=100;
}else if (strstr(fmtp,"ptime:120")!=NULL){
s->ptime=120;
}else if (strstr(fmtp,"ptime:140")!=NULL){
s->ptime=140;
}
return 0;
}
static void enc_process(MSFilter *f){
EncState *s=(EncState*)f->data;
mblk_t *im,*om;
int size=s->nsamples*2;
WebRtc_Word16 samples[BLOCKL_MAX * 7]; /* BLOCKL_MAX * 7 is the largest size for ptime == 140 */
WebRtc_Word16 *samples_ptr;
int frame_per_packet=1;
int k;
if (s->ptime>=20 && s->ms_per_frame>0 && s->ptime%s->ms_per_frame==0)
{
frame_per_packet = s->ptime/s->ms_per_frame;
}
if (frame_per_packet<=0)
frame_per_packet=1;
if (frame_per_packet>7) /* 7*20 == 140 ms max */
frame_per_packet=7;
while((im=ms_queue_get(f->inputs[0]))!=NULL){
ms_bufferizer_put(s->bufferizer,im);
}
while(ms_bufferizer_read(s->bufferizer,(uint8_t*)samples,size*frame_per_packet)==(size*frame_per_packet)){
om=allocb(s->nbytes*frame_per_packet,0);
for (k=0;k<frame_per_packet;k++) {
samples_ptr = samples + k * s->nsamples;
WebRtcIlbcfix_Encode(s->ilbc_enc, samples_ptr, s->nsamples, (WebRtc_Word16 *)om->b_wptr);
om->b_wptr+=s->nbytes;
}
s->ts+=s->nsamples*frame_per_packet;
mblk_set_timestamp_info(om,s->ts);
ms_bufferizer_fill_current_metas(s->bufferizer,om);
ms_queue_put(f->outputs[0],om);
}
}
static MSFilterMethod enc_methods[]={
{ MS_FILTER_ADD_FMTP, enc_add_fmtp },
{ MS_FILTER_ADD_ATTR, enc_add_attr},
{ 0 , NULL }
};
#ifdef _MSC_VER
MSFilterDesc ms_webrtc_ilbc_enc_desc={
MS_FILTER_PLUGIN_ID,
"MSWebRtcIlbcEnc",
"WebRtc's iLBC encoder",
MS_FILTER_ENCODER,
"iLBC",
1,
1,
enc_init,
enc_preprocess,
enc_process,
NULL,
enc_uninit,
enc_methods
};
#else
MSFilterDesc ms_webrtc_ilbc_enc_desc={
.id=MS_FILTER_PLUGIN_ID,
.name="MSWebRtcIlbcEnc",
.text="WebRtc's iLBC encoder",
.category=MS_FILTER_ENCODER,
.enc_fmt="iLBC",
.ninputs=1,
.noutputs=1,
.init=enc_init,
.preprocess=enc_preprocess,
.process=enc_process,
.uninit=enc_uninit,
.methods=enc_methods
};
#endif
typedef struct DecState{
int nsamples;
int nbytes;
int ms_per_frame;
iLBC_decinst_t *ilbc_dec;
bool_t ready;
MSConcealerContext *plcctx;
}DecState;
static void dec_init(MSFilter *f){
DecState *s=ms_new0(DecState,1);
s->nsamples=0;
s->nbytes=0;
s->ms_per_frame=0;
WebRtcIlbcfix_DecoderCreate(&s->ilbc_dec);
s->ready=FALSE;
s->plcctx=ms_concealer_context_new(200);
f->data=s;
}
static void dec_uninit(MSFilter *f){
DecState *s=(DecState*)f->data;
WebRtcIlbcfix_DecoderFree(s->ilbc_dec);
if (s->plcctx) ms_concealer_context_destroy(s->plcctx);
ms_free(s);
}
static void dec_process(MSFilter *f){
DecState *s=(DecState*)f->data;
mblk_t *im,*om;
int nbytes;
int i;
while ((im=ms_queue_get(f->inputs[0]))!=NULL){
nbytes=msgdsize(im);
if (nbytes==0 || (nbytes%NO_OF_BYTES_20MS!=0 && nbytes%NO_OF_BYTES_30MS!=0)){
freemsg(im);
continue;
}
if (nbytes%NO_OF_BYTES_20MS==0 && s->nbytes!=NO_OF_BYTES_20MS) {
/* not yet configured, or misconfigured */
s->ms_per_frame=20;
s->nbytes=NO_OF_BYTES_20MS;
s->nsamples=BLOCKL_20MS;
s->ready=TRUE;
WebRtcIlbcfix_DecoderInit(s->ilbc_dec, s->ms_per_frame);
}
else if (nbytes%NO_OF_BYTES_30MS==0 && s->nbytes!=NO_OF_BYTES_30MS) {
/* not yet configured, or misconfigured */
s->ms_per_frame=30;
s->nbytes=NO_OF_BYTES_30MS;
s->nsamples=BLOCKL_30MS;
s->ready=TRUE;
WebRtcIlbcfix_DecoderInit(s->ilbc_dec, s->ms_per_frame);
}
if (s->nbytes>0 && nbytes>=s->nbytes){
int frame_per_packet = nbytes/s->nbytes;
int k;
int plctime;
for (k=0;k<frame_per_packet;k++) {
WebRtc_Word16 speech_type;
om=allocb(s->nsamples*2,0);
WebRtcIlbcfix_Decode(s->ilbc_dec, (WebRtc_Word16 *)(im->b_rptr+k*s->nbytes), s->nbytes, (WebRtc_Word16 *)om->b_wptr, &speech_type);
om->b_wptr += s->nsamples * 2;
mblk_meta_copy(im,om);
ms_queue_put(f->outputs[0],om);
}
if (s->plcctx){
plctime=ms_concealer_inc_sample_time(s->plcctx,f->ticker->time,frame_per_packet*s->ms_per_frame,1);
if (plctime>0){
ms_warning("ilbc: did plc during %i ms",plctime);
}
}
}else{
ms_warning("bad iLBC frame !");
}
freemsg(im);
}
if (s->plcctx && s->ready && ms_concealer_context_is_concealement_required(s->plcctx,f->ticker->time)){
om=allocb(s->nsamples*2,0);
WebRtcIlbcfix_DecodePlc(s->ilbc_dec, (WebRtc_Word16 *)om->b_wptr, 1);
om->b_wptr += s->nsamples * 2;
mblk_set_plc_flag(om,TRUE);
ms_queue_put(f->outputs[0],om);
ms_concealer_inc_sample_time(s->plcctx,f->ticker->time,s->ms_per_frame,0);
}
}
static int dec_have_plc(MSFilter *f, void *arg){
DecState *s=(DecState*)f->data;
*((int *)arg) = (s->plcctx!=NULL);
return 0;
}
static MSFilterMethod dec_methods[]={
{ MS_DECODER_HAVE_PLC, dec_have_plc },
{ 0 , NULL }
};
#ifdef _MSC_VER
MSFilterDesc ms_webrtc_ilbc_dec_desc={
MS_FILTER_PLUGIN_ID,
"MSWebRtcIlbcDec",
"WebRtc's iLBC decoder",
MS_FILTER_DECODER,
"iLBC",
1,
1,
dec_init,
NULL,
dec_process,
NULL,
dec_uninit,
dec_methods,
MS_FILTER_IS_PUMP
};
#else
MSFilterDesc ms_webrtc_ilbc_dec_desc={
.id=MS_FILTER_PLUGIN_ID,
.name="MSWebRtcIlbcDec",
.text="WebRtc's iLBC decoder",
.category=MS_FILTER_DECODER,
.enc_fmt="iLBC",
.ninputs=1,
.noutputs=1,
.init=dec_init,
.process=dec_process,
.uninit=dec_uninit,
.methods=dec_methods,
.flags=MS_FILTER_IS_PUMP
};
#endif
#ifdef _MSC_VER
#define MS_PLUGIN_DECLARE(type) __declspec(dllexport) type
#else
#define MS_PLUGIN_DECLARE(type) type
#endif
MS_PLUGIN_DECLARE(void) libmsilbc_init(){
ms_filter_register(&ms_webrtc_ilbc_enc_desc);
ms_filter_register(&ms_webrtc_ilbc_dec_desc);
}
......@@ -26,6 +26,10 @@
#include "isacfix.h"
#endif
#ifdef BUILD_ILBC
#include "ilbc.h"
#endif
#include "signal_processing_library.h"
#include "mediastreamer2/msfilter.h"
......@@ -39,6 +43,10 @@ extern MSFilterDesc ms_isac_enc_desc;
#ifdef BUILD_AEC
extern MSFilterDesc ms_webrtc_aec_desc;
#endif
#ifdef BUILD_ILBC
MSFilterDesc ms_webrtc_ilbc_enc_desc;
MSFilterDesc ms_webrtc_ilbc_dec_desc;
#endif
#ifndef VERSION
#define VERSION "debug"
......@@ -52,10 +60,12 @@ extern MSFilterDesc ms_webrtc_aec_desc;
MS_PLUGIN_DECLARE ( void ) libmswebrtc_init() {
#ifdef BUILD_ISAC
char isac_version[64];
isac_version[0] = 0;
char isac_version[20] = "";
#endif
#ifdef BUILD_ILBC
char ilbc_version[20] = "";
#endif
WebRtcSpl_Init();
#ifdef BUILD_ISAC
......@@ -66,10 +76,24 @@ MS_PLUGIN_DECLARE ( void ) libmswebrtc_init() {
#ifdef BUILD_AEC
ms_filter_register(&ms_webrtc_aec_desc);
#endif
#ifdef BUILD_ILBC
WebRtcIlbcfix_version(ilbc_version);
ms_filter_register(&ms_webrtc_ilbc_enc_desc);
ms_filter_register(&ms_webrtc_ilbc_dec_desc);
#endif
ms_message("libmswebrtc " VERSION " plugin loaded"
#ifdef BUILD_ISAC
", iSAC codec version %s", isac_version
", iSAC codec version %s"
#endif
#ifdef BUILD_ILBC
", iLBC codec version %s"
#endif
#ifdef BUILD_ISAC
, isac_version
#endif
#ifdef BUILD_ILBC
, ilbc_version
#endif
);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment