Update for in-band FEC

This commit is contained in:
Koen Vos 2011-02-14 15:04:59 -05:00 committed by Jean-Marc Valin
parent 5d56fc78b0
commit 1e1562c121
8 changed files with 80 additions and 47 deletions

2
celt

@ -1 +1 @@
Subproject commit 0b405d1170122c859faab435405666506d52fa2e Subproject commit b3c05b6be2a6579af55a625903e9e70687a4d77f

2
silk

@ -1 +1 @@
Subproject commit fc06bda89e40f8adfa1af9cebf869e63ef693bb5 Subproject commit 485d64dfdf4145bf45929c697cdb2b3eed9c91c1

View file

@ -6,7 +6,7 @@ silk/interface/SKP_Silk_typedef.h
silk/src_common/SKP_Silk_define.h silk/src_common/SKP_Silk_define.h
silk/src_common/SKP_Silk_main.h silk/src_common/SKP_Silk_main.h
silk/src_common/SKP_Silk_PLC.h silk/src_common/SKP_Silk_PLC.h
silk/src_common/SKP_Silk_setup_complexity.h silk/src_common/SKP_Silk_setup.h
silk/src_common/SKP_Silk_structs.h silk/src_common/SKP_Silk_structs.h
silk/src_common/SKP_Silk_tables.h silk/src_common/SKP_Silk_tables.h
silk/src_common/SKP_Silk_tables_NLSF_CB.h silk/src_common/SKP_Silk_tables_NLSF_CB.h

View file

@ -13,13 +13,13 @@ silk/src_common/SKP_Silk_encode_indices.c \
silk/src_common/SKP_Silk_encode_pulses.c \ silk/src_common/SKP_Silk_encode_pulses.c \
silk/src_common/SKP_Silk_gain_quant.c \ silk/src_common/SKP_Silk_gain_quant.c \
silk/src_common/SKP_Silk_interpolate.c \ silk/src_common/SKP_Silk_interpolate.c \
silk/src_common/SKP_Silk_LBRR_embed.c \
silk/src_common/SKP_Silk_LP_variable_cutoff.c \ silk/src_common/SKP_Silk_LP_variable_cutoff.c \
silk/src_common/SKP_Silk_NLSF2A_stable.c \ silk/src_common/SKP_Silk_NLSF2A_stable.c \
silk/src_common/SKP_Silk_NLSF_MSVQ_decode.c \ silk/src_common/SKP_Silk_NLSF_MSVQ_decode.c \
silk/src_common/SKP_Silk_NSQ.c \ silk/src_common/SKP_Silk_NSQ.c \
silk/src_common/SKP_Silk_NSQ_del_dec.c \ silk/src_common/SKP_Silk_NSQ_del_dec.c \
silk/src_common/SKP_Silk_PLC.c \ silk/src_common/SKP_Silk_PLC.c \
silk/src_common/SKP_Silk_pulses_to_bytes.c \
silk/src_common/SKP_Silk_shell_coder.c \ silk/src_common/SKP_Silk_shell_coder.c \
silk/src_common/SKP_Silk_tables_gain.c \ silk/src_common/SKP_Silk_tables_gain.c \
silk/src_common/SKP_Silk_tables_LTP.c \ silk/src_common/SKP_Silk_tables_LTP.c \
@ -51,7 +51,6 @@ silk/src_FLP/SKP_Silk_NLSF_MSVQ_decode_FLP.c \
silk/src_FLP/SKP_Silk_NLSF_MSVQ_encode_FLP.c \ silk/src_FLP/SKP_Silk_NLSF_MSVQ_encode_FLP.c \
silk/src_FLP/SKP_Silk_NLSF_VQ_rate_distortion_FLP.c \ silk/src_FLP/SKP_Silk_NLSF_VQ_rate_distortion_FLP.c \
silk/src_FLP/SKP_Silk_NLSF_VQ_sum_error_FLP.c \ silk/src_FLP/SKP_Silk_NLSF_VQ_sum_error_FLP.c \
silk/src_FLP/SKP_Silk_NLSF_VQ_weights_laroia_FLP.c \
silk/src_FLP/SKP_Silk_noise_shape_analysis_FLP.c \ silk/src_FLP/SKP_Silk_noise_shape_analysis_FLP.c \
silk/src_FLP/SKP_Silk_prefilter_FLP.c \ silk/src_FLP/SKP_Silk_prefilter_FLP.c \
silk/src_FLP/SKP_Silk_process_gains_FLP.c \ silk/src_FLP/SKP_Silk_process_gains_FLP.c \
@ -111,12 +110,9 @@ silk/src_SigProc_FIX/SKP_Silk_schur.c \
silk/src_SigProc_FIX/SKP_Silk_sigm_Q15.c \ silk/src_SigProc_FIX/SKP_Silk_sigm_Q15.c \
silk/src_SigProc_FIX/SKP_Silk_sort.c \ silk/src_SigProc_FIX/SKP_Silk_sort.c \
silk/src_SigProc_FIX/SKP_Silk_sum_sqr_shift.c \ silk/src_SigProc_FIX/SKP_Silk_sum_sqr_shift.c \
silk/src_SigProc_FLP/SKP_Silk_allpass_int_FLP.c \
silk/src_SigProc_FLP/SKP_Silk_autocorrelation_FLP.c \ silk/src_SigProc_FLP/SKP_Silk_autocorrelation_FLP.c \
silk/src_SigProc_FLP/SKP_Silk_burg_modified_FLP.c \ silk/src_SigProc_FLP/SKP_Silk_burg_modified_FLP.c \
silk/src_SigProc_FLP/SKP_Silk_bwexpander_FLP.c \ silk/src_SigProc_FLP/SKP_Silk_bwexpander_FLP.c \
silk/src_SigProc_FLP/SKP_Silk_decimate2_coarse_FLP.c \
silk/src_SigProc_FLP/SKP_Silk_decimate2_coarsest_FLP.c \
silk/src_SigProc_FLP/SKP_Silk_energy_FLP.c \ silk/src_SigProc_FLP/SKP_Silk_energy_FLP.c \
silk/src_SigProc_FLP/SKP_Silk_inner_product_FLP.c \ silk/src_SigProc_FLP/SKP_Silk_inner_product_FLP.c \
silk/src_SigProc_FLP/SKP_Silk_k2a_FLP.c \ silk/src_SigProc_FLP/SKP_Silk_k2a_FLP.c \

View file

@ -114,7 +114,7 @@ OpusDecoder *opus_decoder_create(int Fs, int channels);
/* returns (CELT) error code */ /* returns (CELT) error code */
int opus_decode(OpusDecoder *st, const unsigned char *data, int len, int opus_decode(OpusDecoder *st, const unsigned char *data, int len,
short *pcm, int frame_size); short *pcm, int frame_size, int decode_fec);
void opus_decoder_ctl(OpusDecoder *st, int request, ...); void opus_decoder_ctl(OpusDecoder *st, int request, ...);

View file

@ -71,7 +71,7 @@ OpusDecoder *opus_decoder_create(int Fs, int channels)
} }
int opus_decode(OpusDecoder *st, const unsigned char *data, int opus_decode(OpusDecoder *st, const unsigned char *data,
int len, short *pcm, int frame_size) int len, short *pcm, int frame_size, int decode_fec)
{ {
int i, silk_ret=0, celt_ret=0; int i, silk_ret=0, celt_ret=0;
ec_dec dec; ec_dec dec;
@ -131,6 +131,7 @@ int opus_decode(OpusDecoder *st, const unsigned char *data,
/* SILK processing */ /* SILK processing */
if (st->mode != MODE_CELT_ONLY) if (st->mode != MODE_CELT_ONLY)
{ {
int lost_flag, decoded_samples;
SKP_int16 *pcm_ptr = pcm; SKP_int16 *pcm_ptr = pcm;
DecControl.API_sampleRate = st->Fs; DecControl.API_sampleRate = st->Fs;
DecControl.payloadSize_ms = 1000 * audiosize / st->Fs; DecControl.payloadSize_ms = 1000 * audiosize / st->Fs;
@ -149,15 +150,20 @@ int opus_decode(OpusDecoder *st, const unsigned char *data,
DecControl.internalSampleRate = 16000; DecControl.internalSampleRate = 16000;
} }
lost_flag = data == NULL ? 1 : 2 * decode_fec;
decoded_samples = 0;
do { do {
/* Call SILK decoder */ /* Call SILK decoder */
silk_ret = SKP_Silk_SDK_Decode( st->silk_dec, &DecControl, data == NULL, &dec, len, pcm_ptr, &silk_frame_size ); int first_frame = decoded_samples == 0;
silk_ret = SKP_Silk_SDK_Decode( st->silk_dec, &DecControl,
lost_flag, first_frame, &dec, len, pcm_ptr, &silk_frame_size );
if( silk_ret ) { if( silk_ret ) {
fprintf (stderr, "SILK decode error\n"); fprintf (stderr, "SILK decode error\n");
/* Handle error */ /* Handle error */
} }
pcm_ptr += silk_frame_size; pcm_ptr += silk_frame_size;
} while( DecControl.moreInternalDecoderFrames ); decoded_samples += silk_frame_size;
} while( decoded_samples < frame_size );
} else { } else {
for (i=0;i<frame_size*st->channels;i++) for (i=0;i<frame_size*st->channels;i++)
pcm[i] = 0; pcm[i] = 0;

View file

@ -134,7 +134,9 @@ int opus_encode(OpusEncoder *st, const short *pcm, int frame_size,
} }
if( st->mode == MODE_HYBRID ) { if( st->mode == MODE_HYBRID ) {
/* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */ /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */
st->silk_mode.minInternalSampleRate = st->silk_mode.maxInternalSampleRate ; st->silk_mode.minInternalSampleRate = 16000;
} else {
st->silk_mode.minInternalSampleRate = 8000;
} }
/* Call SILK encoder for the low band */ /* Call SILK encoder for the low band */

View file

@ -71,10 +71,10 @@ int main(int argc, char *argv[])
OpusEncoder *enc; OpusEncoder *enc;
OpusDecoder *dec; OpusDecoder *dec;
int args; int args;
int len; int len[2];
int frame_size, channels; int frame_size, channels;
int bitrate_bps; int bitrate_bps;
unsigned char *data; unsigned char *data[2];
int sampling_rate; int sampling_rate;
int use_vbr; int use_vbr;
int internal_sampling_rate_Hz; int internal_sampling_rate_Hz;
@ -92,6 +92,10 @@ int main(int argc, char *argv[])
double bits=0.0, bits_act=0.0, bits2=0.0, nrg; double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
int bandwidth=-1; int bandwidth=-1;
const char *bandwidth_string; const char *bandwidth_string;
int write_samples;
int lost, lost_prev = 1;
int toggle = 0;
int enc_final_range[2];
if (argc < 7 ) if (argc < 7 )
{ {
@ -257,20 +261,19 @@ int main(int argc, char *argv[])
enc = opus_encoder_create(sampling_rate, channels); enc = opus_encoder_create(sampling_rate, channels);
dec = opus_decoder_create(sampling_rate, channels); dec = opus_decoder_create(sampling_rate, channels);
opus_encoder_ctl(enc, OPUS_SET_MODE(mode));
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
if (bandwidth == -1) if (bandwidth == -1)
{ {
fprintf (stderr, "Please specify a bandwidth when the sampling rate does not match one exactly\n"); fprintf (stderr, "Please specify a bandwidth when the sampling rate does not match one exactly\n");
return 1; return 1;
} }
opus_encoder_ctl(enc, OPUS_SET_MODE(mode));
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth)); opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr)); opus_encoder_ctl(enc, OPUS_SET_VBR_FLAG(use_vbr));
opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec)); opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC_FLAG(use_inbandfec));
opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx)); opus_encoder_ctl(enc, OPUS_SET_DTX_FLAG(use_dtx));
opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
skip = 5*sampling_rate/1000; skip = 5*sampling_rate/1000;
/* When SILK resamples, add 18 samples delay */ /* When SILK resamples, add 18 samples delay */
@ -302,11 +305,13 @@ int main(int argc, char *argv[])
in = (short*)malloc(frame_size*channels*sizeof(short)); in = (short*)malloc(frame_size*channels*sizeof(short));
out = (short*)malloc(frame_size*channels*sizeof(short)); out = (short*)malloc(frame_size*channels*sizeof(short));
data = (unsigned char*)calloc(max_payload_bytes,sizeof(char)); data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
if( use_inbandfec ) {
data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
}
while (!stop) while (!stop)
{ {
int write_samples;
int lost;
err = fread(in, sizeof(short), frame_size*channels, fin); err = fread(in, sizeof(short), frame_size*channels, fin);
tot_read += err; tot_read += err;
if (err < frame_size*channels) if (err < frame_size*channels)
@ -315,51 +320,75 @@ int main(int argc, char *argv[])
for (i=err;i<frame_size*channels;i++) for (i=err;i<frame_size*channels;i++)
in[i] = 0; in[i] = 0;
} }
len = opus_encode(enc, in, frame_size, data, max_payload_bytes);
if (len <= 0) len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
#if OPUS_TEST_RANGE_CODER_STATE
enc_final_range[toggle] = opus_encoder_get_final_range( enc );
#endif
if (len[toggle] <= 0)
{ {
fprintf (stderr, "opus_encode() returned %d\n", len); fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
return 1; return 1;
} }
lost = rand()%100<packet_loss_perc; lost = rand()%100<packet_loss_perc;
opus_decode(dec, lost ? NULL : data, len, out, frame_size); if( count >= use_inbandfec ) {
count++; /* delay by one packet when using in-band FEC */
tot_written += (frame_size-skip)*channels; if( use_inbandfec ) {
write_samples = frame_size; if( lost_prev ) {
if (tot_written > tot_read && skip==0) /* attempt to decode with in-band FEC from next packet */
{ opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 1);
write_samples -= (tot_written-tot_read)/channels; } else {
stop = 1; /* regular decode */
opus_decode(dec, data[1-toggle], len[1-toggle], out, frame_size, 0);
}
} else {
opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, frame_size, 0);
}
write_samples = frame_size-skip;
tot_written += write_samples*channels;
if (tot_written > tot_read)
{
write_samples -= (tot_written-tot_read)/channels;
stop = 1;
}
fwrite(out+skip, sizeof(short), write_samples*channels, fout);
skip = 0;
} }
fwrite(out+skip, sizeof(short), (write_samples-skip)*channels, fout);
skip = 0;
#if OPUS_TEST_RANGE_CODER_STATE #if OPUS_TEST_RANGE_CODER_STATE
/* compare final range encoder rng values of encoder and decoder */ /* compare final range encoder rng values of encoder and decoder */
if( !lost && opus_decoder_get_final_range( dec ) != opus_encoder_get_final_range( enc ) ) { if( !lost && !lost_prev && opus_decoder_get_final_range( dec ) != enc_final_range[toggle^use_inbandfec] ) {
fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder.\n"); fprintf (stderr, "Error: Range coder state mismatch between encoder and decoder.\n");
return 0; return 0;
} }
#endif #endif
lost_prev = lost;
/* count bits */ /* count bits */
bits += len*8; bits += len[toggle]*8;
nrg = 0.0; if( count >= use_inbandfec ) {
for ( k = 0; k < frame_size * channels; k++ ) { nrg = 0.0;
nrg += out[ k ] * (double)out[ k ]; for ( k = 0; k < frame_size * channels; k++ ) {
nrg += in[ k ] * (double)in[ k ];
}
if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
bits_act += len[toggle]*8;
count_act++;
}
/* Variance */
bits2 += len[toggle]*len[toggle]*64;
} }
if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) { count++;
bits_act += len*8; toggle = (toggle + use_inbandfec) & 1;
count_act++;
}
/* Variance */
bits2 += len*len*64;
} }
fprintf (stderr, "average bitrate: %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count)); fprintf (stderr, "average bitrate: %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
fprintf (stderr, "active bitrate: %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act)); fprintf (stderr, "active bitrate: %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
fprintf (stderr, "bitrate standard deviation: %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size); fprintf (stderr, "bitrate standard deviation: %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
DEBUG_STORE_CLOSE_FILES /* Close any files to which intermediate results were stored */ /* Close any files to which intermediate results were stored */
DEBUG_STORE_CLOSE_FILES
SKP_TimerSave("opus_timing.txt");
opus_encoder_destroy(enc); opus_encoder_destroy(enc);
opus_decoder_destroy(dec); opus_decoder_destroy(dec);
fclose(fin); fclose(fin);