| /* |
| * Copyright (c) 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. |
| */ |
| |
| #include <limits.h> |
| #include <math.h> |
| #include <stdio.h> |
| |
| #include "./av1_rtcd.h" |
| #include "./aom_dsp_rtcd.h" |
| #include "./aom_config.h" |
| |
| #include "aom_dsp/aom_dsp_common.h" |
| #include "aom_ports/mem.h" |
| #include "aom_ports/aom_timer.h" |
| #include "aom_ports/system_state.h" |
| |
| #include "av1/common/common.h" |
| #include "av1/common/entropy.h" |
| #include "av1/common/entropymode.h" |
| #include "av1/common/idct.h" |
| #include "av1/common/mvref_common.h" |
| #include "av1/common/pred_common.h" |
| #include "av1/common/quant_common.h" |
| #include "av1/common/reconintra.h" |
| #include "av1/common/reconinter.h" |
| #include "av1/common/seg_common.h" |
| #include "av1/common/tile_common.h" |
| |
| #include "av1/encoder/aq_complexity.h" |
| #include "av1/encoder/aq_cyclicrefresh.h" |
| #include "av1/encoder/aq_variance.h" |
| #if CONFIG_SUPERTX |
| #include "av1/encoder/cost.h" |
| #endif |
| #if CONFIG_GLOBAL_MOTION |
| #include "av1/common/warped_motion.h" |
| #include "av1/encoder/global_motion.h" |
| #endif |
| #include "av1/encoder/encodeframe.h" |
| #include "av1/encoder/encodemb.h" |
| #include "av1/encoder/encodemv.h" |
| #include "av1/encoder/ethread.h" |
| #include "av1/encoder/extend.h" |
| #include "av1/encoder/rd.h" |
| #include "av1/encoder/rdopt.h" |
| #include "av1/encoder/segmentation.h" |
| #include "av1/encoder/tokenize.h" |
| |
| #if CONFIG_AOM_HIGHBITDEPTH |
| #define IF_HBD(...) __VA_ARGS__ |
| #else |
| #define IF_HBD(...) |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| |
| static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td, |
| TOKENEXTRA **t, RUN_TYPE dry_run, int mi_row, |
| int mi_col, BLOCK_SIZE bsize, |
| PICK_MODE_CONTEXT *ctx, int *rate); |
| |
| #if CONFIG_SUPERTX |
| static int check_intra_b(PICK_MODE_CONTEXT *ctx); |
| |
| static int check_intra_sb(const AV1_COMP *cpi, const TileInfo *const tile, |
| int mi_row, int mi_col, BLOCK_SIZE bsize, |
| PC_TREE *pc_tree); |
| static void predict_superblock(const AV1_COMP *const cpi, ThreadData *td, |
| #if CONFIG_EXT_INTER |
| int mi_row_ori, int mi_col_ori, |
| #endif // CONFIG_EXT_INTER |
| int mi_row_pred, int mi_col_pred, |
| BLOCK_SIZE bsize_pred, int b_sub8x8, int block); |
| static int check_supertx_sb(BLOCK_SIZE bsize, TX_SIZE supertx_size, |
| PC_TREE *pc_tree); |
| static void predict_sb_complex(const AV1_COMP *const cpi, ThreadData *td, |
| const TileInfo *const tile, int mi_row, |
| int mi_col, int mi_row_ori, int mi_col_ori, |
| RUN_TYPE dry_run, BLOCK_SIZE bsize, |
| BLOCK_SIZE top_bsize, uint8_t *dst_buf[3], |
| int dst_stride[3], PC_TREE *pc_tree); |
| static void update_state_sb_supertx(const AV1_COMP *const cpi, ThreadData *td, |
| const TileInfo *const tile, int mi_row, |
| int mi_col, BLOCK_SIZE bsize, |
| RUN_TYPE dry_run, PC_TREE *pc_tree); |
| static void rd_supertx_sb(const AV1_COMP *const cpi, ThreadData *td, |
| const TileInfo *const tile, int mi_row, int mi_col, |
| BLOCK_SIZE bsize, int *tmp_rate, int64_t *tmp_dist, |
| TX_TYPE *best_tx, PC_TREE *pc_tree); |
| #endif // CONFIG_SUPERTX |
| |
| // This is used as a reference when computing the source variance for the |
| // purposes of activity masking. |
| // Eventually this should be replaced by custom no-reference routines, |
| // which will be faster. |
| static const uint8_t AV1_VAR_OFFS[MAX_SB_SIZE] = { |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| #if CONFIG_EXT_PARTITION |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 |
| #endif // CONFIG_EXT_PARTITION |
| }; |
| |
| #if CONFIG_AOM_HIGHBITDEPTH |
| static const uint16_t AV1_HIGH_VAR_OFFS_8[MAX_SB_SIZE] = { |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| #if CONFIG_EXT_PARTITION |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 |
| #endif // CONFIG_EXT_PARTITION |
| }; |
| |
| static const uint16_t AV1_HIGH_VAR_OFFS_10[MAX_SB_SIZE] = { |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| #if CONFIG_EXT_PARTITION |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, |
| 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4, 128 * 4 |
| #endif // CONFIG_EXT_PARTITION |
| }; |
| |
| static const uint16_t AV1_HIGH_VAR_OFFS_12[MAX_SB_SIZE] = { |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, |
| #if CONFIG_EXT_PARTITION |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, 128 * 16, |
| 128 * 16 |
| #endif // CONFIG_EXT_PARTITION |
| }; |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| |
| unsigned int av1_get_sby_perpixel_variance(const AV1_COMP *cpi, |
| const struct buf_2d *ref, |
| BLOCK_SIZE bs) { |
| unsigned int sse; |
| const unsigned int var = |
| cpi->fn_ptr[bs].vf(ref->buf, ref->stride, AV1_VAR_OFFS, 0, &sse); |
| return ROUND_POWER_OF_TWO(var, num_pels_log2_lookup[bs]); |
| } |
| |
| #if CONFIG_AOM_HIGHBITDEPTH |
| unsigned int av1_high_get_sby_perpixel_variance(const AV1_COMP *cpi, |
| const struct buf_2d *ref, |
| BLOCK_SIZE bs, int bd) { |
| unsigned int var, sse; |
| switch (bd) { |
| case 10: |
| var = |
| cpi->fn_ptr[bs].vf(ref->buf, ref->stride, |
| CONVERT_TO_BYTEPTR(AV1_HIGH_VAR_OFFS_10), 0, &sse); |
| break; |
| case 12: |
| var = |
| cpi->fn_ptr[bs].vf(ref->buf, ref->stride, |
| CONVERT_TO_BYTEPTR(AV1_HIGH_VAR_OFFS_12), 0, &sse); |
| break; |
| case 8: |
| default: |
| var = |
| cpi->fn_ptr[bs].vf(ref->buf, ref->stride, |
| CONVERT_TO_BYTEPTR(AV1_HIGH_VAR_OFFS_8), 0, &sse); |
| break; |
| } |
| return ROUND_POWER_OF_TWO(var, num_pels_log2_lookup[bs]); |
| } |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| |
| static unsigned int get_sby_perpixel_diff_variance(const AV1_COMP *const cpi, |
| const struct buf_2d *ref, |
| int mi_row, int mi_col, |
| BLOCK_SIZE bs) { |
| unsigned int sse, var; |
| uint8_t *last_y; |
| const YV12_BUFFER_CONFIG *last = get_ref_frame_buffer(cpi, LAST_FRAME); |
| |
| assert(last != NULL); |
| last_y = |
| &last->y_buffer[mi_row * MI_SIZE * last->y_stride + mi_col * MI_SIZE]; |
| var = cpi->fn_ptr[bs].vf(ref->buf, ref->stride, last_y, last->y_stride, &sse); |
| return ROUND_POWER_OF_TWO(var, num_pels_log2_lookup[bs]); |
| } |
| |
| static BLOCK_SIZE get_rd_var_based_fixed_partition(AV1_COMP *cpi, MACROBLOCK *x, |
| int mi_row, int mi_col) { |
| unsigned int var = get_sby_perpixel_diff_variance( |
| cpi, &x->plane[0].src, mi_row, mi_col, BLOCK_64X64); |
| if (var < 8) |
| return BLOCK_64X64; |
| else if (var < 128) |
| return BLOCK_32X32; |
| else if (var < 2048) |
| return BLOCK_16X16; |
| else |
| return BLOCK_8X8; |
| } |
| |
| // Lighter version of set_offsets that only sets the mode info |
| // pointers. |
| static void set_mode_info_offsets(const AV1_COMP *const cpi, |
| MACROBLOCK *const x, MACROBLOCKD *const xd, |
| int mi_row, int mi_col) { |
| const AV1_COMMON *const cm = &cpi->common; |
| const int idx_str = xd->mi_stride * mi_row + mi_col; |
| xd->mi = cm->mi_grid_visible + idx_str; |
| xd->mi[0] = cm->mi + idx_str; |
| x->mbmi_ext = cpi->mbmi_ext_base + (mi_row * cm->mi_cols + mi_col); |
| } |
| |
| static void set_offsets_without_segment_id(const AV1_COMP *const cpi, |
| const TileInfo *const tile, |
| MACROBLOCK *const x, int mi_row, |
| int mi_col, BLOCK_SIZE bsize) { |
| const AV1_COMMON *const cm = &cpi->common; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| const int mi_width = num_8x8_blocks_wide_lookup[bsize]; |
| const int mi_height = num_8x8_blocks_high_lookup[bsize]; |
| const int bwl = b_width_log2_lookup[AOMMAX(bsize, BLOCK_8X8)]; |
| const int bhl = b_height_log2_lookup[AOMMAX(bsize, BLOCK_8X8)]; |
| |
| set_skip_context(xd, mi_row, mi_col); |
| |
| set_mode_info_offsets(cpi, x, xd, mi_row, mi_col); |
| |
| #if CONFIG_VAR_TX |
| xd->above_txfm_context = cm->above_txfm_context + mi_col; |
| xd->left_txfm_context = |
| xd->left_txfm_context_buffer + (mi_row & MAX_MIB_MASK); |
| xd->max_tx_size = max_txsize_lookup[bsize]; |
| #endif |
| |
| // Set up destination pointers. |
| av1_setup_dst_planes(xd->plane, get_frame_new_buffer(cm), mi_row, mi_col); |
| |
| // Set up limit values for MV components. |
| // Mv beyond the range do not produce new/different prediction block. |
| x->mv_row_min = -(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND); |
| x->mv_col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND); |
| x->mv_row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND; |
| x->mv_col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND; |
| |
| set_plane_n4(xd, mi_width, mi_height, bwl, bhl); |
| |
| // Set up distance of MB to edge of frame in 1/8th pel units. |
| assert(!(mi_col & (mi_width - 1)) && !(mi_row & (mi_height - 1))); |
| set_mi_row_col(xd, tile, mi_row, mi_height, mi_col, mi_width, cm->mi_rows, |
| cm->mi_cols); |
| |
| // Set up source buffers. |
| av1_setup_src_planes(x, cpi->Source, mi_row, mi_col); |
| |
| // R/D setup. |
| x->rddiv = cpi->rd.RDDIV; |
| x->rdmult = cpi->rd.RDMULT; |
| |
| // required by av1_append_sub8x8_mvs_for_idx() and av1_find_best_ref_mvs() |
| xd->tile = *tile; |
| } |
| |
| static void set_offsets(const AV1_COMP *const cpi, const TileInfo *const tile, |
| MACROBLOCK *const x, int mi_row, int mi_col, |
| BLOCK_SIZE bsize) { |
| const AV1_COMMON *const cm = &cpi->common; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| MB_MODE_INFO *mbmi; |
| const struct segmentation *const seg = &cm->seg; |
| |
| set_offsets_without_segment_id(cpi, tile, x, mi_row, mi_col, bsize); |
| |
| mbmi = &xd->mi[0]->mbmi; |
| |
| // Setup segment ID. |
| if (seg->enabled) { |
| if (!cpi->vaq_refresh) { |
| const uint8_t *const map = |
| seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map; |
| mbmi->segment_id = get_segment_id(cm, map, bsize, mi_row, mi_col); |
| } |
| av1_init_plane_quantizers(cpi, x, mbmi->segment_id); |
| } else { |
| mbmi->segment_id = 0; |
| } |
| |
| #if CONFIG_SUPERTX |
| mbmi->segment_id_supertx = MAX_SEGMENTS; |
| #endif // CONFIG_SUPERTX |
| } |
| |
| #if CONFIG_SUPERTX |
| static void set_offsets_supertx(const AV1_COMP *const cpi, ThreadData *td, |
| const TileInfo *const tile, int mi_row, |
| int mi_col, BLOCK_SIZE bsize) { |
| MACROBLOCK *const x = &td->mb; |
| const AV1_COMMON *const cm = &cpi->common; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| const int mi_width = num_8x8_blocks_wide_lookup[bsize]; |
| const int mi_height = num_8x8_blocks_high_lookup[bsize]; |
| |
| set_mode_info_offsets(cpi, x, xd, mi_row, mi_col); |
| |
| // Set up distance of MB to edge of frame in 1/8th pel units. |
| assert(!(mi_col & (mi_width - 1)) && !(mi_row & (mi_height - 1))); |
| set_mi_row_col(xd, tile, mi_row, mi_height, mi_col, mi_width, cm->mi_rows, |
| cm->mi_cols); |
| } |
| |
| static void set_offsets_extend(const AV1_COMP *const cpi, ThreadData *td, |
| const TileInfo *const tile, int mi_row_pred, |
| int mi_col_pred, int mi_row_ori, int mi_col_ori, |
| BLOCK_SIZE bsize_pred) { |
| // Used in supertx |
| // (mi_row_ori, mi_col_ori, bsize_ori): region for mv |
| // (mi_row_pred, mi_col_pred, bsize_pred): region to predict |
| MACROBLOCK *const x = &td->mb; |
| const AV1_COMMON *const cm = &cpi->common; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| const int mi_width = num_8x8_blocks_wide_lookup[bsize_pred]; |
| const int mi_height = num_8x8_blocks_high_lookup[bsize_pred]; |
| |
| set_mode_info_offsets(cpi, x, xd, mi_row_ori, mi_col_ori); |
| |
| // Set up limit values for MV components. |
| // Mv beyond the range do not produce new/different prediction block. |
| x->mv_row_min = -(((mi_row_pred + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND); |
| x->mv_col_min = -(((mi_col_pred + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND); |
| x->mv_row_max = (cm->mi_rows - mi_row_pred) * MI_SIZE + AOM_INTERP_EXTEND; |
| x->mv_col_max = (cm->mi_cols - mi_col_pred) * MI_SIZE + AOM_INTERP_EXTEND; |
| |
| // Set up distance of MB to edge of frame in 1/8th pel units. |
| assert(!(mi_col_pred & (mi_width - 1)) && !(mi_row_pred & (mi_height - 1))); |
| set_mi_row_col(xd, tile, mi_row_pred, mi_height, mi_col_pred, mi_width, |
| cm->mi_rows, cm->mi_cols); |
| xd->up_available = (mi_row_ori > tile->mi_row_start); |
| xd->left_available = (mi_col_ori > tile->mi_col_start); |
| |
| // R/D setup. |
| x->rddiv = cpi->rd.RDDIV; |
| x->rdmult = cpi->rd.RDMULT; |
| } |
| |
| static void set_segment_id_supertx(const AV1_COMP *const cpi, |
| MACROBLOCK *const x, const int mi_row, |
| const int mi_col, const BLOCK_SIZE bsize) { |
| const AV1_COMMON *cm = &cpi->common; |
| const struct segmentation *seg = &cm->seg; |
| const int miw = |
| AOMMIN(num_8x8_blocks_wide_lookup[bsize], cm->mi_cols - mi_col); |
| const int mih = |
| AOMMIN(num_8x8_blocks_high_lookup[bsize], cm->mi_rows - mi_row); |
| const int mi_offset = mi_row * cm->mi_stride + mi_col; |
| MODE_INFO **const mip = cm->mi_grid_visible + mi_offset; |
| int r, c; |
| int seg_id_supertx = MAX_SEGMENTS; |
| |
| if (!seg->enabled) { |
| seg_id_supertx = 0; |
| } else { |
| // Find the minimum segment_id |
| for (r = 0; r < mih; r++) |
| for (c = 0; c < miw; c++) |
| seg_id_supertx = |
| AOMMIN(mip[r * cm->mi_stride + c]->mbmi.segment_id, seg_id_supertx); |
| assert(0 <= seg_id_supertx && seg_id_supertx < MAX_SEGMENTS); |
| |
| // Initialize plane quantisers |
| av1_init_plane_quantizers(cpi, x, seg_id_supertx); |
| } |
| |
| // Assign the the segment_id back to segment_id_supertx |
| for (r = 0; r < mih; r++) |
| for (c = 0; c < miw; c++) |
| mip[r * cm->mi_stride + c]->mbmi.segment_id_supertx = seg_id_supertx; |
| } |
| #endif // CONFIG_SUPERTX |
| |
| static void set_block_size(AV1_COMP *const cpi, MACROBLOCK *const x, |
| MACROBLOCKD *const xd, int mi_row, int mi_col, |
| BLOCK_SIZE bsize) { |
| if (cpi->common.mi_cols > mi_col && cpi->common.mi_rows > mi_row) { |
| set_mode_info_offsets(cpi, x, xd, mi_row, mi_col); |
| xd->mi[0]->mbmi.sb_type = bsize; |
| } |
| } |
| |
| static void set_vt_partitioning(AV1_COMP *cpi, MACROBLOCK *const x, |
| MACROBLOCKD *const xd, VAR_TREE *vt, int mi_row, |
| int mi_col, const int64_t *const threshold, |
| const BLOCK_SIZE *const bsize_min) { |
| AV1_COMMON *const cm = &cpi->common; |
| const int hbw = num_8x8_blocks_wide_lookup[vt->bsize] / 2; |
| const int hbh = num_8x8_blocks_high_lookup[vt->bsize] / 2; |
| const int has_cols = mi_col + hbw < cm->mi_cols; |
| const int has_rows = mi_row + hbh < cm->mi_rows; |
| |
| if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; |
| |
| assert(vt->bsize >= BLOCK_8X8); |
| |
| assert(hbh == hbw); |
| |
| if (vt->bsize == BLOCK_8X8 && cm->frame_type != KEY_FRAME) { |
| set_block_size(cpi, x, xd, mi_row, mi_col, BLOCK_8X8); |
| return; |
| } |
| |
| if (vt->force_split || (!has_cols && !has_rows)) goto split; |
| |
| // For bsize=bsize_min (16x16/8x8 for 8x8/4x4 downsampling), select if |
| // variance is below threshold, otherwise split will be selected. |
| // No check for vert/horiz split as too few samples for variance. |
| if (vt->bsize == bsize_min[0]) { |
| if (has_cols && has_rows && vt->variances.none.variance < threshold[0]) { |
| set_block_size(cpi, x, xd, mi_row, mi_col, vt->bsize); |
| return; |
| } else { |
| BLOCK_SIZE subsize = get_subsize(vt->bsize, PARTITION_SPLIT); |
| set_block_size(cpi, x, xd, mi_row, mi_col, subsize); |
| if (vt->bsize > BLOCK_8X8) { |
| set_block_size(cpi, x, xd, mi_row, mi_col + hbw, subsize); |
| set_block_size(cpi, x, xd, mi_row + hbh, mi_col, subsize); |
| set_block_size(cpi, x, xd, mi_row + hbh, mi_col + hbw, subsize); |
| } |
| return; |
| } |
| } else if (vt->bsize > bsize_min[0]) { |
| // For key frame: take split for bsize above 32X32 or very high variance. |
| if (cm->frame_type == KEY_FRAME && |
| (vt->bsize > BLOCK_32X32 || |
| vt->variances.none.variance > (threshold[0] << 4))) { |
| goto split; |
| } |
| // If variance is low, take the bsize (no split). |
| if (has_cols && has_rows && vt->variances.none.variance < threshold[0]) { |
| set_block_size(cpi, x, xd, mi_row, mi_col, vt->bsize); |
| return; |
| } |
| |
| // Check vertical split. |
| if (has_rows) { |
| BLOCK_SIZE subsize = get_subsize(vt->bsize, PARTITION_VERT); |
| if (vt->variances.vert[0].variance < threshold[0] && |
| vt->variances.vert[1].variance < threshold[0] && |
| get_plane_block_size(subsize, &xd->plane[1]) < BLOCK_INVALID) { |
| set_block_size(cpi, x, xd, mi_row, mi_col, subsize); |
| set_block_size(cpi, x, xd, mi_row, mi_col + hbw, subsize); |
| return; |
| } |
| } |
| // Check horizontal split. |
| if (has_cols) { |
| BLOCK_SIZE subsize = get_subsize(vt->bsize, PARTITION_HORZ); |
| if (vt->variances.horz[0].variance < threshold[0] && |
| vt->variances.horz[1].variance < threshold[0] && |
| get_plane_block_size(subsize, &xd->plane[1]) < BLOCK_INVALID) { |
| set_block_size(cpi, x, xd, mi_row, mi_col, subsize); |
| set_block_size(cpi, x, xd, mi_row + hbh, mi_col, subsize); |
| return; |
| } |
| } |
| } |
| |
| split : { |
| set_vt_partitioning(cpi, x, xd, vt->split[0], mi_row, mi_col, threshold + 1, |
| bsize_min + 1); |
| set_vt_partitioning(cpi, x, xd, vt->split[1], mi_row, mi_col + hbw, |
| threshold + 1, bsize_min + 1); |
| set_vt_partitioning(cpi, x, xd, vt->split[2], mi_row + hbh, mi_col, |
| threshold + 1, bsize_min + 1); |
| set_vt_partitioning(cpi, x, xd, vt->split[3], mi_row + hbh, mi_col + hbw, |
| threshold + 1, bsize_min + 1); |
| return; |
| } |
| } |
| |
| // Set the variance split thresholds for following the block sizes: |
| // 0 - threshold_64x64, 1 - threshold_32x32, 2 - threshold_16x16, |
| // 3 - vbp_threshold_8x8. vbp_threshold_8x8 (to split to 4x4 partition) is |
| // currently only used on key frame. |
| static void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[], int q) { |
| AV1_COMMON *const cm = &cpi->common; |
| const int is_key_frame = (cm->frame_type == KEY_FRAME); |
| const int threshold_multiplier = is_key_frame ? 20 : 1; |
| const int64_t threshold_base = |
| (int64_t)(threshold_multiplier * cpi->y_dequant[q][1]); |
| if (is_key_frame) { |
| thresholds[1] = threshold_base; |
| thresholds[2] = threshold_base >> 2; |
| thresholds[3] = threshold_base >> 2; |
| thresholds[4] = threshold_base << 2; |
| } else { |
| thresholds[2] = threshold_base; |
| if (cm->width <= 352 && cm->height <= 288) { |
| thresholds[1] = threshold_base >> 2; |
| thresholds[3] = threshold_base << 3; |
| } else { |
| thresholds[1] = threshold_base; |
| thresholds[2] = (5 * threshold_base) >> 2; |
| if (cm->width >= 1920 && cm->height >= 1080) |
| thresholds[2] = (7 * threshold_base) >> 2; |
| thresholds[3] = threshold_base << cpi->oxcf.speed; |
| } |
| } |
| thresholds[0] = INT64_MIN; |
| } |
| |
| void av1_set_variance_partition_thresholds(AV1_COMP *cpi, int q) { |
| AV1_COMMON *const cm = &cpi->common; |
| SPEED_FEATURES *const sf = &cpi->sf; |
| const int is_key_frame = (cm->frame_type == KEY_FRAME); |
| if (sf->partition_search_type != VAR_BASED_PARTITION && |
| sf->partition_search_type != REFERENCE_PARTITION) { |
| return; |
| } else { |
| set_vbp_thresholds(cpi, cpi->vbp_thresholds, q); |
| // The thresholds below are not changed locally. |
| if (is_key_frame) { |
| cpi->vbp_threshold_sad = 0; |
| cpi->vbp_bsize_min = BLOCK_8X8; |
| } else { |
| if (cm->width <= 352 && cm->height <= 288) |
| cpi->vbp_threshold_sad = 100; |
| else |
| cpi->vbp_threshold_sad = (cpi->y_dequant[q][1] << 1) > 1000 |
| ? (cpi->y_dequant[q][1] << 1) |
| : 1000; |
| cpi->vbp_bsize_min = BLOCK_16X16; |
| } |
| cpi->vbp_threshold_minmax = 15 + (q >> 3); |
| } |
| } |
| |
| // Compute the minmax over the 8x8 subblocks. |
| static int compute_minmax_8x8(const uint8_t *src, int src_stride, |
| const uint8_t *ref, int ref_stride, |
| #if CONFIG_AOM_HIGHBITDEPTH |
| int highbd, |
| #endif |
| int pixels_wide, int pixels_high) { |
| int k; |
| int minmax_max = 0; |
| int minmax_min = 255; |
| // Loop over the 4 8x8 subblocks. |
| for (k = 0; k < 4; k++) { |
| const int x8_idx = ((k & 1) << 3); |
| const int y8_idx = ((k >> 1) << 3); |
| int min = 0; |
| int max = 0; |
| if (x8_idx < pixels_wide && y8_idx < pixels_high) { |
| const int src_offset = y8_idx * src_stride + x8_idx; |
| const int ref_offset = y8_idx * ref_stride + x8_idx; |
| #if CONFIG_AOM_HIGHBITDEPTH |
| if (highbd) { |
| aom_highbd_minmax_8x8(src + src_offset, src_stride, ref + ref_offset, |
| ref_stride, &min, &max); |
| } else { |
| aom_minmax_8x8(src + src_offset, src_stride, ref + ref_offset, |
| ref_stride, &min, &max); |
| } |
| #else |
| aom_minmax_8x8(src + src_offset, src_stride, ref + ref_offset, ref_stride, |
| &min, &max); |
| #endif |
| if ((max - min) > minmax_max) minmax_max = (max - min); |
| if ((max - min) < minmax_min) minmax_min = (max - min); |
| } |
| } |
| return (minmax_max - minmax_min); |
| } |
| |
| #if CONFIG_AOM_HIGHBITDEPTH |
| static INLINE int avg_4x4(const uint8_t *const src, const int stride, |
| const int highbd) { |
| if (highbd) { |
| return aom_highbd_avg_4x4(src, stride); |
| } else { |
| return aom_avg_4x4(src, stride); |
| } |
| } |
| #else |
| static INLINE int avg_4x4(const uint8_t *const src, const int stride) { |
| return aom_avg_4x4(src, stride); |
| } |
| #endif |
| |
| #if CONFIG_AOM_HIGHBITDEPTH |
| static INLINE int avg_8x8(const uint8_t *const src, const int stride, |
| const int highbd) { |
| if (highbd) { |
| return aom_highbd_avg_8x8(src, stride); |
| } else { |
| return aom_avg_8x8(src, stride); |
| } |
| } |
| #else |
| static INLINE int avg_8x8(const uint8_t *const src, const int stride) { |
| return aom_avg_8x8(src, stride); |
| } |
| #endif |
| |
| static void init_variance_tree(VAR_TREE *const vt, |
| #if CONFIG_AOM_HIGHBITDEPTH |
| const int highbd, |
| #endif |
| BLOCK_SIZE bsize, BLOCK_SIZE leaf_size, |
| const int width, const int height, |
| const uint8_t *const src, const int src_stride, |
| const uint8_t *const ref, const int ref_stride) { |
| assert(bsize >= leaf_size); |
| |
| vt->bsize = bsize; |
| |
| vt->force_split = 0; |
| |
| vt->src = src; |
| vt->src_stride = src_stride; |
| vt->ref = ref; |
| vt->ref_stride = ref_stride; |
| |
| vt->width = width; |
| vt->height = height; |
| |
| #if CONFIG_AOM_HIGHBITDEPTH |
| vt->highbd = highbd; |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| |
| if (bsize > leaf_size) { |
| const BLOCK_SIZE subsize = get_subsize(bsize, PARTITION_SPLIT); |
| const int px = num_4x4_blocks_wide_lookup[subsize] * 4; |
| |
| init_variance_tree(vt->split[0], |
| #if CONFIG_AOM_HIGHBITDEPTH |
| highbd, |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| subsize, leaf_size, AOMMIN(px, width), |
| AOMMIN(px, height), src, src_stride, ref, ref_stride); |
| init_variance_tree(vt->split[1], |
| #if CONFIG_AOM_HIGHBITDEPTH |
| highbd, |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| subsize, leaf_size, width - px, AOMMIN(px, height), |
| src + px, src_stride, ref + px, ref_stride); |
| init_variance_tree(vt->split[2], |
| #if CONFIG_AOM_HIGHBITDEPTH |
| highbd, |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| subsize, leaf_size, AOMMIN(px, width), height - px, |
| src + px * src_stride, src_stride, ref + px * ref_stride, |
| ref_stride); |
| init_variance_tree(vt->split[3], |
| #if CONFIG_AOM_HIGHBITDEPTH |
| highbd, |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| subsize, leaf_size, width - px, height - px, |
| src + px * src_stride + px, src_stride, |
| ref + px * ref_stride + px, ref_stride); |
| } |
| } |
| |
| // Fill the variance tree based on averaging pixel values (sub-sampling), at |
| // the leaf node size. |
| static void fill_variance_tree(VAR_TREE *const vt, const BLOCK_SIZE leaf_size) { |
| if (vt->bsize > leaf_size) { |
| fill_variance_tree(vt->split[0], leaf_size); |
| fill_variance_tree(vt->split[1], leaf_size); |
| fill_variance_tree(vt->split[2], leaf_size); |
| fill_variance_tree(vt->split[3], leaf_size); |
| fill_variance_node(vt); |
| } else if (vt->width <= 0 || vt->height <= 0) { |
| fill_variance(0, 0, 0, &vt->variances.none); |
| } else { |
| unsigned int sse = 0; |
| int sum = 0; |
| int src_avg; |
| int ref_avg; |
| assert(leaf_size == BLOCK_4X4 || leaf_size == BLOCK_8X8); |
| if (leaf_size == BLOCK_4X4) { |
| src_avg = avg_4x4(vt->src, vt->src_stride IF_HBD(, vt->highbd)); |
| ref_avg = avg_4x4(vt->ref, vt->ref_stride IF_HBD(, vt->highbd)); |
| } else { |
| src_avg = avg_8x8(vt->src, vt->src_stride IF_HBD(, vt->highbd)); |
| ref_avg = avg_8x8(vt->ref, vt->ref_stride IF_HBD(, vt->highbd)); |
| } |
| sum = src_avg - ref_avg; |
| sse = sum * sum; |
| fill_variance(sse, sum, 0, &vt->variances.none); |
| } |
| } |
| |
| static void refine_variance_tree(VAR_TREE *const vt, const int64_t threshold) { |
| if (vt->bsize >= BLOCK_8X8) { |
| if (vt->bsize == BLOCK_16X16) { |
| if (vt->variances.none.variance <= threshold) |
| return; |
| else |
| vt->force_split = 0; |
| } |
| |
| refine_variance_tree(vt->split[0], threshold); |
| refine_variance_tree(vt->split[1], threshold); |
| refine_variance_tree(vt->split[2], threshold); |
| refine_variance_tree(vt->split[3], threshold); |
| |
| if (vt->bsize <= BLOCK_16X16) fill_variance_node(vt); |
| } else if (vt->width <= 0 || vt->height <= 0) { |
| fill_variance(0, 0, 0, &vt->variances.none); |
| } else { |
| const int src_avg = avg_4x4(vt->src, vt->src_stride IF_HBD(, vt->highbd)); |
| const int ref_avg = avg_4x4(vt->ref, vt->ref_stride IF_HBD(, vt->highbd)); |
| const int sum = src_avg - ref_avg; |
| const unsigned int sse = sum * sum; |
| assert(vt->bsize == BLOCK_4X4); |
| fill_variance(sse, sum, 0, &vt->variances.none); |
| } |
| } |
| |
| static int check_split_key_frame(VAR_TREE *const vt, const int64_t threshold) { |
| if (vt->bsize == BLOCK_32X32) { |
| vt->force_split = vt->variances.none.variance > threshold; |
| } else { |
| vt->force_split |= check_split_key_frame(vt->split[0], threshold); |
| vt->force_split |= check_split_key_frame(vt->split[1], threshold); |
| vt->force_split |= check_split_key_frame(vt->split[2], threshold); |
| vt->force_split |= check_split_key_frame(vt->split[3], threshold); |
| } |
| return vt->force_split; |
| } |
| |
| static int check_split(AV1_COMP *const cpi, VAR_TREE *const vt, |
| const int segment_id, const int64_t *const thresholds) { |
| if (vt->bsize == BLOCK_16X16) { |
| vt->force_split = vt->variances.none.variance > thresholds[0]; |
| if (!vt->force_split && vt->variances.none.variance > thresholds[-1] && |
| !cyclic_refresh_segment_id_boosted(segment_id)) { |
| // We have some nominal amount of 16x16 variance (based on average), |
| // compute the minmax over the 8x8 sub-blocks, and if above threshold, |
| // force split to 8x8 block for this 16x16 block. |
| int minmax = |
| compute_minmax_8x8(vt->src, vt->src_stride, vt->ref, vt->ref_stride, |
| #if CONFIG_AOM_HIGHBITDEPTH |
| vt->highbd, |
| #endif |
| vt->width, vt->height); |
| vt->force_split = minmax > cpi->vbp_threshold_minmax; |
| } |
| } else { |
| vt->force_split |= |
| check_split(cpi, vt->split[0], segment_id, thresholds + 1); |
| vt->force_split |= |
| check_split(cpi, vt->split[1], segment_id, thresholds + 1); |
| vt->force_split |= |
| check_split(cpi, vt->split[2], segment_id, thresholds + 1); |
| vt->force_split |= |
| check_split(cpi, vt->split[3], segment_id, thresholds + 1); |
| |
| if (vt->bsize == BLOCK_32X32 && !vt->force_split) { |
| vt->force_split = vt->variances.none.variance > thresholds[0]; |
| } |
| } |
| |
| return vt->force_split; |
| } |
| |
| // This function chooses partitioning based on the variance between source and |
| // reconstructed last (or golden), where variance is computed for down-sampled |
| // inputs. |
| static void choose_partitioning(AV1_COMP *const cpi, ThreadData *const td, |
| const TileInfo *const tile, MACROBLOCK *const x, |
| const int mi_row, const int mi_col) { |
| AV1_COMMON *const cm = &cpi->common; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| VAR_TREE *const vt = td->var_root[cm->mib_size_log2 - MIN_MIB_SIZE_LOG2]; |
| #if CONFIG_DUAL_FILTER |
| int i; |
| #endif |
| const uint8_t *src; |
| const uint8_t *ref; |
| int src_stride; |
| int ref_stride; |
| int pixels_wide = 8 * num_8x8_blocks_wide_lookup[cm->sb_size]; |
| int pixels_high = 8 * num_8x8_blocks_high_lookup[cm->sb_size]; |
| int64_t thresholds[5] = { |
| cpi->vbp_thresholds[0], cpi->vbp_thresholds[1], cpi->vbp_thresholds[2], |
| cpi->vbp_thresholds[3], cpi->vbp_thresholds[4], |
| }; |
| BLOCK_SIZE bsize_min[5] = { BLOCK_16X16, BLOCK_16X16, BLOCK_16X16, |
| cpi->vbp_bsize_min, BLOCK_8X8 }; |
| const int start_level = cm->sb_size == BLOCK_64X64 ? 1 : 0; |
| const int64_t *const thre = thresholds + start_level; |
| const BLOCK_SIZE *const bmin = bsize_min + start_level; |
| |
| const int is_key_frame = (cm->frame_type == KEY_FRAME); |
| const int low_res = (cm->width <= 352 && cm->height <= 288); |
| |
| int segment_id = CR_SEGMENT_ID_BASE; |
| |
| if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled) { |
| const uint8_t *const map = |
| cm->seg.update_map ? cpi->segmentation_map : cm->last_frame_seg_map; |
| segment_id = get_segment_id(cm, map, cm->sb_size, mi_row, mi_col); |
| |
| if (cyclic_refresh_segment_id_boosted(segment_id)) { |
| int q = av1_get_qindex(&cm->seg, segment_id, cm->base_qindex); |
| set_vbp_thresholds(cpi, thresholds, q); |
| } |
| } |
| |
| set_offsets(cpi, tile, x, mi_row, mi_col, cm->sb_size); |
| |
| if (xd->mb_to_right_edge < 0) pixels_wide += (xd->mb_to_right_edge >> 3); |
| if (xd->mb_to_bottom_edge < 0) pixels_high += (xd->mb_to_bottom_edge >> 3); |
| |
| src = x->plane[0].src.buf; |
| src_stride = x->plane[0].src.stride; |
| |
| if (!is_key_frame) { |
| MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi; |
| const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME); |
| const YV12_BUFFER_CONFIG *yv12_g = get_ref_frame_buffer(cpi, GOLDEN_FRAME); |
| unsigned int y_sad, y_sad_g; |
| |
| const int hbs = cm->mib_size / 2; |
| const int split_vert = mi_col + hbs >= cm->mi_cols; |
| const int split_horz = mi_row + hbs >= cm->mi_rows; |
| BLOCK_SIZE bsize; |
| |
| if (split_vert && split_horz) |
| bsize = get_subsize(cm->sb_size, PARTITION_SPLIT); |
| else if (split_vert) |
| bsize = get_subsize(cm->sb_size, PARTITION_VERT); |
| else if (split_horz) |
| bsize = get_subsize(cm->sb_size, PARTITION_HORZ); |
| else |
| bsize = cm->sb_size; |
| |
| assert(yv12 != NULL); |
| |
| if (yv12_g && yv12_g != yv12) { |
| av1_setup_pre_planes(xd, 0, yv12_g, mi_row, mi_col, |
| &cm->frame_refs[GOLDEN_FRAME - 1].sf); |
| y_sad_g = cpi->fn_ptr[bsize].sdf( |
| x->plane[0].src.buf, x->plane[0].src.stride, xd->plane[0].pre[0].buf, |
| xd->plane[0].pre[0].stride); |
| } else { |
| y_sad_g = UINT_MAX; |
| } |
| |
| av1_setup_pre_planes(xd, 0, yv12, mi_row, mi_col, |
| &cm->frame_refs[LAST_FRAME - 1].sf); |
| mbmi->ref_frame[0] = LAST_FRAME; |
| mbmi->ref_frame[1] = NONE; |
| mbmi->sb_type = cm->sb_size; |
| mbmi->mv[0].as_int = 0; |
| #if CONFIG_DUAL_FILTER |
| for (i = 0; i < 4; ++i) mbmi->interp_filter[i] = BILINEAR; |
| #else |
| mbmi->interp_filter = BILINEAR; |
| #endif |
| |
| y_sad = av1_int_pro_motion_estimation(cpi, x, bsize, mi_row, mi_col); |
| |
| if (y_sad_g < y_sad) { |
| av1_setup_pre_planes(xd, 0, yv12_g, mi_row, mi_col, |
| &cm->frame_refs[GOLDEN_FRAME - 1].sf); |
| mbmi->ref_frame[0] = GOLDEN_FRAME; |
| mbmi->mv[0].as_int = 0; |
| y_sad = y_sad_g; |
| } else { |
| x->pred_mv[LAST_FRAME] = mbmi->mv[0].as_mv; |
| } |
| |
| av1_build_inter_predictors_sb(xd, mi_row, mi_col, cm->sb_size); |
| |
| ref = xd->plane[0].dst.buf; |
| ref_stride = xd->plane[0].dst.stride; |
| |
| // If the y_sad is very small, take the largest partition and exit. |
| // Don't check on boosted segment for now, as largest is suppressed there. |
| if (segment_id == CR_SEGMENT_ID_BASE && y_sad < cpi->vbp_threshold_sad) { |
| if (!split_vert && !split_horz) { |
| set_block_size(cpi, x, xd, mi_row, mi_col, cm->sb_size); |
| return; |
| } |
| } |
| } else { |
| ref = AV1_VAR_OFFS; |
| ref_stride = 0; |
| #if CONFIG_AOM_HIGHBITDEPTH |
| if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { |
| switch (xd->bd) { |
| case 10: ref = CONVERT_TO_BYTEPTR(AV1_HIGH_VAR_OFFS_10); break; |
| case 12: ref = CONVERT_TO_BYTEPTR(AV1_HIGH_VAR_OFFS_12); break; |
| case 8: |
| default: ref = CONVERT_TO_BYTEPTR(AV1_HIGH_VAR_OFFS_8); break; |
| } |
| } |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| } |
| |
| init_variance_tree( |
| vt, |
| #if CONFIG_AOM_HIGHBITDEPTH |
| xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH, |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| cm->sb_size, (is_key_frame || low_res) ? BLOCK_4X4 : BLOCK_8X8, |
| pixels_wide, pixels_high, src, src_stride, ref, ref_stride); |
| |
| // Fill in the entire tree of variances and compute splits. |
| if (is_key_frame) { |
| fill_variance_tree(vt, BLOCK_4X4); |
| check_split_key_frame(vt, thre[1]); |
| } else { |
| fill_variance_tree(vt, BLOCK_8X8); |
| check_split(cpi, vt, segment_id, thre); |
| if (low_res) { |
| refine_variance_tree(vt, thre[1] << 1); |
| } |
| } |
| |
| vt->force_split |= mi_col + cm->mib_size > cm->mi_cols || |
| mi_row + cm->mib_size > cm->mi_rows; |
| |
| // Now go through the entire structure, splitting every block size until |
| // we get to one that's got a variance lower than our threshold. |
| set_vt_partitioning(cpi, x, xd, vt, mi_row, mi_col, thre, bmin); |
| } |
| |
| #if CONFIG_DUAL_FILTER |
| static void reset_intmv_filter_type(const AV1_COMMON *const cm, MACROBLOCKD *xd, |
| MB_MODE_INFO *mbmi) { |
| int dir; |
| for (dir = 0; dir < 2; ++dir) { |
| if (!has_subpel_mv_component(xd->mi[0], xd, dir) && |
| (mbmi->ref_frame[1] == NONE || |
| !has_subpel_mv_component(xd->mi[0], xd, dir + 2))) |
| mbmi->interp_filter[dir] = (cm->interp_filter == SWITCHABLE) |
| ? EIGHTTAP_REGULAR |
| : cm->interp_filter; |
| mbmi->interp_filter[dir + 2] = mbmi->interp_filter[dir]; |
| } |
| } |
| |
| static void update_filter_type_count(FRAME_COUNTS *counts, |
| const MACROBLOCKD *xd, |
| const MB_MODE_INFO *mbmi) { |
| int dir; |
| for (dir = 0; dir < 2; ++dir) { |
| if (has_subpel_mv_component(xd->mi[0], xd, dir) || |
| (mbmi->ref_frame[1] > INTRA_FRAME && |
| has_subpel_mv_component(xd->mi[0], xd, dir + 2))) { |
| const int ctx = av1_get_pred_context_switchable_interp(xd, dir); |
| ++counts->switchable_interp[ctx][mbmi->interp_filter[dir]]; |
| } |
| } |
| } |
| #endif |
| #if CONFIG_GLOBAL_MOTION |
| static void update_global_motion_used(PREDICTION_MODE mode, |
| const MB_MODE_INFO *mbmi, AV1_COMP *cpi) { |
| if (mode == ZEROMV) { |
| ++cpi->global_motion_used[mbmi->ref_frame[0]]; |
| if (has_second_ref(mbmi)) ++cpi->global_motion_used[mbmi->ref_frame[1]]; |
| } |
| } |
| #endif // CONFIG_GLOBAL_MOTION |
| |
| static void update_state(const AV1_COMP *const cpi, ThreadData *td, |
| PICK_MODE_CONTEXT *ctx, int mi_row, int mi_col, |
| BLOCK_SIZE bsize, RUN_TYPE dry_run) { |
| int i, x_idx, y; |
| const AV1_COMMON *const cm = &cpi->common; |
| RD_COUNTS *const rdc = &td->rd_counts; |
| MACROBLOCK *const x = &td->mb; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| struct macroblock_plane *const p = x->plane; |
| struct macroblockd_plane *const pd = xd->plane; |
| MODE_INFO *mi = &ctx->mic; |
| MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi; |
| MODE_INFO *mi_addr = xd->mi[0]; |
| const struct segmentation *const seg = &cm->seg; |
| const int bw = num_8x8_blocks_wide_lookup[mi->mbmi.sb_type]; |
| const int bh = num_8x8_blocks_high_lookup[mi->mbmi.sb_type]; |
| const int x_mis = AOMMIN(bw, cm->mi_cols - mi_col); |
| const int y_mis = AOMMIN(bh, cm->mi_rows - mi_row); |
| MV_REF *const frame_mvs = cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col; |
| int w, h; |
| |
| const int mis = cm->mi_stride; |
| const int mi_width = num_8x8_blocks_wide_lookup[bsize]; |
| const int mi_height = num_8x8_blocks_high_lookup[bsize]; |
| int max_plane; |
| |
| #if CONFIG_REF_MV |
| int8_t rf_type; |
| #endif |
| |
| #if !CONFIG_SUPERTX |
| assert(mi->mbmi.sb_type == bsize); |
| #endif |
| |
| *mi_addr = *mi; |
| *x->mbmi_ext = ctx->mbmi_ext; |
| |
| #if CONFIG_DUAL_FILTER |
| reset_intmv_filter_type(cm, xd, mbmi); |
| #endif |
| |
| #if CONFIG_REF_MV |
| rf_type = av1_ref_frame_type(mbmi->ref_frame); |
| if (x->mbmi_ext->ref_mv_count[rf_type] > 1 && mbmi->sb_type >= BLOCK_8X8 && |
| mbmi->mode == NEWMV) { |
| for (i = 0; i < 1 + has_second_ref(mbmi); ++i) { |
| int_mv this_mv = |
| (i == 0) |
| ? x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].this_mv |
| : x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].comp_mv; |
| clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd); |
| x->mbmi_ext->ref_mvs[mbmi->ref_frame[i]][0] = this_mv; |
| mbmi->pred_mv[i] = this_mv; |
| mi->mbmi.pred_mv[i] = this_mv; |
| } |
| } |
| #endif |
| |
| // If segmentation in use |
| if (seg->enabled) { |
| // For in frame complexity AQ copy the segment id from the segment map. |
| if (cpi->oxcf.aq_mode == COMPLEXITY_AQ) { |
| const uint8_t *const map = |
| seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map; |
| mi_addr->mbmi.segment_id = get_segment_id(cm, map, bsize, mi_row, mi_col); |
| } |
| // Else for cyclic refresh mode update the segment map, set the segment id |
| // and then update the quantizer. |
| if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { |
| av1_cyclic_refresh_update_segment(cpi, &xd->mi[0]->mbmi, mi_row, mi_col, |
| bsize, ctx->rate, ctx->dist, x->skip); |
| } |
| } |
| |
| max_plane = is_inter_block(mbmi) ? MAX_MB_PLANE : 1; |
| for (i = 0; i < max_plane; ++i) { |
| p[i].coeff = ctx->coeff[i][1]; |
| p[i].qcoeff = ctx->qcoeff[i][1]; |
| pd[i].dqcoeff = ctx->dqcoeff[i][1]; |
| p[i].eobs = ctx->eobs[i][1]; |
| } |
| |
| for (i = max_plane; i < MAX_MB_PLANE; ++i) { |
| p[i].coeff = ctx->coeff[i][2]; |
| p[i].qcoeff = ctx->qcoeff[i][2]; |
| pd[i].dqcoeff = ctx->dqcoeff[i][2]; |
| p[i].eobs = ctx->eobs[i][2]; |
| } |
| |
| #if CONFIG_PALETTE |
| for (i = 0; i < 2; ++i) pd[i].color_index_map = ctx->color_index_map[i]; |
| #endif // CONFIG_PALETTE |
| |
| // Restore the coding context of the MB to that that was in place |
| // when the mode was picked for it |
| for (y = 0; y < mi_height; y++) |
| for (x_idx = 0; x_idx < mi_width; x_idx++) |
| if ((xd->mb_to_right_edge >> (3 + MI_SIZE_LOG2)) + mi_width > x_idx && |
| (xd->mb_to_bottom_edge >> (3 + MI_SIZE_LOG2)) + mi_height > y) { |
| xd->mi[x_idx + y * mis] = mi_addr; |
| } |
| |
| #if CONFIG_DELTA_Q |
| if (cpi->oxcf.aq_mode > NO_AQ && cpi->oxcf.aq_mode < DELTA_AQ) |
| av1_init_plane_quantizers(cpi, x, xd->mi[0]->mbmi.segment_id); |
| #else |
| if (cpi->oxcf.aq_mode) |
| av1_init_plane_quantizers(cpi, x, xd->mi[0]->mbmi.segment_id); |
| #endif |
| |
| if (is_inter_block(mbmi) && mbmi->sb_type < BLOCK_8X8) { |
| mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int; |
| mbmi->mv[1].as_int = mi->bmi[3].as_mv[1].as_int; |
| } |
| |
| x->skip = ctx->skip; |
| |
| #if CONFIG_VAR_TX |
| for (i = 0; i < 1; ++i) |
| memcpy(x->blk_skip[i], ctx->blk_skip[i], |
| sizeof(uint8_t) * ctx->num_4x4_blk); |
| #endif |
| |
| if (dry_run) return; |
| |
| #if CONFIG_INTERNAL_STATS |
| { |
| unsigned int *const mode_chosen_counts = |
| (unsigned int *)cpi->mode_chosen_counts; // Cast const away. |
| if (frame_is_intra_only(cm)) { |
| static const int kf_mode_index[] = { |
| THR_DC /*DC_PRED*/, THR_V_PRED /*V_PRED*/, |
| THR_H_PRED /*H_PRED*/, THR_D45_PRED /*D45_PRED*/, |
| THR_D135_PRED /*D135_PRED*/, THR_D117_PRED /*D117_PRED*/, |
| THR_D153_PRED /*D153_PRED*/, THR_D207_PRED /*D207_PRED*/, |
| THR_D63_PRED /*D63_PRED*/, THR_TM /*TM_PRED*/, |
| }; |
| ++mode_chosen_counts[kf_mode_index[mbmi->mode]]; |
| } else { |
| // Note how often each mode chosen as best |
| ++mode_chosen_counts[ctx->best_mode_index]; |
| } |
| } |
| #endif |
| if (!frame_is_intra_only(cm)) { |
| if (is_inter_block(mbmi)) { |
| av1_update_mv_count(td); |
| #if CONFIG_GLOBAL_MOTION |
| if (bsize >= BLOCK_8X8) { |
| // TODO(sarahparker): global motion stats need to be handled per-tile |
| // to be compatible with tile-based threading. |
| update_global_motion_used(mbmi->mode, mbmi, (AV1_COMP *)cpi); |
| } else { |
| const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize]; |
| const int num_4x4_h = num_4x4_blocks_high_lookup[bsize]; |
| int idx, idy; |
| for (idy = 0; idy < 2; idy += num_4x4_h) { |
| for (idx = 0; idx < 2; idx += num_4x4_w) { |
| const int j = idy * 2 + idx; |
| update_global_motion_used(mi->bmi[j].as_mode, mbmi, |
| (AV1_COMP *)cpi); |
| } |
| } |
| } |
| #endif // CONFIG_GLOBAL_MOTION |
| if (cm->interp_filter == SWITCHABLE |
| #if CONFIG_EXT_INTERP |
| && av1_is_interp_needed(xd) |
| #endif |
| ) { |
| #if CONFIG_DUAL_FILTER |
| update_filter_type_count(td->counts, xd, mbmi); |
| #else |
| const int switchable_ctx = av1_get_pred_context_switchable_interp(xd); |
| ++td->counts->switchable_interp[switchable_ctx][mbmi->interp_filter]; |
| #endif |
| } |
| } |
| |
| rdc->comp_pred_diff[SINGLE_REFERENCE] += ctx->single_pred_diff; |
| rdc->comp_pred_diff[COMPOUND_REFERENCE] += ctx->comp_pred_diff; |
| rdc->comp_pred_diff[REFERENCE_MODE_SELECT] += ctx->hybrid_pred_diff; |
| } |
| |
| for (h = 0; h < y_mis; ++h) { |
| MV_REF *const frame_mv = frame_mvs + h * cm->mi_cols; |
| for (w = 0; w < x_mis; ++w) { |
| MV_REF *const mv = frame_mv + w; |
| mv->ref_frame[0] = mi->mbmi.ref_frame[0]; |
| mv->ref_frame[1] = mi->mbmi.ref_frame[1]; |
| mv->mv[0].as_int = mi->mbmi.mv[0].as_int; |
| mv->mv[1].as_int = mi->mbmi.mv[1].as_int; |
| } |
| } |
| } |
| |
| #if CONFIG_SUPERTX |
| static void update_state_supertx(const AV1_COMP *const cpi, ThreadData *td, |
| PICK_MODE_CONTEXT *ctx, int mi_row, int mi_col, |
| BLOCK_SIZE bsize, RUN_TYPE dry_run) { |
| int y, x_idx; |
| #if CONFIG_VAR_TX || CONFIG_REF_MV |
| int i; |
| #endif |
| const AV1_COMMON *const cm = &cpi->common; |
| RD_COUNTS *const rdc = &td->rd_counts; |
| MACROBLOCK *const x = &td->mb; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| MODE_INFO *mi = &ctx->mic; |
| MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi; |
| MODE_INFO *mi_addr = xd->mi[0]; |
| const struct segmentation *const seg = &cm->seg; |
| const int mis = cm->mi_stride; |
| const int mi_width = num_8x8_blocks_wide_lookup[bsize]; |
| const int mi_height = num_8x8_blocks_high_lookup[bsize]; |
| const int x_mis = AOMMIN(mi_width, cm->mi_cols - mi_col); |
| const int y_mis = AOMMIN(mi_height, cm->mi_rows - mi_row); |
| MV_REF *const frame_mvs = cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col; |
| int w, h; |
| |
| #if CONFIG_REF_MV |
| int8_t rf_type; |
| #endif |
| |
| *mi_addr = *mi; |
| *x->mbmi_ext = ctx->mbmi_ext; |
| assert(is_inter_block(mbmi)); |
| assert(mbmi->tx_size == ctx->mic.mbmi.tx_size); |
| |
| #if CONFIG_DUAL_FILTER |
| reset_intmv_filter_type(cm, xd, mbmi); |
| #endif |
| |
| #if CONFIG_REF_MV |
| rf_type = av1_ref_frame_type(mbmi->ref_frame); |
| if (x->mbmi_ext->ref_mv_count[rf_type] > 1 && mbmi->sb_type >= BLOCK_8X8 && |
| mbmi->mode == NEWMV) { |
| for (i = 0; i < 1 + has_second_ref(mbmi); ++i) { |
| int_mv this_mv = |
| (i == 0) |
| ? x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].this_mv |
| : x->mbmi_ext->ref_mv_stack[rf_type][mbmi->ref_mv_idx].comp_mv; |
| clamp_mv_ref(&this_mv.as_mv, xd->n8_w << 3, xd->n8_h << 3, xd); |
| lower_mv_precision(&this_mv.as_mv, cm->allow_high_precision_mv); |
| x->mbmi_ext->ref_mvs[mbmi->ref_frame[i]][0] = this_mv; |
| mbmi->pred_mv[i] = this_mv; |
| } |
| } |
| #endif |
| |
| // If segmentation in use |
| if (seg->enabled) { |
| if (cpi->vaq_refresh) { |
| const int energy = |
| bsize <= BLOCK_16X16 ? x->mb_energy : av1_block_energy(cpi, x, bsize); |
| mi_addr->mbmi.segment_id = av1_vaq_segment_id(energy); |
| } else if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) { |
| // For cyclic refresh mode, now update the segment map |
| // and set the segment id. |
| av1_cyclic_refresh_update_segment(cpi, &xd->mi[0]->mbmi, mi_row, mi_col, |
| bsize, ctx->rate, ctx->dist, 1); |
| } else { |
| // Otherwise just set the segment id based on the current segment map |
| const uint8_t *const map = |
| seg->update_map ? cpi->segmentation_map : cm->last_frame_seg_map; |
| mi_addr->mbmi.segment_id = get_segment_id(cm, map, bsize, mi_row, mi_col); |
| } |
| mi_addr->mbmi.segment_id_supertx = MAX_SEGMENTS; |
| } |
| |
| // Restore the coding context of the MB to that that was in place |
| // when the mode was picked for it |
| for (y = 0; y < mi_height; y++) |
| for (x_idx = 0; x_idx < mi_width; x_idx++) |
| if ((xd->mb_to_right_edge >> (3 + MI_SIZE_LOG2)) + mi_width > x_idx && |
| (xd->mb_to_bottom_edge >> (3 + MI_SIZE_LOG2)) + mi_height > y) { |
| xd->mi[x_idx + y * mis] = mi_addr; |
| } |
| |
| if (is_inter_block(mbmi) && mbmi->sb_type < BLOCK_8X8) { |
| mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int; |
| mbmi->mv[1].as_int = mi->bmi[3].as_mv[1].as_int; |
| } |
| |
| x->skip = ctx->skip; |
| |
| #if CONFIG_VAR_TX |
| for (i = 0; i < 1; ++i) |
| memcpy(x->blk_skip[i], ctx->blk_skip[i], |
| sizeof(uint8_t) * ctx->num_4x4_blk); |
| |
| if (!is_inter_block(mbmi) || mbmi->skip) |
| mbmi->min_tx_size = get_min_tx_size(mbmi->tx_size); |
| #endif // CONFIG_VAR_TX |
| |
| #if CONFIG_VAR_TX |
| { |
| const TX_SIZE mtx = mbmi->tx_size; |
| const int num_4x4_blocks_wide = tx_size_wide_unit[mtx] >> 1; |
| const int num_4x4_blocks_high = tx_size_high_unit[mtx] >> 1; |
| int idy, idx; |
| mbmi->inter_tx_size[0][0] = mtx; |
| for (idy = 0; idy < num_4x4_blocks_high; ++idy) |
| for (idx = 0; idx < num_4x4_blocks_wide; ++idx) |
| mbmi->inter_tx_size[idy][idx] = mtx; |
| } |
| #endif // CONFIG_VAR_TX |
| // Turn motion variation off for supertx |
| mbmi->motion_mode = SIMPLE_TRANSLATION; |
| |
| if (dry_run) return; |
| |
| if (!frame_is_intra_only(cm)) { |
| av1_update_mv_count(td); |
| |
| if (cm->interp_filter == SWITCHABLE |
| #if CONFIG_EXT_INTERP |
| && av1_is_interp_needed(xd) |
| #endif |
| ) { |
| #if CONFIG_DUAL_FILTER |
| update_filter_type_count(td->counts, xd, mbmi); |
| #else |
| const int pred_ctx = av1_get_pred_context_switchable_interp(xd); |
| ++td->counts->switchable_interp[pred_ctx][mbmi->interp_filter]; |
| #endif |
| } |
| |
| rdc->comp_pred_diff[SINGLE_REFERENCE] += ctx->single_pred_diff; |
| rdc->comp_pred_diff[COMPOUND_REFERENCE] += ctx->comp_pred_diff; |
| rdc->comp_pred_diff[REFERENCE_MODE_SELECT] += ctx->hybrid_pred_diff; |
| } |
| |
| for (h = 0; h < y_mis; ++h) { |
| MV_REF *const frame_mv = frame_mvs + h * cm->mi_cols; |
| for (w = 0; w < x_mis; ++w) { |
| MV_REF *const mv = frame_mv + w; |
| mv->ref_frame[0] = mi->mbmi.ref_frame[0]; |
| mv->ref_frame[1] = mi->mbmi.ref_frame[1]; |
| mv->mv[0].as_int = mi->mbmi.mv[0].as_int; |
| mv->mv[1].as_int = mi->mbmi.mv[1].as_int; |
| } |
| } |
| } |
| |
| static void update_state_sb_supertx(const AV1_COMP *const cpi, ThreadData *td, |
| const TileInfo *const tile, int mi_row, |
| int mi_col, BLOCK_SIZE bsize, |
| RUN_TYPE dry_run, PC_TREE *pc_tree) { |
| const AV1_COMMON *const cm = &cpi->common; |
| MACROBLOCK *const x = &td->mb; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| struct macroblock_plane *const p = x->plane; |
| struct macroblockd_plane *const pd = xd->plane; |
| int bsl = b_width_log2_lookup[bsize], hbs = (1 << bsl) / 4; |
| PARTITION_TYPE partition = pc_tree->partitioning; |
| BLOCK_SIZE subsize = get_subsize(bsize, partition); |
| int i; |
| #if CONFIG_EXT_PARTITION_TYPES |
| BLOCK_SIZE bsize2 = get_subsize(bsize, PARTITION_SPLIT); |
| #endif |
| PICK_MODE_CONTEXT *pmc = NULL; |
| |
| if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; |
| |
| if (bsize == BLOCK_16X16 && cpi->vaq_refresh) |
| x->mb_energy = av1_block_energy(cpi, x, bsize); |
| |
| switch (partition) { |
| case PARTITION_NONE: |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col, subsize); |
| update_state_supertx(cpi, td, &pc_tree->none, mi_row, mi_col, subsize, |
| dry_run); |
| break; |
| case PARTITION_VERT: |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col, subsize); |
| update_state_supertx(cpi, td, &pc_tree->vertical[0], mi_row, mi_col, |
| subsize, dry_run); |
| if (mi_col + hbs < cm->mi_cols && bsize > BLOCK_8X8) { |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col + hbs, subsize); |
| update_state_supertx(cpi, td, &pc_tree->vertical[1], mi_row, |
| mi_col + hbs, subsize, dry_run); |
| } |
| pmc = &pc_tree->vertical_supertx; |
| break; |
| case PARTITION_HORZ: |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col, subsize); |
| update_state_supertx(cpi, td, &pc_tree->horizontal[0], mi_row, mi_col, |
| subsize, dry_run); |
| if (mi_row + hbs < cm->mi_rows && bsize > BLOCK_8X8) { |
| set_offsets_supertx(cpi, td, tile, mi_row + hbs, mi_col, subsize); |
| update_state_supertx(cpi, td, &pc_tree->horizontal[1], mi_row + hbs, |
| mi_col, subsize, dry_run); |
| } |
| pmc = &pc_tree->horizontal_supertx; |
| break; |
| case PARTITION_SPLIT: |
| if (bsize == BLOCK_8X8) { |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col, subsize); |
| update_state_supertx(cpi, td, pc_tree->leaf_split[0], mi_row, mi_col, |
| subsize, dry_run); |
| } else { |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col, subsize); |
| update_state_sb_supertx(cpi, td, tile, mi_row, mi_col, subsize, dry_run, |
| pc_tree->split[0]); |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col + hbs, subsize); |
| update_state_sb_supertx(cpi, td, tile, mi_row, mi_col + hbs, subsize, |
| dry_run, pc_tree->split[1]); |
| set_offsets_supertx(cpi, td, tile, mi_row + hbs, mi_col, subsize); |
| update_state_sb_supertx(cpi, td, tile, mi_row + hbs, mi_col, subsize, |
| dry_run, pc_tree->split[2]); |
| set_offsets_supertx(cpi, td, tile, mi_row + hbs, mi_col + hbs, subsize); |
| update_state_sb_supertx(cpi, td, tile, mi_row + hbs, mi_col + hbs, |
| subsize, dry_run, pc_tree->split[3]); |
| } |
| pmc = &pc_tree->split_supertx; |
| break; |
| #if CONFIG_EXT_PARTITION_TYPES |
| case PARTITION_HORZ_A: |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col, bsize2); |
| update_state_supertx(cpi, td, &pc_tree->horizontala[0], mi_row, mi_col, |
| bsize2, dry_run); |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col + hbs, bsize2); |
| update_state_supertx(cpi, td, &pc_tree->horizontala[1], mi_row, |
| mi_col + hbs, bsize2, dry_run); |
| set_offsets_supertx(cpi, td, tile, mi_row + hbs, mi_col, subsize); |
| update_state_supertx(cpi, td, &pc_tree->horizontala[2], mi_row + hbs, |
| mi_col, subsize, dry_run); |
| pmc = &pc_tree->horizontala_supertx; |
| break; |
| case PARTITION_HORZ_B: |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col, subsize); |
| update_state_supertx(cpi, td, &pc_tree->horizontalb[0], mi_row, mi_col, |
| subsize, dry_run); |
| set_offsets_supertx(cpi, td, tile, mi_row + hbs, mi_col, bsize2); |
| update_state_supertx(cpi, td, &pc_tree->horizontalb[1], mi_row + hbs, |
| mi_col, bsize2, dry_run); |
| set_offsets_supertx(cpi, td, tile, mi_row + hbs, mi_col + hbs, bsize2); |
| update_state_supertx(cpi, td, &pc_tree->horizontalb[2], mi_row + hbs, |
| mi_col + hbs, bsize2, dry_run); |
| pmc = &pc_tree->horizontalb_supertx; |
| break; |
| case PARTITION_VERT_A: |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col, bsize2); |
| update_state_supertx(cpi, td, &pc_tree->verticala[0], mi_row, mi_col, |
| bsize2, dry_run); |
| set_offsets_supertx(cpi, td, tile, mi_row + hbs, mi_col, bsize2); |
| update_state_supertx(cpi, td, &pc_tree->verticala[1], mi_row + hbs, |
| mi_col, bsize2, dry_run); |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col + hbs, subsize); |
| update_state_supertx(cpi, td, &pc_tree->verticala[2], mi_row, |
| mi_col + hbs, subsize, dry_run); |
| pmc = &pc_tree->verticala_supertx; |
| break; |
| case PARTITION_VERT_B: |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col, subsize); |
| update_state_supertx(cpi, td, &pc_tree->verticalb[0], mi_row, mi_col, |
| subsize, dry_run); |
| set_offsets_supertx(cpi, td, tile, mi_row, mi_col + hbs, bsize2); |
| update_state_supertx(cpi, td, &pc_tree->verticalb[1], mi_row, |
| mi_col + hbs, bsize2, dry_run); |
| set_offsets_supertx(cpi, td, tile, mi_row + hbs, mi_col + hbs, bsize2); |
| update_state_supertx(cpi, td, &pc_tree->verticalb[2], mi_row + hbs, |
| mi_col + hbs, bsize2, dry_run); |
| pmc = &pc_tree->verticalb_supertx; |
| break; |
| #endif // CONFIG_EXT_PARTITION_TYPES |
| default: assert(0); |
| } |
| |
| for (i = 0; i < MAX_MB_PLANE; ++i) { |
| if (pmc != NULL) { |
| p[i].coeff = pmc->coeff[i][1]; |
| p[i].qcoeff = pmc->qcoeff[i][1]; |
| pd[i].dqcoeff = pmc->dqcoeff[i][1]; |
| p[i].eobs = pmc->eobs[i][1]; |
| } else { |
| // These should never be used |
| p[i].coeff = NULL; |
| p[i].qcoeff = NULL; |
| pd[i].dqcoeff = NULL; |
| p[i].eobs = NULL; |
| } |
| } |
| } |
| |
| static void update_supertx_param(ThreadData *td, PICK_MODE_CONTEXT *ctx, |
| int best_tx, TX_SIZE supertx_size) { |
| MACROBLOCK *const x = &td->mb; |
| #if CONFIG_VAR_TX |
| int i; |
| |
| for (i = 0; i < 1; ++i) |
| memcpy(ctx->blk_skip[i], x->blk_skip[i], |
| sizeof(uint8_t) * ctx->num_4x4_blk); |
| ctx->mic.mbmi.min_tx_size = get_min_tx_size(supertx_size); |
| #endif // CONFIG_VAR_TX |
| ctx->mic.mbmi.tx_size = supertx_size; |
| ctx->skip = x->skip; |
| ctx->mic.mbmi.tx_type = best_tx; |
| } |
| |
| static void update_supertx_param_sb(const AV1_COMP *const cpi, ThreadData *td, |
| int mi_row, int mi_col, BLOCK_SIZE bsize, |
| int best_tx, TX_SIZE supertx_size, |
| PC_TREE *pc_tree) { |
| const AV1_COMMON *const cm = &cpi->common; |
| int bsl = b_width_log2_lookup[bsize], hbs = (1 << bsl) / 4; |
| PARTITION_TYPE partition = pc_tree->partitioning; |
| BLOCK_SIZE subsize = get_subsize(bsize, partition); |
| #if CONFIG_EXT_PARTITION_TYPES |
| int i; |
| #endif |
| |
| if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; |
| |
| switch (partition) { |
| case PARTITION_NONE: |
| update_supertx_param(td, &pc_tree->none, best_tx, supertx_size); |
| break; |
| case PARTITION_VERT: |
| update_supertx_param(td, &pc_tree->vertical[0], best_tx, supertx_size); |
| if (mi_col + hbs < cm->mi_cols && bsize > BLOCK_8X8) |
| update_supertx_param(td, &pc_tree->vertical[1], best_tx, supertx_size); |
| break; |
| case PARTITION_HORZ: |
| update_supertx_param(td, &pc_tree->horizontal[0], best_tx, supertx_size); |
| if (mi_row + hbs < cm->mi_rows && bsize > BLOCK_8X8) |
| update_supertx_param(td, &pc_tree->horizontal[1], best_tx, |
| supertx_size); |
| break; |
| case PARTITION_SPLIT: |
| if (bsize == BLOCK_8X8) { |
| update_supertx_param(td, pc_tree->leaf_split[0], best_tx, supertx_size); |
| } else { |
| update_supertx_param_sb(cpi, td, mi_row, mi_col, subsize, best_tx, |
| supertx_size, pc_tree->split[0]); |
| update_supertx_param_sb(cpi, td, mi_row, mi_col + hbs, subsize, best_tx, |
| supertx_size, pc_tree->split[1]); |
| update_supertx_param_sb(cpi, td, mi_row + hbs, mi_col, subsize, best_tx, |
| supertx_size, pc_tree->split[2]); |
| update_supertx_param_sb(cpi, td, mi_row + hbs, mi_col + hbs, subsize, |
| best_tx, supertx_size, pc_tree->split[3]); |
| } |
| break; |
| #if CONFIG_EXT_PARTITION_TYPES |
| case PARTITION_HORZ_A: |
| for (i = 0; i < 3; i++) |
| update_supertx_param(td, &pc_tree->horizontala[i], best_tx, |
| supertx_size); |
| break; |
| case PARTITION_HORZ_B: |
| for (i = 0; i < 3; i++) |
| update_supertx_param(td, &pc_tree->horizontalb[i], best_tx, |
| supertx_size); |
| break; |
| case PARTITION_VERT_A: |
| for (i = 0; i < 3; i++) |
| update_supertx_param(td, &pc_tree->verticala[i], best_tx, supertx_size); |
| break; |
| case PARTITION_VERT_B: |
| for (i = 0; i < 3; i++) |
| update_supertx_param(td, &pc_tree->verticalb[i], best_tx, supertx_size); |
| break; |
| #endif // CONFIG_EXT_PARTITION_TYPES |
| default: assert(0); |
| } |
| } |
| #endif // CONFIG_SUPERTX |
| |
| void av1_setup_src_planes(MACROBLOCK *x, const YV12_BUFFER_CONFIG *src, |
| int mi_row, int mi_col) { |
| uint8_t *const buffers[3] = { src->y_buffer, src->u_buffer, src->v_buffer }; |
| const int widths[3] = { src->y_crop_width, src->uv_crop_width, |
| src->uv_crop_width }; |
| const int heights[3] = { src->y_crop_height, src->uv_crop_height, |
| src->uv_crop_height }; |
| const int strides[3] = { src->y_stride, src->uv_stride, src->uv_stride }; |
| int i; |
| |
| // Set current frame pointer. |
| x->e_mbd.cur_buf = src; |
| |
| for (i = 0; i < MAX_MB_PLANE; i++) |
| setup_pred_plane(&x->plane[i].src, buffers[i], widths[i], heights[i], |
| strides[i], mi_row, mi_col, NULL, |
| x->e_mbd.plane[i].subsampling_x, |
| x->e_mbd.plane[i].subsampling_y); |
| } |
| |
| static int set_segment_rdmult(const AV1_COMP *const cpi, MACROBLOCK *const x, |
| int8_t segment_id) { |
| int segment_qindex; |
| const AV1_COMMON *const cm = &cpi->common; |
| av1_init_plane_quantizers(cpi, x, segment_id); |
| aom_clear_system_state(); |
| segment_qindex = av1_get_qindex(&cm->seg, segment_id, cm->base_qindex); |
| return av1_compute_rd_mult(cpi, segment_qindex + cm->y_dc_delta_q); |
| } |
| |
| static void rd_pick_sb_modes(const AV1_COMP *const cpi, TileDataEnc *tile_data, |
| MACROBLOCK *const x, int mi_row, int mi_col, |
| RD_COST *rd_cost, |
| #if CONFIG_SUPERTX |
| int *totalrate_nocoef, |
| #endif |
| #if CONFIG_EXT_PARTITION_TYPES |
| PARTITION_TYPE partition, |
| #endif |
| BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, |
| int64_t best_rd) { |
| const AV1_COMMON *const cm = &cpi->common; |
| TileInfo *const tile_info = &tile_data->tile_info; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| MB_MODE_INFO *mbmi; |
| struct macroblock_plane *const p = x->plane; |
| struct macroblockd_plane *const pd = xd->plane; |
| const AQ_MODE aq_mode = cpi->oxcf.aq_mode; |
| int i, orig_rdmult; |
| |
| aom_clear_system_state(); |
| |
| // Use the lower precision, but faster, 32x32 fdct for mode selection. |
| x->use_lp32x32fdct = 1; |
| |
| set_offsets(cpi, tile_info, x, mi_row, mi_col, bsize); |
| mbmi = &xd->mi[0]->mbmi; |
| mbmi->sb_type = bsize; |
| #if CONFIG_RD_DEBUG |
| mbmi->mi_row = mi_row; |
| mbmi->mi_col = mi_col; |
| #endif |
| #if CONFIG_SUPERTX |
| // We set tx_size here as skip blocks would otherwise not set it. |
| // tx_size needs to be set at this point as supertx_enable in |
| // write_modes_sb is computed based on this, and if the garbage in memory |
| // just happens to be the supertx_size, then the packer will code this |
| // block as a supertx block, even if rdopt did not pick it as such. |
| mbmi->tx_size = max_txsize_lookup[bsize]; |
| #endif |
| #if CONFIG_EXT_PARTITION_TYPES |
| mbmi->partition = partition; |
| #endif |
| |
| for (i = 0; i < MAX_MB_PLANE; ++i) { |
| p[i].coeff = ctx->coeff[i][0]; |
| p[i].qcoeff = ctx->qcoeff[i][0]; |
| pd[i].dqcoeff = ctx->dqcoeff[i][0]; |
| p[i].eobs = ctx->eobs[i][0]; |
| } |
| |
| #if CONFIG_PALETTE |
| for (i = 0; i < 2; ++i) pd[i].color_index_map = ctx->color_index_map[i]; |
| #endif // CONFIG_PALETTE |
| |
| ctx->skippable = 0; |
| ctx->pred_pixel_ready = 0; |
| |
| // Set to zero to make sure we do not use the previous encoded frame stats |
| mbmi->skip = 0; |
| |
| #if CONFIG_AOM_HIGHBITDEPTH |
| if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { |
| x->source_variance = av1_high_get_sby_perpixel_variance( |
| cpi, &x->plane[0].src, bsize, xd->bd); |
| } else { |
| x->source_variance = |
| av1_get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize); |
| } |
| #else |
| x->source_variance = |
| av1_get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize); |
| #endif // CONFIG_AOM_HIGHBITDEPTH |
| |
| // Save rdmult before it might be changed, so it can be restored later. |
| orig_rdmult = x->rdmult; |
| |
| if (aq_mode == VARIANCE_AQ) { |
| if (cpi->vaq_refresh) { |
| const int energy = |
| bsize <= BLOCK_16X16 ? x->mb_energy : av1_block_energy(cpi, x, bsize); |
| mbmi->segment_id = av1_vaq_segment_id(energy); |
| // Re-initialise quantiser |
| av1_init_plane_quantizers(cpi, x, mbmi->segment_id); |
| } |
| x->rdmult = set_segment_rdmult(cpi, x, mbmi->segment_id); |
| } else if (aq_mode == COMPLEXITY_AQ) { |
| x->rdmult = set_segment_rdmult(cpi, x, mbmi->segment_id); |
| } else if (aq_mode == CYCLIC_REFRESH_AQ) { |
| // If segment is boosted, use rdmult for that segment. |
| if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) |
| x->rdmult = av1_cyclic_refresh_get_rdmult(cpi->cyclic_refresh); |
| } |
| |
| // Find best coding mode & reconstruct the MB so it is available |
| // as a predictor for MBs that follow in the SB |
| if (frame_is_intra_only(cm)) { |
| av1_rd_pick_intra_mode_sb(cpi, x, rd_cost, bsize, ctx, best_rd); |
| #if CONFIG_SUPERTX |
| *totalrate_nocoef = 0; |
| #endif // CONFIG_SUPERTX |
| } else { |
| if (bsize >= BLOCK_8X8) { |
| if (segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { |
| av1_rd_pick_inter_mode_sb_seg_skip(cpi, tile_data, x, rd_cost, bsize, |
| ctx, best_rd); |
| #if CONFIG_SUPERTX |
| *totalrate_nocoef = rd_cost->rate; |
| #endif // CONFIG_SUPERTX |
| } else { |
| av1_rd_pick_inter_mode_sb(cpi, tile_data, x, mi_row, mi_col, rd_cost, |
| #if CONFIG_SUPERTX |
| totalrate_nocoef, |
| #endif // CONFIG_SUPERTX |
| bsize, ctx, best_rd); |
| #if CONFIG_SUPERTX |
| assert(*totalrate_nocoef >= 0); |
| #endif // CONFIG_SUPERTX |
| } |
| } else { |
| if (segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { |
| // The decoder rejects sub8x8 partitions when SEG_LVL_SKIP is set. |
| rd_cost->rate = INT_MAX; |
| } else { |
| av1_rd_pick_inter_mode_sub8x8(cpi, tile_data, x, mi_row, mi_col, |
| rd_cost, |
| #if CONFIG_SUPERTX |
| totalrate_nocoef, |
| #endif // CONFIG_SUPERTX |
| bsize, ctx, best_rd); |
| #if CONFIG_SUPERTX |
| assert(*totalrate_nocoef >= 0); |
| #endif // CONFIG_SUPERTX |
| } |
| } |
| } |
| |
| // Examine the resulting rate and for AQ mode 2 make a segment choice. |
| if ((rd_cost->rate != INT_MAX) && (aq_mode == COMPLEXITY_AQ) && |
| (bsize >= BLOCK_16X16) && |
| (cm->frame_type == KEY_FRAME || cpi->refresh_alt_ref_frame || |
| (cpi->refresh_golden_frame && !cpi->rc.is_src_frame_alt_ref))) { |
| av1_caq_select_segment(cpi, x, bsize, mi_row, mi_col, rd_cost->rate); |
| } |
| |
| x->rdmult = orig_rdmult; |
| |
| // TODO(jingning) The rate-distortion optimization flow needs to be |
| // refactored to provide proper exit/return handle. |
| if (rd_cost->rate == INT_MAX) rd_cost->rdcost = INT64_MAX; |
| |
| ctx->rate = rd_cost->rate; |
| ctx->dist = rd_cost->dist; |
| } |
| |
| #if CONFIG_REF_MV |
| static void update_inter_mode_stats(FRAME_COUNTS *counts, PREDICTION_MODE mode, |
| #if CONFIG_EXT_INTER |
| int is_compound, |
| #endif // CONFIG_EXT_INTER |
| int16_t mode_context) { |
| int16_t mode_ctx = mode_context & NEWMV_CTX_MASK; |
| #if CONFIG_EXT_INTER |
| if (mode == NEWMV || mode == NEWFROMNEARMV) { |
| if (!is_compound) ++counts->new2mv_mode[mode == NEWFROMNEARMV]; |
| #else |
| if (mode == NEWMV) { |
| #endif // CONFIG_EXT_INTER |
| ++counts->newmv_mode[mode_ctx][0]; |
| return; |
| } else { |
| ++counts->newmv_mode[mode_ctx][1]; |
| |
| if (mode_context & (1 << ALL_ZERO_FLAG_OFFSET)) { |
| return; |
| } |
| |
| mode_ctx = (mode_context >> ZEROMV_OFFSET) & ZEROMV_CTX_MASK; |
| if (mode == ZEROMV) { |
| ++counts->zeromv_mode[mode_ctx][0]; |
| return; |
| } else { |
| ++counts->zeromv_mode[mode_ctx][1]; |
| mode_ctx = (mode_context >> REFMV_OFFSET) & REFMV_CTX_MASK; |
| |
| if (mode_context & (1 << SKIP_NEARESTMV_OFFSET)) mode_ctx = 6; |
| if (mode_context & (1 << SKIP_NEARMV_OFFSET)) mode_ctx = 7; |
| if (mode_context & (1 << SKIP_NEARESTMV_SUB8X8_OFFSET)) mode_ctx = 8; |
| |
| ++counts->refmv_mode[mode_ctx][mode != NEARESTMV]; |
| } |
| } |
| } |
| #endif |
| |
| static void update_stats(const AV1_COMMON *const cm, ThreadData *td, int mi_row, |
| int mi_col |
| #if CONFIG_SUPERTX |
| , |
| int supertx_enabled |
| #endif |
| ) { |
| #if CONFIG_DELTA_Q |
| MACROBLOCK *x = &td->mb; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| #else |
| const MACROBLOCK *x = &td->mb; |
| const MACROBLOCKD *const xd = &x->e_mbd; |
| #endif |
| const MODE_INFO *const mi = xd->mi[0]; |
| const MB_MODE_INFO *const mbmi = &mi->mbmi; |
| const MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext; |
| const BLOCK_SIZE bsize = mbmi->sb_type; |
| |
| #if CONFIG_DELTA_Q |
| // delta quant applies to both intra and inter |
| const int super_block_upper_left = ((mi_row & 7) == 0) && ((mi_col & 7) == 0); |
| |
| if (cm->delta_q_present_flag && (bsize != BLOCK_64X64 || !mbmi->skip) && |
| super_block_upper_left) { |
| const int dq = (mbmi->current_q_index - xd->prev_qindex) / cm->delta_q_res; |
| const int absdq = abs(dq); |
| int i; |
| for (i = 0; i < absdq; ++i) { |
| td->counts->delta_q[i][1]++; |
| } |
| if (absdq < DELTA_Q_SMALL) td->counts->delta_q[absdq][0]++; |
| xd->prev_qindex = mbmi->current_q_index; |
| } |
| #else |
| (void)mi_row; |
| (void)mi_col; |
| #endif |
| if (!frame_is_intra_only(cm)) { |
| FRAME_COUNTS *const counts = td->counts; |
| const int inter_block = is_inter_block(mbmi); |
| const int seg_ref_active = |
| segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_REF_FRAME); |
| if (!seg_ref_active) { |
| #if CONFIG_SUPERTX |
| if (!supertx_enabled) |
| #endif |
| counts->intra_inter[av1_get_intra_inter_context(xd)][inter_block]++; |
| // If the segment reference feature is enabled we have only a single |
| // reference frame allowed for the segment so exclude it from |
| // the reference frame counts used to work out probabilities. |
| if (inter_block) { |
| const MV_REFERENCE_FRAME ref0 = mbmi->ref_frame[0]; |
| #if CONFIG_EXT_REFS |
| const MV_REFERENCE_FRAME ref1 = mbmi->ref_frame[1]; |
| #endif // CONFIG_EXT_REFS |
| |
| if (cm->reference_mode == REFERENCE_MODE_SELECT) |
| counts->comp_inter[av1_get_reference_mode_context(cm, xd)] |
| [has_second_ref(mbmi)]++; |
| |
| if (has_second_ref(mbmi)) { |
| #if CONFIG_EXT_REFS |
| const int bit = (ref0 == GOLDEN_FRAME || ref0 == LAST3_FRAME); |
| |
| counts->comp_ref[av1_get_pred_context_comp_ref_p(cm, xd)][0][bit]++; |
| if (!bit) { |
| counts->comp_ref[av1_get_pred_context_comp_ref_p1(cm, xd)][1] |
| [ref0 == LAST_FRAME]++; |
| } else { |
| counts->comp_ref[av1_get_pred_context_comp_ref_p2(cm, xd)][2] |
| [ref0 == GOLDEN_FRAME]++; |
| } |
| |
| counts->comp_bwdref[av1_get_pred_context_comp_bwdref_p(cm, xd)][0] |
| [ref1 == ALTREF_FRAME]++; |
| #else |
| counts->comp_ref[av1_get_pred_context_comp_ref_p(cm, xd)][0] |
| [ref0 == GOLDEN_FRAME]++; |
| #endif // CONFIG_EXT_REFS |
| } else { |
| #if CONFIG_EXT_REFS |
| const int bit = (ref0 == ALTREF_FRAME || ref0 == BWDREF_FRAME); |
| |
| counts->single_ref[av1_get_pred_context_single_ref_p1(xd)][0][bit]++; |
| if (bit) { |
| counts->single_ref[av1_get_pred_context_single_ref_p2(xd)][1] |
| [ref0 != BWDREF_FRAME]++; |
| } else { |
| const int bit1 = !(ref0 == LAST2_FRAME || ref0 == LAST_FRAME); |
| counts->single_ref[av1_get_pred_context_single_ref_p3(xd)][2] |
| [bit1]++; |
| if (!bit1) { |
| counts->single_ref[av1_get_pred_context_single_ref_p4(xd)][3] |
| [ref0 != LAST_FRAME]++; |
| } else { |
| counts->single_ref[av1_get_pred_context_single_ref_p5(xd)][4] |
| [ref0 != LAST3_FRAME]++; |
| } |
| } |
| #else |
| counts->single_ref[av1_get_pred_context_single_ref_p1(xd)][0] |
| [ref0 != LAST_FRAME]++; |
| if (ref0 != LAST_FRAME) { |
| counts->single_ref[av1_get_pred_context_single_ref_p2(xd)][1] |
| [ref0 != GOLDEN_FRAME]++; |
| } |
| #endif // CONFIG_EXT_REFS |
| } |
| |
| #if CONFIG_EXT_INTER |
| if (cm->reference_mode != COMPOUND_REFERENCE && |
| #if CONFIG_SUPERTX |
| !supertx_enabled && |
| #endif |
| is_interintra_allowed(mbmi)) { |
| const int bsize_group = size_group_lookup[bsize]; |
| if (mbmi->ref_frame[1] == INTRA_FRAME) { |
| counts->interintra[bsize_group][1]++; |
| counts->interintra_mode[bsize_group][mbmi->interintra_mode]++; |
| if (is_interintra_wedge_used(bsize)) |
| counts->wedge_interintra[bsize][mbmi->use_wedge_interintra]++; |
| } else { |
| counts->interintra[bsize_group][0]++; |
| } |
| } |
| #endif // CONFIG_EXT_INTER |
| |
| #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION |
| #if CONFIG_SUPERTX |
| if (!supertx_enabled) |
| #endif // CONFIG_SUPERTX |
| #if CONFIG_EXT_INTER |
| if (mbmi->ref_frame[1] != INTRA_FRAME) |
| #endif // CONFIG_EXT_INTER |
| if (is_motion_variation_allowed(mbmi)) |
| counts->motion_mode[mbmi->sb_type][mbmi->motion_mode]++; |
| #endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION |
| |
| #if CONFIG_EXT_INTER |
| if (cm->reference_mode != SINGLE_REFERENCE && |
| is_inter_compound_mode(mbmi->mode) && |
| #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION |
| !(is_motion_variation_allowed(mbmi) && |
| mbmi->motion_mode != SIMPLE_TRANSLATION) && |
| #endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION |
| is_interinter_wedge_used(bsize)) { |
| counts->wedge_interinter[bsize][mbmi->use_wedge_interinter]++; |
| } |
| #endif // CONFIG_EXT_INTER |
| } |
| } |
| |
| if (inter_block && |
| !segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) { |
| int16_t mode_ctx = mbmi_ext->mode_context[mbmi->ref_frame[0]]; |
| if (bsize >= BLOCK_8X8) { |
| const PREDICTION_MODE mode = mbmi->mode; |
| #if CONFIG_REF_MV |
| #if CONFIG_EXT_INTER |
| if (has_second_ref(mbmi)) { |
| mode_ctx = mbmi_ext->compound_mode_context[mbmi->ref_frame[0]]; |
| ++counts->inter_compound_mode[mode_ctx][INTER_COMPOUND_OFFSET(mode)]; |
| } else { |
| #endif // CONFIG_EXT_INTER |
| mode_ctx = av1_mode_context_analyzer(mbmi_ext->mode_context, |
| mbmi->ref_frame, bsize, -1); |
| update_inter_mode_stats(counts, mode, |
| #if CONFIG_EXT_INTER |
| has_second_ref(mbmi), |
| #endif // CONFIG_EXT_INTER |
| mode_ctx); |
| |
| if (mode == NEWMV) { |
| uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame); |
| int idx; |
| |
| for (idx = 0; idx < 2; ++idx) { |
| if (mbmi_ext->ref_mv_count[ref_frame_type] > idx + 1) { |
| uint8_t drl_ctx = |
| av1_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], idx); |
| ++counts->drl_mode[drl_ctx][mbmi->ref_mv_idx != idx]; |
| |
| if (mbmi->ref_mv_idx == idx) break; |
| } |
| } |
| } |
| |
| if (mode == NEARMV) { |
| uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame); |
| int idx; |
| |
| for (idx = 1; idx < 3; ++idx) { |
| if (mbmi_ext->ref_mv_count[ref_frame_type] > idx + 1) { |
| uint8_t drl_ctx = |
| av1_drl_ctx(mbmi_ext->ref_mv_stack[ref_frame_type], idx); |
| ++counts->drl_mode[drl_ctx][mbmi->ref_mv_idx != idx - 1]; |
| |
| if (mbmi->ref_mv_idx == idx - 1) break; |
| } |
| } |
| } |
| #if CONFIG_EXT_INTER |
| } |
| #endif // CONFIG_EXT_INTER |
| #else |
| #if CONFIG_EXT_INTER |
| if (is_inter_compound_mode(mode)) |
| ++counts->inter_compound_mode[mode_ctx][INTER_COMPOUND_OFFSET(mode)]; |
| else |
| #endif // CONFIG_EXT_INTER |
| ++counts->inter_mode[mode_ctx][INTER_OFFSET(mode)]; |
| #endif |
| } else { |
| const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize]; |
| const int num_4x4_h = num_4x4_blocks_high_lookup[bsize]; |
| int idx, idy; |
| for (idy = 0; idy < 2; idy += num_4x4_h) { |
| for (idx = 0; idx < 2; idx += num_4x4_w) { |
| const int j = idy * 2 + idx; |
| const PREDICTION_MODE b_mode = mi->bmi[j].as_mode; |
| #if CONFIG_REF_MV |
| #if CONFIG_EXT_INTER |
| if (has_second_ref(mbmi)) { |
| mode_ctx = mbmi_ext->compound_mode_context[mbmi->ref_frame[0]]; |
| ++counts->inter_compound_mode[mode_ctx] |
| [INTER_COMPOUND_OFFSET(b_mode)]; |
| } else { |
| #endif // CONFIG_EXT_INTER |
| mode_ctx = av1_mode_context_analyzer(mbmi_ext->mode_context, |
| mbmi->ref_frame, bsize, j); |
| update_inter_mode_stats(counts, b_mode, |
| #if CONFIG_EXT_INTER |
| has_second_ref(mbmi), |
| #endif // CONFIG_EXT_INTER |
| mode_ctx); |
| #if CONFIG_EXT_INTER |
| } |
| #endif // CONFIG_EXT_INTER |
| #else |
| #if CONFIG_EXT_INTER |
| if (is_inter_compound_mode(b_mode)) |
| ++counts->inter_compound_mode[mode_ctx] |
| [INTER_COMPOUND_OFFSET(b_mode)]; |
| else |
| #endif // CONFIG_EXT_INTER |
| ++counts->inter_mode[mode_ctx][INTER_OFFSET(b_mode)]; |
| #endif |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| typedef struct { |
| ENTROPY_CONTEXT a[2 * MAX_MIB_SIZE * MAX_MB_PLANE]; |
| ENTROPY_CONTEXT l[2 * MAX_MIB_SIZE * MAX_MB_PLANE]; |
| PARTITION_CONTEXT sa[MAX_MIB_SIZE]; |
| PARTITION_CONTEXT sl[MAX_MIB_SIZE]; |
| #if CONFIG_VAR_TX |
| TXFM_CONTEXT *p_ta; |
| TXFM_CONTEXT *p_tl; |
| TXFM_CONTEXT ta[MAX_MIB_SIZE]; |
| TXFM_CONTEXT tl[MAX_MIB_SIZE]; |
| #endif |
| } RD_SEARCH_MACROBLOCK_CONTEXT; |
| |
| static void restore_context(MACROBLOCK *x, |
| const RD_SEARCH_MACROBLOCK_CONTEXT *ctx, int mi_row, |
| int mi_col, BLOCK_SIZE bsize) { |
| MACROBLOCKD *xd = &x->e_mbd; |
| int p; |
| const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize]; |
| const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize]; |
| int mi_width = num_8x8_blocks_wide_lookup[bsize]; |
| int mi_height = num_8x8_blocks_high_lookup[bsize]; |
| for (p = 0; p < MAX_MB_PLANE; p++) { |
| memcpy(xd->above_context[p] + ((mi_col * 2) >> xd->plane[p].subsampling_x), |
| ctx->a + num_4x4_blocks_wide * p, |
| (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >> |
| xd->plane[p].subsampling_x); |
| memcpy(xd->left_context[p] + |
| ((mi_row & MAX_MIB_MASK) * 2 >> xd->plane[p].subsampling_y), |
| ctx->l + num_4x4_blocks_high * p, |
| (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_high) >> |
| xd->plane[p].subsampling_y); |
| } |
| memcpy(xd->above_seg_context + mi_col, ctx->sa, |
| sizeof(*xd->above_seg_context) * mi_width); |
| memcpy(xd->left_seg_context + (mi_row & MAX_MIB_MASK), ctx->sl, |
| sizeof(xd->left_seg_context[0]) * mi_height); |
| #if CONFIG_VAR_TX |
| xd->above_txfm_context = ctx->p_ta; |
| xd->left_txfm_context = ctx->p_tl; |
| memcpy(xd->above_txfm_context, ctx->ta, |
| sizeof(*xd->above_txfm_context) * mi_width); |
| memcpy(xd->left_txfm_context, ctx->tl, |
| sizeof(*xd->left_txfm_context) * mi_height); |
| #endif |
| } |
| |
| static void save_context(const MACROBLOCK *x, RD_SEARCH_MACROBLOCK_CONTEXT *ctx, |
| int mi_row, int mi_col, BLOCK_SIZE bsize) { |
| const MACROBLOCKD *xd = &x->e_mbd; |
| int p; |
| const int num_4x4_blocks_wide = num_4x4_blocks_wide_lookup[bsize]; |
| const int num_4x4_blocks_high = num_4x4_blocks_high_lookup[bsize]; |
| int mi_width = num_8x8_blocks_wide_lookup[bsize]; |
| int mi_height = num_8x8_blocks_high_lookup[bsize]; |
| |
| // buffer the above/left context information of the block in search. |
| for (p = 0; p < MAX_MB_PLANE; ++p) { |
| memcpy(ctx->a + num_4x4_blocks_wide * p, |
| xd->above_context[p] + (mi_col * 2 >> xd->plane[p].subsampling_x), |
| (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_wide) >> |
| xd->plane[p].subsampling_x); |
| memcpy(ctx->l + num_4x4_blocks_high * p, |
| xd->left_context[p] + |
| ((mi_row & MAX_MIB_MASK) * 2 >> xd->plane[p].subsampling_y), |
| (sizeof(ENTROPY_CONTEXT) * num_4x4_blocks_high) >> |
| xd->plane[p].subsampling_y); |
| } |
| memcpy(ctx->sa, xd->above_seg_context + mi_col, |
| sizeof(*xd->above_seg_context) * mi_width); |
| memcpy(ctx->sl, xd->left_seg_context + (mi_row & MAX_MIB_MASK), |
| sizeof(xd->left_seg_context[0]) * mi_height); |
| #if CONFIG_VAR_TX |
| memcpy(ctx->ta, xd->above_txfm_context, |
| sizeof(*xd->above_txfm_context) * mi_width); |
| memcpy(ctx->tl, xd->left_txfm_context, |
| sizeof(*xd->left_txfm_context) * mi_height); |
| ctx->p_ta = xd->above_txfm_context; |
| ctx->p_tl = xd->left_txfm_context; |
| #endif |
| } |
| |
| static void encode_b(const AV1_COMP *const cpi, const TileInfo *const tile, |
| ThreadData *td, TOKENEXTRA **tp, int mi_row, int mi_col, |
| RUN_TYPE dry_run, BLOCK_SIZE bsize, |
| #if CONFIG_EXT_PARTITION_TYPES |
| PARTITION_TYPE partition, |
| #endif |
| PICK_MODE_CONTEXT *ctx, int *rate) { |
| MACROBLOCK *const x = &td->mb; |
| set_offsets(cpi, tile, x, mi_row, mi_col, bsize); |
| #if CONFIG_EXT_PARTITION_TYPES |
| x->e_mbd.mi[0]->mbmi.partition = partition; |
| #endif |
| update_state(cpi, td, ctx, mi_row, mi_col, bsize, dry_run); |
| encode_superblock(cpi, td, tp, dry_run, mi_row, mi_col, bsize, ctx, rate); |
| |
| if (!dry_run) { |
| #if CONFIG_SUPERTX |
| update_stats(&cpi->common, td, mi_row, mi_col, 0); |
| #else |
| update_stats(&cpi->common, td, mi_row, mi_col); |
| #endif |
| } |
| } |
| |
| static void encode_sb(const AV1_COMP *const cpi, ThreadData *td, |
| const TileInfo *const tile, TOKENEXTRA **tp, int mi_row, |
| int mi_col, RUN_TYPE dry_run, BLOCK_SIZE bsize, |
| PC_TREE *pc_tree, int *rate) { |
| const AV1_COMMON *const cm = &cpi->common; |
| MACROBLOCK *const x = &td->mb; |
| MACROBLOCKD *const xd = &x->e_mbd; |
| |
| const int ctx = partition_plane_context(xd, mi_row, mi_col, bsize); |
| const int hbs = num_8x8_blocks_wide_lookup[bsize] / 2; |
| const PARTITION_TYPE partition = pc_tree->partitioning; |
| const BLOCK_SIZE subsize = get_subsize(bsize, partition); |
| #if CONFIG_EXT_PARTITION_TYPES |
| const BLOCK_SIZE bsize2 = get_subsize(bsize, PARTITION_SPLIT); |
| #endif |
| |
| assert(bsize >= BLOCK_8X8); |
| |
| if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; |
| |
| if (!dry_run) td->counts->partition[ctx][partition]++; |
| |
| #if CONFIG_SUPERTX |
| if (!frame_is_intra_only(cm) && bsize <= MAX_SUPERTX_BLOCK_SIZE && |
| partition != PARTITION_NONE && !xd->lossless[0]) { |
| int supertx_enabled; |
| TX_SIZE supertx_size = max_txsize_lookup[bsize]; |
| supertx_enabled = check_supertx_sb(bsize, supertx_size, pc_tree); |
| if (supertx_enabled) { |
| const int mi_width = num_8x8_blocks_wide_lookup[bsize]; |
| const int mi_height = num_8x8_blocks_high_lookup[bsize]; |
| int x_idx, y_idx, i; |
| uint8_t *dst_buf[3]; |
| int dst_stride[3]; |
| set_skip_context(xd, mi_row, mi_col); |
| set_mode_info_offsets(cpi, x, xd, mi_row, mi_col); |
| update_state_sb_supertx(cpi, td, tile, mi_row, mi_col, bsize, dry_run, |
| pc_tree); |
| |
| av1_setup_dst_planes(xd->plane, get_frame_new_buffer(cm), mi_row, mi_col); |
| for (i = 0; i < MAX_MB_PLANE; i++) { |
| dst_buf[i] = xd->plane[i].dst.buf; |
| dst_stride[i] = xd->plane[i].dst.stride; |
| } |
| predict_sb_complex(cpi, td, tile, mi_row, mi_col, mi_row, mi_col, dry_run, |
| bsize, bsize, dst_buf, dst_stride, pc_tree); |
| |
| set_offsets_without_segment_id(cpi, tile, x, mi_row, mi_col, bsize); |
| set_segment_id_supertx(cpi, x, mi_row, mi_col, bsize); |
| |
| if (!x->skip) { |
| int this_rate = 0; |
| x->use_lp32x32fdct = cpi->sf.use_lp32x32fdct; |
| |
| av1_encode_sb_supertx((AV1_COMMON *)cm, x, bsize); |
| av1_tokenize_sb_supertx(cpi, td, tp, dry_run, bsize, rate); |
| if (rate) *rate += this_rate; |
| } else { |
| xd->mi[0]->mbmi.skip = 1; |
| if (!dry_run) td->counts->skip[av1_get_skip_context(xd)][1]++; |
| reset_skip_context(xd, bsize); |
| } |
| if (!dry_run) { |
| for (y_idx = 0; y_idx < mi_height; y_idx++) |
| for (x_idx = 0; x_idx < mi_width; x_idx++) { |
| if ((xd->mb_to_right_edge >> (3 + MI_SIZE_LOG2)) + mi_width > |
| x_idx && |
| (xd->mb_to_bottom_edge >> (3 + MI_SIZE_LOG2)) + mi_height > |
| y_idx) { |
| xd->mi[x_idx + y_idx * cm->mi_stride]->mbmi.skip = |
| xd->mi[0]->mbmi.skip; |
| } |
| } |
| td->counts->supertx[partition_supertx_context_lookup[partition]] |
| [supertx_size][1]++; |
| td->counts->supertx_size[supertx_size]++; |
| #if CONFIG_EXT_TX |
| if (get_ext_tx_types(supertx_size, bsize, 1) > 1 && |
| !xd->mi[0]->mbmi.skip) { |
| int eset = get_ext_tx_set(supertx_size, bsize, 1); |
| if (eset > 0) { |
| ++td->counts->inter_ext_tx[eset][supertx_size] |
| [xd->mi[0]->mbmi.tx_type]; |
| } |
| } |
| #else |
| if (supertx_size < TX_32X32 && !xd->mi[0]->mbmi.skip) { |
| ++td->counts->inter_ext_tx[supertx_size][xd->mi[0]->mbmi.tx_type]; |
| } |
| #endif // CONFIG_EXT_TX |
| } |
| #if CONFIG_EXT_PARTITION_TYPES |
| update_ext_partition_context(xd, mi_row, mi_col, subsize, bsize, |
| partition); |
| #else |
| if (partition != PARTITION_SPLIT || bsize == BLOCK_8X8) |
| update_partition_context(xd, mi_row, mi_col, subsize, bsize); |
| #endif |
| #if CONFIG_VAR_TX |
| set_txfm_ctxs(supertx_size, mi_width, mi_height, xd); |
| #endif // CONFIG_VAR_TX |
| return; |
| } else { |
| if (!dry_run) { |
| td->counts->supertx[partition_supertx_context_lookup[partition]] |
| [supertx_size][0]++; |
| } |
| } |
| } |
| #endif // CONFIG_SUPERTX |
| |
| switch (partition) { |
| case PARTITION_NONE: |
| encode_b(cpi, tile, td, tp, mi_row, mi_col, dry_run, subsize, |
| #if CONFIG_EXT_PARTITION_TYPES |
| partition, |
| #endif |
| &pc_tree->none, rate); |
| break; |
| case PARTITION_VERT: |
| encode_b(cpi, tile, td, tp, mi_row, mi_col, dry_run, subsize, |
| #if CONFIG_EXT_PARTITION_TYPES |
| partition, |
| #endif |
| &pc_tree->vertical[0], rate); |
| if (mi_col + hbs < cm->mi_cols && bsize > BLOCK_8X8) { |
| encode_b(cpi, tile, td, tp, mi_row, mi_col + hbs, dry_run, subsize, |
| #if CONFIG_EXT_PARTITION_TYPES |
| partition, |
| #endif |
| &pc_tree->vertical[1], rate); |
| } |
| break; |
| case PARTITION_HORZ: |
| encode_b(cpi, tile, td, tp, mi_row, mi_col, dry_run, subsize, |
| #if CONFIG_EXT_PARTITION_TYPES |
| partition, |
| #endif |
| &pc_tree->horizontal[0], rate); |
| if (mi_row + hbs < cm->mi_rows && bsize > BLOCK_8X8) { |
| encode_b(cpi, tile, td, tp, mi_row + hbs, mi_col, dry_run, subsize, |
| #if CONFIG_EXT_PARTITION_TYPES |
| partition, |
| #endif |
| &pc_tree->horizontal[1], rate); |
| } |
| break; |
| case PARTITION_SPLIT: |
| if (bsize == BLOCK_8X8) { |
| encode_b(cpi, tile, td, tp, mi_row, mi_col, dry_run, subsize, |
| #if CONFIG_EXT_PARTITION_TYPES |
| partition, |
| #endif |
| pc_tree->leaf_split[0], rate); |
| } else { |
| encode_sb(cpi, td, tile, tp, mi_row, mi_col, dry_run, subsize, |
| pc_tree->split[0], rate); |
| encode_sb(cpi, td, tile, tp, mi_row, mi_col + hbs, dry_run, subsize, |
| pc_tree->split[1], rate); |
| encode_sb(cpi, td, tile, tp, mi_row + hbs, mi_col, dry_run, subsize, |
| pc_tree->split[2], rate); |
| encode_sb(cpi, td, tile, tp, mi_row + hbs, mi_col + hbs, dry_run, |
| subsize, pc_tree->split[3], rate); |
| } |
| break; |
| #if CONFIG_EXT_PARTITION_TYPES |
| case PARTITION_HORZ_A: |
| encode_b(cpi, tile, td, tp, mi_row, mi_col, dry_run, bsize2, partition, |
| &pc_tree->horizontala[0], rate); |
| encode_b(cpi, tile, td, tp, mi_row, mi_col + hbs, dry_run, bsize2, |
| partition, &pc_tree->horizontala[1], rate); |
| encode_b(cpi, tile, td, tp, mi_row + hbs, mi_col, dry_run, subsize, |
| partition, &pc_tree->horizontala[2], rate); |
| break; |
| case PARTITION_HORZ_B: |
| encode_b(cpi, tile, td, tp, mi_row, mi_col, dry_run, subsize, partition, |
| &pc_tree->horizontalb[0], rate); |
| encode_b(cpi, tile, td, tp, mi_row + hbs, mi_col, dry_run, bsize2, |
| partition, &pc_tree->horizontalb[1], rate); |
| encode_b(cpi, tile, td, tp, mi_row + hbs, mi_col + hbs, dry_run, bsize2, |
| partition, &pc_tree->horizontalb[2], rate); |
| break; |
| case PARTITION_VERT_A: |
| encode_b(cpi, tile, td, tp, mi_row, mi_col, dry_run, bsize2, partition, |
| &pc_tree->verticala[0], rate); |
| encode_b(cpi, tile, td, tp, mi_row + hbs, mi_col, dry_run, bsize2, |
| partition, &pc_tree->verticala[1], rate); |
| encode_b(cpi, tile, td, tp, mi_row, mi_col + hbs, dry_run, subsize, |
| partition, &pc_tree->verticala[2], rate); |
| |
| break; |
| case PARTITION_VERT_B: |
| encode_b(cpi, tile, td, tp, mi_row, mi_col, dry_run, subsize, partition, |
| &pc_tree->verticalb[0], rate); |
| encode_b(cpi, tile, td, tp, mi_row, mi_col + hbs<
|