shithub: opus

Download patch

ref: 8bbfb2ec479624f80c60a3fc1b0180f0bf36a922
parent: 6b124314887b7b02d2f128ce4126ee0dc29da25d
author: Jean-Marc Valin <jmvalin@amazon.com>
date: Tue Dec 20 22:30:31 EST 2022

Controlling DRED on the encode side

--- a/include/opus_defines.h
+++ b/include/opus_defines.h
@@ -169,6 +169,8 @@
 #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
@@ -619,6 +621,14 @@
   * </dl>
   * @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)
+
 
 /**@}*/
 
--- a/silk/dred_encoder.c
+++ b/silk/dred_encoder.c
@@ -74,7 +74,7 @@
     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 @@
     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;
--- a/silk/dred_encoder.h
+++ b/silk/dred_encoder.h
@@ -51,6 +51,6 @@
 
 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
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -658,6 +658,7 @@
    /* 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 @@
 
       }
    }
+#endif
    if (len==0 || data==NULL)
    {
       int pcm_count=0;
--- a/src/opus_demo.c
+++ b/src/opus_demo.c
@@ -64,6 +64,7 @@
     fprintf(stderr, "-dtx                 : enable SILK DTX\n" );
     fprintf(stderr, "-loss <perc>         : optimize for loss percentage and simulate packet loss, in percent (0-100); default: 0\n" );
     fprintf(stderr, "-lossfile <file>     : simulate packet loss, reading loss from file\n" );
+    fprintf(stderr, "-dred <frames>       : 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 ret = EXIT_FAILURE;
     int lost_count=0;
     FILE *packet_loss_file=NULL;
+    int dred_duration=0;
 
     if (argc < 5 )
     {
@@ -431,6 +433,9 @@
                 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 @@
        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)
     {
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -116,6 +116,9 @@
     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 @@
     /* 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 @@
             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;
--