From c49ef3a15f6faa0289f025652e9a790666052d27 Mon Sep 17 00:00:00 2001 From: Yushin Cho Date: Mon, 13 Mar 2017 17:27:25 -0700 Subject: [PATCH] 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 --- av1/common/generic_code.c | 2 +- av1/common/pvq_state.h | 2 +- av1/decoder/decodeframe.c | 20 ++++++++++++-------- av1/decoder/pvq_decoder.c | 10 +++++----- av1/encoder/bitstream.c | 11 +++++------ av1/encoder/daala_compat_enc.c | 4 ++-- av1/encoder/encodeframe.c | 11 +++++------ av1/encoder/encodemb.c | 4 ++-- av1/encoder/firstpass.c | 9 +++++---- av1/encoder/pvq_encoder.c | 22 +++++++++++----------- 10 files changed, 49 insertions(+), 46 deletions(-) diff --git a/av1/common/generic_code.c b/av1/common/generic_code.c index bb5d4a6fd..aae929430 100644 --- a/av1/common/generic_code.c +++ b/av1/common/generic_code.c @@ -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; diff --git a/av1/common/pvq_state.h b/av1/common/pvq_state.h index e52c313b5..84d454e70 100644 --- a/av1/common/pvq_state.h +++ b/av1/common/pvq_state.h @@ -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]; diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 35de101b3..c72648315 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c @@ -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 diff --git a/av1/decoder/pvq_decoder.c b/av1/decoder/pvq_decoder.c index d264bf8e4..28b2e683f 100644 --- a/av1/decoder/pvq_decoder.c +++ b/av1/decoder/pvq_decoder.c @@ -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)); } diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index f8026620e..5c5599f70 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c @@ -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); diff --git a/av1/encoder/daala_compat_enc.c b/av1/encoder/daala_compat_enc.c index 1933d5c55..3df424cac 100644 --- a/av1/encoder/daala_compat_enc.c +++ b/av1/encoder/daala_compat_enc.c @@ -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); } diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index d101f02d2..fa65bb9a6 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c @@ -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); diff --git a/av1/encoder/encodemb.c b/av1/encoder/encodemb.c index ceeac845b..03ec98149 100644 --- a/av1/encoder/encodemb.c +++ b/av1/encoder/encodemb.c @@ -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); diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c index 74c84914b..03b3b491f 100644 --- a/av1/encoder/firstpass.c +++ b/av1/encoder/firstpass.c @@ -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. diff --git a/av1/encoder/pvq_encoder.c b/av1/encoder/pvq_encoder.c index 48115445c..945ecf833 100644 --- a/av1/encoder/pvq_encoder.c +++ b/av1/encoder/pvq_encoder.c @@ -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