silk_enc.c 10.1 KB
Newer Older
1 2 3
/*
 silk_enc.c
 Copyright (C) 2011 Belledonne Communications, Grenoble, France
Simon Morlat's avatar
Simon Morlat committed
4

5 6 7 8
 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.
Simon Morlat's avatar
Simon Morlat committed
9

10 11 12 13
 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.
Simon Morlat's avatar
Simon Morlat committed
14

15 16 17 18 19 20 21 22 23 24 25 26
 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 "SKP_Silk_SDK_API.h"
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/mscodecutils.h"

/* Define codec specific settings */
#define MAX_BYTES_PER_FRAME     250 // Equals peak bitrate of 100 kbps 
#define MAX_INPUT_FRAMES        5

27 28 29 30 31 32
#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

33 34 35 36 37 38 39 40 41 42 43
/*filter common method*/
struct silk_enc_struct {
	SKP_SILK_SDK_EncControlStruct control;
	void* psEnc;
	uint32_t ts;
	MSBufferizer *bufferizer;
	unsigned char ptime;
	unsigned char max_ptime;
	unsigned int max_network_bitrate;
};

Simon Morlat's avatar
Simon Morlat committed
44 45
static void filter_init ( MSFilter *f ) {
	struct silk_enc_struct* obj;
46 47
	SKP_int16 ret;
	SKP_int32 encSizeBytes;
Simon Morlat's avatar
Simon Morlat committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61
	f->data = ms_new0 ( struct silk_enc_struct,1 );
	obj = ( struct silk_enc_struct* ) f->data;

	/* Create encoder */
	ret = SKP_Silk_SDK_Get_Encoder_Size ( &encSizeBytes );
	if ( ret ) {
		ms_error ( "SKP_Silk_SDK_Get_Encoder_Size returned %i", ret );
	}
	obj->psEnc = ms_malloc ( encSizeBytes );
	/* Reset decoder */
	ret = SKP_Silk_SDK_InitEncoder ( obj->psEnc,&obj->control );
	if ( ret ) {
		ms_error ( "SKP_Silk_SDK_InitEncoder returned %i", ret );
	}
62 63 64 65 66 67 68 69
	obj->ptime=20;
	obj->max_ptime=100;
	obj->bufferizer=ms_bufferizer_new();
	obj->control.useInBandFEC=1;
	obj->control.complexity=1;
	obj->control.packetLossPercentage=5;
}

Simon Morlat's avatar
Simon Morlat committed
70 71
static void filter_preprocess ( MSFilter *f ) {

72 73 74

}

Simon Morlat's avatar
Simon Morlat committed
75
static void filter_process ( MSFilter *f ) {
76 77 78 79 80
	mblk_t *im;
	mblk_t *om=NULL;
	SKP_int16 ret;
	SKP_int16 nBytes;
	uint8_t * buff=NULL;
Simon Morlat's avatar
Simon Morlat committed
81
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
82
	obj->control.packetSize = obj->control.API_sampleRate*obj->ptime/1000; /*in sample*/
Simon Morlat's avatar
Simon Morlat committed
83 84 85

	while ( ( im=ms_queue_get ( f->inputs[0] ) ) !=NULL ) {
		ms_bufferizer_put ( obj->bufferizer,im );
86
	}
Simon Morlat's avatar
Simon Morlat committed
87
	while ( ms_bufferizer_get_avail ( obj->bufferizer ) >=obj->control.packetSize*2 ) {
88
		/* max payload size */
Simon Morlat's avatar
Simon Morlat committed
89 90 91 92 93 94 95 96 97 98 99 100 101 102
		nBytes = MAX_BYTES_PER_FRAME * MAX_INPUT_FRAMES;
		om = allocb ( nBytes,0 );
		if ( !buff ) buff=ms_malloc ( obj->control.packetSize*2 );
		ms_bufferizer_read ( obj->bufferizer,buff,obj->control.packetSize*2 );
		ret = SKP_Silk_SDK_Encode ( obj->psEnc
									, &obj->control
									, ( const SKP_int16* ) buff
									, ( SKP_int16 ) ( obj->control.packetSize )
									, om->b_wptr
									, &nBytes );
		if ( ret ) {
			ms_error ( "SKP_Silk_Encode returned %i", ret );
			freeb ( om );
		} else  if ( nBytes > 0 ) {
103
			obj->ts+=obj->control.packetSize;
Simon Morlat's avatar
Simon Morlat committed
104
			om->b_wptr+=nBytes;
105 106 107
			mblk_set_timestamp_info(om, obj->ts);
			ms_bufferizer_fill_current_metas(obj->bufferizer, om);
			ms_queue_put(f->outputs[0], om);
108
			om=NULL;
Simon Morlat's avatar
Simon Morlat committed
109 110
		}

111
	}
Simon Morlat's avatar
Simon Morlat committed
112 113
	if ( buff!=NULL ) {
		ms_free ( buff );
114 115 116 117
	}

}

Simon Morlat's avatar
Simon Morlat committed
118 119
static void filter_postprocess ( MSFilter *f ) {

120 121
}

Simon Morlat's avatar
Simon Morlat committed
122 123 124 125 126
static void filter_uninit ( MSFilter *f ) {
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
	ms_bufferizer_destroy ( obj->bufferizer );
	ms_free ( obj->psEnc );
	ms_free ( f->data );
127 128 129 130 131
}


/*filter specific method*/

Simon Morlat's avatar
Simon Morlat committed
132 133 134
static int filter_set_sample_rate ( MSFilter *f, void *arg ) {
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
	switch ( * ( SKP_int32* ) arg ) {
135 136 137 138
		case 8000:
		case 12000:
		case 16000:
		case 24000:
Simon Morlat's avatar
Simon Morlat committed
139 140
			obj->control.maxInternalSampleRate=* ( SKP_int32* ) arg;
			obj->control.API_sampleRate=* ( SKP_int32* ) arg;
141 142
			break;
		default:
Simon Morlat's avatar
Simon Morlat committed
143
			ms_warning ( "unsupported max sampling rate [%i] for silk, using 16 000",* ( SKP_int32* ) arg );
144 145 146 147 148 149
			obj->control.API_sampleRate=obj->control.maxInternalSampleRate=16000;
	}

	return 0;
}

Simon Morlat's avatar
Simon Morlat committed
150 151 152
static int filter_get_sample_rate ( MSFilter *f, void *arg ) {
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
	* ( int* ) arg = obj->control.maxInternalSampleRate;
153 154
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
155 156
static int filter_set_bitrate ( MSFilter *f, void *arg );

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
#ifdef MS_AUDIO_ENCODER_SET_PTIME
static int filter_get_ptime(MSFilter *f, void *arg){
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
	*(int*)arg=obj->ptime;
	return 0;
}
#endif

static int filter_set_ptime(MSFilter *f, void *arg){
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
	obj->ptime=*(int*)arg;
	if ( obj->ptime > obj->max_ptime ) {
		obj->ptime=obj->max_ptime;
	} else if ( obj->ptime%20 ) {
		//if the ptime is not a mulptiple of 20, go to the next multiple
		obj->ptime = obj->ptime - obj->ptime%20 + 20;
	}
	ms_message ( "MSSilkEnc: got ptime=%i",obj->ptime );
	/*new encoder bitrate must be computed*/
	filter_set_bitrate ( f,&obj->max_network_bitrate );
	return 0;
}

Simon Morlat's avatar
Simon Morlat committed
180 181 182 183 184 185 186 187 188
static int filter_add_fmtp ( MSFilter *f, void *arg ) {
	char buf[64]= {0};
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
	const char *fmtp= ( const char * ) arg;

	if ( fmtp_get_value ( fmtp,"maxptime",buf,sizeof ( buf ) ) ) {
		obj->max_ptime=atoi ( buf );
		if ( obj->max_ptime <20 || obj->max_ptime >100 ) {
			ms_warning ( "MSSilkEnc unknown value [%i] for maxptime, use default value (100) instead",obj->max_ptime );
189 190
			obj->max_ptime=100;
		}
Simon Morlat's avatar
Simon Morlat committed
191 192
		ms_message ( "MSSilkEnc: got maxptime=%i",obj->max_ptime );
	} else 	if ( fmtp_get_value ( fmtp,"ptime",buf,sizeof ( buf ) ) ) {
193 194
		int val=atoi(buf);
		filter_set_ptime(f,&val);
Simon Morlat's avatar
Simon Morlat committed
195 196 197 198
	} else 	if ( fmtp_get_value ( fmtp,"useinbandfec",buf,sizeof ( buf ) ) ) {
		obj->control.useInBandFEC=atoi ( buf );
		if ( obj->control.useInBandFEC != 0 && obj->control.useInBandFEC != 1 ) {
			ms_warning ( "MSSilkEnc unknown value [%i] for useinbandfec, use default value (1) instead",obj->control.useInBandFEC );
199 200
			obj->control.useInBandFEC=1;
		}
Simon Morlat's avatar
Simon Morlat committed
201 202 203
		ms_message ( "MSSilkEnc: got useinbandfec=%i",obj->control.useInBandFEC );
	} else ms_message ( "MSSilkEnc: unhandled fmtp %s",fmtp );

204 205
	return 0;
}
Simon Morlat's avatar
Simon Morlat committed
206 207
static int filter_set_bitrate ( MSFilter *f, void *arg ) {
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
208
	int inital_cbr=0;
Simon Morlat's avatar
Simon Morlat committed
209
	int normalized_cbr=0;
jehan's avatar
jehan committed
210 211 212
	float pps=1000.0f/obj->ptime;
	unsigned int network_bitrate=* ( int* ) arg;
	normalized_cbr=inital_cbr= ( int ) ( ( ( ( ( float ) network_bitrate ) / ( pps*8 ) )-20-12-8 ) *pps*8 );
Simon Morlat's avatar
Simon Morlat committed
213
	switch ( obj->control.maxInternalSampleRate ) {
214
		case 8000:
Simon Morlat's avatar
Simon Morlat committed
215 216
			normalized_cbr=MIN ( normalized_cbr,20000 );
			normalized_cbr=MAX ( normalized_cbr,5000 );
217 218
			break;
		case 12000:
Simon Morlat's avatar
Simon Morlat committed
219 220
			normalized_cbr=MIN ( normalized_cbr,25000 );
			normalized_cbr=MAX ( normalized_cbr,7000 );
221 222
			break;
		case 16000:
Simon Morlat's avatar
Simon Morlat committed
223 224
			normalized_cbr=MIN ( normalized_cbr,32000 );
			normalized_cbr=MAX ( normalized_cbr,8000 );
225 226
			break;
		case 24000:
Simon Morlat's avatar
Simon Morlat committed
227 228
			normalized_cbr=MIN ( normalized_cbr,40000 );
			normalized_cbr=MAX ( normalized_cbr,20000 );
229
			break;
Simon Morlat's avatar
Simon Morlat committed
230

231
	}
Simon Morlat's avatar
Simon Morlat committed
232 233
	if ( normalized_cbr!=inital_cbr ) {
		ms_warning ( "Silk enc unsupported codec bitrate [%i], normalizing",inital_cbr );
234 235
	}
	obj->control.bitRate=normalized_cbr;
jehan's avatar
jehan committed
236
	obj->max_network_bitrate=(unsigned int)(((float)normalized_cbr/(pps*8) +20+12+8)*pps*8);
Simon Morlat's avatar
Simon Morlat committed
237
	ms_message ( "MSSilkEnc: Setting silk codec birate to [%i] from network bitrate [%i] with ptime [%i]",obj->control.bitRate,obj->max_network_bitrate,obj->ptime );
jehan's avatar
jehan committed
238

239 240 241
	return 0;
}

Simon Morlat's avatar
Simon Morlat committed
242 243 244
static int filter_get_bitrate ( MSFilter *f, void *arg ) {
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
	* ( int* ) arg=obj->max_network_bitrate;
245 246
	return 0;
}
247
#ifdef MS_AUDIO_ENCODER_SET_PACKET_LOSS
248 249 250 251 252 253 254 255 256 257 258
static int filter_set_packetloss(MSFilter *f, void *arg){
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
	obj->control.packetLossPercentage=* ( int* ) arg;
	return 0;
}

static int filter_enable_inband_fec(MSFilter *f, void *arg){
	struct silk_enc_struct* obj= ( struct silk_enc_struct* ) f->data;
	obj->control.useInBandFEC=* ( int* ) arg;
	return 0;
}
259
#endif /*MS_AUDIO_ENCODER_SET_PACKET_LOSS*/
260

Simon Morlat's avatar
Simon Morlat committed
261
static MSFilterMethod filter_methods[]= {
262
	{	MS_FILTER_SET_SAMPLE_RATE , filter_set_sample_rate },
Simon Morlat's avatar
Simon Morlat committed
263
	{	MS_FILTER_GET_SAMPLE_RATE , filter_get_sample_rate },
264 265 266
	{	MS_FILTER_SET_BITRATE		,	filter_set_bitrate	},
	{	MS_FILTER_GET_BITRATE		,	filter_get_bitrate	},
	{	MS_FILTER_ADD_FMTP		,	filter_add_fmtp },
267 268 269
#ifdef MS_AUDIO_ENCODER_SET_PTIME
	{	MS_AUDIO_ENCODER_SET_PTIME	,	filter_set_ptime	},
	{	MS_AUDIO_ENCODER_GET_PTIME	,	filter_get_ptime	},
270 271 272 273
#endif
#ifdef MS_AUDIO_ENCODER_SET_PACKET_LOSS
	{	MS_AUDIO_ENCODER_SET_PACKET_LOSS	,	filter_set_packetloss	},
	{	MS_AUDIO_ENCODER_ENABLE_FEC	,	filter_enable_inband_fec	},
274
#endif
275 276 277 278
	{	0, NULL}
};


Ghislain MARY's avatar
Ghislain MARY committed
279 280
#ifdef _MSC_VER

Simon Morlat's avatar
Simon Morlat committed
281
MSFilterDesc ms_silk_enc_desc= {
Ghislain MARY's avatar
Ghislain MARY committed
282 283 284 285 286 287 288 289 290 291
	MS_FILTER_PLUGIN_ID, /* from Allfilters.h*/
	"MSSILKEnc",
	"SILK audio encoder filter.",
	MS_FILTER_ENCODER,
	"SILK",
	1, /*number of inputs*/
	1, /*number of outputs*/
	filter_init,
	filter_preprocess,
	filter_process,
Simon Morlat's avatar
Simon Morlat committed
292 293
	filter_postprocess,
	filter_uninit,
Ghislain MARY's avatar
Ghislain MARY committed
294 295 296 297 298
	filter_methods,
	0
};

#else
299

Simon Morlat's avatar
Simon Morlat committed
300
MSFilterDesc ms_silk_enc_desc= {
301 302 303 304 305 306 307 308 309 310
	.id=MS_FILTER_PLUGIN_ID, /* from Allfilters.h*/
	.name="MSSILKEnc",
	.text="SILK audio encoder filter.",
	.category=MS_FILTER_ENCODER,
	.enc_fmt="SILK",
	.ninputs=1, /*number of inputs*/
	.noutputs=1, /*number of outputs*/
	.init=filter_init,
	.preprocess=filter_preprocess,
	.process=filter_process,
Simon Morlat's avatar
Simon Morlat committed
311 312
	.postprocess=filter_postprocess,
	.uninit=filter_uninit,
313 314
	.methods=filter_methods
};
Ghislain MARY's avatar
Ghislain MARY committed
315 316 317

#endif

Simon Morlat's avatar
Simon Morlat committed
318
MS_FILTER_DESC_EXPORT ( ms_silk_enc_desc )
319 320

extern MSFilterDesc ms_silk_dec_desc;
Ghislain MARY's avatar
Ghislain MARY committed
321

322
#ifndef VERSION
Simon Morlat's avatar
Simon Morlat committed
323
#define VERSION "debug"
324
#endif
Ghislain MARY's avatar
Ghislain MARY committed
325 326 327 328 329 330 331

#ifdef _MSC_VER
#define MS_PLUGIN_DECLARE(type) __declspec(dllexport) type
#else
#define MS_PLUGIN_DECLARE(type) type
#endif

Simon Morlat's avatar
Simon Morlat committed
332 333 334 335
MS_PLUGIN_DECLARE ( void ) libmssilk_init() {
	ms_filter_register ( &ms_silk_enc_desc );
	ms_filter_register ( &ms_silk_dec_desc );
	ms_message ( " libmssilk " VERSION " plugin loaded" );
336
}
Simon Morlat's avatar
Simon Morlat committed
337

Simon Morlat's avatar
Simon Morlat committed
338