shithub: opus

Download patch

ref: 2b011b64d8ca5f3f7b26806aeb77939ff7703c06
parent: 099fc05ebf443e2bcc8c5ab9c627c86ec1e743e0
author: Jean-Marc Valin <[email protected]>
date: Tue Jun 21 08:38:25 EDT 2016

Moving FEC decision to the Opus encoder level (from SILK level)

--- a/silk/control.h
+++ b/silk/control.h
@@ -77,6 +77,9 @@
     /* I:   Flag to enable in-band Forward Error Correction (FEC); 0/1                      */
     opus_int useInBandFEC;
 
+    /* I:   Flag to actually code in-band Forward Error Correction (FEC) in the current packet; 0/1 */
+    opus_int LBRR_coded;
+
     /* I:   Flag to enable discontinuous transmission (DTX); 0/1                            */
     opus_int useDTX;
 
--- a/silk/control_codec.c
+++ b/silk/control_codec.c
@@ -57,7 +57,7 @@
 
 static OPUS_INLINE opus_int silk_setup_LBRR(
     silk_encoder_state              *psEncC,            /* I/O                      */
-    const opus_int32                TargetRate_bps      /* I                        */
+    const silk_EncControlStruct     *encControl         /* I                        */
 );
 
 
@@ -65,7 +65,6 @@
 opus_int silk_control_encoder(
     silk_encoder_state_Fxx          *psEnc,                                 /* I/O  Pointer to Silk encoder state                                               */
     silk_EncControlStruct           *encControl,                            /* I    Control structure                                                           */
-    const opus_int32                TargetRate_bps,                         /* I    Target max bitrate (bps)                                                    */
     const opus_int                  allow_bw_switch,                        /* I    Flag to allow switching audio bandwidth                                     */
     const opus_int                  channelNb,                              /* I    Channel number                                                              */
     const opus_int                  force_fs_kHz
@@ -125,7 +124,7 @@
     /********************************************/
     /* Set LBRR usage                           */
     /********************************************/
-    ret += silk_setup_LBRR( &psEnc->sCmn, TargetRate_bps );
+    ret += silk_setup_LBRR( &psEnc->sCmn, encControl );
 
     psEnc->sCmn.controlled_since_last_payload = 1;
 
@@ -403,33 +402,20 @@
 
 static OPUS_INLINE opus_int silk_setup_LBRR(
     silk_encoder_state          *psEncC,            /* I/O                      */
-    const opus_int32            TargetRate_bps      /* I                        */
+    const silk_EncControlStruct *encControl         /* I                        */
 )
 {
     opus_int   LBRR_in_previous_packet, ret = SILK_NO_ERROR;
-    opus_int32 LBRR_rate_thres_bps;
 
     LBRR_in_previous_packet = psEncC->LBRR_enabled;
-    psEncC->LBRR_enabled = 0;
-    if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) {
-        if( psEncC->fs_kHz == 8 ) {
-            LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS;
-        } else if( psEncC->fs_kHz == 12 ) {
-            LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS;
+    psEncC->LBRR_enabled = encControl->LBRR_coded;
+    if( psEncC->LBRR_enabled ) {
+        /* Set gain increase for coding LBRR excitation */
+        if( LBRR_in_previous_packet == 0 ) {
+            /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */
+            psEncC->LBRR_GainIncreases = 7;
         } else {
-            LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS;
-        }
-        LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) );
-
-        if( TargetRate_bps > LBRR_rate_thres_bps ) {
-            /* Set gain increase for coding LBRR excitation */
-            if( LBRR_in_previous_packet == 0 ) {
-                /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */
-                psEncC->LBRR_GainIncreases = 7;
-            } else {
-                psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 );
-            }
-            psEncC->LBRR_enabled = 1;
+            psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 );
         }
     }
 
--- a/silk/enc_API.c
+++ b/silk/enc_API.c
@@ -237,7 +237,7 @@
     for( n = 0; n < encControl->nChannelsInternal; n++ ) {
         /* Force the side channel to the same rate as the mid */
         opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0;
-        if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, TargetRate_bps, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) {
+        if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) {
             silk_assert( 0 );
             RESTORE_STACK;
             return ret;
--- a/silk/fixed/main_FIX.h
+++ b/silk/fixed/main_FIX.h
@@ -81,7 +81,6 @@
 opus_int silk_control_encoder(
     silk_encoder_state_Fxx          *psEnc,                                 /* I/O  Pointer to Silk encoder state                                               */
     silk_EncControlStruct           *encControl,                            /* I    Control structure                                                           */
-    const opus_int32                TargetRate_bps,                         /* I    Target max bitrate (bps)                                                    */
     const opus_int                  allow_bw_switch,                        /* I    Flag to allow switching audio bandwidth                                     */
     const opus_int                  channelNb,                              /* I    Channel number                                                              */
     const opus_int                  force_fs_kHz
--- a/silk/float/main_FLP.h
+++ b/silk/float/main_FLP.h
@@ -79,7 +79,6 @@
 opus_int silk_control_encoder(
     silk_encoder_state_FLP          *psEnc,                             /* I/O  Pointer to Silk encoder state FLP           */
     silk_EncControlStruct           *encControl,                        /* I    Control structure                           */
-    const opus_int32                TargetRate_bps,                     /* I    Target max bitrate (bps)                    */
     const opus_int                  allow_bw_switch,                    /* I    Flag to allow switching audio bandwidth     */
     const opus_int                  channelNb,                          /* I    Channel number                              */
     const opus_int                  force_fs_kHz
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -156,6 +156,14 @@
       {  36000,      16000}, /* stereo */
 };
 
+static const opus_int32 fec_thresholds[] = {
+        12000, 1000, /* NB */
+        14000, 1000, /* MB */
+        16000, 1000, /* WB */
+        20000, 1000, /* SWB */
+        22000, 1000, /* FB */
+};
+
 int opus_encoder_get_size(int channels)
 {
     int silkEncSizeBytes, celtEncSizeBytes;
@@ -943,6 +951,39 @@
    return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower)));
 }
 
+static int decide_fec(int useInBandFEC, int PacketLoss_perc, int last_fec, int mode, int *bandwidth, opus_int32 rate)
+{
+   int orig_bandwidth;
+   if (!useInBandFEC || PacketLoss_perc == 0 || mode == MODE_CELT_ONLY)
+      return 0;
+   orig_bandwidth = *bandwidth;
+   for (;;)
+   {
+      opus_int32 hysteresis;
+      opus_int32 LBRR_rate_thres_bps;
+      /* Compute threshold for using FEC at the current bandwidth setting */
+      LBRR_rate_thres_bps = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND)];
+      hysteresis = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND) + 1];
+      if (last_fec == 1) LBRR_rate_thres_bps -= hysteresis;
+      if (last_fec == 0) LBRR_rate_thres_bps += hysteresis;
+      LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps,
+            125 - silk_min( PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) );
+      /* If loss <= 5%, we look at whether we have enough rate to enable FEC.
+         If loss > 5%, we decrease the bandwidth until we can enable FEC. */
+      if (rate > LBRR_rate_thres_bps)
+         return 1;
+      else if (PacketLoss_perc <= 5)
+         return 0;
+      else if (*bandwidth > OPUS_BANDWIDTH_NARROWBAND)
+         (*bandwidth)--;
+      else
+         break;
+   }
+   /* Couldn't find any bandwidth to enable FEC, keep original bandwidth. */
+   *bandwidth = orig_bandwidth;
+   return 0;
+}
+
 static int compute_silk_rate_for_hybrid(int rate, int bandwidth, int frame20ms, int vbr) {
    int entry;
    int i;
@@ -1543,6 +1584,8 @@
        st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth);
     }
 #endif
+    st->silk_mode.LBRR_coded = decide_fec(st->silk_mode.useInBandFEC, st->silk_mode.packetLossPercentage,
+          st->silk_mode.LBRR_coded, st->mode, &st->bandwidth, equiv_rate);
     celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth));
 
     /* CELT mode doesn't support mediumband, use wideband instead */