static double od_pvq_rate(int qg, int icgr, int theta, int ts, const od_adapt_ctx *adapt, const od_coeff *y0, int k, int n, int is_keyframe, int pli) { double rate; #if OD_PVQ_RATE_APPROX /* Estimates the number of bits it will cost to encode K pulses in N dimensions based on experimental data for bitrate vs K. */ rate = n*OD_LOG2(1+log(n*2)*k/n); OD_UNUSED(adapt); OD_UNUSED(y0); OD_UNUSED(bs); #else if (k > 0){ od_ec_enc ec; od_pvq_codeword_ctx cd; int tell; od_ec_enc_init(&ec, 1000); OD_COPY(&cd, &adapt->pvq.pvq_codeword_ctx, 1); tell = od_ec_enc_tell_frac(&ec); od_encode_pvq_codeword(&ec, &cd, y0, n - (theta != -1), k); rate = (od_ec_enc_tell_frac(&ec)-tell)/8.; od_ec_enc_clear(&ec); } else rate = 0; #endif if (qg > 0 && theta >= 0) { /* Approximate cost of entropy-coding theta */ rate += .9*OD_LOG2(ts); /* Adding a cost to using the H/V pred because it's going to be off most of the time. Cost is optimized on subset1, while making sure we don't hurt the checkerboard image too much. FIXME: Do real RDO instead of this arbitrary cost. */ if (is_keyframe && pli == 0) rate += 6; if (qg == icgr) rate -= .5; } return rate; }
/** Computes Householder reflection that aligns the reference r to the * dimension in r with the greatest absolute value. The reflection * vector is returned in r. * * @param [in,out] r reference vector to be reflected, reflection * also returned in r * @param [in] n number of dimensions in r * @param [in] gr gain of reference vector * @param [out] sign sign of reflection * @return dimension number to which reflection aligns **/ int od_compute_householder(od_val16 *r, int n, od_val32 gr, int *sign, int shift) { int m; int i; int s; od_val16 maxr; OD_UNUSED(shift); /* Pick component with largest magnitude. Not strictly * necessary, but it helps numerical stability */ m = 0; maxr = 0; for (i = 0; i < n; i++) { if (OD_ABS(r[i]) > maxr) { maxr = OD_ABS(r[i]); m = i; } } s = r[m] > 0 ? 1 : -1; /* This turns r into a Householder reflection vector that would reflect * the original r[] to e_m */ r[m] += OD_SHR_ROUND(gr*s, shift); *sign = s; return m; }
/** Encode a coefficient block (excepting DC) using PVQ * * @param [in,out] enc daala encoder context * @param [in] ref 'reference' (prediction) vector * @param [in] in coefficient block to quantize and encode * @param [out] out quantized coefficient block * @param [in] q0 scale/quantizer * @param [in] pli plane index * @param [in] bs log of the block size minus two * @param [in] beta per-band activity masking beta param * @param [in] robust make stream robust to error in the reference * @param [in] is_keyframe whether we're encoding a keyframe * @param [in] q_scaling scaling factor to apply to quantizer * @param [in] bx x-coordinate of this block * @param [in] by y-coordinate of this block * @param [in] qm QM with magnitude compensation * @param [in] qm_inv Inverse of QM with magnitude compensation * @return Returns 1 if both DC and AC coefficients are skipped, * zero otherwise */ int od_pvq_encode(daala_enc_ctx *enc, od_coeff *ref, const od_coeff *in, od_coeff *out, int q0, int pli, int bs, const double *beta, int robust, int is_keyframe, int q_scaling, int bx, int by, const int16_t *qm, const int16_t *qm_inv){ int theta[PVQ_MAX_PARTITIONS]; int max_theta[PVQ_MAX_PARTITIONS]; int qg[PVQ_MAX_PARTITIONS]; int k[PVQ_MAX_PARTITIONS]; od_coeff y[OD_BSIZE_MAX*OD_BSIZE_MAX]; int *exg; int *ext; int nb_bands; int i; const int *off; int size[PVQ_MAX_PARTITIONS]; generic_encoder *model; double skip_diff; int tell; uint16_t *skip_cdf; od_rollback_buffer buf; int dc_quant; int flip; int cfl_encoded; int skip_rest; int skip_dir; int skip_theta_value; const unsigned char *pvq_qm; double dc_rate; #if !OD_SIGNAL_Q_SCALING OD_UNUSED(q_scaling); OD_UNUSED(bx); OD_UNUSED(by); #endif pvq_qm = &enc->state.pvq_qm_q4[pli][0]; exg = &enc->state.adapt.pvq.pvq_exg[pli][bs][0]; ext = enc->state.adapt.pvq.pvq_ext + bs*PVQ_MAX_PARTITIONS; skip_cdf = enc->state.adapt.skip_cdf[2*bs + (pli != 0)]; model = enc->state.adapt.pvq.pvq_param_model; nb_bands = OD_BAND_OFFSETS[bs][0]; off = &OD_BAND_OFFSETS[bs][1]; dc_quant = OD_MAXI(1, q0*pvq_qm[od_qm_get_index(bs, 0)] >> 4); tell = 0; for (i = 0; i < nb_bands; i++) size[i] = off[i+1] - off[i]; skip_diff = 0; flip = 0; /*If we are coding a chroma block of a keyframe, we are doing CfL.*/ if (pli != 0 && is_keyframe) { od_val32 xy; xy = 0; /*Compute the dot-product of the first band of chroma with the luma ref.*/ for (i = off[0]; i < off[1]; i++) { #if defined(OD_FLOAT_PVQ) xy += ref[i]*(double)qm[i]*OD_QM_SCALE_1* (double)in[i]*(double)qm[i]*OD_QM_SCALE_1; #else xy += (ref[i] >> OD_CFL_FLIP_SHIFT)*(in[i] >> OD_CFL_FLIP_SHIFT); #endif } /*If cos(theta) < 0, then |theta| > pi/2 and we should negate the ref.*/ if (xy < 0) { flip = 1; for(i = off[0]; i < off[nb_bands]; i++) ref[i] = -ref[i]; } }