Reduces rate/max rate to make room for redundancy
authorJean-Marc Valin <jmvalin@jmvalin.ca>
Fri, 21 Sep 2012 02:00:22 +0000 (22:00 -0400)
committerJean-Marc Valin <jmvalin@jmvalin.ca>
Fri, 21 Sep 2012 02:04:37 +0000 (22:04 -0400)
This fixes a problem where we could end up starving the redundancy
frame, especially for CBR. The solution is to make sure that some
bits are left available -- assuming we use the same rate for redundancy
as for the rest of the frame.

silk/control_audio_bandwidth.c
src/opus_encoder.c

index a9af913..b645dd5 100644 (file)
@@ -80,6 +80,8 @@ opus_int silk_control_audio_bandwidth(
                 } else {
                    if( psEncC->sLP.transition_frame_no <= 0 ) {
                        encControl->switchReady = 1;
+                       /* Make room for redundancy */
+                       encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
                    } else {
                        /* Direction: down (at double speed) */
                        psEncC->sLP.mode = -2;
@@ -106,6 +108,8 @@ opus_int silk_control_audio_bandwidth(
                 } else {
                    if( psEncC->sLP.mode == 0 ) {
                        encControl->switchReady = 1;
+                       /* Make room for redundancy */
+                       encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
                    } else {
                        /* Direction: up */
                        psEncC->sLP.mode = 1;
index ea6bfa3..aae3125 100644 (file)
@@ -458,20 +458,20 @@ opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_s
     int prefill=0;
     int start_band = 0;
     int redundancy = 0;
-    int redundancy_bytes = 0;
+    int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */
     int celt_to_silk = 0;
     VARDECL(opus_val16, pcm_buf);
     int nb_compr_bytes;
     int to_celt = 0;
     opus_uint32 redundant_rng = 0;
     int cutoff_Hz, hp_freq_smth1;
-    int voice_est;
+    int voice_est; /* Probability of voice in Q7 */
     opus_int32 equiv_rate;
     int delay_compensation;
     int frame_rate;
-    opus_int32 max_rate;
+    opus_int32 max_rate; /* Max bitrate we're allowed to use */
     int curr_bandwidth;
-    opus_int32 max_data_bytes;
+    opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */
     VARDECL(opus_val16, tmp_prefill);
 
     ALLOC_STACK;
@@ -652,6 +652,7 @@ opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_s
             }
         }
     }
+    /* For the first frame at a new SILK bandwidth */
     if (st->silk_bw_switch)
     {
        redundancy = 1;
@@ -659,6 +660,15 @@ opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_s
        st->silk_bw_switch = 0;
     }
 
+    if (redundancy)
+    {
+       /* Fair share of the max size allowed */
+       redundancy_bytes = IMIN(257, max_data_bytes*(opus_int32)(st->Fs/200)/(frame_size+st->Fs/200));
+       /* For VBR, target the actual bitrate (subject to the limit above) */
+       if (st->use_vbr)
+          redundancy_bytes = IMIN(redundancy_bytes, st->bitrate_bps/1600);
+    }
+
     if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY)
     {
         silk_EncControlStruct dummy;
@@ -823,7 +833,7 @@ opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_s
         st->mode = MODE_SILK_ONLY;
 
     /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */
-    bytes_target = IMIN(max_data_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1;
+    bytes_target = IMIN(max_data_bytes-redundancy_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1;
 
     data += 1;
 
@@ -929,7 +939,7 @@ opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_s
         st->silk_mode.useCBR = !st->use_vbr;
 
         /* Call SILK encoder for the low band */
-        nBytes = IMIN(1275, max_data_bytes-1);
+        nBytes = IMIN(1275, max_data_bytes-1-redundancy_bytes);
 
         st->silk_mode.maxBits = nBytes*8;
         /* Only allow up to 90% of the bits for hybrid mode*/
@@ -941,8 +951,6 @@ opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_s
            /* Reduce the initial target to make it easier to reach the CBR rate */
            st->silk_mode.bitRate = IMAX(1, st->silk_mode.bitRate-2000);
         }
-        if (redundancy)
-           st->silk_mode.maxBits -= st->silk_mode.maxBits/(1 + frame_size/(st->Fs/200));
 
         if (prefill)
         {
@@ -990,6 +998,7 @@ opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_s
         }
 
         st->silk_mode.opusCanSwitch = st->silk_mode.switchReady;
+        /* FIXME: How do we allocate the redundancy for CBR? */
         if (st->silk_mode.opusCanSwitch)
         {
            redundancy = 1;
@@ -1047,7 +1056,7 @@ opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_s
                 celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1));
                 celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint));
                 celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps));
-                nb_compr_bytes = max_data_bytes-1;
+                nb_compr_bytes = max_data_bytes-1-redundancy_bytes;
             } else {
                 nb_compr_bytes = bytes_target;
             }
@@ -1119,8 +1128,10 @@ opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_s
     }
 
     if (!redundancy)
+    {
        st->silk_bw_switch = 0;
-
+       redundancy_bytes = 0;
+    }
     if (st->mode != MODE_CELT_ONLY)start_band=17;
 
     if (st->mode == MODE_SILK_ONLY)