ref: 294bfec27b82f879e3c3004d31bb91bcb34014f4
parent: dbf2ea841e5b022f0b6d15a606dd7288f25c35dd
author: Jean-Marc Valin <[email protected]>
date: Wed Oct 19 20:39:41 EDT 2011
Implements hard CBR for SILK 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.
--- a/silk/API.h
+++ b/silk/API.h
@@ -56,7 +56,7 @@
/* 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 @@
/* 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 */
);
/*************************/
--- a/silk/SigProc_FIX.h
+++ b/silk/SigProc_FIX.h
@@ -99,7 +99,7 @@
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. */
--- a/silk/biquad_alt.c
+++ b/silk/biquad_alt.c
@@ -47,7 +47,7 @@
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 @@
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 @@
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 ) );
}
}
--- a/silk/control.h
+++ b/silk/control.h
@@ -83,6 +83,9 @@
/* 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;
--- a/silk/control_codec.c
+++ b/silk/control_codec.c
@@ -38,7 +38,7 @@
#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},
--- a/silk/enc_API.c
+++ b/silk/enc_API.c
@@ -44,7 +44,7 @@
/* 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_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 @@
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 @@
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 @@
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 @@
/* 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 @@
} 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 @@
} else {
break;
}
+ curr_block++;
}
psEnc->nPrevChannelsInternal = encControl->nChannelsInternal;
--- a/silk/fixed/LTP_scale_ctrl_FIX.c
+++ b/silk/fixed/LTP_scale_ctrl_FIX.c
@@ -35,7 +35,6 @@
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;
--- a/silk/fixed/encode_frame_FIX.c
+++ b/silk/fixed/encode_frame_FIX.c
@@ -79,14 +79,23 @@
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 @@
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;
+ gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
+ 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 );
+ } 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 @@
}
/****************************************/
- /* 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
{
--- a/silk/fixed/find_pred_coefs_FIX.c
+++ b/silk/fixed/find_pred_coefs_FIX.c
@@ -127,6 +127,6 @@
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 ) );
}
--- a/silk/fixed/main_FIX.h
+++ b/silk/fixed/main_FIX.h
@@ -66,7 +66,9 @@
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 */
--- a/silk/fixed/process_gains_FIX.c
+++ b/silk/fixed/process_gains_FIX.c
@@ -86,6 +86,10 @@
}
}
+ /* 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 );
--- a/silk/fixed/structs_FIX.h
+++ b/silk/fixed/structs_FIX.h
@@ -109,6 +109,9 @@
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;
/************************/
--- a/silk/float/encode_frame_FLP.c
+++ b/silk/float/encode_frame_FLP.c
@@ -82,17 +82,31 @@
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,13 +173,129 @@
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;
+ gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
+ 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 );
+ } 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 ],
( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) );
@@ -182,31 +312,15 @@
}
/****************************************/
- /* 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 @@
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;
}
--- a/silk/float/find_pred_coefs_FLP.c
+++ b/silk/float/find_pred_coefs_FLP.c
@@ -112,7 +112,7 @@
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 ) );
}
--- a/silk/float/inner_product_FLP.c
+++ b/silk/float/inner_product_FLP.c
@@ -42,18 +42,18 @@
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;
--- a/silk/float/main_FLP.h
+++ b/silk/float/main_FLP.h
@@ -64,7 +64,9 @@
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 */
--- a/silk/float/pitch_analysis_core_FLP.c
+++ b/silk/float/pitch_analysis_core_FLP.c
@@ -202,8 +202,8 @@
/* 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 @@
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 ) {
--- a/silk/float/process_gains_FLP.c
+++ b/silk/float/process_gains_FLP.c
@@ -67,6 +67,10 @@
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 );
--- a/silk/float/silk_float.vcxproj
+++ b/silk/float/silk_float.vcxproj
@@ -127,4 +127,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
+</Project>
\ No newline at end of file
--- a/silk/float/structs_FLP.h
+++ b/silk/float/structs_FLP.h
@@ -107,6 +107,10 @@
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;
/************************/
--- a/silk/process_NLSFs.c
+++ b/silk/process_NLSFs.c
@@ -54,7 +54,7 @@
/* 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 );
@@ -61,7 +61,7 @@
}
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 );
--- a/silk/structs.h
+++ b/silk/structs.h
@@ -189,7 +189,7 @@
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 */
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -726,7 +726,7 @@
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;
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -219,6 +219,44 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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;
}
--- a/src/test_opus.c
+++ b/src/test_opus.c
@@ -110,7 +110,7 @@
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 @@
/* 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 @@
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);