[NORMATIVE] New coded_lossless and all_lossless. - 'coded_lossless' means that the frame is fully-lossless at the *coded* resolution. When a 'coded_lossless' is on, loop filter and CDEF are disabled. - 'all_lossless' means that the frame is fully-lossless at the *upscaled* resolution. 'all_lossless' implies 'coded_lossless', and additionally, loop restoration and super-resolution are also disabled. This changes the semantics, but no new bits are transmitted in the bitstream. BUG=aomedia:1646 Change-Id: If192dcf0c9230e9e202993317859a6aaa00483c7
diff --git a/av1/common/alloccommon.c b/av1/common/alloccommon.c index 9106070..fab30a7 100644 --- a/av1/common/alloccommon.c +++ b/av1/common/alloccommon.c
@@ -145,7 +145,7 @@ static int alloc_loop_filter(AV1_COMMON *cm) { aom_free(cm->lf.lfm); cm->lf.lfm = NULL; - if (cm->all_lossless) return 0; + if (cm->coded_lossless) return 0; // Each lfm holds bit masks for all the 4x4 blocks in a max // 64x64 (128x128 for ext_partitions) region. The stride // and rows are rounded up / truncated to a multiple of 16
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h index 83beea7..adc81f1 100644 --- a/av1/common/onyxc_int.h +++ b/av1/common/onyxc_int.h
@@ -446,7 +446,8 @@ struct loopfilter lf; struct segmentation seg; - int all_lossless; + int coded_lossless; // frame is fully lossless at the coded resolution. + int all_lossless; // frame is fully lossless at the upscaled resolution. int reduced_tx_set_used; @@ -1318,20 +1319,23 @@ seq_params->mib_size_log2 = mi_size_wide_log2[seq_params->sb_size]; } -static INLINE int all_lossless(const AV1_COMMON *cm, const MACROBLOCKD *xd) { - int i; - int all_lossless = 1; +// Returns true if the frame is fully lossless at the coded resolution. +// Note: If super-resolution is used, such a frame will still NOT be lossless at +// the upscaled resolution. +static INLINE int is_coded_lossless(const AV1_COMMON *cm, + const MACROBLOCKD *xd) { + int coded_lossless = 1; if (cm->seg.enabled) { - for (i = 0; i < MAX_SEGMENTS; ++i) { + for (int i = 0; i < MAX_SEGMENTS; ++i) { if (!xd->lossless[i]) { - all_lossless = 0; + coded_lossless = 0; break; } } } else { - all_lossless = xd->lossless[0]; + coded_lossless = xd->lossless[0]; } - return all_lossless; + return coded_lossless; } #ifdef __cplusplus
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index eeaddf8..b76e453 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c
@@ -123,7 +123,7 @@ } static TX_MODE read_tx_mode(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { - if (cm->all_lossless) return ONLY_4X4; + if (cm->coded_lossless) return ONLY_4X4; return aom_rb_read_bit(rb) ? TX_MODE_SELECT : TX_MODE_LARGEST; } @@ -1117,13 +1117,13 @@ static void setup_loopfilter(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) { const int num_planes = av1_num_planes(cm); struct loopfilter *lf = &cm->lf; - if ((cm->allow_intrabc && NO_FILTER_FOR_IBC) || cm->all_lossless) { + if ((cm->allow_intrabc && NO_FILTER_FOR_IBC) || cm->coded_lossless) { // write default deltas to frame buffer av1_set_default_ref_deltas(cm->cur_frame->ref_deltas); av1_set_default_mode_deltas(cm->cur_frame->mode_deltas); return; } - assert(!cm->all_lossless); + assert(!cm->coded_lossless); if (cm->prev_frame) { // write deltas to frame buffer memcpy(lf->ref_deltas, cm->prev_frame->ref_deltas, TOTAL_REFS_PER_FRAME); @@ -1582,8 +1582,8 @@ cm->rst_info[0].frame_restoration_type == RESTORE_NONE && cm->rst_info[1].frame_restoration_type == RESTORE_NONE && cm->rst_info[2].frame_restoration_type == RESTORE_NONE; - assert( - IMPLIES(cm->all_lossless, no_loopfilter && no_cdef && no_restoration)); + assert(IMPLIES(cm->coded_lossless, no_loopfilter && no_cdef)); + assert(IMPLIES(cm->all_lossless, no_restoration)); cm->single_tile_decoding = no_loopfilter && no_cdef && no_restoration; // Read the tile width/height if (cm->seq_params.sb_size == BLOCK_128X128) { @@ -3097,26 +3097,28 @@ cm->v_dc_delta_q == 0 && cm->v_ac_delta_q == 0; xd->qindex[i] = qindex; } - cm->all_lossless = all_lossless(cm, xd); + cm->coded_lossless = is_coded_lossless(cm, xd); + cm->all_lossless = cm->coded_lossless && av1_superres_unscaled(cm); setup_segmentation_dequant(cm); - if (cm->all_lossless) { + if (cm->coded_lossless) { cm->lf.filter_level[0] = 0; cm->lf.filter_level[1] = 0; cm->cdef_bits = 0; cm->cdef_strengths[0] = 0; cm->cdef_uv_strengths[0] = 0; + } + if (cm->all_lossless) { cm->rst_info[0].frame_restoration_type = RESTORE_NONE; cm->rst_info[1].frame_restoration_type = RESTORE_NONE; cm->rst_info[2].frame_restoration_type = RESTORE_NONE; - if (!av1_superres_unscaled(cm)) { - aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME, - "Fully lossless frame cannot use super-resolution"); - } + assert(av1_superres_unscaled(cm)); } setup_loopfilter(cm, rb); - if (!cm->all_lossless) { + if (!cm->coded_lossless) { setup_cdef(cm, rb); + } + if (!cm->all_lossless) { decode_restoration_mode(cm, rb); } @@ -3214,6 +3216,7 @@ BufferPool *const pool = cm->buffer_pool; if (av1_superres_unscaled(cm)) return; + assert(!cm->all_lossless); lock_buffer_pool(pool); av1_superres_upscale(cm, pool); @@ -3374,7 +3377,7 @@ av1_loop_restoration_save_boundary_lines(&pbi->cur_buf->buf, cm, 0); } - if (!cm->skip_loop_filter && !cm->all_lossless && + if (!cm->skip_loop_filter && !cm->coded_lossless && (cm->cdef_bits || cm->cdef_strengths[0] || cm->cdef_uv_strengths[0])) { av1_cdef_frame(&pbi->cur_buf->buf, cm, &pbi->mb); }
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c index 46f30e0..0d18a0c 100644 --- a/av1/decoder/decodemv.c +++ b/av1/decoder/decodemv.c
@@ -38,7 +38,7 @@ static void read_cdef(AV1_COMMON *cm, aom_reader *r, MB_MODE_INFO *const mbmi, int mi_col, int mi_row) { - if (cm->all_lossless) return; + if (cm->coded_lossless) return; if (cm->allow_intrabc && NO_FILTER_FOR_IBC) { assert(cm->cdef_bits == 0); return;
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index 3d21c75..e08891a 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c
@@ -872,7 +872,7 @@ static void write_cdef(AV1_COMMON *cm, aom_writer *w, int skip, int mi_col, int mi_row) { - if (cm->all_lossless || (cm->allow_intrabc && NO_FILTER_FOR_IBC)) { + if (cm->coded_lossless || (cm->allow_intrabc && NO_FILTER_FOR_IBC)) { // Initialize to indicate no CDEF for safety. cm->cdef_bits = 0; cm->cdef_strengths[0] = 0; @@ -1989,7 +1989,7 @@ } static void encode_loopfilter(AV1_COMMON *cm, struct aom_write_bit_buffer *wb) { - assert(!cm->all_lossless); + assert(!cm->coded_lossless); if (cm->allow_intrabc && NO_FILTER_FOR_IBC) return; const int num_planes = av1_num_planes(cm); int i; @@ -2050,6 +2050,7 @@ } static void encode_cdef(const AV1_COMMON *cm, struct aom_write_bit_buffer *wb) { + assert(!cm->coded_lossless); if (cm->allow_intrabc && NO_FILTER_FOR_IBC) return; const int num_planes = av1_num_planes(cm); int i; @@ -2153,7 +2154,7 @@ static void write_tx_mode(AV1_COMMON *cm, TX_MODE *mode, struct aom_write_bit_buffer *wb) { - if (cm->all_lossless) { + if (cm->coded_lossless) { *mode = ONLY_4X4; return; } @@ -3242,8 +3243,10 @@ if (cm->all_lossless) { assert(av1_superres_unscaled(cm)); } else { - encode_loopfilter(cm, wb); - encode_cdef(cm, wb); + if (!cm->coded_lossless) { + encode_loopfilter(cm, wb); + encode_cdef(cm, wb); + } encode_restoration_mode(cm, wb); }
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index 19ade46..eb885bf 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c
@@ -3640,7 +3640,7 @@ } static TX_MODE select_tx_mode(const AV1_COMP *cpi) { - if (cpi->common.all_lossless) return ONLY_4X4; + if (cpi->common.coded_lossless) return ONLY_4X4; if (cpi->sf.tx_size_search_method == USE_LARGESTALL) return TX_MODE_LARGEST; else if (cpi->sf.tx_size_search_method == USE_FULL_RD || @@ -4161,7 +4161,8 @@ cpi->optimize_seg_arr[i] = cpi->optimize_speed_feature; } } - cm->all_lossless = all_lossless(cm, xd); + cm->coded_lossless = is_coded_lossless(cm, xd); + cm->all_lossless = cm->coded_lossless && av1_superres_unscaled(cm); cm->tx_mode = select_tx_mode(cpi); @@ -4192,7 +4193,7 @@ else cm->last_frame_seg_map = NULL; cm->current_frame_seg_map = cm->cur_frame->seg_map; - if ((cm->allow_intrabc && NO_FILTER_FOR_IBC) || cm->all_lossless) { + if ((cm->allow_intrabc && NO_FILTER_FOR_IBC) || cm->coded_lossless) { av1_set_default_ref_deltas(cm->lf.ref_deltas); av1_set_default_mode_deltas(cm->lf.mode_deltas); } else if (cm->prev_frame) {
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index c955756..f256113 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -3793,6 +3793,8 @@ // There has been a change in the encoded frame size set_size_literal(cpi, width, height); set_mv_search_params(cpi); + // Recalculate 'all_lossless' in case super-resolution was (un)selected. + cm->all_lossless = cm->coded_lossless && av1_superres_unscaled(cm); } if (cpi->oxcf.pass == 2) { @@ -4040,6 +4042,7 @@ assert(cpi->oxcf.enable_superres); assert(!is_lossless_requested(&cpi->oxcf)); + assert(!cm->all_lossless); av1_superres_upscale(cm, NULL); @@ -4074,21 +4077,16 @@ const int num_planes = av1_num_planes(cm); MACROBLOCKD *xd = &cpi->td.mb.e_mbd; - assert(IMPLIES(is_lossless_requested(&cpi->oxcf), cm->all_lossless)); + assert(IMPLIES(is_lossless_requested(&cpi->oxcf), + cm->coded_lossless && cm->all_lossless)); + + const int no_loopfilter = cm->coded_lossless || cm->large_scale_tile; + const int no_cdef = + !cpi->oxcf.using_cdef || cm->coded_lossless || cm->large_scale_tile; + const int no_restoration = + !cpi->oxcf.using_restoration || cm->all_lossless || cm->large_scale_tile; struct loopfilter *lf = &cm->lf; - int no_loopfilter = 0; - int no_restoration = !cpi->oxcf.using_restoration; - - if (cm->all_lossless || cm->large_scale_tile) { - no_loopfilter = 1; - no_restoration = 1; - } - - int no_cdef = 0; - if (cm->all_lossless || !cpi->oxcf.using_cdef || cm->large_scale_tile) { - no_cdef = 1; - } if (no_loopfilter) { lf->filter_level[0] = 0;