From d186c913f76aaf99ef045e7eef860d8ba79d3cf5 Mon Sep 17 00:00:00 2001 From: Jean-Marc Valin <jmvalin@jmvalin.ca> Date: Thu, 8 Sep 2011 15:13:46 -0400 Subject: [PATCH] Adds OPUS_SET_RESTRICTED_LOWDELAY() encoder ctl Right now it will uncleanly switch to SILK if asked for 40 or 60 ms frames --- libcelt/opus_defines.h | 26 +++++++++++++++------ src/opus_encoder.c | 53 ++++++++++++++++++++++++++++++++---------- src/test_opus.c | 10 ++++---- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/libcelt/opus_defines.h b/libcelt/opus_defines.h index ac1c46626..4445be7b7 100644 --- a/libcelt/opus_defines.h +++ b/libcelt/opus_defines.h @@ -103,6 +103,8 @@ extern "C" { #define OPUS_SET_DTX_REQUEST 4016 #define OPUS_GET_DTX_REQUEST 4017 #define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_SET_RESTRICTED_LOWDELAY_REQUEST 4032 +#define OPUS_GET_RESTRICTED_LOWDELAY_REQUEST 4033 /* Macros to trigger compilation errors when the wrong types are provided to a CTL */ #define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) @@ -117,14 +119,11 @@ extern "C" { /** \cond DOXYGEN_EXCLUDE */ /* Values for the varrious encoder CTLs */ #define OPUS_AUTO -1000 /**<Auto bitrate @hideinitializer*/ -//#define OPUS_BITRATE_AUTO -2 /**<Auto bitrate @hideinitializer*/ #define OPUS_BITRATE_MAX -1 /**<Maximum bitrate @hideinitializer*/ #define OPUS_APPLICATION_VOIP 2000 #define OPUS_APPLICATION_AUDIO 2001 -//#define OPUS_SIGNAL_AUTO 3000 #define OPUS_SIGNAL_VOICE 3001 #define OPUS_SIGNAL_MUSIC 3002 -//#define OPUS_BANDWIDTH_AUTO 1100 /**<Automatic bandpass @hideinitializer*/ #define OPUS_BANDWIDTH_NARROWBAND 1101 /**< 4kHz bandpass @hideinitializer*/ #define OPUS_BANDWIDTH_MEDIUMBAND 1102 /**< 6kHz bandpass @hideinitializer*/ #define OPUS_BANDWIDTH_WIDEBAND 1103 /**< 8kHz bandpass @hideinitializer*/ @@ -190,14 +189,14 @@ extern "C" { * @hideinitializer */ #define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x) -/** Configures mono forcing in the encoder. +/** Configures mono/stereo forcing in the encoder. * This is useful when the caller knows that the input signal is currently a mono * source embedded in a stereo stream. - * \param[in] x <tt>int</tt>: 0 (default); 1 (forced mono) + * \param[in] x <tt>int</tt>: OPUS_AUTO (default); 1 (forced mono); 2 (forced stereo) * @hideinitializer */ #define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x) -/** Gets the encoder's forced mono configuration, @see [OPUS_SET_FORCE_MONO] - * \param[out] x <tt>int*</tt>: 0; 1 +/** Gets the encoder's forced channel configuration, @see [OPUS_SET_FORCE_CHANNELS] + * \param[out] x <tt>int*</tt>: OPUS_AUTO; 0; 1 * @hideinitializer */ #define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x) @@ -337,6 +336,19 @@ extern "C" { * * @hideinitializer */ #define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x) + +/** Configures low-delay mode that disables the speech-optimized mode in exchange for slightly reduced delay. + * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution). + * The setting can only be changed right after initialization or after a reset. + * \param[in] x <tt>int</tt>: 0 (default); 1 (lowdelay) + * @hideinitializer */ +#define OPUS_SET_RESTRICTED_LOWDELAY(x) OPUS_SET_RESTRICTED_LOWDELAY_REQUEST, __opus_check_int(x) +/** Gets the encoder's forced channel configuration, @see [OPUS_SET_RESTRICTED_LOWDELAY] + * \param[out] x <tt>int*</tt>: 0; 1 + * @hideinitializer */ +#define OPUS_GET_RESTRICTED_LOWDELAY(x) OPUS_GET_RESTRICTED_LOWDELAY_REQUEST, __opus_check_int_ptr(x) + + /**@}*/ /** \defgroup libinfo Opus library information functions diff --git a/src/opus_encoder.c b/src/opus_encoder.c index e5a94754d..7987e31da 100644 --- a/src/opus_encoder.c +++ b/src/opus_encoder.c @@ -67,6 +67,7 @@ struct OpusEncoder { int vbr_constraint; int bitrate_bps; int user_bitrate_bps; + int lowdelay; int encoder_buffer; #define OPUS_ENCODER_RESET_START stream_channels @@ -374,6 +375,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, int cutoff_Hz, hp_freq_smth1; int voice_est; opus_int32 equiv_rate; + int delay_compensation; ALLOC_STACK; st->rangeFinal = 0; @@ -386,6 +388,11 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, silk_enc = (char*)st+st->silk_enc_offset; celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + if (st->lowdelay) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + if (st->user_bitrate_bps==OPUS_AUTO) st->bitrate_bps = 60*st->Fs/frame_size + st->Fs*st->channels; else if (st->user_bitrate_bps==OPUS_BITRATE_MAX) @@ -446,7 +453,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, } #else /* Mode selection depending on application and signal type */ - if (st->user_forced_mode == OPUS_AUTO) + if (st->lowdelay) + { + st->mode = MODE_CELT_ONLY; + } else if (st->user_forced_mode == OPUS_AUTO) { int chan; opus_int32 mode_voice, mode_music; @@ -578,9 +588,9 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, ec_enc_init(&enc, data, max_data_bytes-1); - ALLOC(pcm_buf, (st->delay_compensation+frame_size)*st->channels, opus_val16); - for (i=0;i<st->delay_compensation*st->channels;i++) - pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-st->delay_compensation)*st->channels+i]; + ALLOC(pcm_buf, (delay_compensation+frame_size)*st->channels, opus_val16); + for (i=0;i<delay_compensation*st->channels;i++) + pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-delay_compensation)*st->channels+i]; if (st->mode == MODE_CELT_ONLY) hp_freq_smth1 = SKP_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); @@ -595,10 +605,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, if (st->application == OPUS_APPLICATION_VOIP) { - hp_cutoff(pcm, cutoff_Hz, &pcm_buf[st->delay_compensation*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); + hp_cutoff(pcm, cutoff_Hz, &pcm_buf[delay_compensation*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); } else { for (i=0;i<frame_size*st->channels;i++) - pcm_buf[st->delay_compensation*st->channels + i] = pcm[i]; + pcm_buf[delay_compensation*st->channels + i] = pcm[i]; } /* SILK processing */ @@ -671,10 +681,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, } #ifdef FIXED_POINT - pcm_silk = pcm_buf+st->delay_compensation*st->channels; + pcm_silk = pcm_buf+delay_compensation*st->channels; #else for (i=0;i<frame_size*st->channels;i++) - pcm_silk[i] = FLOAT2INT16(pcm_buf[st->delay_compensation*st->channels + i]); + pcm_silk[i] = FLOAT2INT16(pcm_buf[delay_compensation*st->channels + i]); #endif ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 ); if( ret ) { @@ -736,7 +746,7 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); /* TODO: This wastes CPU a bit compared to just prefilling the buffer */ - celt_encode_with_ec(celt_enc, &st->delay_buffer[(st->encoder_buffer-st->delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10, NULL); + celt_encode_with_ec(celt_enc, &st->delay_buffer[(st->encoder_buffer-delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10, NULL); } else { celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(2)); } @@ -768,10 +778,10 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, nb_compr_bytes = 0; } - for (i=0;i<st->channels*(st->encoder_buffer-(frame_size+st->delay_compensation));i++) + for (i=0;i<st->channels*(st->encoder_buffer-(frame_size+delay_compensation));i++) st->delay_buffer[i] = st->delay_buffer[i+st->channels*frame_size]; for (;i<st->encoder_buffer*st->channels;i++) - st->delay_buffer[i] = pcm_buf[(frame_size+st->delay_compensation-st->encoder_buffer)*st->channels+i]; + st->delay_buffer[i] = pcm_buf[(frame_size+delay_compensation-st->encoder_buffer)*st->channels+i]; if( st->mode == MODE_HYBRID && st->stream_channels == 2 ) { @@ -1117,7 +1127,9 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) case OPUS_GET_LOOKAHEAD_REQUEST: { opus_int32 *value = va_arg(ap, opus_int32*); - *value = st->delay_compensation+st->Fs/400; + *value = st->Fs/400; + if (!st->lowdelay) + *value += st->delay_compensation; } break; case OPUS_GET_FINAL_RANGE_REQUEST: @@ -1154,6 +1166,23 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) st->user_forced_mode = value; } break; + case OPUS_SET_RESTRICTED_LOWDELAY_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (!st->first && st->lowdelay != !!value) + { + ret = OPUS_BAD_ARG; + break; + } + st->lowdelay = !!value; + } + break; + case OPUS_GET_RESTRICTED_LOWDELAY_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->lowdelay; + } + break; default: /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/ ret = OPUS_UNIMPLEMENTED; diff --git a/src/test_opus.c b/src/test_opus.c index cd5975824..be208cc65 100644 --- a/src/test_opus.c +++ b/src/test_opus.c @@ -118,6 +118,7 @@ int main(int argc, char *argv[]) int max_frame_size = 960*6; int curr_read=0; int sweep_bps = 0; + int lowdelay = 0; if (argc < 7 ) { @@ -216,6 +217,9 @@ int main(int argc, char *argv[]) } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-forcemono" ) == 0 ) { forcechannels = 1; args++; + } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-lowdelay" ) == 0 ) { + lowdelay = 1; + args++; } else if( STR_CASEINSENSITIVE_COMPARE( argv[ args ], "-cvbr" ) == 0 ) { cvbr = 1; args++; @@ -295,11 +299,9 @@ int main(int argc, char *argv[]) opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(forcechannels)); opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx)); opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc)); + opus_encoder_ctl(enc, OPUS_SET_RESTRICTED_LOWDELAY(lowdelay)); - skip = 5*sampling_rate/1000; - /* When SILK resamples, add 18 samples delay */ - /*if (mode != MODE_SILK_ONLY || sampling_rate > 16000) - skip += 18;*/ + opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip)); switch(bandwidth) { -- GitLab