diff options
author | Jean-Marc Valin <Jean-Marc.Valin@csiro.au> | 2008-05-07 07:44:39 +0400 |
---|---|---|
committer | Jean-Marc Valin <Jean-Marc.Valin@csiro.au> | 2008-05-07 07:44:39 +0400 |
commit | ad6371906a816bef202f10fb3cca602280a8765f (patch) | |
tree | 2acd65ecbef687f409826b9e3e40022e4b7f943b | |
parent | 827f93175bc532beab5c5d49eed6649282795708 (diff) |
Implemented rate-dependant allocation for the fine energy quantisation.
-rw-r--r-- | libcelt/celt.c | 4 | ||||
-rw-r--r-- | libcelt/dump_modes.c | 1 | ||||
-rw-r--r-- | libcelt/modes.c | 35 | ||||
-rw-r--r-- | libcelt/modes.h | 1 | ||||
-rw-r--r-- | libcelt/quant_bands.c | 86 |
5 files changed, 108 insertions, 19 deletions
diff --git a/libcelt/celt.c b/libcelt/celt.c index f28be89..fddd416 100644 --- a/libcelt/celt.c +++ b/libcelt/celt.c @@ -321,7 +321,7 @@ int EXPORT celt_encode(CELTEncoder * restrict st, celt_int16_t * restrict pcm, u for (i=0;i<C*N;i++) P[i] = 0; } - quant_energy(st->mode, bandE, st->oldBandE, nbCompressedBytes*8/3, st->mode->prob, &st->enc); + quant_energy(st->mode, bandE, st->oldBandE, 20+nbCompressedBytes*8/5, st->mode->prob, &st->enc); if (C==2) { @@ -589,7 +589,7 @@ int EXPORT celt_decode(CELTDecoder * restrict st, unsigned char *data, int len, } /* Get band energies */ - unquant_energy(st->mode, bandE, st->oldBandE, len*8/3, st->mode->prob, &dec); + unquant_energy(st->mode, bandE, st->oldBandE, 20+len*8/5, st->mode->prob, &dec); /* Pitch MDCT */ compute_mdcts(st->mode, st->mode->window, st->out_mem+pitch_index*C, freq); diff --git a/libcelt/dump_modes.c b/libcelt/dump_modes.c index 6a19086..9f00dcc 100644 --- a/libcelt/dump_modes.c +++ b/libcelt/dump_modes.c @@ -161,6 +161,7 @@ void dump_modes(FILE *file, CELTMode **modes, int nb_modes) fprintf(file, "window%d,\t/* window */\n", mode->overlap); fprintf(file, "{psy_decayR_%d},\t/* psy */\n", mode->Fs); fprintf(file, "0,\t/* prob */\n"); + fprintf(file, "0,\t/* energy_alloc */\n"); fprintf(file, "0x%x,\t/* marker */\n", 0xa110ca7e); fprintf(file, "};\n"); } diff --git a/libcelt/modes.c b/libcelt/modes.c index 29ea983..6b9af97 100644 --- a/libcelt/modes.c +++ b/libcelt/modes.c @@ -232,6 +232,38 @@ static void compute_allocation_table(CELTMode *mode, int res) #endif /* STATIC_MODES */ +static void compute_energy_allocation_table(CELTMode *mode) +{ + int i, j; + celt_int16_t *alloc; + + alloc = celt_alloc(sizeof(celt_int16_t)*(mode->nbAllocVectors*(mode->nbEBands+1))); + for (i=0;i<mode->nbAllocVectors;i++) + { + int sum = 0; + int min_bits = 1; + if (mode->allocVectors[i*mode->nbEBands]>12) + min_bits = 2; + if (mode->allocVectors[i*mode->nbEBands]>24) + min_bits = 3; + for (j=0;j<mode->nbEBands;j++) + { + alloc[i*(mode->nbEBands+1)+j] = mode->allocVectors[i*mode->nbEBands+j] + / (mode->eBands[j+1]-mode->eBands[j]-1); + if (alloc[i*(mode->nbEBands+1)+j]<min_bits) + alloc[i*(mode->nbEBands+1)+j] = min_bits; + if (alloc[i*(mode->nbEBands+1)+j]>7) + alloc[i*(mode->nbEBands+1)+j] = 7; + sum += alloc[i*(mode->nbEBands+1)+j]; + /*printf ("%d ", alloc[i*(mode->nbEBands+1)+j]);*/ + /*printf ("%f ", mode->allocVectors[i*mode->nbEBands+j]*1.f/(mode->eBands[j+1]-mode->eBands[j]-1));*/ + } + alloc[i*(mode->nbEBands+1)+mode->nbEBands] = sum; + /*printf ("\n");*/ + } + mode->energy_alloc = alloc; +} + CELTMode EXPORT *celt_mode_create(celt_int32_t Fs, int channels, int frame_size, int lookahead, int *error) { int i; @@ -342,6 +374,8 @@ CELTMode EXPORT *celt_mode_create(celt_int32_t Fs, int channels, int frame_size, mode->fft = pitch_state_alloc(MAX_PERIOD); mode->prob = quant_prob_alloc(mode); + compute_energy_allocation_table(mode); + if (error) *error = CELT_OK; return mode; @@ -378,6 +412,7 @@ void EXPORT celt_mode_destroy(CELTMode *mode) mdct_clear(&mode->mdct); pitch_state_free(mode->fft); quant_prob_free(mode->prob); + celt_free((celt_int16_t *)mode->energy_alloc); celt_free((CELTMode *)mode); } diff --git a/libcelt/modes.h b/libcelt/modes.h index d7b59f0..d47825e 100644 --- a/libcelt/modes.h +++ b/libcelt/modes.h @@ -96,6 +96,7 @@ struct CELTMode { struct PsyDecay psy; int *prob; + const celt_int16_t *energy_alloc; celt_uint32_t marker_end; }; diff --git a/libcelt/quant_bands.c b/libcelt/quant_bands.c index 5e6ec9a..2c6fb63 100644 --- a/libcelt/quant_bands.c +++ b/libcelt/quant_bands.c @@ -48,7 +48,47 @@ const celt_word16_t eMeans[24] = {45.f, -8.f, -12.f, -2.5f, 1.f, 0.f, 0.f, 0.f, #endif /*const int frac[24] = {4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};*/ -const int frac[24] = {8, 6, 5, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; +/*const int frac[24] = {8, 6, 5, 4, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};*/ + +static void compute_fine_allocation(const CELTMode *m, celt_int16_t *bits, int budget) +{ + int i,j; + int len; + len = m->nbEBands; + for (i=0;i<m->nbAllocVectors;i++) + { + if (m->energy_alloc[i*(len+1)+len] > budget) + break; + } + if (i==0) + { + for (j=0;j<len;j++) + bits[j] = 0; + } else { + for (j=0;j<len;j++) + bits[j] = m->energy_alloc[(i-1)*(len+1)+j]; + budget -= m->energy_alloc[(i-1)*(len+1)+len]; + } + if (i<m->nbAllocVectors) + { + j=0; + while (budget>0) + { + if (m->energy_alloc[i*(len+1)+j]>bits[j]) + { + bits[j]++; + budget--; + } + j++; + if (j>=len) + j=0; + } + } + + /*for (j=0;j<len;j++) + printf ("%d ", bits[j]); + printf ("\n");*/ +} #ifdef FIXED_POINT static inline celt_ener_t dB2Amp(celt_ener_t dB) @@ -155,11 +195,13 @@ static void quant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_word1 celt_word16_t coef = m->ePredCoef; celt_word16_t beta; VARDECL(celt_word16_t, error); + VARDECL(celt_int16_t, fine_quant); SAVE_STACK; /* The .7 is a heuristic */ beta = MULT16_16_Q15(QCONST16(.8f,15),coef); ALLOC(error, m->nbEBands, celt_word16_t); + ALLOC(fine_quant, m->nbEBands, celt_int16_t); bits = ec_enc_tell(enc, 0); /* Encode at a fixed coarse resolution */ for (i=0;i<m->nbEBands;i++) @@ -177,8 +219,9 @@ static void quant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_word1 #else qi = (int)floor(.5+f); #endif - /* If we don't have enough bits to encode all the energy, just assume something safe. */ - if (ec_enc_tell(enc, 0) - bits > budget) + /* If we don't have enough bits to encode all the energy, just assume something safe. + We allow slightly busting the budget here */ + if (ec_enc_tell(enc, 0) - bits > budget+16) qi = -1; else ec_laplace_encode_start(enc, qi, prob[2*i], prob[2*i+1]); @@ -189,24 +232,25 @@ static void quant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_word1 prev = mean+prev+MULT16_16_Q15(Q15ONE-beta,q); } + + compute_fine_allocation(m, fine_quant, budget-(ec_enc_tell(enc, 0)-bits)); + /* Encode finer resolution */ for (i=0;i<m->nbEBands;i++) { int q2; - celt_word16_t offset = (error[i]+QCONST16(.5f,8))*frac[i]; - /* FIXME: Instead of giving up without warning, we should degrade everything gracefully */ - if (ec_enc_tell(enc, 0) - bits + celt_ilog2(frac[i]) >= budget) - break; + celt_int16_t frac = 1<<fine_quant[i]; + celt_word16_t offset = (error[i]+QCONST16(.5f,8))*frac; #ifdef FIXED_POINT /* Has to be without rounding */ q2 = offset>>8; #else q2 = (int)floor(offset); #endif - if (q2 > frac[i]-1) - q2 = frac[i]-1; - enc_frac(enc, q2, frac[i]); - offset = EXTRACT16(celt_div(SHL16(q2,8)+QCONST16(.5,8),frac[i])-QCONST16(.5f,8)); + if (q2 > frac-1) + q2 = frac-1; + enc_frac(enc, q2, frac); + offset = EXTRACT16(celt_div(SHL16(q2,8)+QCONST16(.5,8),frac)-QCONST16(.5f,8)); oldEBands[i] += PSHR32(MULT16_16(DB_SCALING*6,offset),8); /*printf ("%f ", error[i] - offset);*/ } @@ -227,7 +271,11 @@ static void unquant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_wor celt_word16_t prev = 0; celt_word16_t coef = m->ePredCoef; /* The .7 is a heuristic */ + VARDECL(celt_int16_t, fine_quant); celt_word16_t beta = MULT16_16_Q15(QCONST16(.8f,15),coef); + SAVE_STACK; + + ALLOC(fine_quant, m->nbEBands, celt_int16_t); bits = ec_dec_tell(dec, 0); /* Decode at a fixed coarse resolution */ @@ -236,8 +284,9 @@ static void unquant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_wor int qi; celt_word16_t q; celt_word16_t mean = MULT16_16_Q15(Q15ONE-coef,eMeans[i]); - /* If we didn't have enough bits to encode all the energy, just assume something safe. */ - if (ec_dec_tell(dec, 0) - bits > budget) + /* If we didn't have enough bits to encode all the energy, just assume something safe. + We allow slightly busting the budget here */ + if (ec_dec_tell(dec, 0) - bits > budget+16) qi = -1; else qi = ec_laplace_decode_start(dec, prob[2*i], prob[2*i+1]); @@ -247,21 +296,24 @@ static void unquant_energy_mono(const CELTMode *m, celt_ener_t *eBands, celt_wor prev = mean+prev+MULT16_16_Q15(Q15ONE-beta,q); } + + compute_fine_allocation(m, fine_quant, budget-(ec_dec_tell(dec, 0)-bits)); + /* Decode finer resolution */ for (i=0;i<m->nbEBands;i++) { int q2; + celt_int16_t frac = 1<<fine_quant[i]; celt_word16_t offset; - if (ec_dec_tell(dec, 0) - bits + celt_ilog2(frac[i]) >= budget) - break; - q2 = dec_frac(dec, frac[i]); - offset = EXTRACT16(celt_div(SHL16(q2,8)+QCONST16(.5,8),frac[i])-QCONST16(.5f,8)); + q2 = dec_frac(dec, frac); + offset = EXTRACT16(celt_div(SHL16(q2,8)+QCONST16(.5,8),frac)-QCONST16(.5f,8)); oldEBands[i] += PSHR32(MULT16_16(DB_SCALING*6,offset),8); } for (i=0;i<m->nbEBands;i++) { eBands[i] = dB2Amp(oldEBands[i]); } + RESTORE_STACK; /*printf ("\n");*/ } |