shithub: opus

Download patch

ref: 9f36bfc9623d0af495913b073a0b5e9e627e3086
parent: 9b1da1fb1f07265dda3621b30ea989911dd4f0bf
author: Jean-Marc Valin <jmvalin@jmvalin.ca>
date: Fri Feb 2 11:55:21 EST 2024

Chopping the oldest silence in a DRED payload

--- a/silk/dred_encoder.c
+++ b/silk/dred_encoder.c
@@ -249,7 +249,15 @@
     }
 }
 
-int dred_encode_silk_frame(const DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes, int q0, int dQ, int arch) {
+static int dred_voice_active(const unsigned char *activity_mem, int offset) {
+    int i;
+    for (i=0;i<16;i++) {
+        if (activity_mem[8*offset + i] == 1) return 1;
+    }
+    return 0;
+}
+
+int dred_encode_silk_frame(const DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes, int q0, int dQ, unsigned char *activity_mem, int arch) {
     ec_enc ec_encoder;
 
     int q_level;
@@ -257,6 +265,9 @@
     int offset;
     int ec_buffer_fill;
     int state_qoffset;
+    ec_enc ec_bak;
+    int prev_active=0;
+    int dred_encoded=0;
 
     /* entropy coding of state and latents */
     ec_enc_init(&ec_encoder, buf, max_bytes);
@@ -276,11 +287,10 @@
     if (ec_tell(&ec_encoder) > 8*max_bytes) {
       return 0;
     }
+    ec_bak = ec_encoder;
     for (i = 0; i < IMIN(2*max_chunks, enc->latents_buffer_fill-enc->latent_offset-1); i += 2)
     {
-        ec_enc ec_bak;
-        ec_bak = ec_encoder;
-
+        int active;
         q_level = compute_quantizer(q0, dQ, i/2);
         offset = q_level * DRED_LATENT_DIM;
 
@@ -295,12 +305,21 @@
             arch
         );
         if (ec_tell(&ec_encoder) > 8*max_bytes) {
-          ec_encoder = ec_bak;
           /* If we haven't been able to code one chunk, give up on DRED completely. */
           if (i==0) return 0;
           break;
         }
+        active = dred_voice_active(activity_mem, i+enc->latent_offset);
+        if (active || prev_active) {
+           ec_bak = ec_encoder;
+           dred_encoded = i+2;
+        }
+        prev_active = active;
     }
+    /* Avoid sending empty DRED packets. */
+    if (dred_encoded==0) return 0;
+
+    ec_encoder = ec_bak;
 
     ec_buffer_fill = (ec_tell(&ec_encoder)+7)/8;
     ec_enc_shrink(&ec_encoder, ec_buffer_fill);
--- a/silk/dred_encoder.h
+++ b/silk/dred_encoder.h
@@ -66,6 +66,6 @@
 
 void dred_compute_latents(DREDEnc *enc, const float *pcm, int frame_size, int extra_delay, int arch);
 
-int dred_encode_silk_frame(const DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes, int q0, int dQ, int arch);
+int dred_encode_silk_frame(const DREDEnc *enc, unsigned char *buf, int max_chunks, int max_bytes, int q0, int dQ, unsigned char *activity_mem, int arch);
 
 #endif
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -132,6 +132,7 @@
     int          dred_q0;
     int          dred_dQ;
     int          dred_target_chunks;
+    unsigned char activity_mem[DRED_MAX_FRAMES*4]; /* 2.5ms resolution*/
 #endif
     int          nonfinal_frame; /* current frame is not the final in a packet */
     opus_uint32  rangeFinal;
@@ -1841,10 +1842,16 @@
 
 #ifdef ENABLE_DRED
     if ( st->dred_duration > 0 && st->dred_encoder.loaded ) {
+        int frame_size_400Hz;
         /* DRED Encoder */
         dred_compute_latents( &st->dred_encoder, &pcm_buf[total_buffer*st->channels], frame_size, total_buffer, st->arch );
+        frame_size_400Hz = frame_size*400/st->Fs;
+        OPUS_MOVE(&st->activity_mem[frame_size_400Hz], st->activity_mem, 4*DRED_MAX_FRAMES-frame_size_400Hz);
+        for (i=0;i<frame_size_400Hz;i++)
+           st->activity_mem[i] = activity;
     } else {
         st->dred_encoder.latents_buffer_fill = 0;
+        OPUS_CLEAR(st->activity_mem, DRED_MAX_FRAMES);
     }
 #endif
 
@@ -2410,7 +2417,8 @@
            buf[0] = 'D';
            buf[1] = DRED_EXPERIMENTAL_VERSION;
 #endif
-           dred_bytes = dred_encode_silk_frame(&st->dred_encoder, buf+DRED_EXPERIMENTAL_BYTES, dred_chunks, dred_bytes_left-DRED_EXPERIMENTAL_BYTES, st->dred_q0, st->dred_dQ, st->arch);
+           dred_bytes = dred_encode_silk_frame(&st->dred_encoder, buf+DRED_EXPERIMENTAL_BYTES, dred_chunks, dred_bytes_left-DRED_EXPERIMENTAL_BYTES,
+                                               st->dred_q0, st->dred_dQ, st->activity_mem, st->arch);
            if (dred_bytes > 0) {
               dred_bytes += DRED_EXPERIMENTAL_BYTES;
               celt_assert(dred_bytes <= dred_bytes_left);
--