ref: bcd6abad43338d7a60e1fab222869e099590f32f
parent: 0247d34d6ad5dfebc65c6de1d9f5a23981f0f40b
author: Jean-Marc Valin <[email protected]>
date: Sun Dec 6 05:50:15 EST 2015
Quality: Makes real CELT VBR work for hybrid too
--- a/celt/celt_encoder.c
+++ b/celt/celt_encoder.c
@@ -1345,6 +1345,7 @@
opus_int32 total_boost;
opus_int32 balance;
opus_int32 tell;
+ opus_int32 tell0_frac;
int prefilter_tapset=0;
int pf_on;
int anti_collapse_rsv;
@@ -1367,6 +1368,7 @@
opus_val16 temporal_vbr=0;
opus_val16 surround_trim = 0;
opus_int32 equiv_rate = 510000;
+ int hybrid;
VARDECL(opus_val16, surround_dynalloc);
ALLOC_STACK;
@@ -1376,6 +1378,7 @@
eBands = mode->eBands;
start = st->start;
end = st->end;
+ hybrid = start != 0;
tf_estimate = 0;
if (nbCompressedBytes<2 || pcm==NULL)
{
@@ -1402,9 +1405,10 @@
if (enc==NULL)
{
- tell=1;
+ tell0_frac=tell=1;
nbFilledBytes=0;
} else {
+ tell0_frac=tell=ec_tell_frac(enc);
tell=ec_tell(enc);
nbFilledBytes=(tell+4)>>3;
}
@@ -1457,7 +1461,7 @@
if (st->bitrate!=OPUS_BITRATE_MAX)
nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes,
(tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling));
- effectiveBytes = nbCompressedBytes;
+ effectiveBytes = nbCompressedBytes - nbFilledBytes;
}
if (st->bitrate != OPUS_BITRATE_MAX)
equiv_rate = st->bitrate - (40*C+20)*((400>>LM) - 50);
@@ -1912,17 +1916,30 @@
/* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms.
The CELT allocator will just not be able to use more than that anyway. */
nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM));
- base_target = vbr_rate - ((40*C+20)<<BITRES);
+ if (!hybrid)
+ {
+ base_target = vbr_rate - ((40*C+20)<<BITRES);
+ } else {
+ base_target = IMAX(0, vbr_rate - ((9*C+4)<<BITRES));
+ }
if (st->constrained_vbr)
base_target += (st->vbr_offset>>lm_diff);
- target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate,
+ if (!hybrid)
+ {
+ target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate,
st->lastCodedBands, C, st->intensity, st->constrained_vbr,
st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth,
st->variable_duration, st->lfe, st->energy_mask!=NULL, surround_masking,
temporal_vbr);
-
+ } else {
+ target = base_target;
+ /* If we have a strong transient, let's make sure it has enough bits to code
+ the first two bands, so that it can use folding rather than noise. */
+ if (tf_estimate > QCONST16(.7f,14))
+ target = IMAX(base_target, 50<<BITRES);
+ }
/* The current offset is removed from the target and the space used
so far is added*/
target=target+tell;
@@ -1930,11 +1947,16 @@
result in the encoder running out of bits.
The margin of 2 bytes ensures that none of the bust-prevention logic
in the decoder will have triggered so far. */
- min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2 - nbFilledBytes;
+ min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2;
+ /* Take into account the 37 bits we need to have left in the packet to
+ signal a redundant frame in hybrid mode. Creating a shorter packet would
+ create an entropy coder desync. */
+ if (hybrid)
+ min_allowed = IMAX(min_allowed, (tell0_frac+(37<<BITRES)+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3));
nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3);
nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes);
- nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes) - nbFilledBytes;
+ nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes);
/* By how much did we "miss" the target on that frame */
delta = target - vbr_rate;
@@ -1981,7 +2003,7 @@
st->vbr_reservoir = 0;
/*printf ("+%d\n", adjust);*/
}
- nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes);
+ nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes);
/*printf("%d\n", nbCompressedBytes*50*8);*/
/* This moves the raw bits to take into account the new compressed size */
ec_enc_shrink(enc, nbCompressedBytes);
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -1733,7 +1733,9 @@
if (redundancy)
len += st->mode == MODE_HYBRID ? 3 : 1;
if( st->use_vbr ) {
- nb_compr_bytes = len + bytes_target - (st->silk_mode.bitRate * frame_size) / (8 * st->Fs);
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate));
+ nb_compr_bytes = max_data_bytes-1-redundancy_bytes;
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0));
} else {
/* check if SILK used up too much */
nb_compr_bytes = len > bytes_target ? len : bytes_target;
@@ -1858,6 +1860,7 @@
int err;
celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL);
if (err < 0)
{
@@ -1884,6 +1887,10 @@
/* If false, we already busted the budget and we'll end up with a "PLC packet" */
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)
{
@@ -1890,6 +1897,12 @@
RESTORE_STACK;
return OPUS_INTERNAL_ERROR;
}
+ /* Put CELT->SILK redundancy data in the right place. */
+ if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr)
+ {
+ OPUS_COPY(data+ret, data+nb_compr_bytes, redundancy_bytes);
+ nb_compr_bytes = nb_compr_bytes+redundancy_bytes;
+ }
}
}
@@ -1905,7 +1918,15 @@
celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
+ if (st->mode == MODE_HYBRID)
+ {
+ /* Shrink packet to what the encoder actually used. */
+ nb_compr_bytes = ret;
+ ec_enc_shrink(&enc, nb_compr_bytes);
+ }
/* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */
celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL);