shithub: opus

Download patch

ref: 43a0de4af15b6cf61938d5c442e3b689773d085b
parent: 3b2aee062d08fc72f12a4379ce2d6e2b444d5021
author: Koen Vos <[email protected]>
date: Mon Oct 24 05:10:58 EDT 2011

Optimization of the CBR loop

Also some comment/warning fixes

--- a/celt/vq.c
+++ b/celt/vq.c
@@ -258,7 +258,7 @@
 #endif
    if (pulsesLeft > N+3)
    {
-      opus_val16 tmp = pulsesLeft;
+      opus_val16 tmp = (opus_val16)pulsesLeft;
       yy = MAC16_16(yy, tmp, tmp);
       yy = MAC16_16(yy, tmp, y[0]);
       iy[0] += pulsesLeft;
--- a/silk/enc_API.c
+++ b/silk/enc_API.c
@@ -214,7 +214,7 @@
 
     TargetRate_bps = silk_RSHIFT32( encControl->bitRate, encControl->nChannelsInternal - 1 );
     for( n = 0; n < encControl->nChannelsInternal; n++ ) {
-        /* JMV: Force the side channel to the same rate as the mid. Is this the right way? */
+        /* 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 ) {
             silk_assert( 0 );
@@ -426,9 +426,6 @@
 
                 /* Handling rate constraints */
                 maxBits = encControl->maxBits;
-                /*if( encControl->useCBR ) {
-                    maxBits = (encControl->bitRate * nBlocksOf10ms / 800) * 8;
-                }*/
                 if( tot_blocks == 2 && curr_block == 0 ) {
                     maxBits = maxBits * 3 / 5;
                 } else if( tot_blocks == 3 ) {
--- a/silk/fixed/encode_frame_FIX.c
+++ b/silk/fixed/encode_frame_FIX.c
@@ -92,6 +92,7 @@
     ec_enc       sRangeEnc_copy, sRangeEnc_copy2;
     silk_nsq_state sNSQ_copy, sNSQ_copy2;
     opus_int32   seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+    opus_int32   gainsID, gainsID_lower, gainsID_upper;
     opus_int16   gainMult_Q8;
     opus_int16   ec_prevLagIndex_copy;
     opus_int     ec_prevSignalType_copy;
@@ -178,60 +179,68 @@
         }
 TOC(NSQ)
     } else {
-        /* Loop over quantizer and entroy coding to control bitrate */
+        /* Loop over quantizer and entropy coding to control bitrate */
         maxIter = 5;
         gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
         found_lower = 0;
         found_upper = 0;
+        gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+        gainsID_lower = -1;
+        gainsID_upper = -1;
+        /* Copy part of the input state */
+        silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
+        silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+        seed_copy = psEnc->sCmn.indices.Seed;
+        ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
+        ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
         for( iter = 0; ; iter++ ) {
-            /* Copy part of the input state */
-            silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
-            silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
-            seed_copy = psEnc->sCmn.indices.Seed;
-            ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
-            ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
-
-            /*****************************************/
-            /* Noise shaping quantization            */
-            /*****************************************/
-TIC(NSQ)
-            if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
-                silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw, psEnc->sCmn.pulses,
-                       sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
-                       sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 );
+            if( gainsID == gainsID_lower ) {
+                nBits = nBits_lower;
+            } else if( gainsID == gainsID_upper ) {
+                nBits = nBits_upper;
             } else {
-                silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw, psEnc->sCmn.pulses,
-                        sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
-                        sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 );
-            }
+                /*****************************************/
+                /* Noise shaping quantization            */
+                /*****************************************/
+TIC(NSQ)
+                if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+                    silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw, psEnc->sCmn.pulses,
+                           sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
+                           sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 );
+                } else {
+                    silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw, psEnc->sCmn.pulses,
+                            sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
+                            sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 );
+                }
 TOC(NSQ)
 
-            /****************************************/
-            /* Encode Parameters                    */
-            /****************************************/
+                /****************************************/
+                /* Encode Parameters                    */
+                /****************************************/
 TIC(ENCODE_PARAMS)
-            silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+                silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
 TOC(ENCODE_PARAMS)
 
-            /****************************************/
-            /* Encode Excitation Signal             */
-            /****************************************/
+                /****************************************/
+                /* Encode Excitation Signal             */
+                /****************************************/
 TIC(ENCODE_PULSES)
-            silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
-                psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+                silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+                    psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
 TOC(ENCODE_PULSES)
 
-            nBits = ec_tell( psRangeEnc );
+                nBits = ec_tell( psRangeEnc );
 
-            if( maxBits == 0 || ( useCBR == 0 && iter == 0 && nBits <= maxBits ) ) {
-                break;
+                if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+                    break;
+                }
             }
 
             if( iter == maxIter ) {
-                if( nBits > maxBits && found_lower ) {
+                if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
                     /* Restore output state from earlier iteration that did meet the bitrate budget */
                     silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
-                    silk_assert( sRangeEnc_copy2.offs<=1275 );
+                    silk_assert( sRangeEnc_copy2.offs <= 1275 );
                     silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
                     silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
                     psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
@@ -243,6 +252,7 @@
                 found_upper = 1;
                 nBits_upper = nBits;
                 gainMult_upper = gainMult_Q8;
+                gainsID_upper = gainsID;
                 if( found_lower == 0 && iter >= 2 ) {
                     /* Adjust the quantizer's rate/distortion tradeoff */
                     sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 );
@@ -251,12 +261,15 @@
                 found_lower = 1;
                 nBits_lower = nBits;
                 gainMult_lower = gainMult_Q8;
-                /* Copy part of the output state */
-                silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
-                silk_assert( psRangeEnc->offs<=1275 );
-                silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
-                silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
-                LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+                if( gainsID != gainsID_lower ) {
+                    gainsID_lower = gainsID;
+                    /* Copy part of the output state */
+                    silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+                    silk_assert( psRangeEnc->offs <= 1275 );
+                    silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
+                    silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+                    LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+                }
             } else {
                 /* Within 5 bits of budget: close enough */
                 break;
@@ -266,6 +279,7 @@
                 /* Adjust gain according to high-rate rate/distortion curve */
                 opus_int32 gain_factor_Q16;
                 gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
+                gain_factor_Q16 = silk_min_32(gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) );
                 if( nBits > maxBits ) {
                     gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) );
                 }
@@ -274,22 +288,25 @@
                 /* Adjust gain by interpolating */
                 gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower );
                 /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
-                if( gainMult_Q8 > gainMult_lower + silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 ) ) {
-                   gainMult_Q8 = gainMult_lower + silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 );
+                if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
+                    gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
                 } else
-                    if( gainMult_Q8 < gainMult_upper - silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 ) ) {
-                        gainMult_Q8 = gainMult_upper - silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 );
-                    }
+                if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
+                    gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
+                }
             }
 
             for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
                 sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 );
             }
+ 
+            /* Quantize gains */
             psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
-
-            /* Noise shaping quantization */
             silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16,
                   &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+            /* Unique identifier of gains vector */
+            gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
 
             /* Restore part of the input state */
             silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
--- a/silk/fixed/process_gains_FIX.c
+++ b/silk/fixed/process_gains_FIX.c
@@ -90,7 +90,7 @@
     silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
     psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
 
-    /* Noise shaping quantization */
+    /* Quantize gains */
     silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16,
         &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
 
--- a/silk/float/encode_frame_FLP.c
+++ b/silk/float/encode_frame_FLP.c
@@ -95,6 +95,7 @@
     ec_enc       sRangeEnc_copy, sRangeEnc_copy2;
     silk_nsq_state sNSQ_copy, sNSQ_copy2;
     opus_int32   seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+    opus_int32   gainsID, gainsID_lower, gainsID_upper;
     opus_int16   gainMult_Q8;
     opus_int16   ec_prevLagIndex_copy;
     opus_int     ec_prevSignalType_copy;
@@ -185,50 +186,58 @@
         gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
         found_lower = 0;
         found_upper = 0;
+        gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+        gainsID_lower = -1;
+        gainsID_upper = -1;
+        /* Copy part of the input state */
+        silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
+        silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+        seed_copy = psEnc->sCmn.indices.Seed;
+        ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
+        ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
         for( iter = 0; ; iter++ ) {
-            /* Copy part of the input state */
-            silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
-            silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
-            seed_copy = psEnc->sCmn.indices.Seed;
-            ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
-            ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
-
-            /*****************************************/
-            /* Noise shaping quantization            */
-            /*****************************************/
+            if( gainsID == gainsID_lower ) {
+                nBits = nBits_lower;
+            } else if( gainsID == gainsID_upper ) {
+                nBits = nBits_upper;
+            } else {
+                /*****************************************/
+                /* Noise shaping quantization            */
+                /*****************************************/
 TIC(NSQ)
-            silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw );
+                silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw );
 TOC(NSQ)
 
-            /****************************************/
-            /* Encode Parameters                    */
-            /****************************************/
+                /****************************************/
+                /* Encode Parameters                    */
+                /****************************************/
 TIC(ENCODE_PARAMS)
-            silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+                silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
 TOC(ENCODE_PARAMS)
 
-            /****************************************/
-            /* Encode Excitation Signal             */
-            /****************************************/
+                /****************************************/
+                /* Encode Excitation Signal             */
+                /****************************************/
 TIC(ENCODE_PULSES)
-            silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
-                  psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+                silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+                      psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
 TOC(ENCODE_PULSES)
+   
+                nBits = ec_tell( psRangeEnc );
 
-            nBits = ec_tell( psRangeEnc );
-
-            if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
-                break;
+                if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+                    break;
+                }
             }
 
             if( iter == maxIter ) {
-                if( nBits > maxBits && found_lower ) {
+                if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
                     /* Restore output state from earlier iteration that did meet the bitrate budget */
-                   silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
-                   silk_assert( sRangeEnc_copy2.offs<=1275 );
-                   silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
-                   silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
-                   psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
+                    silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+                    silk_assert( sRangeEnc_copy2.offs <= 1275 );
+                    silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
+                    silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
+                    psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
                 }
                 break;
             }
@@ -237,7 +246,8 @@
                 found_upper = 1;
                 nBits_upper = nBits;
                 gainMult_upper = gainMult_Q8;
-                if( found_lower == 0 && iter >= 3 ) {
+                gainsID_upper = gainsID;
+                if( found_lower == 0 && iter >= 2 ) {
                     /* Adjust the quantizer's rate/distortion tradeoff */
                     sEncCtrl.Lambda *= 1.5f;
                 }
@@ -245,12 +255,15 @@
                 found_lower = 1;
                 nBits_lower = nBits;
                 gainMult_lower = gainMult_Q8;
-                /* Copy part of the output state */
-                silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
-                silk_assert( psRangeEnc->offs<=1275 );
-                silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
-                silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
-                LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+                if( gainsID != gainsID_lower ) {
+                    gainsID_lower = gainsID;
+                    /* Copy part of the output state */
+                    silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+                    silk_assert( psRangeEnc->offs <= 1275 );
+                    silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
+                    silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+                    LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+                }
             } else {
                 /* Within 5 bits of budget: close enough */
                 break;
@@ -269,22 +282,25 @@
                 /* Adjust gain by interpolating */
                 gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower );
                 /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
-                if( gainMult_Q8 > gainMult_lower + silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 ) ) {
-                    gainMult_Q8 = gainMult_lower + silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 );
+                if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
+                    gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
                 } else
-                    if( gainMult_Q8 < gainMult_upper - silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 ) ) {
-                        gainMult_Q8 = gainMult_upper - silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 );
-                    }
+                if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
+                    gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
+                }
             }
 
             for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
                 pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 );
             }
-            psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
 
-            /* Noise shaping quantization */
+            /* Quantize gains */
+            psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
             silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
                   &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+            /* Unique identifier of gains vector */
+            gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
 
             /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
             for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
--- a/silk/float/process_gains_FLP.c
+++ b/silk/float/process_gains_FLP.c
@@ -71,7 +71,7 @@
     silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
     psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
 
-    /* Noise shaping quantization */
+    /* Quantize gains */
     silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
             &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
 
--- a/silk/gain_quant.c
+++ b/silk/gain_quant.c
@@ -121,3 +121,20 @@
         gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
     }
 }
+
+/* Compute unique identifier of gain indices vector */
+opus_int32 silk_gains_ID(                                        /* O    returns unique identifier of gains      */
+    const opus_int8                  ind[ MAX_NB_SUBFR ],        /* I    gain indices                            */
+    const opus_int                   nb_subfr                    /* I    number of subframes                     */
+)
+{
+    opus_int   k;
+    opus_int32 gainsID;
+
+    gainsID = 0;
+    for( k = 0; k < nb_subfr; k++ ) {
+        gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 );
+    }
+
+    return gainsID;
+}
--- a/silk/main.h
+++ b/silk/main.h
@@ -192,6 +192,12 @@
     const opus_int                   nb_subfr                    /* I    number of subframes                     */
 );
 
+/* Compute unique identifier of gain indices vector */
+opus_int32 silk_gains_ID(                                        /* O    returns unique identifier of gains      */
+    const opus_int8                  ind[ MAX_NB_SUBFR ],        /* I    gain indices                            */
+    const opus_int                   nb_subfr                    /* I    number of subframes                     */
+);
+
 /* Interpolate two vectors */
 void silk_interpolate(
     opus_int16                       xi[ MAX_LPC_ORDER ],    /* O    interpolated vector                     */
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -499,7 +499,7 @@
        st->bitrate_bps = cbrBytes * (8*frame_rate);
        max_data_bytes = cbrBytes;
     }
-    max_rate = frame_rate*max_data_bytes;
+    max_rate = frame_rate*max_data_bytes*8;
 
     /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */
     equiv_rate = st->bitrate_bps - 60*(st->Fs/frame_size - 50);