PVQ uses backward updated context in a tile

In the beginning of encoding and bitstream packing,
the frame context in common of codec is copied to the frame context
in each tile.
Initial prob and context is based on flat probability and
does not come from table at the moment.

The bd-rate change for the test set objective-1-fast
on awcy with high delay mode is:

PSNR   PSNR  HVS  SSIM  CIEDE 2000  PSNR Cb PSNR Cr MS SSIM
-0.77  -1.05      -0.74 -0.67       -0.67   -0.77   -0.88

Change-Id: Ic9105ac68aceb7486cb5f6f1c0b19df5853f2cb9
This commit is contained in:
Yushin Cho 2017-03-13 17:27:25 -07:00
Родитель b188ea1402
Коммит c49ef3a15f
10 изменённых файлов: 49 добавлений и 46 удалений

Просмотреть файл

@ -30,7 +30,7 @@ void aom_cdf_init(uint16_t *cdf, int ncdfs, int nsyms, int val, int first) {
void aom_cdf_init_q15_1D(uint16_t *cdf, int nsyms, int cdf_size) {
int i;
for (i = 0; i < nsyms; i++)
cdf[i] = (i + 1)*32768/nsyms;
cdf[i] = (i + 1)*CDF_PROB_TOP/nsyms;
#if CONFIG_EC_ADAPT
cdf[cdf_size - 1] = 0;

Просмотреть файл

@ -38,7 +38,7 @@ struct od_adapt_ctx {
};
struct od_state {
od_adapt_ctx adapt;
od_adapt_ctx *adapt;
unsigned char pvq_qm_q4[OD_NPLANES_MAX][OD_QM_SIZE];
/* Quantization matrices and their inverses. */
int16_t qm[OD_QM_BUFFER_SIZE];

Просмотреть файл

@ -396,9 +396,9 @@ static int av1_pvq_decode_helper(MACROBLOCKD *xd, tran_low_t *ref_coeff,
if (!has_dc_skip || out_int32[0]) {
out_int32[0] =
has_dc_skip + generic_decode(dec->r, &dec->state.adapt.model_dc[pli],
-1, &dec->state.adapt.ex_dc[pli][bs][0], 2,
"dc:mag");
has_dc_skip + generic_decode(dec->r, &dec->state.adapt->model_dc[pli],
-1, &dec->state.adapt->ex_dc[pli][bs][0],
2, "dc:mag");
if (out_int32[0]) out_int32[0] *= aom_read_bit(dec->r, "dc:sign") ? -1 : 1;
}
out_int32[0] = out_int32[0] * pvq_dc_quant + ref_int32[0];
@ -427,7 +427,7 @@ static PVQ_SKIP_TYPE read_pvq_skip(AV1_COMMON *cm, MACROBLOCKD *const xd,
// So, only AC/DC skip info is coded
const int ac_dc_coded = aom_read_symbol(
xd->daala_dec.r,
xd->daala_dec.state.adapt.skip_cdf[2 * tx_size + (plane != 0)], 4,
xd->daala_dec.state.adapt->skip_cdf[2 * tx_size + (plane != 0)], 4,
"skip");
if (ac_dc_coded < 0 || ac_dc_coded > 3) {
aom_internal_error(&cm->error, AOM_CODEC_INVALID_PARAM,
@ -3297,7 +3297,6 @@ static void get_tile_buffers(
static void daala_dec_init(AV1_COMMON *const cm, daala_dec_ctx *daala_dec,
aom_reader *r) {
daala_dec->r = r;
od_adapt_ctx_reset(&daala_dec->state.adapt, 0);
// TODO(yushin) : activity masking info needs be signaled by a bitstream
daala_dec->use_activity_masking = AV1_PVQ_ENABLE_ACTIVITY_MASKING;
@ -3448,14 +3447,18 @@ static const uint8_t *decode_tiles(AV1Decoder *pbi, const uint8_t *data,
td->pvq_ref_coeff,
#endif
td->dqcoeff);
#if CONFIG_PVQ
daala_dec_init(cm, &td->xd.daala_dec, &td->bit_reader);
#endif
#if CONFIG_EC_ADAPT
// Initialise the tile context from the frame context
td->tctx = *cm->fc;
td->xd.tile_ctx = &td->tctx;
#endif
#if CONFIG_PVQ
daala_dec_init(cm, &td->xd.daala_dec, &td->bit_reader);
td->xd.daala_dec.state.adapt = &td->tctx.pvq_context;
#endif
#if CONFIG_PALETTE
td->xd.plane[0].color_index_map = td->color_index_map[0];
td->xd.plane[1].color_index_map = td->color_index_map[1];
@ -3816,6 +3819,7 @@ static const uint8_t *decode_tiles_mt(AV1Decoder *pbi, const uint8_t *data,
twd->dqcoeff);
#if CONFIG_PVQ
daala_dec_init(cm, &twd->xd.daala_dec, &twd->bit_reader);
twd->xd.daala_dec.state.adapt = &twd->tctx.pvq_context;
#endif
#if CONFIG_EC_ADAPT
// Initialise the tile context from the frame context

Просмотреть файл

@ -337,9 +337,9 @@ void od_pvq_decode(daala_dec_ctx *dec,
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;
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;
@ -361,7 +361,7 @@ void od_pvq_decode(daala_dec_ctx *dec,
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],
model, dec->state.adapt, exg + i, ext + i, ref + off[i], out + off[i],
&noref[i], beta[i], nodesync, 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],
@ -370,7 +370,7 @@ void od_pvq_decode(daala_dec_ctx *dec,
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,
&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));
}

Просмотреть файл

@ -1037,7 +1037,7 @@ static void pack_pvq_tokens(aom_writer *w, MACROBLOCK *const x,
const BLOCK_SIZE plane_bsize =
get_plane_block_size(AOMMAX(bsize, BLOCK_8X8), pd);
adapt = &x->daala_enc.state.adapt;
adapt = x->daala_enc.state.adapt;
max_blocks_wide = max_block_wide(xd, plane_bsize, plane);
max_blocks_high = max_block_high(xd, plane_bsize, plane);
@ -4121,6 +4121,10 @@ static uint32_t write_tiles(AV1_COMP *const cpi, uint8_t *const dst,
this_tile->tctx = *cm->fc;
cpi->td.mb.e_mbd.tile_ctx = &this_tile->tctx;
#endif
#if CONFIG_PVQ
cpi->td.mb.pvq_q = &this_tile->pvq_q;
cpi->td.mb.daala_enc.state.adapt = &this_tile->tctx.pvq_context;
#endif // CONFIG_PVQ
#if CONFIG_ANS
buf_ans_write_init(buf_ans, dst + total_size);
write_modes(cpi, &tile_info, buf_ans, &tok, tok_end);
@ -4129,11 +4133,6 @@ static uint32_t write_tiles(AV1_COMP *const cpi, uint8_t *const dst,
tile_size = buf_ans_write_end(buf_ans);
#else
aom_start_encode(&mode_bc, dst + total_size);
#if CONFIG_PVQ
// NOTE: This will not work with CONFIG_ANS turned on.
od_adapt_ctx_reset(&cpi->td.mb.daala_enc.state.adapt, 0);
cpi->td.mb.pvq_q = &this_tile->pvq_q;
#endif
write_modes(cpi, &tile_info, &mode_bc, &tok, tok_end);
#if !CONFIG_LV_MAP
assert(tok == tok_end);

Просмотреть файл

@ -17,7 +17,7 @@ void od_encode_checkpoint(const daala_enc_ctx *enc, od_rollback_buffer *rbuf) {
#else
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
#endif
OD_COPY(&rbuf->adapt, &enc->state.adapt, 1);
OD_COPY(&rbuf->adapt, enc->state.adapt, 1);
}
void od_encode_rollback(daala_enc_ctx *enc, const od_rollback_buffer *rbuf) {
@ -26,5 +26,5 @@ void od_encode_rollback(daala_enc_ctx *enc, const od_rollback_buffer *rbuf) {
#else
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
#endif
OD_COPY(&enc->state.adapt, &rbuf->adapt, 1);
OD_COPY(enc->state.adapt, &rbuf->adapt, 1);
}

Просмотреть файл

@ -4866,9 +4866,7 @@ void av1_encode_tile(AV1_COMP *cpi, ThreadData *td, int tile_row,
const TileInfo *const tile_info = &this_tile->tile_info;
TOKENEXTRA *tok = cpi->tile_tok[tile_row][tile_col];
int mi_row;
#if CONFIG_PVQ
od_adapt_ctx *adapt;
#endif
#if CONFIG_DEPENDENT_HORZTILES
#if CONFIG_TILE_GROUPS
if ((!cm->dependent_horz_tiles) || (tile_row == 0) ||
@ -4957,14 +4955,11 @@ void av1_encode_tile(AV1_COMP *cpi, ThreadData *td, int tile_row,
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
#endif
adapt = &td->mb.daala_enc.state.adapt;
#if CONFIG_DAALA_EC
od_ec_enc_reset(&td->mb.daala_enc.w.ec);
#else
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
#endif
od_adapt_ctx_reset(adapt, 0);
#endif // #if CONFIG_PVQ
#if CONFIG_EC_ADAPT
@ -4972,6 +4967,10 @@ void av1_encode_tile(AV1_COMP *cpi, ThreadData *td, int tile_row,
td->mb.e_mbd.tile_ctx = &this_tile->tctx;
#endif // #if CONFIG_EC_ADAPT
#if CONFIG_PVQ
td->mb.daala_enc.state.adapt = &this_tile->tctx.pvq_context;
#endif // CONFIG_PVQ
for (mi_row = tile_info->mi_row_start; mi_row < tile_info->mi_row_end;
mi_row += cm->mib_size) {
encode_rd_sb_row(cpi, td, this_tile, mi_row, &tok);

Просмотреть файл

@ -1257,9 +1257,9 @@ PVQ_SKIP_TYPE av1_pvq_encode_helper(MACROBLOCK *x, tran_low_t *const coeff,
// Encode residue of DC coeff, if required.
if (!has_dc_skip || out_int32[0]) {
generic_encode(&daala_enc->w, &daala_enc->state.adapt.model_dc[plane],
generic_encode(&daala_enc->w, &daala_enc->state.adapt->model_dc[plane],
abs(out_int32[0]) - has_dc_skip, -1,
&daala_enc->state.adapt.ex_dc[plane][tx_size][0], 2);
&daala_enc->state.adapt->ex_dc[plane][tx_size][0], 2);
}
if (out_int32[0]) {
aom_write_bit(&daala_enc->w, out_int32[0] < 0);

Просмотреть файл

@ -503,6 +503,7 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
const int mb_scale = mi_size_wide[BLOCK_16X16];
#if CONFIG_PVQ
PVQ_QUEUE pvq_q;
od_adapt_ctx pvq_context;
#endif
// First pass code requires valid last and new frame buffers.
@ -541,8 +542,6 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
#if CONFIG_PVQ
// For pass 1 of 2-pass encoding, init here for PVQ for now.
{
od_adapt_ctx *adapt;
pvq_q.buf_len = 5000;
CHECK_MEM_ERROR(cm, pvq_q.buf,
aom_malloc(pvq_q.buf_len * sizeof(PVQ_INFO)));
@ -567,13 +566,11 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
#endif
adapt = &x->daala_enc.state.adapt;
#if CONFIG_DAALA_EC
od_ec_enc_reset(&x->daala_enc.w.ec);
#else
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
#endif
od_adapt_ctx_reset(adapt, 0);
}
#endif
@ -595,6 +592,10 @@ void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
av1_init_scan_order(cm);
#endif
av1_convolve_init(cm);
#if CONFIG_PVQ
od_adapt_ctx_reset(&pvq_context, 0);
x->daala_enc.state.adapt = &pvq_context;
#endif // CONFIG_PVQ
av1_initialize_rd_consts(cpi);
// Tiling is ignored in the first pass.

Просмотреть файл

@ -797,10 +797,10 @@ PVQ_SKIP_TYPE od_pvq_encode(daala_enc_ctx *enc,
else
pvq_qm = 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;
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];
@ -847,7 +847,7 @@ PVQ_SKIP_TYPE od_pvq_encode(daala_enc_ctx *enc,
qg[i] = pvq_theta(out + off[i], in + off[i], ref + off[i], size[i],
q, y + off[i], &theta[i], &max_theta[i],
&k[i], beta[i], &skip_diff, nodesync, is_keyframe, pli, &enc->state.adapt,
&k[i], beta[i], &skip_diff, nodesync, is_keyframe, pli, enc->state.adapt,
qm + off[i], qm_inv + off[i], enc->pvq_norm_lambda, speed);
}
od_encode_checkpoint(enc, &buf);
@ -871,8 +871,8 @@ PVQ_SKIP_TYPE od_pvq_encode(daala_enc_ctx *enc,
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
#endif
od_encode_checkpoint(enc, &dc_buf);
generic_encode(&enc->w, &enc->state.adapt.model_dc[pli],
n - 1, -1, &enc->state.adapt.ex_dc[pli][bs][0], 2);
generic_encode(&enc->w, &enc->state.adapt->model_dc[pli],
n - 1, -1, &enc->state.adapt->ex_dc[pli][bs][0], 2);
#if CONFIG_DAALA_EC
tell2 = od_ec_enc_tell_frac(&enc->w.ec) - tell2;
#else
@ -926,14 +926,14 @@ PVQ_SKIP_TYPE od_pvq_encode(daala_enc_ctx *enc,
encode_flip = pli != 0 && is_keyframe && theta[i] != -1 && !cfl_encoded;
if (i == 0 || (!skip_rest && !(skip_dir & (1 << ((i - 1)%3))))) {
pvq_encode_partition(&enc->w, qg[i], theta[i], max_theta[i], y + off[i],
size[i], k[i], model, &enc->state.adapt, exg + i, ext + i,
size[i], k[i], model, enc->state.adapt, exg + i, ext + i,
nodesync, (pli != 0)*OD_TXSIZES*PVQ_MAX_PARTITIONS
+ bs*PVQ_MAX_PARTITIONS + i, is_keyframe, i == 0 && (i < nb_bands - 1),
skip_rest, encode_flip, flip);
}
if (i == 0 && !skip_rest && bs > 0) {
aom_write_symbol(&enc->w, skip_dir,
&enc->state.adapt.pvq.pvq_skip_dir_cdf[(pli != 0) + 2*(bs - 1)][0], 7);
&enc->state.adapt->pvq.pvq_skip_dir_cdf[(pli != 0) + 2*(bs - 1)][0], 7);
}
if (encode_flip) cfl_encoded = 1;
}
@ -977,8 +977,8 @@ PVQ_SKIP_TYPE od_pvq_encode(daala_enc_ctx *enc,
#error "CONFIG_PVQ currently requires CONFIG_DAALA_EC."
#endif
od_encode_checkpoint(enc, &dc_buf);
generic_encode(&enc->w, &enc->state.adapt.model_dc[pli],
n - 1, -1, &enc->state.adapt.ex_dc[pli][bs][0], 2);
generic_encode(&enc->w, &enc->state.adapt->model_dc[pli],
n - 1, -1, &enc->state.adapt->ex_dc[pli][bs][0], 2);
#if CONFIG_DAALA_EC
tell2 = od_ec_enc_tell_frac(&enc->w.ec) - tell2;
#else