aom/av1/decoder/laplace_decoder.c

324 строки
9.6 KiB
C
Исходник Обычный вид История

New experiment: Perceptual Vector Quantization from Daala PVQ replaces the scalar quantizer and coefficient coding with a new design originally developed in Daala. It currently depends on the Daala entropy coder although it could be adapted to work with another entropy coder if needed: ./configure --enable-experimental --enable-daala_ec --enable-pvq The version of PVQ in this commit is adapted from the following revision of Daala: https://github.com/xiph/daala/commit/fb51c1ade6a31b668a0157d89de8f0a4493162a8 More information about PVQ: - https://people.xiph.org/~jm/daala/pvq_demo/ - https://jmvalin.ca/papers/spie_pvq.pdf The following files are copied as-is from Daala with minimal adaptations, therefore we disable clang-format on those files to make it easier to synchronize the AV1 and Daala codebases in the future: av1/common/generic_code.c av1/common/generic_code.h av1/common/laplace_tables.c av1/common/partition.c av1/common/partition.h av1/common/pvq.c av1/common/pvq.h av1/common/state.c av1/common/state.h av1/common/zigzag.h av1/common/zigzag16.c av1/common/zigzag32.c av1/common/zigzag4.c av1/common/zigzag64.c av1/common/zigzag8.c av1/decoder/decint.h av1/decoder/generic_decoder.c av1/decoder/laplace_decoder.c av1/decoder/pvq_decoder.c av1/decoder/pvq_decoder.h av1/encoder/daala_compat_enc.c av1/encoder/encint.h av1/encoder/generic_encoder.c av1/encoder/laplace_encoder.c av1/encoder/pvq_encoder.c av1/encoder/pvq_encoder.h Known issues: - Lossless mode is not supported, '--lossless=1' will give the same result as '--end-usage=q --cq-level=1'. - High bit depth is not supported by PVQ. Change-Id: I1ae0d6517b87f4c1ccea944b2e12dc906979f25e
2016-11-05 02:36:56 +03:00
/*
* 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 "aom_dsp/entdec.h"
#include "av1/common/pvq.h"
#include "pvq_decoder.h"
#if OD_ACCOUNTING
# define od_decode_pvq_split(ec, adapt, sum, ctx, str) od_decode_pvq_split_(ec, adapt, sum, ctx, str)
#else
# define od_decode_pvq_split(ec, adapt, sum, ctx, str) od_decode_pvq_split_(ec, adapt, sum, ctx)
#endif
static int od_decode_pvq_split_(od_ec_dec *ec, od_pvq_codeword_ctx *adapt,
int sum, int ctx OD_ACC_STR) {
int shift;
int count;
int msbs;
int fctx;
count = 0;
if (sum == 0) return 0;
shift = OD_MAXI(0, OD_ILOG(sum) - 3);
fctx = 7*ctx + (sum >> shift) - 1;
msbs = od_decode_cdf_adapt(ec, adapt->pvq_split_cdf[fctx],
(sum >> shift) + 1, adapt->pvq_split_increment, acc_str);
if (shift) count = od_ec_dec_bits(ec, shift, acc_str);
count += msbs << shift;
if (count > sum) {
count = sum;
ec->error = 1;
}
return count;
}
void od_decode_band_pvq_splits(od_ec_dec *ec, od_pvq_codeword_ctx *adapt,
od_coeff *y, int n, int k, int level) {
int mid;
int count_right;
if (n == 1) {
y[0] = k;
}
else if (k == 0) {
OD_CLEAR(y, n);
}
else if (k == 1 && n <= 16) {
int cdf_id;
int pos;
cdf_id = od_pvq_k1_ctx(n, level == 0);
OD_CLEAR(y, n);
pos = od_decode_cdf_adapt(ec, adapt->pvq_k1_cdf[cdf_id], n,
adapt->pvq_k1_increment, "pvq:k1");
y[pos] = 1;
}
else {
mid = n >> 1;
count_right = od_decode_pvq_split(ec, adapt, k, od_pvq_size_ctx(n),
"pvq:split");
od_decode_band_pvq_splits(ec, adapt, y, mid, k - count_right, level + 1);
od_decode_band_pvq_splits(ec, adapt, y + mid, n - mid, count_right,
level + 1);
}
}
/** Decodes the tail of a Laplace-distributed variable, i.e. it doesn't
* do anything special for the zero case.
*
* @param [dec] range decoder
* @param [decay] decay factor of the distribution, i.e. pdf ~= decay^x
* @param [max] maximum possible value of x (used to truncate the pdf)
*
* @retval decoded variable x
*/
int od_laplace_decode_special_(od_ec_dec *dec, unsigned decay, int max OD_ACC_STR) {
int pos;
int shift;
int xs;
int ms;
int sym;
const uint16_t *cdf;
shift = 0;
if (max == 0) return 0;
/* We don't want a large decay value because that would require too many
symbols. However, it's OK if the max is below 15. */
while (((max >> shift) >= 15 || max == -1) && decay > 235) {
decay = (decay*decay + 128) >> 8;
shift++;
}
decay = OD_MINI(decay, 254);
decay = OD_MAXI(decay, 2);
ms = max >> shift;
cdf = EXP_CDF_TABLE[(decay + 1) >> 1];
OD_LOG((OD_LOG_PVQ, OD_LOG_DEBUG, "decay = %d\n", decay));
xs = 0;
do {
sym = OD_MINI(xs, 15);
{
int i;
OD_LOG((OD_LOG_PVQ, OD_LOG_DEBUG, "%d %d %d %d", xs, shift, sym, max));
for (i = 0; i < 16; i++) {
OD_LOG_PARTIAL((OD_LOG_PVQ, OD_LOG_DEBUG, "%d ", cdf[i]));
}
OD_LOG_PARTIAL((OD_LOG_PVQ, OD_LOG_DEBUG, "\n"));
}
if (ms > 0 && ms < 15) {
/* Simple way of truncating the pdf when we have a bound. */
sym = od_ec_decode_cdf_unscaled(dec, cdf, ms + 1);
}
else sym = od_ec_decode_cdf_q15(dec, cdf, 16);
xs += sym;
ms -= 15;
}
while (sym >= 15 && ms != 0);
if (shift) pos = (xs << shift) + od_ec_dec_bits(dec, shift, acc_str);
else pos = xs;
OD_ASSERT(pos >> shift <= max >> shift || max == -1);
if (max != -1 && pos > max) {
pos = max;
dec->error = 1;
}
OD_ASSERT(pos <= max || max == -1);
return pos;
}
/** Decodes a Laplace-distributed variable for use in PVQ.
*
* @param [in,out] dec range decoder
* @param [in] ExQ8 expectation of the absolute value of x
* @param [in] K maximum value of |x|
*
* @retval decoded variable (including sign)
*/
int od_laplace_decode_(od_ec_dec *dec, unsigned ex_q8, int k OD_ACC_STR) {
int j;
int shift;
uint16_t cdf[16];
int sym;
int lsb;
int decay;
int offset;
lsb = 0;
/* Shift down x if expectation is too high. */
shift = OD_ILOG(ex_q8) - 11;
if (shift < 0) shift = 0;
/* Apply the shift with rounding to Ex, K and xs. */
ex_q8 = (ex_q8 + (1 << shift >> 1)) >> shift;
k = (k + (1 << shift >> 1)) >> shift;
decay = OD_MINI(254, OD_DIVU(256*ex_q8, (ex_q8 + 256)));
offset = LAPLACE_OFFSET[(decay + 1) >> 1];
for (j = 0; j < 16; j++) {
cdf[j] = EXP_CDF_TABLE[(decay + 1) >> 1][j] - offset;
}
/* Simple way of truncating the pdf when we have a bound */
if (k == 0) sym = 0;
else sym = od_ec_decode_cdf_unscaled(dec, cdf, OD_MINI(k + 1, 16));
if (shift) {
int special;
/* Because of the rounding, there's only half the number of possibilities
for xs=0 */
special = (sym == 0);
if (shift - special > 0) lsb = od_ec_dec_bits(dec, shift - special, acc_str);
lsb -= (!special << (shift - 1));
}
/* Handle the exponentially-decaying tail of the distribution */
if (sym == 15) sym += laplace_decode_special(dec, decay, k - 15, acc_str);
return (sym << shift) + lsb;
}
#if OD_ACCOUNTING
# define laplace_decode_vector_delta(dec, y, n, k, curr, means, str) laplace_decode_vector_delta_(dec, y, n, k, curr, means, str)
#else
# define laplace_decode_vector_delta(dec, y, n, k, curr, means, str) laplace_decode_vector_delta_(dec, y, n, k, curr, means)
#endif
static void laplace_decode_vector_delta_(od_ec_dec *dec, od_coeff *y, int n, int k,
int32_t *curr, const int32_t *means
OD_ACC_STR) {
int i;
int prev;
int sum_ex;
int sum_c;
int coef;
int pos;
int k0;
int sign;
int first;
int k_left;
prev = 0;
sum_ex = 0;
sum_c = 0;
coef = 256*means[OD_ADAPT_COUNT_Q8]/
(1 + means[OD_ADAPT_COUNT_EX_Q8]);
pos = 0;
sign = 0;
first = 1;
k_left = k;
for (i = 0; i < n; i++) y[i] = 0;
k0 = k_left;
coef = OD_MAXI(coef, 1);
for (i = 0; i < k0; i++) {
int count;
if (first) {
int decay;
int ex = coef*(n - prev)/k_left;
if (ex > 65280) decay = 255;
else {
decay = OD_MINI(255,
(int)((256*ex/(ex + 256) + (ex>>5)*ex/((n + 1)*(n - 1)*(n - 1)))));
}
/*Update mean position.*/
count = laplace_decode_special(dec, decay, n - 1, acc_str);
first = 0;
}
else count = laplace_decode(dec, coef*(n - prev)/k_left, n - prev - 1, acc_str);
sum_ex += 256*(n - prev);
sum_c += count*k_left;
pos += count;
OD_ASSERT(pos < n);
if (y[pos] == 0)
sign = od_ec_dec_bits(dec, 1, acc_str);
y[pos] += sign ? -1 : 1;
prev = pos;
k_left--;
if (k_left == 0) break;
}
if (k > 0) {
curr[OD_ADAPT_COUNT_Q8] = 256*sum_c;
curr[OD_ADAPT_COUNT_EX_Q8] = sum_ex;
}
else {
curr[OD_ADAPT_COUNT_Q8] = -1;
curr[OD_ADAPT_COUNT_EX_Q8] = 0;
}
curr[OD_ADAPT_K_Q8] = 0;
curr[OD_ADAPT_SUM_EX_Q8] = 0;
}
/** Decodes a vector of integers assumed to come from rounding a sequence of
* Laplace-distributed real values in decreasing order of variance.
*
* @param [in,out] dec range decoder
* @param [in] y decoded vector
* @param [in] N dimension of the vector
* @param [in] K sum of the absolute value of components of y
* @param [out] curr Adaptation context output, may alias means.
* @param [in] means Adaptation context input.
*/
void od_laplace_decode_vector_(od_ec_dec *dec, od_coeff *y, int n, int k,
int32_t *curr, const int32_t *means OD_ACC_STR) {
int i;
int sum_ex;
int kn;
int exp_q8;
int mean_k_q8;
int mean_sum_ex_q8;
int ran_delta;
ran_delta = 0;
if (k <= 1) {
laplace_decode_vector_delta(dec, y, n, k, curr, means, acc_str);
return;
}
if (k == 0) {
curr[OD_ADAPT_COUNT_Q8] = OD_ADAPT_NO_VALUE;
curr[OD_ADAPT_COUNT_EX_Q8] = OD_ADAPT_NO_VALUE;
curr[OD_ADAPT_K_Q8] = 0;
curr[OD_ADAPT_SUM_EX_Q8] = 0;
for (i = 0; i < n; i++) y[i] = 0;
return;
}
sum_ex = 0;
kn = k;
/* Estimates the factor relating pulses_left and positions_left to E(|x|).*/
mean_k_q8 = means[OD_ADAPT_K_Q8];
mean_sum_ex_q8 = means[OD_ADAPT_SUM_EX_Q8];
if (mean_k_q8 < 1 << 23) exp_q8 = 256*mean_k_q8/(1 + mean_sum_ex_q8);
else exp_q8 = mean_k_q8/(1 + (mean_sum_ex_q8 >> 8));
for (i = 0; i < n; i++) {
int ex;
int x;
if (kn == 0) break;
if (kn <= 1 && i != n - 1) {
laplace_decode_vector_delta(dec, y + i, n - i, kn, curr, means, acc_str);
ran_delta = 1;
i = n;
break;
}
/* Expected value of x (round-to-nearest) is
expQ8*pulses_left/positions_left. */
ex = (2*exp_q8*kn + (n - i))/(2*(n - i));
if (ex > kn*256) ex = kn*256;
sum_ex += (2*256*kn + (n - i))/(2*(n - i));
/* No need to encode the magnitude for the last bin. */
if (i != n - 1) x = laplace_decode(dec, ex, kn, acc_str);
else x = kn;
if (x != 0) {
if (od_ec_dec_bits(dec, 1, acc_str)) x = -x;
}
y[i] = x;
kn -= abs(x);
}
/* Adapting the estimates for expQ8. */
if (!ran_delta) {
curr[OD_ADAPT_COUNT_Q8] = OD_ADAPT_NO_VALUE;
curr[OD_ADAPT_COUNT_EX_Q8] = OD_ADAPT_NO_VALUE;
}
curr[OD_ADAPT_K_Q8] = k - kn;
curr[OD_ADAPT_SUM_EX_Q8] = sum_ex;
for (; i < n; i++) y[i] = 0;
}