From 87f8270f7959535c4fb2a2d9c8c6842466e49785 Mon Sep 17 00:00:00 2001 From: Jean-Marc Valin Date: Wed, 21 Dec 2022 03:30:31 -0500 Subject: Controlling DRED on the encode side --- include/opus_defines.h | 10 ++++++++++ silk/dred_encoder.c | 4 ++-- silk/dred_encoder.h | 2 +- src/opus_decoder.c | 2 ++ src/opus_demo.c | 9 +++++++++ src/opus_encoder.c | 31 +++++++++++++++++++++++++++++-- 6 files changed, 53 insertions(+), 5 deletions(-) diff --git a/include/opus_defines.h b/include/opus_defines.h index 94b9e0d9..3ca90188 100644 --- a/include/opus_defines.h +++ b/include/opus_defines.h @@ -169,6 +169,8 @@ extern "C" { #define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046 #define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047 #define OPUS_GET_IN_DTX_REQUEST 4049 +#define OPUS_SET_DRED_DURATION_REQUEST 4050 +#define OPUS_GET_DRED_DURATION_REQUEST 4051 /** Defines for the presence of extended APIs. */ #define OPUS_HAVE_OPUS_PROJECTION_H @@ -620,6 +622,14 @@ extern "C" { * @hideinitializer */ #define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x) +/** If non-zero, enables Deep Redundancy (DRED) and use the specified maximum number of 10-ms redundant frames + * @hideinitializer */ +#define OPUS_SET_DRED_DURATION(x) OPUS_SET_DRED_DURATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured Deep Redundancy (DRED) maximum number of frames. + * @hideinitializer */ +#define OPUS_GET_DRED_DURATION(x) OPUS_GET_DRED_DURATION_REQUEST, __opus_check_int_ptr(x) + + /**@}*/ /** @defgroup opus_genericctls Generic CTLs diff --git a/silk/dred_encoder.c b/silk/dred_encoder.c index 9e9077f8..5ab56ed1 100644 --- a/silk/dred_encoder.c +++ b/silk/dred_encoder.c @@ -74,7 +74,7 @@ void dred_process_silk_frame(DREDEnc *enc, const opus_int16 *silk_frame) enc->latents_buffer_fill = IMIN(enc->latents_buffer_fill+1, DRED_NUM_REDUNDANCY_FRAMES); } -int dred_encode_silk_frame(DREDEnc *enc, unsigned char *buf, int max_frames, int max_bytes) { +int dred_encode_silk_frame(DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes) { const opus_uint16 *dead_zone = DRED_rdovae_get_dead_zone_pointer(); const opus_uint16 *p0 = DRED_rdovae_get_p0_pointer(); const opus_uint16 *quant_scales = DRED_rdovae_get_quant_scales_pointer(); @@ -90,7 +90,7 @@ int dred_encode_silk_frame(DREDEnc *enc, unsigned char *buf, int max_frames, int ec_enc_init(&ec_encoder, buf, max_bytes); dred_encode_state(&ec_encoder, enc->state_buffer); - for (i = 0; i < enc->latents_buffer_fill-1; i += 2) + for (i = 0; i < IMIN(2*max_chunks, enc->latents_buffer_fill-1); i += 2) { q_level = (int) floor(0.5f + DRED_ENC_Q0 + 1.f * (DRED_ENC_Q1 - DRED_ENC_Q0) * i / (DRED_NUM_REDUNDANCY_FRAMES - 2)); offset = q_level * DRED_LATENT_DIM; diff --git a/silk/dred_encoder.h b/silk/dred_encoder.h index a32cfa97..662cedd6 100644 --- a/silk/dred_encoder.h +++ b/silk/dred_encoder.h @@ -51,6 +51,6 @@ void dred_deinit_encoder(DREDEnc *enc); void dred_process_silk_frame(DREDEnc *enc, const opus_int16 *silk_frame); -int dred_encode_silk_frame(DREDEnc *enc, unsigned char *buf, int max_frames, int max_bytes); +int dred_encode_silk_frame(DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes); #endif diff --git a/src/opus_decoder.c b/src/opus_decoder.c index 4c238a8a..670a898d 100644 --- a/src/opus_decoder.c +++ b/src/opus_decoder.c @@ -658,6 +658,7 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data, /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) return OPUS_BAD_ARG; +#ifdef ENABLE_NEURAL_FEC if (decode_fec > 0 && st->nb_fec_frames > 0) { int features_per_frame; int needed_feature_frames; @@ -674,6 +675,7 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data, } } +#endif if (len==0 || data==NULL) { int pcm_count=0; diff --git a/src/opus_demo.c b/src/opus_demo.c index 50a66db3..af5e30f3 100644 --- a/src/opus_demo.c +++ b/src/opus_demo.c @@ -64,6 +64,7 @@ void print_usage( char* argv[] ) fprintf(stderr, "-dtx : enable SILK DTX\n" ); fprintf(stderr, "-loss : optimize for loss percentage and simulate packet loss, in percent (0-100); default: 0\n" ); fprintf(stderr, "-lossfile : simulate packet loss, reading loss from file\n" ); + fprintf(stderr, "-dred : add Deep REDundancy (in units of 10-ms frames)\n" ); } static void int_to_char(opus_uint32 i, unsigned char ch[4]) @@ -266,6 +267,7 @@ int main(int argc, char *argv[]) int ret = EXIT_FAILURE; int lost_count=0; FILE *packet_loss_file=NULL; + int dred_duration=0; if (argc < 5 ) { @@ -431,6 +433,9 @@ int main(int argc, char *argv[]) exit(1); } args += 2; + } else if( strcmp( argv[ args ], "-dred" ) == 0 ) { + dred_duration = atoi( argv[ args + 1 ] ); + args += 2; } else if( strcmp( argv[ args ], "-sweep" ) == 0 ) { check_encoder_option(decode_only, "-sweep"); sweep_bps = atoi( argv[ args + 1 ] ); @@ -546,6 +551,10 @@ int main(int argc, char *argv[]) opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip)); opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16)); opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration)); + if (dred_duration > 0) + { + opus_encoder_ctl(enc, OPUS_SET_DRED_DURATION(dred_duration)); + } } if (!encode_only) { diff --git a/src/opus_encoder.c b/src/opus_encoder.c index 47a4d6eb..4d571c28 100644 --- a/src/opus_encoder.c +++ b/src/opus_encoder.c @@ -115,6 +115,9 @@ struct OpusEncoder { int detected_bandwidth; int nb_no_activity_ms_Q1; opus_val32 peak_signal_energy; +#endif +#ifdef ENABLE_NEURAL_FEC + int dred_duration; #endif int nonfinal_frame; /* current frame is not the final in a packet */ opus_uint32 rangeFinal; @@ -2180,13 +2183,15 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ /* Count ToC and redundancy */ ret += 1+redundancy_bytes; #ifdef ENABLE_NEURAL_FEC - if (1) { + if (st->dred_duration > 0) { opus_extension_data extension; unsigned char buf[DRED_MAX_DATA_SIZE]; + int dred_chunks; int dred_bytes; DREDEnc *dred = &((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.dred_encoder; + dred_chunks = IMIN(st->dred_duration/4, DRED_NUM_REDUNDANCY_FRAMES/2); dred_bytes = IMIN(DRED_MAX_DATA_SIZE, max_data_bytes-ret-2); - dred_bytes = dred_encode_silk_frame(dred, buf, DRED_NUM_REDUNDANCY_FRAMES/2, dred_bytes); + dred_bytes = dred_encode_silk_frame(dred, buf, dred_chunks, dred_bytes); extension.id = 127; extension.frame = 0; extension.data = buf; @@ -2698,6 +2703,28 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) celt_encoder_ctl(celt_enc, OPUS_GET_PHASE_INVERSION_DISABLED(value)); } break; +#ifdef ENABLE_NEURAL_FEC + case OPUS_SET_DRED_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>DRED_MAX_FRAMES) + { + goto bad_arg; + } + st->dred_duration = value; + } + break; + case OPUS_GET_DRED_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->dred_duration; + } + break; +#endif case OPUS_RESET_STATE: { void *silk_enc; -- cgit v1.2.1