diff options
author | Jean-Marc Valin <jmvalin@jmvalin.ca> | 2012-07-11 10:54:47 +0400 |
---|---|---|
committer | Jean-Marc Valin <jmvalin@jmvalin.ca> | 2012-07-13 22:52:52 +0400 |
commit | cf1053dc85625deff2dfd600c83e9201b314f46b (patch) | |
tree | e0cf0b6ae8149199acf46e83080ff8e5dc5d5838 | |
parent | c5880fe48bdeb5ae40ceeb679b9c1a633448fab4 (diff) |
Implements OPUS_{GET,SET}_LSB_DEPTH
This is used to avoid dynalloc doing silly things on periodic LSB
patterns and to reduce the bitrate on near-silence.
-rw-r--r-- | celt/celt.c | 53 | ||||
-rw-r--r-- | celt/mathops.h | 48 | ||||
-rw-r--r-- | celt/quant_bands.c | 8 | ||||
-rw-r--r-- | celt/quant_bands.h | 6 | ||||
-rw-r--r-- | include/opus_defines.h | 13 | ||||
-rw-r--r-- | src/opus_demo.c | 1 | ||||
-rw-r--r-- | src/opus_encoder.c | 12 |
7 files changed, 114 insertions, 27 deletions
diff --git a/celt/celt.c b/celt/celt.c index 8f7f4287..6c28bcd4 100644 --- a/celt/celt.c +++ b/celt/celt.c @@ -156,6 +156,7 @@ struct OpusCustomEncoder { int signalling; int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */ int loss_rate; + int lsb_depth; /* Everything beyond this point gets cleared on a reset */ #define ENCODER_RESET_START rng @@ -187,6 +188,7 @@ struct OpusCustomEncoder { opus_int32 vbr_drift; opus_int32 vbr_offset; opus_int32 vbr_count; + opus_val16 overlap_max; #ifdef RESYNTH celt_sig syn_mem[2][2*MAX_PERIOD]; @@ -267,6 +269,7 @@ OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_init(CELTEncoder *st, const CELTMod st->vbr = 0; st->force_intra = 0; st->complexity = 5; + st->lsb_depth=24; opus_custom_encoder_ctl(st, OPUS_RESET_STATE); @@ -987,6 +990,8 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int f opus_val16 stereo_saving = 0; int pitch_change=0; opus_int32 tot_boost=0; + opus_val16 sample_max; + opus_val16 maxDepth; ALLOC_STACK; tf_estimate = QCONST16(1.0f,14); @@ -1104,6 +1109,9 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int f ALLOC(in, CC*(N+st->overlap), celt_sig); + sample_max=MAX16(st->overlap_max, celt_maxabs16(pcm, C*(N-st->mode->overlap))); + st->overlap_max=celt_maxabs16(pcm+C*(N-st->mode->overlap), C*st->mode->overlap); + sample_max=MAX16(sample_max, st->overlap_max); /* Find pitch period and gain */ { VARDECL(celt_sig, _pre); @@ -1143,13 +1151,17 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int f *inp = tmp + st->preemph_memE[c]; st->preemph_memE[c] = MULT16_32_Q15(st->mode->preemph[1], *inp) - MULT16_32_Q15(st->mode->preemph[0], tmp); - silence = silence && *inp == 0; inp++; } OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD); OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+st->overlap)+st->overlap, N); } while (++c<CC); +#ifdef FIXED_POINT + silence = (sample_max==0); +#else + silence = (sample_max <= (opus_val16)1/(1<<st->lsb_depth)); +#endif #ifdef FUZZING if ((rand()&0x3F)==0) silence = 1; @@ -1413,10 +1425,12 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int f for (i=0;i<st->mode->nbEBands;i++) offsets[i] = 0; /* Dynamic allocation code */ + maxDepth=-QCONST16(32.f, DB_SHIFT); /* Make sure that dynamic allocation can't make us bust the budget */ if (effectiveBytes > 50 && LM>=1) { - opus_val16 follower[42]={0}; + VARDECL(opus_val16, follower); + ALLOC(follower, C*st->mode->nbEBands, opus_val16); c=0;do { follower[c*st->mode->nbEBands] = bandLogE2[c*st->mode->nbEBands]; @@ -1424,6 +1438,17 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int f follower[c*st->mode->nbEBands+i] = MIN16(follower[c*st->mode->nbEBands+i-1]+QCONST16(1.5f,DB_SHIFT), bandLogE2[c*st->mode->nbEBands+i]); for (i=effEnd-2;i>=0;i--) follower[c*st->mode->nbEBands+i] = MIN16(follower[c*st->mode->nbEBands+i], MIN16(follower[c*st->mode->nbEBands+i+1]+QCONST16(2.f,DB_SHIFT), bandLogE2[c*st->mode->nbEBands+i])); + for (i=0;i<st->end;i++) + { + opus_val16 noise_floor; + /* Noise floor must take into account eMeans, the depth, the width of the bands + and the preemphasis filter (approx. square of bark band ID) */ + noise_floor = MULT16_16(QCONST16(0.0625f, DB_SHIFT),st->mode->logN[i]) + +QCONST16(.5f,DB_SHIFT)+SHL16(9-st->lsb_depth,DB_SHIFT)-SHL16(eMeans[i],6) + +MULT16_16(QCONST16(.0062,DB_SHIFT),(i+5)*(i+5)); + follower[c*st->mode->nbEBands+i] = MAX16(follower[c*st->mode->nbEBands+i], noise_floor); + maxDepth = MAX16(maxDepth, bandLogE[i]-noise_floor); + } } while (++c<C); if (C==2) { @@ -1606,6 +1631,16 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int f } #endif + { + opus_int32 floor_depth; + int bins; + bins = st->mode->eBands[st->mode->nbEBands-2]<<LM; + /*floor_depth = SHR32(MULT16_16((C*bins<<BITRES),celt_log2(SHL32(MAX16(1,sample_max),13))), DB_SHIFT);*/ + floor_depth = SHR32(MULT16_16((C*bins<<BITRES),maxDepth), DB_SHIFT); + floor_depth = IMAX(floor_depth, new_target>>2); + new_target = IMIN(new_target, floor_depth); + /*printf("%f %d\n", maxDepth, floor_depth);*/ + } /* The current offset is removed from the target and the space used so far is added*/ target=new_target+tell; @@ -2004,6 +2039,20 @@ int opus_custom_encoder_ctl(CELTEncoder * restrict st, int request, ...) st->stream_channels = value; } break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + goto bad_arg; + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value=st->lsb_depth; + } + break; case OPUS_RESET_STATE: { int i; diff --git a/celt/mathops.h b/celt/mathops.h index 4e977956..3c7486ad 100644 --- a/celt/mathops.h +++ b/celt/mathops.h @@ -43,6 +43,33 @@ unsigned isqrt32(opus_uint32 _val); +#ifndef OVERRIDE_CELT_MAXABS16 +static inline opus_val16 celt_maxabs16(const opus_val16 *x, int len) +{ + int i; + opus_val16 maxval = 0; + for (i=0;i<len;i++) + maxval = MAX16(maxval, ABS16(x[i])); + return maxval; +} +#endif + +#ifndef OVERRIDE_CELT_MAXABS32 +#ifdef FIXED_POINT +static inline opus_val32 celt_maxabs32(const opus_val32 *x, int len) +{ + int i; + opus_val32 maxval = 0; + for (i=0;i<len;i++) + maxval = MAX32(maxval, ABS32(x[i])); + return maxval; +} +#else +#define celt_maxabs32(x,len) celt_maxabs16(x,len) +#endif +#endif + + #ifndef FIXED_POINT #define PI 3.141592653f @@ -117,27 +144,6 @@ static inline opus_int16 celt_ilog2(opus_int32 x) } #endif -#ifndef OVERRIDE_CELT_MAXABS16 -static inline opus_val16 celt_maxabs16(opus_val16 *x, int len) -{ - int i; - opus_val16 maxval = 0; - for (i=0;i<len;i++) - maxval = MAX16(maxval, ABS16(x[i])); - return maxval; -} -#endif - -#ifndef OVERRIDE_CELT_MAXABS32 -static inline opus_val32 celt_maxabs32(opus_val32 *x, int len) -{ - int i; - opus_val32 maxval = 0; - for (i=0;i<len;i++) - maxval = MAX32(maxval, ABS32(x[i])); - return maxval; -} -#endif /** Integer log in base2. Defined for zero, but not for negative numbers */ static inline opus_int16 celt_zlog2(opus_val32 x) diff --git a/celt/quant_bands.c b/celt/quant_bands.c index b1d4eb15..241392f1 100644 --- a/celt/quant_bands.c +++ b/celt/quant_bands.c @@ -40,8 +40,8 @@ #include "rate.h" #ifdef FIXED_POINT -/* Mean energy in each band quantized in Q6 */ -static const signed char eMeans[25] = { +/* Mean energy in each band quantized in Q4 */ +const signed char eMeans[25] = { 103,100, 92, 85, 81, 77, 72, 70, 78, 75, 73, 71, 78, 74, 69, @@ -49,8 +49,8 @@ static const signed char eMeans[25] = { 60, 60, 60, 60, 60 }; #else -/* Mean energy in each band quantized in Q6 and converted back to float */ -static const opus_val16 eMeans[25] = { +/* Mean energy in each band quantized in Q4 and converted back to float */ +const opus_val16 eMeans[25] = { 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f, 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f, 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f, diff --git a/celt/quant_bands.h b/celt/quant_bands.h index bec2855c..b3187fad 100644 --- a/celt/quant_bands.h +++ b/celt/quant_bands.h @@ -35,6 +35,12 @@ #include "entdec.h" #include "mathops.h" +#ifdef FIXED_POINT +extern const signed char eMeans[25]; +#else +extern const opus_val16 eMeans[25]; +#endif + void amp2Log2(const CELTMode *m, int effEnd, int end, celt_ener *bandE, opus_val16 *bandLogE, int C); diff --git a/include/opus_defines.h b/include/opus_defines.h index 0b828179..5155afc8 100644 --- a/include/opus_defines.h +++ b/include/opus_defines.h @@ -130,6 +130,8 @@ extern "C" { #define OPUS_GET_PITCH_REQUEST 4033 #define OPUS_SET_GAIN_REQUEST 4034 #define OPUS_GET_GAIN_REQUEST 4045 +#define OPUS_SET_LSB_DEPTH_REQUEST 4036 +#define OPUS_GET_LSB_DEPTH_REQUEST 4037 /* Macros to trigger compilation errors when the wrong types are provided to a CTL */ #define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) @@ -440,6 +442,17 @@ extern "C" { * @hideinitializer */ #define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) +/** Configures the depth of signal being encoded. + * This is a hint which helps the encoder identify silence and near-silence. + * The supported values are between 8 and 24 (default) + * @param[in] x <tt>opus_int32</tt>: Input precision + * @hideinitializer */ +#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal depth. @see OPUS_SET_LSB_DEPTH + * + * @param[out] x <tt>opus_int32*</tt>: Input precision + * @hideinitializer */ +#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x) /**@}*/ /** @defgroup opus_decoderctls Decoder related CTLs diff --git a/src/opus_demo.c b/src/opus_demo.c index 0ca7326e..bc357902 100644 --- a/src/opus_demo.c +++ b/src/opus_demo.c @@ -498,6 +498,7 @@ int main(int argc, char *argv[]) opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc)); opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip)); + opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16)); } if (!encode_only) { diff --git a/src/opus_encoder.c b/src/opus_encoder.c index 681a61b4..7283b1cc 100644 --- a/src/opus_encoder.c +++ b/src/opus_encoder.c @@ -1616,6 +1616,18 @@ int opus_encoder_ctl(OpusEncoder *st, int request, ...) *value = st->rangeFinal; } break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + ret = celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(value)); + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + celt_encoder_ctl(celt_enc, OPUS_GET_LSB_DEPTH(value)); + } + break; case OPUS_RESET_STATE: { void *silk_enc; |