| /* |
| * Copyright (c) 2001-2016, Alliance for Open Media. All rights reserved |
| * |
| * This source code is subject to the terms of the BSD 2 Clause License and |
| * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License |
| * was not distributed with this source code in the LICENSE file, you can |
| * obtain it at www.aomedia.org/license/software. If the Alliance for Open |
| * Media Patent License 1.0 was not distributed with this source code in the |
| * PATENTS file, you can obtain it at www.aomedia.org/license/patent. |
| */ |
| |
| /* clang-format off */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include "config.h" |
| #endif |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include "./aom_config.h" |
| #include "aom_dsp/bitreader.h" |
| #include "aom_dsp/entcode.h" |
| #include "aom_dsp/entdec.h" |
| #include "av1/common/odintrin.h" |
| #include "av1/common/partition.h" |
| #include "av1/common/pvq_state.h" |
| #include "av1/decoder/decint.h" |
| #include "av1/decoder/pvq_decoder.h" |
| #include "aom_ports/system_state.h" |
| |
| int aom_read_symbol_pvq_(aom_reader *r, aom_cdf_prob *cdf, int nsymbs |
| ACCT_STR_PARAM) { |
| if (cdf[0] == 0) |
| aom_cdf_init_q15_1D(cdf, nsymbs, CDF_SIZE(nsymbs)); |
| return aom_read_symbol(r, cdf, nsymbs, ACCT_STR_NAME); |
| } |
| |
| static void aom_decode_pvq_codeword(aom_reader *r, od_pvq_codeword_ctx *ctx, |
| od_coeff *y, int n, int k) { |
| int i; |
| aom_decode_band_pvq_splits(r, ctx, y, n, k, 0); |
| for (i = 0; i < n; i++) { |
| if (y[i] && aom_read_bit(r, "pvq:sign")) y[i] = -y[i]; |
| } |
| } |
| |
| /** Inverse of neg_interleave; decodes the interleaved gain. |
| * |
| * @param [in] x quantized/interleaved gain to decode |
| * @param [in] ref quantized gain of the reference |
| * @return original quantized gain value |
| */ |
| static int neg_deinterleave(int x, int ref) { |
| if (x < 2*ref-1) { |
| if (x & 1) return ref - 1 - (x >> 1); |
| else return ref + (x >> 1); |
| } |
| else return x+1; |
| } |
| |
| /** Synthesizes one parition of coefficient values from a PVQ-encoded |
| * vector. |
| * |
| * @param [out] xcoeff output coefficient partition (x in math doc) |
| * @param [in] ypulse PVQ-encoded values (y in math doc); in the noref |
| * case, this vector has n entries, in the |
| * reference case it contains n-1 entries |
| * (the m-th entry is not included) |
| * @param [in] ref reference vector (prediction) |
| * @param [in] n number of elements in this partition |
| * @param [in] gr gain of the reference vector (prediction) |
| * @param [in] noref indicates presence or lack of prediction |
| * @param [in] g decoded quantized vector gain |
| * @param [in] theta decoded theta (prediction error) |
| * @param [in] qm QM with magnitude compensation |
| * @param [in] qm_inv Inverse of QM with magnitude compensation |
| */ |
| static void pvq_synthesis(od_coeff *xcoeff, od_coeff *ypulse, od_val16 *r16, |
| int n, od_val32 gr, int noref, od_val32 g, od_val32 theta, const int16_t *qm_inv, |
| int shift) { |
| int s; |
| int m; |
| /* Sign of the Householder reflection vector */ |
| s = 0; |
| /* Direction of the Householder reflection vector */ |
| m = noref ? 0 : od_compute_householder(r16, n, gr, &s, shift); |
| od_pvq_synthesis_partial(xcoeff, ypulse, r16, n, noref, g, theta, m, s, |
| qm_inv); |
| } |
| |
| typedef struct { |
| od_coeff *ref; |
| int nb_coeffs; |
| int allow_flip; |
| } cfl_ctx; |
| |
| /** Decodes a single vector of integers (eg, a partition within a |
| * coefficient block) encoded using PVQ |
| * |
| * @param [in,out] ec range encoder |
| * @param [in] q0 scale/quantizer |
| * @param [in] n number of coefficients in partition |
| * @param [in,out] model entropy decoder state |
| * @param [in,out] adapt adaptation context |
| * @param [in,out] exg ExQ16 expectation of decoded gain value |
| * @param [in,out] ext ExQ16 expectation of decoded theta value |
| * @param [in] ref 'reference' (prediction) vector |
| * @param [out] out decoded partition |
| * @param [out] noref boolean indicating absence of reference |
| * @param [in] beta per-band activity masking beta param |
| * @param [in] is_keyframe whether we're encoding a keyframe |
| * @param [in] pli plane index |
| * @param [in] cdf_ctx selects which cdf context to use |
| * @param [in,out] skip_rest whether to skip further bands in each direction |
| * @param [in] band index of the band being decoded |
| * @param [in] band index of the band being decoded |
| * @param [out] skip skip flag with range [0,1] |
| * @param [in] qm QM with magnitude compensation |
| * @param [in] qm_inv Inverse of QM with magnitude compensation |
| */ |
| static void pvq_decode_partition(aom_reader *r, |
| int q0, |
| int n, |
| generic_encoder model[3], |
| od_adapt_ctx *adapt, |
| int *exg, |
| int *ext, |
| od_coeff *ref, |
| od_coeff *out, |
| int *noref, |
| od_val16 beta, |
| int is_keyframe, |
| int pli, |
| int cdf_ctx, |
| cfl_ctx *cfl, |
| int has_skip, |
| int *skip_rest, |
| int band, |
| int *skip, |
| const int16_t *qm, |
| const int16_t *qm_inv) { |
| int k; |
| od_val32 qcg; |
| int itheta; |
| od_val32 theta; |
| od_val32 gr; |
| od_val32 gain_offset; |
| od_coeff y[MAXN]; |
| int qg; |
| int id; |
| int i; |
| od_val16 ref16[MAXN]; |
| int rshift; |
| theta = 0; |
| gr = 0; |
| gain_offset = 0; |
| /* Skip is per-direction. For band=0, we can use any of the flags. */ |
| if (skip_rest[(band + 2) % 3]) { |
| qg = 0; |
| if (is_keyframe) { |
| itheta = -1; |
| *noref = 1; |
| } |
| else { |
| itheta = 0; |
| *noref = 0; |
| } |
| } |
| else { |
| /* Jointly decode gain, itheta and noref for small values. Then we handle |
| larger gain. */ |
| id = aom_read_symbol_pvq(r, &adapt->pvq.pvq_gaintheta_cdf[cdf_ctx][0], |
| 8 + 7*has_skip, "pvq:gaintheta"); |
| if (!is_keyframe && id >= 10) id++; |
| if (is_keyframe && id >= 8) id++; |
| if (id >= 8) { |
| id -= 8; |
| skip_rest[0] = skip_rest[1] = skip_rest[2] = 1; |
| } |
| qg = id & 1; |
| itheta = (id >> 1) - 1; |
| *noref = (itheta == -1); |
| } |
| /* The CfL flip bit is only decoded on the first band that has noref=0. */ |
| if (cfl->allow_flip && !*noref) { |
| int flip; |
| flip = aom_read_bit(r, "cfl:flip"); |
| if (flip) { |
| for (i = 0; i < cfl->nb_coeffs; i++) cfl->ref[i] = -cfl->ref[i]; |
| } |
| cfl->allow_flip = 0; |
| } |
| if (qg > 0) { |
| int tmp; |
| tmp = *exg; |
| qg = 1 + generic_decode(r, &model[!*noref], &tmp, 2, "pvq:gain"); |
| OD_IIR_DIADIC(*exg, qg << 16, 2); |
| } |
| *skip = 0; |
| #if defined(OD_FLOAT_PVQ) |
| rshift = 0; |
| #else |
| /* Shift needed to make the reference fit in 15 bits, so that the Householder |
| vector can fit in 16 bits. */ |
| rshift = OD_MAXI(0, od_vector_log_mag(ref, n) - 14); |
| #endif |
| for (i = 0; i < n; i++) { |
| #if defined(OD_FLOAT_PVQ) |
| ref16[i] = ref[i]*(double)qm[i]*OD_QM_SCALE_1; |
| #else |
| ref16[i] = OD_SHR_ROUND(ref[i]*qm[i], OD_QM_SHIFT + rshift); |
| #endif |
| } |
| if(!*noref){ |
| /* we have a reference; compute its gain */ |
| od_val32 cgr; |
| int icgr; |
| int cfl_enabled; |
| cfl_enabled = pli != 0 && is_keyframe && !OD_DISABLE_CFL; |
| cgr = od_pvq_compute_gain(ref16, n, q0, &gr, beta, rshift); |
| if (cfl_enabled) cgr = OD_CGAIN_SCALE; |
| #if defined(OD_FLOAT_PVQ) |
| icgr = (int)floor(.5 + cgr); |
| #else |
| icgr = OD_SHR_ROUND(cgr, OD_CGAIN_SHIFT); |
| #endif |
| /* quantized gain is interleave encoded when there's a reference; |
| deinterleave it now */ |
| if (is_keyframe) qg = neg_deinterleave(qg, icgr); |
| else { |
| qg = neg_deinterleave(qg, icgr + 1) - 1; |
| if (qg == 0) *skip = (icgr ? OD_PVQ_SKIP_ZERO : OD_PVQ_SKIP_COPY); |
| } |
| if (qg == icgr && itheta == 0 && !cfl_enabled) *skip = OD_PVQ_SKIP_COPY; |
| gain_offset = cgr - OD_SHL(icgr, OD_CGAIN_SHIFT); |
| qcg = OD_SHL(qg, OD_CGAIN_SHIFT) + gain_offset; |
| /* read and decode first-stage PVQ error theta */ |
| if (itheta > 1) { |
| int tmp; |
| tmp = *ext; |
| itheta = 2 + generic_decode(r, &model[2], &tmp, 2, "pvq:theta"); |
| OD_IIR_DIADIC(*ext, itheta << 16, 2); |
| } |
| theta = od_pvq_compute_theta(itheta, od_pvq_compute_max_theta(qcg, beta)); |
| } |
| else{ |
| itheta = 0; |
| if (!is_keyframe) qg++; |
| qcg = OD_SHL(qg, OD_CGAIN_SHIFT); |
| if (qg == 0) *skip = OD_PVQ_SKIP_ZERO; |
| } |
| |
| k = od_pvq_compute_k(qcg, itheta, *noref, n, beta); |
| if (k != 0) { |
| /* when noref==0, y is actually size n-1 */ |
| aom_decode_pvq_codeword(r, &adapt->pvq.pvq_codeword_ctx, y, |
| n - !*noref, k); |
| } |
| else { |
| OD_CLEAR(y, n); |
| } |
| if (*skip) { |
| if (*skip == OD_PVQ_SKIP_COPY) OD_COPY(out, ref, n); |
| else OD_CLEAR(out, n); |
| } |
| else { |
| od_val32 g; |
| g = od_gain_expand(qcg, q0, beta); |
| pvq_synthesis(out, y, ref16, n, gr, *noref, g, theta, qm_inv, rshift); |
| } |
| /* If OD_PVQ_SKIP_ZERO or OD_PVQ_SKIP_COPY, set skip to 1 for visualization */ |
| if (*skip) *skip = 1; |
| } |
| |
| /** Decodes a coefficient block (except for DC) encoded using PVQ |
| * |
| * @param [in,out] dec daala decoder context |
| * @param [in] ref 'reference' (prediction) vector |
| * @param [out] out decoded partition |
| * @param [in] q0 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] is_keyframe whether we're encoding a keyframe |
| * @param [out] flags bitmask of the per band skip and noref flags |
| * @param [in] ac_dc_coded skip flag for the block (range 0-3) |
| * @param [in] qm QM with magnitude compensation |
| * @param [in] qm_inv Inverse of QM with magnitude compensation |
| */ |
| void od_pvq_decode(daala_dec_ctx *dec, |
| od_coeff *ref, |
| od_coeff *out, |
| int q0, |
| int pli, |
| int bs, |
| const od_val16 *beta, |
| int is_keyframe, |
| unsigned int *flags, |
| PVQ_SKIP_TYPE ac_dc_coded, |
| const int16_t *qm, |
| const int16_t *qm_inv){ |
| |
| int noref[PVQ_MAX_PARTITIONS]; |
| int skip[PVQ_MAX_PARTITIONS]; |
| int *exg; |
| int *ext; |
| int nb_bands; |
| int i; |
| const int *off; |
| int size[PVQ_MAX_PARTITIONS]; |
| generic_encoder *model; |
| int skip_rest[3] = {0}; |
| cfl_ctx cfl; |
| const unsigned char *pvq_qm; |
| int use_masking; |
| |
| aom_clear_system_state(); |
| |
| /*Default to skip=1 and noref=0 for all bands.*/ |
| for (i = 0; i < PVQ_MAX_PARTITIONS; i++) { |
| noref[i] = 0; |
| skip[i] = 1; |
| } |
| |
| use_masking = dec->use_activity_masking; |
| |
| if (use_masking) |
| pvq_qm = &dec->state.pvq_qm_q4[pli][0]; |
| else |
| pvq_qm = 0; |
| |
| exg = &dec->state.adapt->pvq.pvq_exg[pli][bs][0]; |
| ext = dec->state.adapt->pvq.pvq_ext + bs*PVQ_MAX_PARTITIONS; |
| model = dec->state.adapt->pvq.pvq_param_model; |
| nb_bands = OD_BAND_OFFSETS[bs][0]; |
| off = &OD_BAND_OFFSETS[bs][1]; |
| out[0] = ac_dc_coded & DC_CODED; |
| if (ac_dc_coded < AC_CODED) { |
| if (is_keyframe) for (i = 1; i < 1 << (2*bs + 4); i++) out[i] = 0; |
| else for (i = 1; i < 1 << (2*bs + 4); i++) out[i] = ref[i]; |
| } |
| else { |
| for (i = 0; i < nb_bands; i++) size[i] = off[i+1] - off[i]; |
| cfl.ref = ref; |
| cfl.nb_coeffs = off[nb_bands]; |
| cfl.allow_flip = pli != 0 && is_keyframe; |
| for (i = 0; i < nb_bands; i++) { |
| int q; |
| |
| if (use_masking) |
| q = OD_MAXI(1, q0 * pvq_qm[od_qm_get_index(bs, i + 1)] >> 4); |
| else |
| q = OD_MAXI(1, q0); |
| |
| pvq_decode_partition(dec->r, q, size[i], |
| model, dec->state.adapt, exg + i, ext + i, ref + off[i], out + off[i], |
| &noref[i], beta[i], is_keyframe, pli, |
| (pli != 0)*OD_TXSIZES*PVQ_MAX_PARTITIONS + bs*PVQ_MAX_PARTITIONS + i, |
| &cfl, i == 0 && (i < nb_bands - 1), skip_rest, i, &skip[i], |
| qm + off[i], qm_inv + off[i]); |
| if (i == 0 && !skip_rest[0] && bs > 0) { |
| int skip_dir; |
| int j; |
| skip_dir = aom_read_symbol(dec->r, |
| &dec->state.adapt->pvq.pvq_skip_dir_cdf[(pli != 0) + 2*(bs - 1)][0], 7, |
| "pvq:skiprest"); |
| for (j = 0; j < 3; j++) skip_rest[j] = !!(skip_dir & (1 << j)); |
| } |
| } |
| } |
| *flags = 0; |
| for (i = nb_bands - 1; i >= 0; i--) { |
| *flags <<= 1; |
| *flags |= noref[i]&1; |
| *flags <<= 1; |
| *flags |= skip[i]&1; |
| } |
| } |