Implements hard CBR for SILK
authorJean-Marc Valin <jmvalin@jmvalin.ca>
Thu, 20 Oct 2011 04:39:41 +0000 (00:39 -0400)
committerJean-Marc Valin <jmvalin@jmvalin.ca>
Thu, 20 Oct 2011 04:39:41 +0000 (00:39 -0400)
This is achieved by running the encoding process in a loop and
padding when we don't reach the exact rate. It also implements
VBR-with-cap, which means we no longer need to artificially decrease
the SILK bandwidth when it's close to the cap.

25 files changed:
silk/API.h
silk/SigProc_FIX.h
silk/biquad_alt.c
silk/control.h
silk/control_codec.c
silk/enc_API.c
silk/fixed/LTP_scale_ctrl_FIX.c
silk/fixed/encode_frame_FIX.c
silk/fixed/find_pred_coefs_FIX.c
silk/fixed/main_FIX.h
silk/fixed/process_gains_FIX.c
silk/fixed/structs_FIX.h
silk/float/encode_frame_FLP.c
silk/float/find_pred_coefs_FLP.c
silk/float/inner_product_FLP.c
silk/float/main_FLP.h
silk/float/pitch_analysis_core_FLP.c
silk/float/process_gains_FLP.c
silk/float/silk_float.vcxproj
silk/float/structs_FLP.h
silk/process_NLSFs.c
silk/structs.h
src/opus_decoder.c
src/opus_encoder.c
src/test_opus.c

index ca24808..a96bd54 100644 (file)
@@ -56,7 +56,7 @@ typedef struct {
 /* Get size in bytes of the Silk encoder state */
 /***********************************************/
 opus_int silk_Get_Encoder_Size(                          /* O:   Returns error code                              */
-    int                                  *encSizeBytes   /* O:   Number of bytes in SILK encoder state           */
+    opus_int                           *encSizeBytes   /* O:   Number of bytes in SILK encoder state           */
 );
 
 /*************************/
@@ -98,7 +98,7 @@ opus_int silk_Encode(                                    /* O:   Returns error c
 /* Get size in bytes of the Silk decoder state */
 /***********************************************/
 opus_int silk_Get_Decoder_Size(                          /* O:   Returns error code                              */
-    int                                  *decSizeBytes   /* O:   Number of bytes in SILK decoder state           */
+    opus_int                             *decSizeBytes   /* O:   Number of bytes in SILK decoder state           */
 );
 
 /*************************/
index f9e2664..24052ff 100644 (file)
@@ -99,7 +99,7 @@ void silk_biquad_alt(
     opus_int32           *S,            /* I/O:  State vector [2]             */
     opus_int16           *out,          /* O:    output signal                */
     const opus_int32     len,           /* I:    signal length (must be even) */
-    int stride
+    opus_int             stride          /* I:    Operate on interleaved signal if > 1 */
 );
 
 /* Variable order MA prediction error filter. */
index 617b33a..74a66a5 100644 (file)
@@ -47,7 +47,7 @@ void silk_biquad_alt(
     opus_int32            *S,             /* I/O:  State vector [2]               */
     opus_int16            *out,           /* O:    Output signal                  */
     const opus_int32      len,            /* I:    Signal length (must be even)   */
-    int stride
+    opus_int              stride          /* I:    Operate on interleaved signal if > 1 */
 )
 {
     /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
@@ -62,7 +62,7 @@ void silk_biquad_alt(
 
     for( k = 0; k < len; k++ ) {
         /* S[ 0 ], S[ 1 ]: Q12 */
-        inval = in[ k*stride ];
+        inval = in[ k * stride ];
         out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 );
 
         S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 );
@@ -74,6 +74,6 @@ void silk_biquad_alt(
         S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval );
 
         /* Scale back to Q0 and saturate */
-        out[ k*stride ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) );
+        out[ k * stride ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) );
     }
 }
index ac1b288..c2f906b 100644 (file)
@@ -83,6 +83,9 @@ typedef struct {
     /* I:   Flag to use constant bitrate                                                    */
     opus_int useCBR;
 
+    /* I:   Maximum number of bits allowed for the frame */
+    opus_int maxBits;
+
     /* I:   Causes a smooth downmix to mono */
     opus_int toMono;
 
index 796c3ef..a942336 100644 (file)
@@ -38,7 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "tuning_parameters.h"
 
 
-static const int enc_delay_matrix[3][5] = {
+static const opus_int enc_delay_matrix[3][5] = {
 /*SILK API 8  12  16  24  48 */
 /* 8 */   {5,  0,  3,  4,  8},
 /*12 */   {0,  6,  0,  0,  0},
index fb4b717..149befa 100644 (file)
@@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /* Encoder functions                    */
 /****************************************/
 
-opus_int silk_Get_Encoder_Size( int *encSizeBytes )
+opus_int silk_Get_Encoder_Size( opus_int *encSizeBytes )
 {
     opus_int ret = SILK_NO_ERROR;
 
@@ -139,7 +139,7 @@ opus_int silk_Encode(
     opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol;
     silk_encoder *psEnc = ( silk_encoder * )encState;
     opus_int16 buf[ MAX_FRAME_LENGTH_MS * MAX_API_FS_KHZ + MAX_ENCODER_DELAY];
-    opus_int transition, delay;
+    opus_int transition, delay, curr_block, tot_blocks;
 
     psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0;
 
@@ -172,6 +172,8 @@ opus_int silk_Encode(
     psEnc->nChannelsInternal = encControl->nChannelsInternal;
 
     nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate );
+    tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1;
+    curr_block = 0;
     if( prefillFlag ) {
         /* Only accept input length of 10 ms */
         if( nBlocksOf10ms != 1 ) {
@@ -211,13 +213,12 @@ opus_int silk_Encode(
     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? */
-        int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0;
+        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 );
             return ret;
         }
-        if (psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition)
-        {
+        if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) {
             for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
                 psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0;
             }
@@ -234,7 +235,7 @@ opus_int silk_Encode(
         nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
         /* Resample and write to buffer */
         if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) {
-            int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
+            opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
             for( n = 0; n < nSamplesFromInput; n++ ) {
                 buf[ n+delay ] = samplesIn[ 2 * n ];
             }
@@ -419,10 +420,33 @@ opus_int silk_Encode(
 
             /* Encode */
             for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+                opus_int maxBits, useCBR;
+
+                /* 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 ) {
+                    if( curr_block == 0 ) {
+                        maxBits = maxBits * 2 / 5;
+                    } else if( curr_block == 1 ) {
+                        maxBits = maxBits * 3 / 4;
+                    }
+                }
+                useCBR = encControl->useCBR && curr_block == tot_blocks - 1;
+
                 if( encControl->nChannelsInternal == 1 ) {
                     channelRate_bps = TargetRate_bps;
                 } else {
                     channelRate_bps = MStargetRates_bps[ n ];
+                    if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) {
+                        useCBR = 0;
+                        /* Give mid up to 1/2 of the max bits for that frame */
+                        maxBits -= encControl->maxBits / ( tot_blocks * 2 );
+                    }
                 }
 
                 if( channelRate_bps > 0 ) {
@@ -440,7 +464,7 @@ opus_int silk_Encode(
                     } else {
                         condCoding = CODE_CONDITIONALLY;
                     }
-                    if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding ) ) != 0 ) {
+                    if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) {
                         silk_assert( 0 );
                     }
                 }
@@ -492,6 +516,7 @@ opus_int silk_Encode(
         } else {
             break;
         }
+        curr_block++;
     }
 
     psEnc->nPrevChannelsInternal = encControl->nChannelsInternal;
index 5e85cc7..dd4923f 100644 (file)
@@ -35,7 +35,6 @@ void silk_LTP_scale_ctrl_FIX(
     silk_encoder_state_FIX      *psEnc,     /* I/O  encoder state FIX                           */
     silk_encoder_control_FIX    *psEncCtrl, /* I/O  encoder control FIX                         */
     opus_int                     condCoding /* I    The type of conditional coding to use       */
-
 )
 {
     opus_int round_loss;
index e351def..a8633f5 100644 (file)
@@ -79,14 +79,23 @@ opus_int silk_encode_frame_FIX(
     silk_encoder_state_FIX          *psEnc,             /* I/O  Encoder state FIX                       */
     opus_int32                       *pnBytesOut,        /*   O  Number of payload bytes                 */
     ec_enc                          *psRangeEnc,        /* I/O  compressor data structure               */
-    opus_int                         condCoding         /* I    The type of conditional coding to use   */
+    opus_int                         condCoding,        /* I    The type of conditional coding to use   */
+    opus_int                         maxBits,           /* I    If > 0: maximum number of output bits   */
+    opus_int                         useCBR             /* I    Flag to force constant-bitrate operation */
 )
 {
     silk_encoder_control_FIX sEncCtrl;
-    opus_int     ret = 0;
+    opus_int     i, iter, maxIter, found_upper, found_lower, ret = 0;
     opus_int16   *x_frame, *res_pitch_frame;
     opus_int16   xfw[ MAX_FRAME_LENGTH ];
     opus_int16   res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ];
+    ec_enc       sRangeEnc_copy, sRangeEnc_copy2;
+    silk_nsq_state sNSQ_copy, sNSQ_copy2;
+    opus_int32   seed_copy, nBits, nBits_lower, nBits_upper, gainMult_Q10, gainMult_lower, gainMult_upper;
+    opus_int16   ec_prevLagIndex_copy;
+    opus_int     ec_prevSignalType_copy;
+    opus_int8    LastGainIndex_copy2;
+    opus_uint8   ec_buf_copy[ 512 ];
 
 TIC(ENCODE_FRAME)
 
@@ -151,21 +160,132 @@ TIC(LBRR)
     silk_LBRR_encode_FIX( psEnc, &sEncCtrl, xfw, condCoding );
 TOC(LBRR)
 
-    /*****************************************/
-    /* Noise shaping quantization            */
-    /*****************************************/
+    /* Loop over quantizer and entroy coding to control bitrate */
+    maxIter = 5;
+    gainMult_Q10 = SILK_FIX_CONST( 1, 10 );
+    found_lower = 0;
+    found_upper = 0;
+    for( iter = 0; ; iter++ ) {
+        if( maxBits > 0 && !psEnc->sCmn.prefillFlag ) {
+            /* 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 );
-    } 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 );
-    }
+        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)
 
+        if( psEnc->sCmn.prefillFlag ) {
+            break;
+        } else {
+            /****************************************/
+            /* Encode Parameters                    */
+            /****************************************/
+TIC(ENCODE_PARAMS)
+            silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+TOC(ENCODE_PARAMS)
+
+            /****************************************/
+            /* 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 );
+TOC(ENCODE_PULSES)
+
+        }
+
+        nBits = ec_tell( psRangeEnc );
+
+        if( maxBits == 0 || ( useCBR == 0 && iter == 0 && nBits <= maxBits ) ) {
+            break;
+        }
+
+        if( iter == maxIter ) {
+            if( nBits > maxBits && found_lower ) {
+                /* Restore output state from earlier iteration that did meet the bitrate budget */
+                silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+                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;
+        }
+
+        if( nBits > maxBits ) {
+            found_upper = 1;
+            nBits_upper = nBits;
+            gainMult_upper = gainMult_Q10;
+            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 );
+            }
+        } else if( nBits < maxBits - 5 ) {
+            found_lower = 1;
+            nBits_lower = nBits;
+            gainMult_lower = gainMult_Q10;
+            /* Copy part of the output state */
+            silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+            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;
+        }
+
+        if( ( found_lower & found_upper ) == 0 ) {
+            /* Adjust gain according to high-rate rate/distortion curve */
+            opus_int32 gain_factor_Q16;\r
+            gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );\r
+            if( nBits > maxBits ) {
+                gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) );
+            }
+            gainMult_Q10 = silk_SMULWW( gainMult_Q10, gain_factor_Q16 );\r
+        } else {
+            /* Adjust gain by interpolating */
+            gainMult_Q10 = 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_Q10 > gainMult_lower + silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 ) ) {
+                gainMult_Q10 = gainMult_lower + silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 );
+            } else 
+            if( gainMult_Q10 < gainMult_upper - silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 ) ) {
+                gainMult_Q10 = gainMult_upper - silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 );
+            } 
+        }
+
+        for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+            sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWW( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q10 ), 6 );
+        }
+        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 );
+
+        /* Restore part of the input state */
+        silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
+        silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
+        psEnc->sCmn.indices.Seed = seed_copy;
+        psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+        psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+    }
+
     /* Update input buffer */
     silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
         ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) );
@@ -182,27 +302,13 @@ TOC(NSQ)
     }
 
     /****************************************/
-    /* Encode Parameters                    */
-    /****************************************/
-TIC(ENCODE_PARAMS)
-    silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
-TOC(ENCODE_PARAMS)
-
-    /****************************************/
-    /* 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 );
-TOC(ENCODE_PULSES)
-
-    /****************************************/
     /* Finalize payload                     */
     /****************************************/
     psEnc->sCmn.first_frame_after_reset = 0;
     /* Payload size */
     *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
-TOC(ENCODE_FRAME)
+
+    TOC(ENCODE_FRAME)
 
 #ifdef SAVE_ALL_INTERNAL_DATA
     {
index e9891cd..2cefd90 100644 (file)
@@ -127,6 +127,6 @@ void silk_find_pred_coefs_FIX(
     silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains,
         psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
 
-    /* Copy to prediction struct for use in next frame for fluctuation reduction */
+    /* Copy to prediction struct for use in next frame for interpolation */
     silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
 }
index 57b648e..f4b0270 100644 (file)
@@ -66,7 +66,9 @@ opus_int silk_encode_frame_FIX(
     silk_encoder_state_FIX          *psEnc,             /* I/O  Pointer to Silk FIX encoder state       */
     opus_int32                       *pnBytesOut,        /*   O  Pointer to number of payload bytes;     */
     ec_enc                          *psRangeEnc,        /* I/O  compressor data structure               */
-    opus_int                         condCoding         /* I    The type of conditional coding to use   */
+    opus_int                         condCoding,        /* I    The type of conditional coding to use   */
+    opus_int                         maxBits,           /* I    If > 0: maximum number of output bits   */
+    opus_int                         useCBR             /* I    Flag to force constant-bitrate operation */
 );
 
 /* Initializes the Silk encoder state */
index 25a13a5..c3d5664 100644 (file)
@@ -86,6 +86,10 @@ void silk_process_gains_FIX(
         }
     }
 
+    /* Save unquantized gains and gain Index */
+    silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+    psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
+
     /* Noise shaping quantization */
     silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16,
         &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
index 47e845d..8803c7f 100644 (file)
@@ -109,6 +109,9 @@ typedef struct {
     opus_int32   ResNrg[ MAX_NB_SUBFR ];             /* Residual energy per subframe                             */
     opus_int     ResNrgQ[ MAX_NB_SUBFR ];            /* Q domain for the residual energy > 0                     */
 
+    /* Parameters for CBR mode */
+    opus_int32                    GainsUnq_Q16[ MAX_NB_SUBFR ];
+    opus_int8                     lastGainIndexPrev;
 } silk_encoder_control_FIX;
 
 /************************/
index 6c9e322..a695d8a 100644 (file)
@@ -82,17 +82,31 @@ opus_int silk_encode_frame_FLP(
     silk_encoder_state_FLP          *psEnc,             /* I/O  Encoder state FLP                       */
     opus_int32                       *pnBytesOut,        /*   O  Number of payload bytes                 */
     ec_enc                          *psRangeEnc,        /* I/O  compressor data structure               */
-    opus_int                         condCoding         /* I    The type of conditional coding to use   */
+    opus_int                         condCoding,        /* I    The type of conditional coding to use   */
+    opus_int                         maxBits,           /* I    If > 0: maximum number of output bits   */
+    opus_int                         useCBR             /* I    Flag to force constant-bitrate operation */
 )
 {
     silk_encoder_control_FLP sEncCtrl;
-    opus_int     i, ret = 0;
+    opus_int     i, iter, maxIter, found_upper, found_lower, ret = 0;
     silk_float   *x_frame, *res_pitch_frame;
     silk_float   xfw[ MAX_FRAME_LENGTH ];
     silk_float   res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ];
+    ec_enc       sRangeEnc_copy, sRangeEnc_copy2;
+    silk_nsq_state sNSQ_copy, sNSQ_copy2;
+    opus_int32   seed_copy, nBits, nBits_lower, nBits_upper, gainMult_Q10, gainMult_lower, gainMult_upper;
+    opus_int16   ec_prevLagIndex_copy;
+    opus_int     ec_prevSignalType_copy;
+    opus_int8    LastGainIndex_copy2;
+    opus_int32   pGains_Q16[ MAX_NB_SUBFR ];
+    opus_uint8   ec_buf_copy[ 512 ];
 
 TIC(ENCODE_FRAME)
 
+    /* This is totally unnecessary but many compilers (including gcc) are too dumb
+       to realise it */
+    LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
+
     psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
 
     /**************************************************************/
@@ -159,12 +173,128 @@ TIC(LBRR)
     silk_LBRR_encode_FLP( psEnc, &sEncCtrl, xfw, condCoding );
 TOC(LBRR)
 
-    /*****************************************/
-    /* Noise shaping quantization            */
-    /*****************************************/
+    if ( psEnc->sCmn.prefillFlag )
+    {
 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)
+    } else {
+        /* Loop over quantizer and entroy coding to control bitrate */
+        maxIter = 5;
+        gainMult_Q10 = SILK_FIX_CONST( 1, 10 );
+        found_lower = 0;
+        found_upper = 0;
+        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)
+            silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw );
+TOC(NSQ)
+
+            /****************************************/
+            /* Encode Parameters                    */
+            /****************************************/
+TIC(ENCODE_PARAMS)
+            silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+TOC(ENCODE_PARAMS)
+
+            /****************************************/
+            /* 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 );
+TOC(ENCODE_PULSES)
+
+            nBits = ec_tell( psRangeEnc );
+
+            if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+                break;
+            }
+
+            if( iter == maxIter ) {
+                if( nBits > maxBits && found_lower ) {
+                    /* Restore output state from earlier iteration that did meet the bitrate budget */
+                   silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+                   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;
+            }
+
+            if( nBits > maxBits ) {
+                found_upper = 1;
+                nBits_upper = nBits;
+                gainMult_upper = gainMult_Q10;
+                if( found_lower == 0 && iter >= 3 ) {
+                    /* Adjust the quantizer's rate/distortion tradeoff */
+                    sEncCtrl.Lambda *= 1.5f;
+                }
+            } else if( nBits < maxBits - 5 ) {
+                found_lower = 1;
+                nBits_lower = nBits;
+                gainMult_lower = gainMult_Q10;
+                /* Copy part of the output state */
+                silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+                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;
+            }
+
+            if( ( found_lower & found_upper ) == 0 ) {
+                /* Adjust gain according to high-rate rate/distortion curve */
+                opus_int32 gain_factor_Q16;\r
+                gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );\r
+                if( nBits > maxBits ) {
+                    gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) );
+                }
+                gainMult_Q10 = silk_SMULWW( gainMult_Q10, gain_factor_Q16 );\r
+            } else {
+                /* Adjust gain by interpolating */
+                gainMult_Q10 = 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_Q10 > gainMult_lower + silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 ) ) {
+                    gainMult_Q10 = gainMult_lower + silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 );
+                } else
+                    if( gainMult_Q10 < gainMult_upper - silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 ) ) {
+                        gainMult_Q10 = gainMult_upper - silk_RSHIFT32( gainMult_upper - gainMult_lower, 2 );
+                    }
+            }
+
+            for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+                pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWW( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q10 ), 6 );
+            }
+            psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+
+            /* Noise shaping quantization */
+            silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
+                  &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, 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++ ) {
+                sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f;
+            }
+
+            /* Restore part of the input state */
+            silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
+            silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
+            psEnc->sCmn.indices.Seed = seed_copy;
+            psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+            psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+        }
+    }
 
     /* Update input buffer */
     silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
@@ -182,31 +312,15 @@ TOC(NSQ)
     }
 
     /****************************************/
-    /* Encode Parameters                    */
-    /****************************************/
-TIC(ENCODE_PARAMS)
-    silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
-TOC(ENCODE_PARAMS)
-
-    /****************************************/
-    /* 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 );
-TOC(ENCODE_PULSES)
-
-    /****************************************/
     /* Finalize payload                     */
     /****************************************/
     psEnc->sCmn.first_frame_after_reset = 0;
     /* Payload size */
     *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
+
 TOC(ENCODE_FRAME)
 
 #ifdef SAVE_ALL_INTERNAL_DATA
-    /*DEBUG_STORE_DATA( xf.dat,                   pIn_HP_LP,                           psEnc->sCmn.frame_length * sizeof( opus_int16 ) );*/
-    /*DEBUG_STORE_DATA( xfw.dat,                  xfw,                                 psEnc->sCmn.frame_length * sizeof( silk_float ) );*/
     DEBUG_STORE_DATA( pitchL.dat,               sEncCtrl.pitchL,                                 MAX_NB_SUBFR * sizeof( opus_int   ) );
     DEBUG_STORE_DATA( pitchG_quantized.dat,     sEncCtrl.LTPCoef,            psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( silk_float ) );
     DEBUG_STORE_DATA( LTPcorr.dat,              &psEnc->LTPCorr,                                                sizeof( silk_float ) );
@@ -220,7 +334,6 @@ TOC(ENCODE_FRAME)
     DEBUG_STORE_DATA( per_index.dat,            &psEnc->sCmn.indices.PERIndex,                                  sizeof( opus_int8  ) );
     DEBUG_STORE_DATA( PredCoef.dat,             &sEncCtrl.PredCoef[ 1 ],          psEnc->sCmn.predictLPCOrder * sizeof( silk_float ) );
     DEBUG_STORE_DATA( ltp_scale_idx.dat,        &psEnc->sCmn.indices.LTP_scaleIndex,                            sizeof( opus_int8   ) );
-    /*DEBUG_STORE_DATA( xq.dat,                   psEnc->sCmn.sNSQ.xqBuf,                psEnc->sCmn.frame_length * sizeof( silk_float ) );*/
 #endif
     return ret;
 }
index 0488185..90a4e46 100644 (file)
@@ -112,7 +112,7 @@ TOC(LSF_quant);
     silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains,
         psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
 
-    /* Copy to prediction struct for use in next frame for fluctuation reduction */
+    /* Copy to prediction struct for use in next frame for interpolation */
     silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
 }
 
index 4ed56a3..a8f04d7 100644 (file)
@@ -42,18 +42,18 @@ double silk_inner_product_FLP(      /* O    result              */
     double   result;
 
     /* 4x unrolled loop */
-    result = 0.0f;
+    result = 0.0;
     dataSize4 = dataSize & 0xFFFC;
     for( i = 0; i < dataSize4; i += 4 ) {
-        result += data1[ i + 0 ] * data2[ i + 0 ] +
-                  data1[ i + 1 ] * data2[ i + 1 ] +
-                  data1[ i + 2 ] * data2[ i + 2 ] +
-                  data1[ i + 3 ] * data2[ i + 3 ];
+        result += data1[ i + 0 ] * (double)data2[ i + 0 ] +
+                  data1[ i + 1 ] * (double)data2[ i + 1 ] +
+                  data1[ i + 2 ] * (double)data2[ i + 2 ] +
+                  data1[ i + 3 ] * (double)data2[ i + 3 ];
     }
 
     /* add any remaining products */
     for( ; i < dataSize; i++ ) {
-        result += data1[ i ] * data2[ i ];
+        result += data1[ i ] * (double)data2[ i ];
     }
 
     return result;
index 20a766b..07e31ab 100644 (file)
@@ -64,7 +64,9 @@ opus_int silk_encode_frame_FLP(
     silk_encoder_state_FLP          *psEnc,             /* I/O  Encoder state FLP                       */
     opus_int32                       *pnBytesOut,        /*   O  Number of payload bytes;                */
     ec_enc                          *psRangeEnc,        /* I/O  compressor data structure               */
-    opus_int                         condCoding         /* I    The type of conditional coding to use   */
+    opus_int                         condCoding,        /* I    The type of conditional coding to use   */
+    opus_int                         maxBits,           /* I    If > 0: maximum number of output bits   */
+    opus_int                         useCBR             /* I    Flag to force constant-bitrate operation */
 );
 
 /* Initializes the Silk encoder state */
index 8e66159..4108d63 100644 (file)
@@ -202,8 +202,8 @@ opus_int silk_pitch_analysis_core_FLP( /* O voicing estimate: 0 voiced, 1 unvoic
 
             /* Add contribution of new sample and remove contribution from oldest sample */
             normalizer +=
-                basis_ptr[ 0 ] * basis_ptr[ 0 ] -
-                basis_ptr[ sf_length_8kHz ] * basis_ptr[ sf_length_8kHz ];
+                basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] -
+                basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ];
             C[ 0 ][ d ] += (silk_float)(cross_corr / sqrt( normalizer ));
         }
         /* Update target pointer */
@@ -225,7 +225,7 @@ opus_int silk_pitch_analysis_core_FLP( /* O voicing estimate: 0 voiced, 1 unvoic
     target_ptr = &frame_4kHz[ silk_SMULBB( sf_length_4kHz, nb_subfr ) ];
     energy = 1000.0f;
     for( i = 0; i < silk_LSHIFT( sf_length_4kHz, 2 ); i++ ) {
-        energy += target_ptr[i] * target_ptr[i];
+        energy += target_ptr[i] * (double)target_ptr[i];
     }
     threshold = Cmax * Cmax;
     if( energy / 16.0f > threshold ) {
index 2c7dfdd..0708a5c 100644 (file)
@@ -67,6 +67,10 @@ void silk_process_gains_FLP(
         pGains_Q16[ k ] = ( opus_int32 ) ( psEncCtrl->Gains[ k ] * 65536.0f );
     }
 
+    /* Save unquantized gains and gain Index */
+    silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+    psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
+
     /* Noise shaping quantization */
     silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
             &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
index abcdaf0..4453947 100644 (file)
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
   <ImportGroup Label="ExtensionTargets">\r
   </ImportGroup>\r
-</Project>\r
+</Project>
\ No newline at end of file
index 99264c9..dd776b5 100644 (file)
@@ -107,6 +107,10 @@ typedef struct {
     silk_float                   predGain;
     silk_float                    LTPredCodGain;
     silk_float                    ResNrg[ MAX_NB_SUBFR ];                    /* Residual energy per subframe */
+
+    /* Parameters for CBR mode */
+    opus_int32                    GainsUnq_Q16[ MAX_NB_SUBFR ];
+    opus_int8                     lastGainIndexPrev;
 } silk_encoder_control_FLP;
 
 /************************/
index e077627..6e1cc06 100644 (file)
@@ -54,14 +54,14 @@ void silk_process_NLSFs(
     /* Calculate mu values */
     /***********************/
     /* NLSF_mu  = 0.003 - 0.0015 * psEnc->speech_activity; */
-    NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.0025, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 );
+    NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 );
     if( psEncC->nb_subfr == 2 ) {
         /* Multiply by 1.5 for 10 ms packets */
         NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 );
     }
 
     silk_assert( NLSF_mu_Q20 >  0 );
-    silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.0045, 20 ) );
+    silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) );
 
     /* Calculate NLSF weights */
     silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder );
index d11aa28..51c0f86 100644 (file)
@@ -189,7 +189,7 @@ typedef struct {
     opus_int8                        LBRR_flag;
     opus_int                         LBRR_flags[ MAX_FRAMES_PER_PACKET ];
 
-    SideInfoIndices                 indices;
+    SideInfoIndices                  indices;
     opus_int8                        pulses[ MAX_FRAME_LENGTH ];
 
     /* Input/output buffering */
index 38672b1..4f4d648 100644 (file)
@@ -726,7 +726,7 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data,
    if (ret > 0)
    {
       for (i=0;i<ret*st->channels;i++)
-         pcm[i] = (1./32768.)*(out[i]);
+         pcm[i] = (1.f/32768.f)*(out[i]);
    }
    RESTORE_STACK;
    return ret;
index c1cb2cf..9259fab 100644 (file)
@@ -219,6 +219,44 @@ int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int applicat
     return OPUS_OK;
 }
 
+static int pad_frame(unsigned char *data, int len, int new_len)
+{
+   if (len == new_len)
+      return 0;
+   if (len > new_len)
+      return 1;
+
+   if ((data[0]&0x3)==0)
+   {
+      int i;
+      int padding, nb_255s;
+
+      padding = new_len - len;
+      if (padding >= 2)
+      {
+         nb_255s = (padding-2)/255;
+
+         for (i=len-1;i>=1;i--)
+            data[i+nb_255s+2] = data[i];
+         data[0] |= 0x3;
+         data[1] = 0x41;
+         for (i=0;i<nb_255s;i++)
+            data[i+2] = 255;
+         data[nb_255s+2] = padding-255*nb_255s-2;
+         for (i=len+3+nb_255s;i<new_len;i++)
+            data[i] = 0;
+      } else {
+         for (i=len-1;i>=1;i--)
+            data[i+1] = data[i];
+         data[0] |= 0x3;
+         data[1] = 1;
+      }
+      return 0;
+   } else {
+      return 1;
+   }
+}
+
 static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels)
 {
    int period;
@@ -449,6 +487,15 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
 
     st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes);
 
+    if (!st->use_vbr)
+    {
+       int cbrBytes, frame_rate;
+       frame_rate = st->Fs/frame_size;
+       cbrBytes = IMIN( (st->bitrate_bps + 4*frame_rate)/(8*frame_rate) , max_data_bytes);
+       st->bitrate_bps = cbrBytes * (8*frame_rate);
+       max_data_bytes = cbrBytes;
+    }
+
     /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */
     equiv_rate = st->bitrate_bps - 60*(st->Fs/frame_size - 50);
 
@@ -614,6 +661,21 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     if (st->user_bandwidth != OPUS_AUTO)
         st->bandwidth = st->user_bandwidth;
 
+    /* This enforces safe rates for CBR SILK */
+    if (!st->use_vbr && st->mode != MODE_CELT_ONLY)
+    {
+       int frame_rate;
+       opus_int32 max_rate;
+       frame_rate = st->Fs/frame_size;
+       max_rate = frame_rate*max_data_bytes;
+       if (max_rate < 15000)
+          st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND);
+       if (max_rate < 12000)
+          st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_MEDIUMBAND);
+       if (max_rate < 9000)
+          st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+    }
+
     /* Prevents Opus from wasting bits on frequencies that are above
        the Nyquist rate of the input signal */
     if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND)
@@ -625,6 +687,9 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND)
         st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
 
+    /* If max_data_bytes represents less than 8 kb/s, switch to CELT-only mode */
+    if (max_data_bytes < 8000*frame_size / (st->Fs * 8))
+       st->mode = MODE_CELT_ONLY;
 
     /* Can't support higher than wideband for >20 ms frames */
     if (frame_size > st->Fs/50 && (st->mode == MODE_CELT_ONLY || st->bandwidth > OPUS_BANDWIDTH_WIDEBAND))
@@ -688,9 +753,6 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     if (st->mode == MODE_HYBRID && st->bandwidth <= OPUS_BANDWIDTH_WIDEBAND)
         st->mode = MODE_SILK_ONLY;
 
-    /* If max_data_bytes represents less than 8 kb/s, switch to CELT-only mode */
-    if (max_data_bytes < 8000*frame_size / (st->Fs * 8))
-       st->mode = MODE_CELT_ONLY;
     /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, st->bandwidth); */
     bytes_target = IMIN(max_data_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1;
 
@@ -756,9 +818,6 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
                 st->silk_mode.bitRate = ( st->bitrate_bps - 8*st->Fs/frame_size ) * 4/5;
             }
         }
-        /* SILK is not allow to use more than 50% of max_data_bytes */
-        if (max_data_bytes < st->silk_mode.bitRate*frame_size / (st->Fs * 4))
-           st->silk_mode.bitRate = max_data_bytes*st->Fs*4/frame_size;
 
         st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs;
         st->silk_mode.nChannelsAPI = st->channels;
@@ -779,8 +838,24 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
         }
         st->silk_mode.maxInternalSampleRate = 16000;
 
+        st->silk_mode.useCBR = !st->use_vbr;
+
         /* Call SILK encoder for the low band */
         nBytes = IMIN(1275, max_data_bytes-1);
+
+        st->silk_mode.maxBits = nBytes*8;
+        /* Only allow up to 90% of the bits for hybrid mode*/
+        if (st->mode == MODE_HYBRID)
+           st->silk_mode.maxBits = (opus_int32)st->silk_mode.maxBits*9/10;
+        if (st->silk_mode.useCBR)
+        {
+           st->silk_mode.maxBits = (st->silk_mode.bitRate * frame_size / (st->Fs * 8))*8;
+           /* Reduce the initial target to make it easier to reach the CBR rate */
+           st->silk_mode.bitRate = 1;
+        }
+        if (redundancy)
+           st->silk_mode.maxBits -= st->silk_mode.maxBits/(1 + frame_size/(st->Fs/200));
+
         if (prefill)
         {
             int zero=0;
@@ -1029,6 +1104,12 @@ int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
     st->prev_framesize = frame_size;
 
     st->first = 0;
+    if (!redundancy && st->mode==MODE_SILK_ONLY && !st->use_vbr && ret >= 2)
+    {
+       nb_compr_bytes = st->bitrate_bps * frame_size / (st->Fs * 8);
+       pad_frame(data, ret+1, nb_compr_bytes);
+       return nb_compr_bytes;
+    }
     RESTORE_STACK;
     return ret+1+redundancy_bytes;
 }
index ae5d4c8..c1ef4f9 100644 (file)
@@ -110,7 +110,7 @@ int main(int argc, char *argv[])
     int stop=0;
     short *in, *out;
     int application=OPUS_APPLICATION_AUDIO;
-    double bits=0.0, bits_act=0.0, bits2=0.0, nrg;
+    double bits=0.0, bits_max=0.0, bits_act=0.0, bits2=0.0, nrg;
     int bandwidth=-1;
     const char *bandwidth_string;
     int lost = 0, lost_prev = 1;
@@ -446,6 +446,7 @@ int main(int argc, char *argv[])
 
         /* count bits */
         bits += len[toggle]*8;
+        bits_max = ( len[toggle]*8 > bits_max ) ? len[toggle]*8 : bits_max;
         if( count >= use_inbandfec ) {
             nrg = 0.0;
             if (!decode_only)
@@ -465,6 +466,7 @@ int main(int argc, char *argv[])
         toggle = (toggle + use_inbandfec) & 1;
     }
     fprintf (stderr, "average bitrate:             %7.3f kb/s\n", 1e-3*bits*sampling_rate/(frame_size*(double)count));
+    fprintf (stderr, "maximum bitrate:             %7.3f bkp/s\n", 1e-3*bits_max*sampling_rate/frame_size);
     if (!decode_only)
        fprintf (stderr, "active bitrate:              %7.3f kb/s\n", 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
     fprintf (stderr, "bitrate standard deviation:  %7.3f kb/s\n", 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);