diff --git a/celt/celt_encoder.c b/celt/celt_encoder.c index 637d442cf7d6ca40efaade086c61544de543debb..219dc73f8ab5790ae9f049c684a70c2576b1a76a 100644 --- a/celt/celt_encoder.c +++ b/celt/celt_encoder.c @@ -1565,10 +1565,13 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, vbr_rate = 0; tmp = st->bitrate*frame_size; if (tell>1) - tmp += tell; + tmp += tell*mode->Fs; if (st->bitrate!=OPUS_BITRATE_MAX) + { nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes, (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling)); + ec_enc_shrink(enc, nbCompressedBytes); + } effectiveBytes = nbCompressedBytes - nbFilledBytes; } equiv_rate = ((opus_int32)nbCompressedBytes*8*50 << (3-LM)) - (40*C+20)*((400>>LM) - 50); diff --git a/silk/fixed/encode_frame_FIX.c b/silk/fixed/encode_frame_FIX.c index a02bf87dbb18466cff3c7f16f0adb04d9f906ebf..7c83360ba351e9675ba19a831f5121d97d108ccb 100644 --- a/silk/fixed/encode_frame_FIX.c +++ b/silk/fixed/encode_frame_FIX.c @@ -105,8 +105,11 @@ opus_int silk_encode_frame_FIX( opus_int gain_lock[ MAX_NB_SUBFR ] = {0}; opus_int16 best_gain_mult[ MAX_NB_SUBFR ]; opus_int best_sum[ MAX_NB_SUBFR ]; + opus_int bits_margin; SAVE_STACK; + /* For CBR, 5 bits below budget is close enough. For VBR, allow up to 25% below the cap if we initially busted the budget. */ + bits_margin = useCBR ? 5 : maxBits/4; /* 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; @@ -282,7 +285,7 @@ opus_int silk_encode_frame_FIX( gainMult_upper = gainMult_Q8; gainsID_upper = gainsID; } - } else if( nBits < maxBits - 5 ) { + } else if( nBits < maxBits - bits_margin ) { found_lower = 1; nBits_lower = nBits; gainMult_lower = gainMult_Q8; @@ -296,7 +299,7 @@ opus_int silk_encode_frame_FIX( LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; } } else { - /* Within 5 bits of budget: close enough */ + /* Close enough */ break; } @@ -318,17 +321,10 @@ opus_int silk_encode_frame_FIX( if( ( found_lower & found_upper ) == 0 ) { /* Adjust gain according to high-rate rate/distortion curve */ if( nBits > maxBits ) { - if (gainMult_Q8 < 16384) { - gainMult_Q8 *= 2; - } else { - gainMult_Q8 = 32767; - } + gainMult_Q8 = silk_min_32( 1024, gainMult_Q8*3/2 ); } else { - opus_int32 gain_factor_Q16; - gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); - gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + gainMult_Q8 = silk_max_32( 64, gainMult_Q8*4/5 ); } - } else { /* Adjust gain by interpolating */ gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower ); diff --git a/silk/float/encode_frame_FLP.c b/silk/float/encode_frame_FLP.c index b029c3f5ca830cb983a9e3f0474fc00c684d138d..8a327c56262c4f5c75993bc33eb45cd7c81674af 100644 --- a/silk/float/encode_frame_FLP.c +++ b/silk/float/encode_frame_FLP.c @@ -107,7 +107,10 @@ opus_int silk_encode_frame_FLP( opus_int gain_lock[ MAX_NB_SUBFR ] = {0}; opus_int16 best_gain_mult[ MAX_NB_SUBFR ]; opus_int best_sum[ MAX_NB_SUBFR ]; + opus_int bits_margin; + /* For CBR, 5 bits below budget is close enough. For VBR, allow up to 25% below the cap if we initially busted the budget. */ + bits_margin = useCBR ? 5 : maxBits/4; /* 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; @@ -270,7 +273,7 @@ opus_int silk_encode_frame_FLP( gainMult_upper = gainMult_Q8; gainsID_upper = gainsID; } - } else if( nBits < maxBits - 5 ) { + } else if( nBits < maxBits - bits_margin ) { found_lower = 1; nBits_lower = nBits; gainMult_lower = gainMult_Q8; @@ -284,7 +287,7 @@ opus_int silk_encode_frame_FLP( LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; } } else { - /* Within 5 bits of budget: close enough */ + /* Close enough */ break; } @@ -306,15 +309,9 @@ opus_int silk_encode_frame_FLP( if( ( found_lower & found_upper ) == 0 ) { /* Adjust gain according to high-rate rate/distortion curve */ if( nBits > maxBits ) { - if (gainMult_Q8 < 16384) { - gainMult_Q8 *= 2; - } else { - gainMult_Q8 = 32767; - } + gainMult_Q8 = silk_min_32( 1024, gainMult_Q8*3/2 ); } else { - opus_int32 gain_factor_Q16; - gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); - gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + gainMult_Q8 = silk_max_32( 64, gainMult_Q8*4/5 ); } } else { /* Adjust gain by interpolating */ diff --git a/src/opus_encoder.c b/src/opus_encoder.c index 2701488d7fe80e4dfe4e8d828d6548b7d5a1e1ca..3933ab27775f24ae99d9262d30df933ed9238e17 100644 --- a/src/opus_encoder.c +++ b/src/opus_encoder.c @@ -556,6 +556,24 @@ OpusEncoder *opus_encoder_create(opus_int32 Fs, int channels, int application, i return st; } +#ifdef ENABLE_NEURAL_FEC +static opus_int32 compute_dred_bitrate(OpusEncoder *st, opus_int32 bitrate_bps, int frame_size) +{ + float dred_frac; + int bitrate_offset; + opus_int32 dred_bitrate; + opus_int32 target_dred_bitrate; + opus_int32 max_dred_bitrate; + if (st->dred_duration > 0) max_dred_bitrate = (120 + 6*st->dred_duration)*st->Fs/frame_size; + else max_dred_bitrate = 0; + dred_frac = MIN16(.75f, 3.f*st->silk_mode.packetLossPercentage/100.f); + bitrate_offset = st->silk_mode.useInBandFEC ? 18000 : 12000; + target_dred_bitrate = IMAX(0, (int)(dred_frac*(bitrate_bps-bitrate_offset))); + dred_bitrate = IMIN(target_dred_bitrate, max_dred_bitrate); + return dred_bitrate; +} +#endif + static opus_int32 user_bitrate_to_bitrate(OpusEncoder *st, int frame_size, int max_data_bytes) { if(!frame_size)frame_size=st->Fs/400; @@ -1100,6 +1118,9 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ int analysis_read_pos_bak=-1; int analysis_read_subframe_bak=-1; int is_silence = 0; +#endif +#ifdef ENABLE_NEURAL_FEC + opus_int32 dred_bitrate_bps; #endif opus_int activity = VAD_NO_DECISION; @@ -1235,6 +1256,11 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ /* Make sure we provide at least one byte to avoid failing. */ max_data_bytes = IMAX(1, cbrBytes); } +#ifdef ENABLE_NEURAL_FEC + /* Allocate some of the bits to DRED if needed. */ + dred_bitrate_bps = compute_dred_bitrate(st, st->bitrate_bps, frame_size); + st->bitrate_bps -= dred_bitrate_bps; +#endif if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8 || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400))) { @@ -1816,7 +1842,10 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ { if (st->mode == MODE_HYBRID) { - st->silk_mode.maxBits = IMIN(st->silk_mode.maxBits, st->silk_mode.bitRate * frame_size / st->Fs); + /* Allow SILK to steal up to 25% of the remaining bits */ + opus_int16 other_bits = IMAX(0, st->silk_mode.maxBits - st->silk_mode.bitRate * frame_size / st->Fs); + st->silk_mode.maxBits = IMAX(0, st->silk_mode.maxBits - other_bits*3/4); + st->silk_mode.useCBR = 0; } } else { /* Constrained VBR. */ @@ -1929,26 +1958,10 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->mode != MODE_SILK_ONLY) { opus_val32 celt_pred=2; - celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); /* We may still decide to disable prediction later */ if (st->silk_mode.reducedDependency) celt_pred = 0; celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred)); - - if (st->mode == MODE_HYBRID) - { - if( st->use_vbr ) { - celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); - celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); - } - } else { - if (st->use_vbr) - { - celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); - celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); - celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); - } - } } ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16); @@ -2042,8 +2055,21 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ ec_enc_done(&enc); nb_compr_bytes = ret; } else { - nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes; - ec_enc_shrink(&enc, nb_compr_bytes); + nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes; +#ifdef ENABLE_NEURAL_FEC + if (st->dred_duration > 0) + { + int max_celt_bytes; + opus_int32 dred_bytes = dred_bitrate_bps/(frame_rate*8); + /* Allow CELT to steal up to 25% of the remaining bits. */ + max_celt_bytes = nb_compr_bytes - dred_bytes*3/4; + /* But try to give CELT at least 4 bytes */ + max_celt_bytes = IMAX(ec_tell(&enc)/8 + 4, max_celt_bytes); + /* Subject to the original max. */ + nb_compr_bytes = IMIN(nb_compr_bytes, max_celt_bytes); + } +#endif + ec_enc_shrink(&enc, nb_compr_bytes); } #ifndef DISABLE_FLOAT_API @@ -2078,6 +2104,34 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (st->mode != MODE_SILK_ONLY) { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(st->use_vbr)); + if (st->mode == MODE_HYBRID) + { + if( st->use_vbr ) { + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); + } + } else { + if (st->use_vbr) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); + } + } +#ifdef ENABLE_NEURAL_FEC + /* When Using DRED CBR, we can actually make the CELT part VBR and have DRED pick up the slack. */ + if (!st->use_vbr && st->dred_duration > 0) + { + opus_int32 celt_bitrate = st->bitrate_bps; + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); + if (st->mode == MODE_HYBRID) { + celt_bitrate -= st->silk_mode.bitRate; + } + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(celt_bitrate)); + } +#endif if (st->mode != st->prev_mode && st->prev_mode > 0) { unsigned char dummy[2]; @@ -2090,10 +2144,6 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ /* If false, we already busted the budget and we'll end up with a "PLC frame" */ if (ec_tell(&enc) <= 8*nb_compr_bytes) { - /* Set the bitrate again if it was overridden in the redundancy code above*/ - if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) - celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); - celt_encoder_ctl(celt_enc, OPUS_SET_VBR(st->use_vbr)); ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc); if (ret < 0) { @@ -2104,7 +2154,7 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) { OPUS_MOVE(data+ret, data+nb_compr_bytes, redundancy_bytes); - nb_compr_bytes = nb_compr_bytes+redundancy_bytes; + nb_compr_bytes = ret+redundancy_bytes; } } } @@ -2206,7 +2256,8 @@ opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_ int dred_chunks; int dred_bytes_left; dred_chunks = IMIN((st->dred_duration+5)/4, DRED_NUM_REDUNDANCY_FRAMES/2); - dred_bytes_left = IMIN(DRED_MAX_DATA_SIZE, max_data_bytes-ret-2); + /* Remaining space for DRED, accounting for cost the 3 extra bytes for code 3, padding length, and extension number. */ + dred_bytes_left = IMIN(DRED_MAX_DATA_SIZE, max_data_bytes-ret-3); /* Check whether we actually have something to encode. */ if (dred_chunks >= 1 && dred_bytes_left >= DRED_MIN_BYTES+2) { int dred_bytes;