blob: 5ad34ca7a25a154086df82a7765c2d98134f619c [file] [log] [blame]
/*
* 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_dsp/binary_codes_writer.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/mv.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 || CONFIG_WARPED_MOTION
#include "av1/common/warped_motion.h"
#endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION
#if CONFIG_GLOBAL_MOTION
#include "av1/encoder/global_motion.h"
#endif // CONFIG_GLOBAL_MOTION
#include "av1/encoder/encodeframe.h"
#include "av1/encoder/encodemb.h"
#include "av1/encoder/encodemv.h"
#if CONFIG_LV_MAP
#include "av1/encoder/encodetxb.h"
#endif
#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_PVQ
#include "av1/common/pvq.h"
#include "av1/encoder/pvq_encoder.h"
#endif
#if CONFIG_HIGHBITDEPTH
#define IF_HBD(...) __VA_ARGS__
#else
#define IF_HBD(...)
#endif // CONFIG_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, 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, int plane,
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_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_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_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_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 = mi_size_wide[bsize];
const int mi_height = mi_size_high[bsize];
set_mode_info_offsets(cpi, x, xd, mi_row, mi_col);
set_skip_context(xd, mi_row, mi_col);
#if CONFIG_VAR_TX
xd->above_txfm_context =
cm->above_txfm_context + (mi_col << TX_UNIT_WIDE_LOG2);
xd->left_txfm_context = xd->left_txfm_context_buffer +
((mi_row & MAX_MIB_MASK) << TX_UNIT_HIGH_LOG2);
xd->max_tx_size = max_txsize_lookup[bsize];
#endif
// Set up destination pointers.
av1_setup_dst_planes(xd->plane, bsize, 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_limits.row_min =
-(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND;
x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND;
set_plane_n4(xd, mi_width, mi_height);
// 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,
#if CONFIG_DEPENDENT_HORZTILES
cm->dependent_horz_tiles,
#endif // CONFIG_DEPENDENT_HORZTILES
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->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;
#if CONFIG_CFL
xd->cfl->mi_row = mi_row;
xd->cfl->mi_col = mi_col;
#endif
// 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 = mi_size_wide[bsize];
const int mi_height = mi_size_high[bsize];
#if CONFIG_DEPENDENT_HORZTILES
set_mode_info_offsets(cpi, x, xd, mi_row, mi_col, cm->dependent_horz_tiles);
#else
set_mode_info_offsets(cpi, x, xd, mi_row, mi_col);
#endif
// 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,
#if CONFIG_DEPENDENT_HORZTILES
cm->dependent_horz_tiles,
#endif // CONFIG_DEPENDENT_HORZTILES
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 = mi_size_wide[bsize_pred];
const int mi_height = mi_size_high[bsize_pred];
#if CONFIG_DEPENDENT_HORZTILES
set_mode_info_offsets(cpi, x, xd, mi_row_ori, mi_col_ori,
cm->dependent_horz_tiles);
#else
set_mode_info_offsets(cpi, x, xd, mi_row_ori, mi_col_ori);
#endif
// Set up limit values for MV components.
// Mv beyond the range do not produce new/different prediction block.
x->mv_limits.row_min =
-(((mi_row_pred + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
x->mv_limits.col_min =
-(((mi_col_pred + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
x->mv_limits.row_max =
(cm->mi_rows - mi_row_pred) * MI_SIZE + AOM_INTERP_EXTEND;
x->mv_limits.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.
#if !CONFIG_CB4X4
assert(!(mi_col_pred & (mi_width - mi_size_wide[BLOCK_8X8])) &&
!(mi_row_pred & (mi_height - mi_size_high[BLOCK_8X8])));
#endif
set_mi_row_col(xd, tile, mi_row_pred, mi_height, mi_col_pred, mi_width,
#if CONFIG_DEPENDENT_HORZTILES
cm->dependent_horz_tiles,
#endif // CONFIG_DEPENDENT_HORZTILES
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->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(mi_size_wide[bsize], cm->mi_cols - mi_col);
const int mih = AOMMIN(mi_size_high[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
#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_FRAME ||
!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, BLOCK_SIZE bsize,
const MB_MODE_INFO *mbmi,
RD_COUNTS *rdc) {
if (mode == ZEROMV
#if CONFIG_EXT_INTER
|| mode == ZERO_ZEROMV
#endif
) {
const int num_4x4s =
num_4x4_blocks_wide_lookup[bsize] * num_4x4_blocks_high_lookup[bsize];
int ref;
for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) {
rdc->global_motion_used[mbmi->ref_frame[ref]] += num_4x4s;
}
}
}
#endif // CONFIG_GLOBAL_MOTION
static void reset_tx_size(MACROBLOCKD *xd, MB_MODE_INFO *mbmi,
const TX_MODE tx_mode) {
if (xd->lossless[mbmi->segment_id]) {
mbmi->tx_size = TX_4X4;
} else if (tx_mode != TX_MODE_SELECT) {
mbmi->tx_size =
tx_size_from_tx_mode(mbmi->sb_type, tx_mode, is_inter_block(mbmi));
}
}
static void set_ref_and_pred_mvs(MACROBLOCK *const x, int_mv *const mi_pred_mv,
int8_t rf_type) {
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
const int bw = xd->n8_w << MI_SIZE_LOG2;
const int bh = xd->n8_h << MI_SIZE_LOG2;
int ref_mv_idx = mbmi->ref_mv_idx;
MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
CANDIDATE_MV *const curr_ref_mv_stack = mbmi_ext->ref_mv_stack[rf_type];
#if CONFIG_EXT_INTER
if (has_second_ref(mbmi)) {
// Special case: NEAR_NEWMV and NEW_NEARMV modes use 1 + mbmi->ref_mv_idx
// (like NEARMV) instead
if (mbmi->mode == NEAR_NEWMV || mbmi->mode == NEW_NEARMV) ref_mv_idx += 1;
if (compound_ref0_mode(mbmi->mode) == NEWMV) {
int_mv this_mv = curr_ref_mv_stack[ref_mv_idx].this_mv;
clamp_mv_ref(&this_mv.as_mv, bw, bh, xd);
mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0] = this_mv;
mbmi->pred_mv[0] = this_mv;
mi_pred_mv[0] = this_mv;
}
if (compound_ref1_mode(mbmi->mode) == NEWMV) {
int_mv this_mv = curr_ref_mv_stack[ref_mv_idx].comp_mv;
clamp_mv_ref(&this_mv.as_mv, bw, bh, xd);
mbmi_ext->ref_mvs[mbmi->ref_frame[1]][0] = this_mv;
mbmi->pred_mv[1] = this_mv;
mi_pred_mv[1] = this_mv;
}
#if CONFIG_COMPOUND_SINGLEREF
} else if (is_inter_singleref_comp_mode(mbmi->mode)) {
// Special case: SR_NEAR_NEWMV uses 1 + mbmi->ref_mv_idx
// (like NEARMV) instead
if (mbmi->mode == SR_NEAR_NEWMV) ref_mv_idx += 1;
if (compound_ref0_mode(mbmi->mode) == NEWMV ||
compound_ref1_mode(mbmi->mode) == NEWMV) {
int_mv this_mv = curr_ref_mv_stack[ref_mv_idx].this_mv;
clamp_mv_ref(&this_mv.as_mv, bw, bh, xd);
mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0] = this_mv;
mbmi->pred_mv[0] = this_mv;
mi_pred_mv[0] = this_mv;
}
#endif // CONFIG_COMPOUND_SINGLEREF
} else {
#endif // CONFIG_EXT_INTER
if (mbmi->mode == NEWMV) {
int i;
for (i = 0; i < 1 + has_second_ref(mbmi); ++i) {
int_mv this_mv = (i == 0) ? curr_ref_mv_stack[ref_mv_idx].this_mv
: curr_ref_mv_stack[ref_mv_idx].comp_mv;
clamp_mv_ref(&this_mv.as_mv, bw, bh, xd);
mbmi_ext->ref_mvs[mbmi->ref_frame[i]][0] = this_mv;
mbmi->pred_mv[i] = this_mv;
mi_pred_mv[i] = this_mv;
}
}
#if CONFIG_EXT_INTER
}
#endif // CONFIG_EXT_INTER
}
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 = mi_size_wide[mi->mbmi.sb_type];
const int bh = mi_size_high[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 = mi_size_wide[bsize];
const int mi_height = mi_size_high[bsize];
const int unify_bsize = CONFIG_CB4X4;
int8_t rf_type;
#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
rf_type = av1_ref_frame_type(mbmi->ref_frame);
if (x->mbmi_ext->ref_mv_count[rf_type] > 1 &&
(mbmi->sb_type >= BLOCK_8X8 || unify_bsize)) {
set_ref_and_pred_mvs(x, mi->mbmi.pred_mv, rf_type);
}
// 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);
reset_tx_size(xd, &mi_addr->mbmi, cm->tx_mode);
}
// 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);
reset_tx_size(xd, &mi_addr->mbmi, cm->tx_mode);
}
}
for (i = 0; i < MAX_MB_PLANE; ++i) {
p[i].coeff = ctx->coeff[i];
p[i].qcoeff = ctx->qcoeff[i];
pd[i].dqcoeff = ctx->dqcoeff[i];
#if CONFIG_PVQ
pd[i].pvq_ref_coeff = ctx->pvq_ref_coeff[i];
#endif
p[i].eobs = ctx->eobs[i];
#if CONFIG_LV_MAP
p[i].txb_entropy_ctx = ctx->txb_entropy_ctx[i];
#endif // CONFIG_LV_MAP
}
#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 && !CONFIG_EXT_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 && !unify_bsize) {
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*/,
#if CONFIG_ALT_INTRA
THR_SMOOTH, /*SMOOTH_PRED*/
#if CONFIG_SMOOTH_HV
THR_SMOOTH_V, /*SMOOTH_V_PRED*/
THR_SMOOTH_H, /*SMOOTH_H_PRED*/
#endif // CONFIG_SMOOTH_HV
#endif // CONFIG_ALT_INTRA
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, bsize, mbmi, rdc);
} 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, bsize, mbmi, rdc);
}
}
}
#endif // CONFIG_GLOBAL_MOTION
if (cm->interp_filter == SWITCHABLE
#if CONFIG_WARPED_MOTION
&& mbmi->motion_mode != WARPED_CAUSAL
#endif // CONFIG_WARPED_MOTION
#if CONFIG_GLOBAL_MOTION
&& !is_nontrans_global_motion(xd)
#endif // CONFIG_GLOBAL_MOTION
) {
#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
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 = mi_size_wide[bsize];
const int mi_height = mi_size_high[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);
const int unify_bsize = CONFIG_CB4X4;
MV_REF *const frame_mvs = cm->cur_frame->mvs + mi_row * cm->mi_cols + mi_col;
int w, h;
int8_t rf_type;
*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
rf_type = av1_ref_frame_type(mbmi->ref_frame);
if (x->mbmi_ext->ref_mv_count[rf_type] > 1 &&
(mbmi->sb_type >= BLOCK_8X8 || unify_bsize)) {
set_ref_and_pred_mvs(x, mi->mbmi.pred_mv, rf_type);
}
// 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 !CONFIG_CB4X4
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;
}
#endif
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 CONFIG_GLOBAL_MOTION
if (is_inter_block(mbmi)) {
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, bsize, mbmi, rdc);
} 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, bsize, mbmi, rdc);
}
}
}
}
#endif // CONFIG_GLOBAL_MOTION
if (cm->interp_filter == SWITCHABLE
#if CONFIG_GLOBAL_MOTION
&& !is_nontrans_global_motion(xd)
#endif // CONFIG_GLOBAL_MOTION
) {
#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 hbs = mi_size_wide[bsize] / 2;
#if CONFIG_CB4X4
const int unify_bsize = 1;
#else
const int unify_bsize = 0;
#endif
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 || unify_bsize)) {
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 || unify_bsize)) {
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 && !unify_bsize) {
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];
p[i].qcoeff = pmc->qcoeff[i];
pd[i].dqcoeff = pmc->dqcoeff[i];
p[i].eobs = pmc->eobs[i];
} 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;
const int hbs = mi_size_wide[bsize] / 2;
PARTITION_TYPE partition = pc_tree->partitioning;
BLOCK_SIZE subsize = get_subsize(bsize, partition);
#if CONFIG_CB4X4
const int unify_bsize = 1;
#else
const int unify_bsize = 0;
#endif
#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 || unify_bsize))
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 || unify_bsize))
update_supertx_param(td, &pc_tree->horizontal[1], best_tx,
supertx_size);
break;
case PARTITION_SPLIT:
if (bsize == BLOCK_8X8 && !unify_bsize) {
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
#if CONFIG_MOTION_VAR && (CONFIG_NCOBMC || CONFIG_NCOBMC_ADAPT_WEIGHT)
static void set_mode_info_b(const AV1_COMP *const cpi,
const TileInfo *const tile, ThreadData *td,
int mi_row, int mi_col, BLOCK_SIZE bsize,
PICK_MODE_CONTEXT *ctx) {
MACROBLOCK *const x = &td->mb;
set_offsets(cpi, tile, x, mi_row, mi_col, bsize);
update_state(cpi, td, ctx, mi_row, mi_col, bsize, 1);
}
static void set_mode_info_sb(const AV1_COMP *const cpi, ThreadData *td,
const TileInfo *const tile, TOKENEXTRA **tp,
int mi_row, int mi_col, BLOCK_SIZE bsize,
PC_TREE *pc_tree) {
const AV1_COMMON *const cm = &cpi->common;
const int hbs = mi_size_wide[bsize] / 2;
const PARTITION_TYPE partition = pc_tree->partitioning;
BLOCK_SIZE subsize = get_subsize(bsize, partition);
#if CONFIG_EXT_PARTITION_TYPES
const BLOCK_SIZE bsize2 = get_subsize(bsize, PARTITION_SPLIT);
#endif
#if CONFIG_CB4X4
const int unify_bsize = 1;
#else
const int unify_bsize = 0;
assert(bsize >= BLOCK_8X8);
#endif
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
switch (partition) {
case PARTITION_NONE:
set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize, &pc_tree->none);
break;
case PARTITION_VERT:
set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize,
&pc_tree->vertical[0]);
if (mi_col + hbs < cm->mi_cols && (bsize > BLOCK_8X8 || unify_bsize)) {
set_mode_info_b(cpi, tile, td, mi_row, mi_col + hbs, subsize,
&pc_tree->vertical[1]);
}
break;
case PARTITION_HORZ:
set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize,
&pc_tree->horizontal[0]);
if (mi_row + hbs < cm->mi_rows && (bsize > BLOCK_8X8 || unify_bsize)) {
set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col, subsize,
&pc_tree->horizontal[1]);
}
break;
case PARTITION_SPLIT:
if (bsize == BLOCK_8X8 && !unify_bsize) {
set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize,
pc_tree->leaf_split[0]);
} else {
set_mode_info_sb(cpi, td, tile, tp, mi_row, mi_col, subsize,
pc_tree->split[0]);
set_mode_info_sb(cpi, td, tile, tp, mi_row, mi_col + hbs, subsize,
pc_tree->split[1]);
set_mode_info_sb(cpi, td, tile, tp, mi_row + hbs, mi_col, subsize,
pc_tree->split[2]);
set_mode_info_sb(cpi, td, tile, tp, mi_row + hbs, mi_col + hbs, subsize,
pc_tree->split[3]);
}
break;
#if CONFIG_EXT_PARTITION_TYPES
case PARTITION_HORZ_A:
set_mode_info_b(cpi, tile, td, mi_row, mi_col, bsize2,
&pc_tree->horizontala[0]);
set_mode_info_b(cpi, tile, td, mi_row, mi_col + hbs, bsize2,
&pc_tree->horizontala[1]);
set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col, subsize,
&pc_tree->horizontala[2]);
break;
case PARTITION_HORZ_B:
set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize,
&pc_tree->horizontalb[0]);
set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col, bsize2,
&pc_tree->horizontalb[1]);
set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col + hbs, bsize2,
&pc_tree->horizontalb[2]);
break;
case PARTITION_VERT_A:
set_mode_info_b(cpi, tile, td, mi_row, mi_col, bsize2,
&pc_tree->verticala[0]);
set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col, bsize2,
&pc_tree->verticala[1]);
set_mode_info_b(cpi, tile, td, mi_row, mi_col + hbs, subsize,
&pc_tree->verticala[2]);
break;
case PARTITION_VERT_B:
set_mode_info_b(cpi, tile, td, mi_row, mi_col, subsize,
&pc_tree->verticalb[0]);
set_mode_info_b(cpi, tile, td, mi_row, mi_col + hbs, bsize2,
&pc_tree->verticalb[1]);
set_mode_info_b(cpi, tile, td, mi_row + hbs, mi_col + hbs, bsize2,
&pc_tree->verticalb[2]);
break;
#endif // CONFIG_EXT_PARTITION_TYPES
default: assert(0 && "Invalid partition type."); break;
}
}
#endif
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, x->e_mbd.mi[0]->mbmi.sb_type, 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);
}
#if CONFIG_DAALA_DIST && CONFIG_CB4X4
static void daala_dist_set_sub8x8_dst(MACROBLOCK *const x, uint8_t *dst8x8,
BLOCK_SIZE bsize, int bw, int bh,
int mi_row, int mi_col) {
MACROBLOCKD *const xd = &x->e_mbd;
struct macroblockd_plane *const pd = &xd->plane[0];
const int dst_stride = pd->dst.stride;
uint8_t *dst = pd->dst.buf;
assert(bsize < BLOCK_8X8);
if (bsize < BLOCK_8X8) {
int i, j;
#if CONFIG_HIGHBITDEPTH
if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) {
uint16_t *dst8x8_16 = (uint16_t *)dst8x8;
uint16_t *dst_sub8x8 = &dst8x8_16[((mi_row & 1) * 8 + (mi_col & 1)) << 2];
for (j = 0; j < bh; ++j)
for (i = 0; i < bw; ++i)
dst_sub8x8[j * 8 + i] = CONVERT_TO_SHORTPTR(dst)[j * dst_stride + i];
} else {
#endif
uint8_t *dst_sub8x8 = &dst8x8[((mi_row & 1) * 8 + (mi_col & 1)) << 2];
for (j = 0; j < bh; ++j)
for (i = 0; i < bw; ++i)
dst_sub8x8[j * 8 + i] = dst[j * dst_stride + i];
#if CONFIG_HIGHBITDEPTH
}
#endif
}
}
#endif
static void rd_pick_sb_modes(const AV1_COMP *const cpi, TileDataEnc *tile_data,
MACROBLOCK *const x, int mi_row, int mi_col,
RD_STATS *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();
#if CONFIG_PVQ
x->pvq_speed = 1;
x->pvq_coded = 0;
#endif
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_CFL
// Don't store luma during RDO. Only store luma when best luma is known
x->cfl_store_y = 0;
#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];
p[i].qcoeff = ctx->qcoeff[i];
pd[i].dqcoeff = ctx->dqcoeff[i];
#if CONFIG_PVQ
pd[i].pvq_ref_coeff = ctx->pvq_ref_coeff[i];
#endif
p[i].eobs = ctx->eobs[i];
#if CONFIG_LV_MAP
p[i].txb_entropy_ctx = ctx->txb_entropy_ctx[i];
#endif
}
#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;
// Set to zero to make sure we do not use the previous encoded frame stats
mbmi->skip = 0;
#if CONFIG_CB4X4
x->skip_chroma_rd =
!is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x,
xd->plane[1].subsampling_y);
#endif
#if CONFIG_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_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 (segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) {
av1_rd_pick_inter_mode_sb_seg_skip(cpi, tile_data, x, mi_row, mi_col,
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
}
}
// 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;
}
static void update_inter_mode_stats(FRAME_COUNTS *counts, PREDICTION_MODE mode,
int16_t mode_context) {
int16_t mode_ctx = mode_context & NEWMV_CTX_MASK;
if (mode == NEWMV) {
++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];
}
}
}
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 < AOMMIN(absdq, DELTA_Q_SMALL); ++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;
#if CONFIG_EXT_DELTA_Q
if (cm->delta_lf_present_flag) {
const int dlf =
(mbmi->current_delta_lf_from_base - xd->prev_delta_lf_from_base) /
cm->delta_lf_res;
const int absdlf = abs(dlf);
for (i = 0; i < AOMMIN(absdlf, DELTA_LF_SMALL); ++i) {
td->counts->delta_lf[i][1]++;
}
if (absdlf < DELTA_LF_SMALL) td->counts->delta_lf[absdlf][0]++;
xd->prev_delta_lf_from_base = mbmi->current_delta_lf_from_base;
}
#endif
}
#else
(void)mi_row;
(void)mi_col;
#endif
if (!frame_is_intra_only(cm)) {
FRAME_COUNTS *const counts = td->counts;
RD_COUNTS *rdc = &td->rd_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) {
if (has_second_ref(mbmi))
// This flag is also updated for 4x4 blocks
rdc->compound_ref_used_flag = 1;
else
// This flag is also updated for 4x4 blocks
rdc->single_ref_used_flag = 1;
#if !SUB8X8_COMP_REF
if (mbmi->sb_type != BLOCK_4X4)
counts->comp_inter[av1_get_reference_mode_context(cm, xd)]
[has_second_ref(mbmi)]++;
#else
counts->comp_inter[av1_get_reference_mode_context(cm, xd)]
[has_second_ref(mbmi)]++;
#endif
}
if (has_second_ref(mbmi)) {
#if CONFIG_EXT_COMP_REFS
const COMP_REFERENCE_TYPE comp_ref_type = has_uni_comp_refs(mbmi)
? UNIDIR_COMP_REFERENCE
: BIDIR_COMP_REFERENCE;
#if !USE_UNI_COMP_REFS
// TODO(zoeliu): Temporarily turn off uni-directional comp refs
assert(comp_ref_type == BIDIR_COMP_REFERENCE);
#endif // !USE_UNI_COMP_REFS
counts->comp_ref_type[av1_get_comp_reference_type_context(cm, xd)]
[comp_ref_type]++;
if (comp_ref_type == UNIDIR_COMP_REFERENCE) {
const int bit = (ref0 == BWDREF_FRAME);
counts->uni_comp_ref[av1_get_pred_context_uni_comp_ref_p(cm, xd)][0]
[bit]++;
if (!bit) {
const int bit1 = (ref1 == GOLDEN_FRAME);
counts->uni_comp_ref[av1_get_pred_context_uni_comp_ref_p1(cm, xd)]
[1][bit1]++;
}
} else {
#endif // CONFIG_EXT_COMP_REFS
#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 // !CONFIG_EXT_REFS
counts->comp_ref[av1_get_pred_context_comp_ref_p(cm, xd)][0]
[ref0 == GOLDEN_FRAME]++;
#endif // CONFIG_EXT_REFS
#if CONFIG_EXT_COMP_REFS
}
#endif // CONFIG_EXT_COMP_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 // !CONFIG_EXT_REFS
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 CONFIG_COMPOUND_SINGLEREF
if (!has_second_ref(mbmi))
counts->comp_inter_mode[av1_get_inter_mode_context(xd)]
[is_inter_singleref_comp_mode(mbmi->mode)]++;
#endif // CONFIG_COMPOUND_SINGLEREF
#if CONFIG_INTERINTRA
if (cm->reference_mode != COMPOUND_REFERENCE &&
#if CONFIG_SUPERTX
!supertx_enabled &&
#endif
cm->allow_interintra_compound && 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_INTERINTRA
#endif // CONFIG_EXT_INTER
#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
#if CONFIG_NCOBMC_ADAPT_WEIGHT
const MOTION_MODE motion_allowed =
motion_mode_allowed_wrapper(0,
#if CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
0, xd->global_motion,
#endif // CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
mi);
#else
const MOTION_MODE motion_allowed = motion_mode_allowed(
#if CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
0, xd->global_motion,
#endif // CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
mi);
#endif // CONFIG_NCOBMC_ADAPT_WEIGHT
#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 CONFIG_MOTION_VAR && CONFIG_WARPED_MOTION
{
if (motion_allowed == WARPED_CAUSAL)
counts->motion_mode[mbmi->sb_type][mbmi->motion_mode]++;
else if (motion_allowed == OBMC_CAUSAL)
counts->obmc[mbmi->sb_type][mbmi->motion_mode == OBMC_CAUSAL]++;
}
#else
if (motion_allowed > SIMPLE_TRANSLATION)
counts->motion_mode[mbmi->sb_type][mbmi->motion_mode]++;
#endif // CONFIG_MOTION_VAR && CONFIG_WARPED_MOTION
#if CONFIG_NCOBMC_ADAPT_WEIGHT
if (motion_allowed == NCOBMC_ADAPT_WEIGHT) {
ADAPT_OVERLAP_BLOCK ao_block =
adapt_overlap_block_lookup[mbmi->sb_type];
++counts->ncobmc_mode[ao_block][mbmi->ncobmc_mode[0]];
if (mi_size_wide[mbmi->sb_type] != mi_size_high[mbmi->sb_type]) {
++counts->ncobmc_mode[ao_block][mbmi->ncobmc_mode[1]];
}
}
#endif
#endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
#if CONFIG_EXT_INTER
if (
#if CONFIG_COMPOUND_SINGLEREF
is_inter_anyref_comp_mode(mbmi->mode)
#else // !CONFIG_COMPOUND_SINGLEREF
cm->reference_mode != SINGLE_REFERENCE &&
is_inter_compound_mode(mbmi->mode)
#endif // CONFIG_COMPOUND_SINGLEREF
#if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
&& mbmi->motion_mode == SIMPLE_TRANSLATION
#endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
) {
counts->compound_interinter[bsize][mbmi->interinter_compound_type]++;
}
#endif // CONFIG_EXT_INTER
}
}
if (inter_block &&
!segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_SKIP)) {
int16_t mode_ctx;
const PREDICTION_MODE mode = mbmi->mode;
#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)];
#if CONFIG_COMPOUND_SINGLEREF
} else if (is_inter_singleref_comp_mode(mode)) {
mode_ctx = mbmi_ext->compound_mode_context[mbmi->ref_frame[0]];
++counts->inter_singleref_comp_mode[mode_ctx]
[INTER_SINGLEREF_COMP_OFFSET(mode)];
#endif // CONFIG_COMPOUND_SINGLEREF
} 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, mode_ctx);
#if CONFIG_EXT_INTER
}
#endif // CONFIG_EXT_INTER
#if CONFIG_EXT_INTER
#if CONFIG_COMPOUND_SINGLEREF
if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV ||
mbmi->mode == SR_NEW_NEWMV) {
#else // !CONFIG_COMPOUND_SINGLEREF
if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV) {
#endif // CONFIG_COMPOUND_SINGLEREF
#else // !CONFIG_EXT_INTER
if (mbmi->mode == NEWMV) {
#endif // CONFIG_EXT_INTER
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 CONFIG_EXT_INTER
if (have_nearmv_in_inter_mode(mbmi->mode)) {
#else
if (mbmi->mode == NEARMV) {
#endif
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_INTRABC
} else {
if (cm->allow_screen_content_tools && bsize >= BLOCK_8X8) {
FRAME_COUNTS *const counts = td->counts;
++counts->intrabc[mbmi->use_intrabc];
} else {
assert(!mbmi->use_intrabc);
}
#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[2 * MAX_MIB_SIZE];
TXFM_CONTEXT tl[2 * 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,
#if CONFIG_PVQ
od_rollback_buffer *rdo_buf,
#endif
BLOCK_SIZE bsize) {
MACROBLOCKD *xd = &x->e_mbd;
int p;
const int num_4x4_blocks_wide =
block_size_wide[bsize] >> tx_size_wide_log2[0];
const int num_4x4_blocks_high =
block_size_high[bsize] >> tx_size_high_log2[0];
int mi_width = mi_size_wide[bsize];
int mi_height = mi_size_high[bsize];
for (p = 0; p < MAX_MB_PLANE; p++) {
int tx_col;
int tx_row;
tx_col = mi_col << (MI_SIZE_LOG2 - tx_size_wide_log2[0]);
tx_row = (mi_row & MAX_MIB_MASK) << (MI_SIZE_LOG2 - tx_size_high_log2[0]);
memcpy(xd->above_context[p] + (tx_col >> 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] + (tx_row >> 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 << TX_UNIT_WIDE_LOG2));
memcpy(xd->left_txfm_context, ctx->tl,
sizeof(*xd->left_txfm_context) * (mi_height << TX_UNIT_HIGH_LOG2));
#endif
#if CONFIG_PVQ
od_encode_rollback(&x->daala_enc, rdo_buf);
#endif
}
static void save_context(const MACROBLOCK *x, RD_SEARCH_MACROBLOCK_CONTEXT *ctx,
int mi_row, int mi_col,
#if CONFIG_PVQ
od_rollback_buffer *rdo_buf,
#endif
BLOCK_SIZE bsize) {
const MACROBLOCKD *xd = &x->e_mbd;
int p;
const int num_4x4_blocks_wide =
block_size_wide[bsize] >> tx_size_wide_log2[0];
const int num_4x4_blocks_high =
block_size_high[bsize] >> tx_size_high_log2[0];
int mi_width = mi_size_wide[bsize];
int mi_height = mi_size_high[bsize];
// buffer the above/left context information of the block in search.
for (p = 0; p < MAX_MB_PLANE; ++p) {
int tx_col;
int tx_row;
tx_col = mi_col << (MI_SIZE_LOG2 - tx_size_wide_log2[0]);
tx_row = (mi_row & MAX_MIB_MASK) << (MI_SIZE_LOG2 - tx_size_high_log2[0]);
memcpy(ctx->a + num_4x4_blocks_wide * p,
xd->above_context[p] + (tx_col >> 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] + (tx_row >> 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 << TX_UNIT_WIDE_LOG2));
memcpy(ctx->tl, xd->left_txfm_context,
sizeof(*xd->left_txfm_context) * (mi_height << TX_UNIT_HIGH_LOG2));
ctx->p_ta = xd->above_txfm_context;
ctx->p_tl = xd->left_txfm_context;
#endif
#if CONFIG_PVQ
od_encode_checkpoint(&x->daala_enc, rdo_buf);
#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;
#if (CONFIG_MOTION_VAR && CONFIG_NCOBMC) | CONFIG_EXT_DELTA_Q
MACROBLOCKD *xd = &x->e_mbd;
MB_MODE_INFO *mbmi;
#if CONFIG_MOTION_VAR && CONFIG_NCOBMC
int check_ncobmc;
#endif
#endif
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);
#if CONFIG_MOTION_VAR && CONFIG_NCOBMC
mbmi = &xd->mi[0]->mbmi;
const MOTION_MODE motion_allowed = motion_mode_allowed(
#if CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
0, xd->global_motion,
#endif // CONFIG_GLOBAL_MOTION && SEPARATE_GLOBAL_MOTION
xd->mi[0]);
check_ncobmc = is_inter_block(mbmi) && motion_allowed >= OBMC_CAUSAL;
if (!dry_run && check_ncobmc) {
av1_check_ncobmc_rd(cpi, x, mi_row, mi_col);
av1_setup_dst_planes(x->e_mbd.plane, bsize,
get_frame_new_buffer(&cpi->common), mi_row, mi_col);
}
#endif
encode_superblock(cpi, td, tp, dry_run, mi_row, mi_col, bsize, rate);
if (!dry_run) {
#if CONFIG_EXT_DELTA_Q
mbmi = &xd->mi[0]->mbmi;
if (bsize == BLOCK_64X64 && mbmi->skip == 1 && is_inter_block(mbmi) &&
cpi->common.delta_lf_present_flag) {
mbmi->current_delta_lf_from_base = xd->prev_delta_lf_from_base;
}
#endif
#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 hbs = mi_size_wide[bsize] / 2;
const int is_partition_root = bsize >= BLOCK_8X8;
const int ctx = is_partition_root
? partition_plane_context(xd, mi_row, mi_col,
#if CONFIG_UNPOISON_PARTITION_CTX
mi_row + hbs < cm->mi_rows,
mi_col + hbs < cm->mi_cols,
#endif
bsize)
: -1;
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
#if CONFIG_CB4X4
const int unify_bsize = 1;
#else
const int unify_bsize = 0;
assert(bsize >= BLOCK_8X8);
#endif
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
#if CONFIG_SPEED_REFS
// First scanning pass of an SB is dry run only.
if (cpi->sb_scanning_pass_idx == 0) assert(dry_run == DRY_RUN_NORMAL);
#endif // CONFIG_SPEED_REFS
if (!dry_run && ctx >= 0) 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 = mi_size_wide[bsize];
const int mi_height = mi_size_high[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, bsize, 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;
av1_encode_sb_supertx((AV1_COMMON *)cm, x, bsize);
av1_tokenize_sb_supertx(cpi, td, tp, dry_run, mi_row, mi_col, 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]++;
av1_reset_skip_context(xd, mi_row, mi_col, 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, cm->reduced_tx_set_used) >
1 &&
!xd->mi[0]->mbmi.skip) {
const int eset =
get_ext_tx_set(supertx_size, bsize, 1, cm->reduced_tx_set_used);
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->mi[0]->mbmi.skip,
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 || unify_bsize)) {
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 || unify_bsize)) {
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 && !unify_bsize) {
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->