/* * Copyright(c) 2019 Intel Corporation * 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 https://www.aomedia.org/license/software-license. 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 #include "EbDefinitions.h" #include "EbAdaptiveMotionVectorPrediction.h" #include "EbSvtAv1.h" #include "EbModeDecisionProcess.h" #include "EbCommonUtils.h" #include "EbEntropyCoding.h" #define UNUSED_FUNC /** ScaleMV is used to scale the motion vector in AMVP process. */ /* static inline void scale_mv( uint64_t current_pic_poc, // Iuput parameter, the POC of the current picture to be encoded. uint64_t target_ref_pic_poc, // Iuput parameter, the POC of the reference picture where the inter coding is searching for. uint64_t col_pu_pic_poc, // Iuput parameter, the POC of picture where the co-located PU is. uint64_t col_pu_ref_pic_poc, // Iuput parameter, the POC of the reference picture where the MV of the co-located PU points to. int16_t *mvx, // Output parameter, int16_t *mvy) // Output parameter, { int16_t td = (int16_t)(col_pu_pic_poc - col_pu_ref_pic_poc); int16_t tb = (int16_t)(current_pic_poc - target_ref_pic_poc); int16_t scale_factor; int16_t temp; if (td != tb) { tb = CLIP3(-128, 127, tb); td = CLIP3(-128, 127, td); temp = (int16_t)((0x4000 + ABS(td >> 1)) / td); scale_factor = CLIP3(-4096, 4095, (tb * temp + 32) >> 6); *mvx = CLIP3(-32768, 32767, (scale_factor * (*mvx) + 127 + (scale_factor * (*mvx) < 0)) >> 8); *mvy = CLIP3(-32768, 32767, (scale_factor * (*mvy) + 127 + (scale_factor * (*mvy) < 0)) >> 8); } return; } */ static PartitionType from_shape_to_part[] = {PARTITION_NONE, PARTITION_HORZ, PARTITION_VERT, PARTITION_HORZ_A, PARTITION_HORZ_B, PARTITION_VERT_A, PARTITION_VERT_B, PARTITION_HORZ_4, PARTITION_VERT_4, PARTITION_SPLIT}; #define MVREF_ROWS 3 #define MVREF_COLS 3 static int32_t have_newmv_in_inter_mode(PredictionMode mode) { return (mode == NEWMV || mode == NEW_NEWMV || mode == NEAREST_NEWMV || mode == NEW_NEARESTMV || mode == NEAR_NEWMV || mode == NEW_NEARMV); } typedef struct position { int32_t row; int32_t col; } Position; // clang-format on static INLINE IntMv get_sub_block_mv(const ModeInfo *candidate, int32_t which_mv, int32_t search_col) { (void)search_col; return candidate->mbmi.block_mi.mv[which_mv]; } static INLINE int32_t is_inside(const TileInfo *const tile, int32_t mi_col, int32_t mi_row, const Position *mi_pos) { return !(mi_row + mi_pos->row < tile->mi_row_start || mi_col + mi_pos->col < tile->mi_col_start || mi_row + mi_pos->row >= tile->mi_row_end || mi_col + mi_pos->col >= tile->mi_col_end); } static INLINE void clamp_mv_ref(MV *mv, int32_t bw, int32_t bh, const MacroBlockD *xd) { clamp_mv(mv, xd->mb_to_left_edge - bw * 8 - MV_BORDER, xd->mb_to_right_edge + bw * 8 + MV_BORDER, xd->mb_to_top_edge - bh * 8 - MV_BORDER, xd->mb_to_bottom_edge + bh * 8 + MV_BORDER); } static void add_ref_mv_candidate(const ModeInfo *const candidate_mi, const MbModeInfo *const candidate, const MvReferenceFrame rf[2], uint8_t refmv_counts[MODE_CTX_REF_FRAMES], uint8_t ref_match_counts[MODE_CTX_REF_FRAMES], uint8_t newmv_counts[MODE_CTX_REF_FRAMES], CandidateMv ref_mv_stacks[][MAX_REF_MV_STACK_SIZE], int32_t len, IntMv *gm_mv_candidates, const EbWarpedMotionParams *gm_params, int32_t col, int32_t weight) { if (!is_inter_block(&candidate->block_mi)) return; // for intrabc assert(weight % 2 == 0); if (rf[1] == NONE_FRAME) { uint8_t * refmv_count = &refmv_counts[rf[0]]; uint8_t * ref_match_count = &ref_match_counts[rf[0]]; uint8_t * newmv_count = &newmv_counts[rf[0]]; CandidateMv *ref_mv_stack = ref_mv_stacks[rf[0]]; (void)ref_match_count; // single reference frame for (int32_t ref = 0; ref < 2; ++ref) { if (candidate->block_mi.ref_frame[ref] == rf[0]) { IntMv this_refmv; if (is_global_mv_block(candidate->block_mi.mode, candidate->block_mi.sb_type, gm_params[rf[0]].wmtype)) this_refmv = gm_mv_candidates[0]; else this_refmv = get_sub_block_mv(candidate_mi, ref, col); int32_t index; for (index = 0; index < *refmv_count; ++index) if (ref_mv_stack[index].this_mv.as_int == this_refmv.as_int) break; if (index < *refmv_count) ref_mv_stack[index].weight += weight * len; // Add a new item to the list. if (index == *refmv_count && *refmv_count < MAX_REF_MV_STACK_SIZE) { ref_mv_stack[index].this_mv = this_refmv; ref_mv_stack[index].weight = weight * len; ++(*refmv_count); } if (have_newmv_in_inter_mode(candidate->block_mi.mode)) ++*newmv_count; ++*ref_match_count; } } } else { MvReferenceFrame ref_frame = av1_ref_frame_type(rf); uint8_t * refmv_count = &refmv_counts[ref_frame]; uint8_t * ref_match_count = &ref_match_counts[ref_frame]; uint8_t * newmv_count = &newmv_counts[ref_frame]; CandidateMv * ref_mv_stack = ref_mv_stacks[ref_frame]; (void)ref_match_count; // compound reference frame if (candidate->block_mi.ref_frame[0] == rf[0] && candidate->block_mi.ref_frame[1] == rf[1]) { IntMv this_refmv[2]; for (int32_t ref = 0; ref < 2; ++ref) { if (is_global_mv_block(candidate->block_mi.mode, candidate->block_mi.sb_type, gm_params[rf[ref]].wmtype)) this_refmv[ref] = gm_mv_candidates[ref]; else this_refmv[ref] = get_sub_block_mv(candidate_mi, ref, col); } int32_t index; for (index = 0; index < *refmv_count; ++index) if ((ref_mv_stack[index].this_mv.as_int == this_refmv[0].as_int) && (ref_mv_stack[index].comp_mv.as_int == this_refmv[1].as_int)) break; if (index < *refmv_count) ref_mv_stack[index].weight += weight * len; // Add a new item to the list. if (index == *refmv_count && *refmv_count < MAX_REF_MV_STACK_SIZE) { ref_mv_stack[index].this_mv = this_refmv[0]; ref_mv_stack[index].comp_mv = this_refmv[1]; ref_mv_stack[index].weight = weight * len; ++(*refmv_count); } if (have_newmv_in_inter_mode(candidate->block_mi.mode)) ++*newmv_count; ++*ref_match_count; } } } static void scan_row_mbmi(const Av1Common *cm, const MacroBlockD *xd, int32_t mi_row, int32_t mi_col, const MvReferenceFrame rf[2], int32_t row_offset, CandidateMv ref_mv_stack[][MAX_REF_MV_STACK_SIZE], uint8_t refmv_count[MODE_CTX_REF_FRAMES], uint8_t ref_match_count[MODE_CTX_REF_FRAMES], uint8_t newmv_count[MODE_CTX_REF_FRAMES], IntMv *gm_mv_candidates, const EbWarpedMotionParams *gm_params, int32_t max_row_offset, int32_t *processed_rows) { int32_t end_mi = AOMMIN(xd->n8_w, cm->mi_cols - mi_col); end_mi = AOMMIN(end_mi, mi_size_wide[BLOCK_64X64]); const int32_t n8_w_8 = mi_size_wide[BLOCK_8X8]; const int32_t n8_w_16 = mi_size_wide[BLOCK_16X16]; int32_t i; int32_t col_offset = 0; const int32_t shift = 0; if (abs(row_offset) > 1) { col_offset = 1; if (mi_col & 0x01 && xd->n8_w < n8_w_8) --col_offset; } const int32_t use_step_16 = (xd->n8_w >= 16); ModeInfo **const candidate_mi0 = xd->mi + row_offset * xd->mi_stride; (void)mi_row; for (i = 0; i < end_mi;) { const ModeInfo *const candidate_mi = candidate_mi0[col_offset + i]; const MbModeInfo *const candidate = &candidate_mi->mbmi; const int32_t candidate_bsize = candidate->block_mi.sb_type; assert(candidate_bsize < BlockSizeS_ALL); const int32_t n8_w = mi_size_wide[candidate_bsize]; int32_t len = AOMMIN(xd->n8_w, n8_w); if (use_step_16) len = AOMMAX(n8_w_16, len); else if (abs(row_offset) > 1) len = AOMMAX(len, n8_w_8); int32_t weight = 2; if (xd->n8_w >= n8_w_8 && xd->n8_w <= n8_w) { int32_t inc = AOMMIN(-max_row_offset + row_offset + 1, mi_size_high[candidate_bsize]); // Obtain range used in weight calculation. weight = AOMMAX(weight, (inc << shift)); // Update processed rows. *processed_rows = inc - row_offset - 1; } add_ref_mv_candidate(candidate_mi, candidate, rf, refmv_count, ref_match_count, newmv_count, ref_mv_stack, len, gm_mv_candidates, gm_params, col_offset + i, weight); i += len; } } static void scan_col_mbmi(const Av1Common *cm, const MacroBlockD *xd, int32_t mi_row, int32_t mi_col, const MvReferenceFrame rf[2], int32_t col_offset, CandidateMv ref_mv_stack[][MAX_REF_MV_STACK_SIZE], uint8_t refmv_count[MODE_CTX_REF_FRAMES], uint8_t ref_match_count[MODE_CTX_REF_FRAMES], uint8_t newmv_count[MODE_CTX_REF_FRAMES], IntMv *gm_mv_candidates, const EbWarpedMotionParams *gm_params, int32_t max_col_offset, int32_t *processed_cols) { int32_t end_mi = AOMMIN(xd->n8_h, cm->mi_rows - mi_row); end_mi = AOMMIN(end_mi, mi_size_high[BLOCK_64X64]); const int32_t n8_h_8 = mi_size_high[BLOCK_8X8]; const int32_t n8_h_16 = mi_size_high[BLOCK_16X16]; int32_t i; int32_t row_offset = 0; const int32_t shift = 0; if (abs(col_offset) > 1) { row_offset = 1; if (mi_row & 0x01 && xd->n8_h < n8_h_8) --row_offset; } const int32_t use_step_16 = (xd->n8_h >= 16); (void)mi_col; for (i = 0; i < end_mi;) { const ModeInfo *const candidate_mi = xd->mi[(row_offset + i) * xd->mi_stride + col_offset]; const MbModeInfo *const candidate = &candidate_mi->mbmi; const int32_t candidate_bsize = candidate->block_mi.sb_type; assert(candidate_bsize < BlockSizeS_ALL); const int32_t n8_h = mi_size_high[candidate_bsize]; int32_t len = AOMMIN(xd->n8_h, n8_h); if (use_step_16) len = AOMMAX(n8_h_16, len); else if (abs(col_offset) > 1) len = AOMMAX(len, n8_h_8); int32_t weight = 2; if (xd->n8_h >= n8_h_8 && xd->n8_h <= n8_h) { int32_t inc = AOMMIN(-max_col_offset + col_offset + 1, mi_size_wide[candidate_bsize]); // Obtain range used in weight calculation. weight = AOMMAX(weight, (inc << shift)); // Update processed cols. *processed_cols = inc - col_offset - 1; } add_ref_mv_candidate(candidate_mi, candidate, rf, refmv_count, ref_match_count, newmv_count, ref_mv_stack, len, gm_mv_candidates, gm_params, col_offset, weight); i += len; } } static void scan_blk_mbmi(const MacroBlockD *xd, const int32_t mi_row, const int32_t mi_col, const MvReferenceFrame rf[2], int32_t row_offset, int32_t col_offset, CandidateMv ref_mv_stack[][MAX_REF_MV_STACK_SIZE], uint8_t ref_match_count[MODE_CTX_REF_FRAMES], uint8_t newmv_count[MODE_CTX_REF_FRAMES], IntMv *gm_mv_candidates, const EbWarpedMotionParams *gm_params, uint8_t refmv_count[MODE_CTX_REF_FRAMES]) { const TileInfo *const tile = &xd->tile; Position mi_pos; mi_pos.row = row_offset; mi_pos.col = col_offset; if (is_inside(tile, mi_col, mi_row, &mi_pos)) { const ModeInfo *const candidate_mi = xd->mi[mi_pos.row * xd->mi_stride + mi_pos.col]; const MbModeInfo *const candidate = &candidate_mi->mbmi; const int32_t len = mi_size_wide[BLOCK_8X8]; add_ref_mv_candidate(candidate_mi, candidate, rf, refmv_count, ref_match_count, newmv_count, ref_mv_stack, len, gm_mv_candidates, gm_params, mi_pos.col, 2); } // Analyze a single 8x8 block motion information. } static int32_t has_top_right(const Av1Common *cm, const BlockSize sb_size, const MacroBlockD *xd, int32_t mi_row, int32_t mi_col, int32_t bs) { (void)xd; (void)cm; const int32_t sb_mi_size = mi_size_wide[sb_size]; const int32_t mask_row = mi_row & (sb_mi_size - 1); const int32_t mask_col = mi_col & (sb_mi_size - 1); if (bs > mi_size_wide[BLOCK_64X64]) return 0; // In a split partition all apart from the bottom right has a top right int32_t has_tr = !((mask_row & bs) && (mask_col & bs)); // bs > 0 and bs is a power of 2 assert(bs > 0 && !(bs & (bs - 1))); // For each 4x4 group of blocks, when the bottom right is decoded the blocks // to the right have not been decoded therefore the bottom right does // not have a top right while (bs < sb_mi_size) { if (mask_col & bs) { if ((mask_col & (2 * bs)) && (mask_row & (2 * bs))) { has_tr = 0; break; } } else break; bs <<= 1; } // The left hand of two vertical rectangles always has a top right (as the // block above will have been decoded) if (xd->n8_w < xd->n8_h) if (!xd->is_sec_rect) has_tr = 1; // The bottom of two horizontal rectangles never has a top right (as the block // to the right won't have been decoded) if (xd->n8_w > xd->n8_h) if (xd->is_sec_rect) has_tr = 0; // The bottom left square of a Vertical A (in the old format) does // not have a top right as it is decoded before the right hand // rectangle of the partition if (xd->mi[0]->mbmi.block_mi.partition == PARTITION_VERT_A) { if (xd->n8_w == xd->n8_h) if (mask_row & bs) has_tr = 0; } return has_tr; } static INLINE int32_t find_valid_row_offset(const TileInfo *const tile, int32_t mi_row, int32_t row_offset) { return clamp(row_offset, tile->mi_row_start - mi_row, tile->mi_row_end - mi_row - 1); } static INLINE int32_t find_valid_col_offset(const TileInfo *const tile, int32_t mi_col, int32_t col_offset) { return clamp(col_offset, tile->mi_col_start - mi_col, tile->mi_col_end - mi_col - 1); } static INLINE int get_relative_dist(const OrderHintInfo *oh, int a, int b) { if (!oh->enable_order_hint) return 0; const int bits = oh->order_hint_bits; assert(bits >= 1); assert(a >= 0 && a < (1 << bits)); assert(b >= 0 && b < (1 << bits)); int diff = a - b; const int m = 1 << (bits - 1); diff = (diff & (m - 1)) - (diff & m); return diff; } static int add_tpl_ref_mv(const Av1Common *cm, PictureControlSet *pcs_ptr, const MacroBlockD *xd, int mi_row, int mi_col, MvReferenceFrame ref_frame, int blk_row, int blk_col, IntMv *gm_mv_candidates, uint8_t *const refmv_count, uint8_t two_symetric_refs, IntMv *mv_ref0, int cur_offset_0, int cur_offset_1, CandidateMv ref_mv_stack[MAX_REF_MV_STACK_SIZE], int16_t *mode_context) { Position mi_pos; mi_pos.row = (mi_row & 0x01) ? blk_row : blk_row + 1; mi_pos.col = (mi_col & 0x01) ? blk_col : blk_col + 1; if (!is_inside(&xd->tile, mi_col, mi_row, &mi_pos)) return 0; const TPL_MV_REF *prev_frame_mvs = pcs_ptr->tpl_mvs + ((mi_row + mi_pos.row) >> 1) * (cm->mi_stride >> 1) + ((mi_col + mi_pos.col) >> 1); if (prev_frame_mvs->mfmv0.as_int == INVALID_MV) return 0; const uint16_t weight_unit = 1; int idx; IntMv this_refmv; if (two_symetric_refs) { if (ref_frame == LAST_FRAME) { get_mv_projection(&this_refmv.as_mv, prev_frame_mvs->mfmv0.as_mv, cur_offset_0, prev_frame_mvs->ref_frame_offset); lower_mv_precision( &this_refmv.as_mv, pcs_ptr->parent_pcs_ptr->frm_hdr.allow_high_precision_mv, 0); //store for future use (*mv_ref0) = this_refmv; } else { if (ref_frame == BWDREF_FRAME) { this_refmv.as_mv.row = -mv_ref0->as_mv.row; this_refmv.as_mv.col = -mv_ref0->as_mv.col; } else { this_refmv.as_mv = (*mv_ref0).as_mv; } } } else { get_mv_projection(&this_refmv.as_mv, prev_frame_mvs->mfmv0.as_mv, cur_offset_0, prev_frame_mvs->ref_frame_offset); lower_mv_precision( &this_refmv.as_mv, pcs_ptr->parent_pcs_ptr->frm_hdr.allow_high_precision_mv, 0); } //single ref case could be detected by ref_frame if (ref_frame < LAST_BWD_FRAME) { if (blk_row == 0 && blk_col == 0) { if (abs(this_refmv.as_mv.row - gm_mv_candidates[0].as_mv.row) >= 16 || abs(this_refmv.as_mv.col - gm_mv_candidates[0].as_mv.col) >= 16) mode_context[ref_frame] |= (1 << GLOBALMV_OFFSET); } for (idx = 0; idx < *refmv_count; ++idx) if (this_refmv.as_int == ref_mv_stack[idx].this_mv.as_int) break; if (idx < *refmv_count) ref_mv_stack[idx].weight += 2 * weight_unit; if (idx == *refmv_count && *refmv_count < MAX_REF_MV_STACK_SIZE) { ref_mv_stack[idx].this_mv.as_int = this_refmv.as_int; ref_mv_stack[idx].weight = 2 * weight_unit; ++(*refmv_count); } } else { // Process compound inter mode IntMv comp_refmv; if (two_symetric_refs) { comp_refmv.as_mv.row = -mv_ref0->as_mv.row; comp_refmv.as_mv.col = -mv_ref0->as_mv.col; } else { get_mv_projection(&comp_refmv.as_mv, prev_frame_mvs->mfmv0.as_mv, cur_offset_1, prev_frame_mvs->ref_frame_offset); lower_mv_precision( &comp_refmv.as_mv, pcs_ptr->parent_pcs_ptr->frm_hdr.allow_high_precision_mv, 0); } if (blk_row == 0 && blk_col == 0) { if (abs(this_refmv.as_mv.row - gm_mv_candidates[0].as_mv.row) >= 16 || abs(this_refmv.as_mv.col - gm_mv_candidates[0].as_mv.col) >= 16 || abs(comp_refmv.as_mv.row - gm_mv_candidates[1].as_mv.row) >= 16 || abs(comp_refmv.as_mv.col - gm_mv_candidates[1].as_mv.col) >= 16) mode_context[ref_frame] |= (1 << GLOBALMV_OFFSET); } for (idx = 0; idx < *refmv_count; ++idx) { if (this_refmv.as_int == ref_mv_stack[idx].this_mv.as_int && comp_refmv.as_int == ref_mv_stack[idx].comp_mv.as_int) break; } if (idx < *refmv_count) ref_mv_stack[idx].weight += 2 * weight_unit; if (idx == *refmv_count && *refmv_count < MAX_REF_MV_STACK_SIZE) { ref_mv_stack[idx].this_mv.as_int = this_refmv.as_int; ref_mv_stack[idx].comp_mv.as_int = comp_refmv.as_int; ref_mv_stack[idx].weight = 2 * weight_unit; ++(*refmv_count); } } return 1; } void setup_ref_mv_list(PictureControlSet *pcs_ptr, const Av1Common *cm, const MacroBlockD *xd, MvReferenceFrame ref_frame, uint8_t refmv_count[MODE_CTX_REF_FRAMES], CandidateMv ref_mv_stack[][MAX_REF_MV_STACK_SIZE], IntMv mv_ref_list[][MAX_MV_REF_CANDIDATES], IntMv *gm_mv_candidates, const EbWarpedMotionParams *gm_params, int32_t mi_row, int32_t mi_col, ModeDecisionContext *ctx, uint8_t symteric_refs, IntMv *mv_ref0, int16_t *mode_context) { const int32_t bs = AOMMAX(xd->n8_w, xd->n8_h); const int32_t has_tr = has_top_right( cm, ((SequenceControlSet *)pcs_ptr->scs_wrapper_ptr->object_ptr)->seq_header.sb_size, xd, mi_row, mi_col, bs); MvReferenceFrame rf[2]; const TileInfo *const tile = &xd->tile; int32_t max_row_offset = 0, max_col_offset = 0; const int32_t row_adj = (xd->n8_h < mi_size_high[BLOCK_8X8]) && (mi_row & 0x01); const int32_t col_adj = (xd->n8_w < mi_size_wide[BLOCK_8X8]) && (mi_col & 0x01); int32_t processed_rows = 0; int32_t processed_cols = 0; av1_set_ref_frame(rf, ref_frame); mode_context[ref_frame] = 0; refmv_count[ref_frame] = 0; // Find valid maximum row/col offset. if (xd->up_available) { max_row_offset = -(MVREF_ROWS << 1) + row_adj; if (xd->n8_h < mi_size_high[BLOCK_8X8]) max_row_offset = -(2 << 1) + row_adj; max_row_offset = find_valid_row_offset(tile, mi_row, max_row_offset); } if (xd->left_available) { max_col_offset = -(MVREF_COLS << 1) + col_adj; if (xd->n8_w < mi_size_wide[BLOCK_8X8]) max_col_offset = -(2 << 1) + col_adj; max_col_offset = find_valid_col_offset(tile, mi_col, max_col_offset); } uint8_t ref_match_count[MODE_CTX_REF_FRAMES]; uint8_t col_match_count[MODE_CTX_REF_FRAMES]; uint8_t row_match_count[MODE_CTX_REF_FRAMES]; uint8_t newmv_count[MODE_CTX_REF_FRAMES] ; ref_match_count[ref_frame] = 0; col_match_count[ref_frame] = 0; row_match_count[ref_frame] = 0; newmv_count[ref_frame] = 0; //CHKN------------- ROW-1 // Scan the first above row mode info. row_offset = -1; if (abs(max_row_offset) >= 1) scan_row_mbmi(cm, xd, mi_row, mi_col, rf, -1, ref_mv_stack, refmv_count, row_match_count, newmv_count, gm_mv_candidates, gm_params, max_row_offset, &processed_rows); //CHKN------------- COL-1 // Scan the first left column mode info. col_offset = -1; if (abs(max_col_offset) >= 1) scan_col_mbmi(cm, xd, mi_row, mi_col, rf, -1, ref_mv_stack, refmv_count, col_match_count, newmv_count, gm_mv_candidates, gm_params, max_col_offset, &processed_cols); //CHKN------------- TOP-RIGHT // Check top-right boundary if (has_tr) scan_blk_mbmi(xd, mi_row, mi_col, rf, -1, xd->n8_w, ref_mv_stack, row_match_count, newmv_count, gm_mv_candidates, gm_params, refmv_count); uint8_t nearest_match[MODE_CTX_REF_FRAMES]; uint8_t nearest_refmv_count[MODE_CTX_REF_FRAMES]; nearest_match[ref_frame] = (row_match_count[ref_frame] > 0) + (col_match_count[ref_frame] > 0); nearest_refmv_count[ref_frame] = refmv_count[ref_frame]; for (int32_t idx = 0; idx < nearest_refmv_count[ref_frame]; ++idx) ref_mv_stack[ref_frame][idx].weight += REF_CAT_LEVEL; //CHKN MFMV - get canididates from reference frames- orderHint has to be on, in order to scale the vectors. if (pcs_ptr->parent_pcs_ptr->frm_hdr.use_ref_frame_mvs) { int is_available = 0; int blk_row_end ,blk_col_end,step_w, step_h , allow_extension; if (ctx->sb64_sq_no4xn_geom) { blk_row_end = xd->n4_w; blk_col_end = xd->n4_w; step_w = (xd->n4_w >= MI_SIZE_W_64X64) ? MI_SIZE_W_16X16 : MI_SIZE_W_8X8; step_h = step_w; allow_extension = (xd->n4_w >= MI_SIZE_W_8X8) && (xd->n4_w < MI_SIZE_W_64X64); } else { blk_row_end = AOMMIN(xd->n4_h, mi_size_high[BLOCK_64X64]); blk_col_end = AOMMIN(xd->n4_w, mi_size_wide[BLOCK_64X64]); allow_extension = (xd->n4_h >= mi_size_high[BLOCK_8X8]) && (xd->n4_h < mi_size_high[BLOCK_64X64]) && (xd->n4_w >= mi_size_wide[BLOCK_8X8]) && (xd->n4_w < mi_size_wide[BLOCK_64X64]); step_h = (xd->n4_h >= mi_size_high[BLOCK_64X64]) ? mi_size_high[BLOCK_16X16] : mi_size_high[BLOCK_8X8]; step_w = (xd->n4_w >= mi_size_wide[BLOCK_64X64]) ? mi_size_wide[BLOCK_16X16] : mi_size_high[BLOCK_8X8]; } int cur_offset_0; int cur_offset_1 = 0; uint8_t list_idx0, list_idx1, ref_idx_l0, ref_idx_l1; list_idx0 = get_list_idx(rf[0]); ref_idx_l0 = get_ref_frame_idx(rf[0]); if (rf[1] == NONE_FRAME) { list_idx1 = get_list_idx(rf[0]); ref_idx_l1 = get_ref_frame_idx(rf[0]); } else { list_idx1 = get_list_idx(rf[1]); ref_idx_l1 = get_ref_frame_idx(rf[1]); } const int cur_frame_index = pcs_ptr->parent_pcs_ptr->cur_order_hint; EbReferenceObject *buf_0 = (EbReferenceObject *)pcs_ptr->ref_pic_ptr_array[list_idx0][ref_idx_l0]->object_ptr; const int frame0_index = buf_0->order_hint; cur_offset_0 = get_relative_dist( &pcs_ptr->parent_pcs_ptr->scs_ptr->seq_header.order_hint_info, cur_frame_index, frame0_index); if (rf[1] != NONE_FRAME) { EbReferenceObject *buf_1 = (EbReferenceObject *)pcs_ptr->ref_pic_ptr_array[list_idx1][ref_idx_l1]->object_ptr; const int frame1_index = buf_1->order_hint; cur_offset_1 = get_relative_dist( &pcs_ptr->parent_pcs_ptr->scs_ptr->seq_header.order_hint_info, cur_frame_index, frame1_index); } for (int blk_row = 0; blk_row < blk_row_end; blk_row += step_h) { for (int blk_col = 0; blk_col < blk_col_end; blk_col += step_w) { int ret = add_tpl_ref_mv(cm, pcs_ptr, xd, mi_row, mi_col, ref_frame, blk_row, blk_col, gm_mv_candidates, &refmv_count[ref_frame], symteric_refs, mv_ref0, cur_offset_0, cur_offset_1, ref_mv_stack[ref_frame], mode_context); if (blk_row == 0 && blk_col == 0) is_available = ret; mv_ref0++; } } if (is_available == 0) mode_context[ref_frame] |= (1 << GLOBALMV_OFFSET); if (allow_extension) { int voffset, hoffset; if (ctx->sb64_sq_no4xn_geom) { voffset = xd->n4_h; hoffset = voffset; } else { voffset = AOMMAX(mi_size_high[BLOCK_8X8], xd->n4_h); hoffset = AOMMAX(mi_size_wide[BLOCK_8X8], xd->n4_w); } const int tpl_sample_pos[3][2] = { {voffset, -2}, {voffset, hoffset}, {voffset - 2, hoffset}, }; for (int i = 0; i < 3; ++i) { const int blk_row = tpl_sample_pos[i][0]; const int blk_col = tpl_sample_pos[i][1]; if (!check_sb_border(mi_row, mi_col, blk_row, blk_col)) continue; add_tpl_ref_mv(cm, pcs_ptr, xd, mi_row, mi_col, ref_frame, blk_row, blk_col, gm_mv_candidates, &refmv_count[ref_frame], symteric_refs, mv_ref0, cur_offset_0, cur_offset_1, ref_mv_stack[ref_frame], mode_context); mv_ref0++; } } } //CHKN------------- TOP-LEFT uint8_t dummy_newmv_count[MODE_CTX_REF_FRAMES] ; dummy_newmv_count[ref_frame] = 0; // Scan the second outer area. scan_blk_mbmi(xd, mi_row, mi_col, rf, -1, -1, ref_mv_stack, row_match_count, dummy_newmv_count, gm_mv_candidates, gm_params, refmv_count); //CHKN------------- ROW-3 COL-3 ROW-5 COL-5 for (int32_t idx = 2; idx <= MVREF_ROWS; ++idx) { const int32_t row_offset = -(idx << 1) + 1 + row_adj; const int32_t col_offset = -(idx << 1) + 1 + col_adj; if (abs(row_offset) <= abs(max_row_offset) && abs(row_offset) > processed_rows) scan_row_mbmi(cm, xd, mi_row, mi_col, rf, row_offset, ref_mv_stack, refmv_count, row_match_count, dummy_newmv_count, gm_mv_candidates, gm_params, max_row_offset, &processed_rows); if (abs(col_offset) <= abs(max_col_offset) && abs(col_offset) > processed_cols) scan_col_mbmi(cm, xd, mi_row, mi_col, rf, col_offset, ref_mv_stack, refmv_count, col_match_count, dummy_newmv_count, gm_mv_candidates, gm_params, max_col_offset, &processed_cols); } //---------- Mode Context Derivation based on 3 counters ------------- ref_match_count[ref_frame] = (row_match_count[ref_frame] > 0) + (col_match_count[ref_frame] > 0); switch (nearest_match[ref_frame]) { case 0: mode_context[ref_frame] |= 0; if (ref_match_count[ref_frame] >= 1) mode_context[ref_frame] |= 1; if (ref_match_count[ref_frame] == 1) mode_context[ref_frame] |= (1 << REFMV_OFFSET); else if (ref_match_count[ref_frame] >= 2) mode_context[ref_frame] |= (2 << REFMV_OFFSET); break; case 1: mode_context[ref_frame] |= (newmv_count[ref_frame] > 0) ? 2 : 3; if (ref_match_count[ref_frame] == 1) mode_context[ref_frame] |= (3 << REFMV_OFFSET); else if (ref_match_count[ref_frame] >= 2) mode_context[ref_frame] |= (4 << REFMV_OFFSET); break; case 2: default: if (newmv_count[ref_frame] >= 1) mode_context[ref_frame] |= 4; else mode_context[ref_frame] |= 5; mode_context[ref_frame] |= (5 << REFMV_OFFSET); break; } //---------- Mode Context Derivation based on 3 counters ------------- // Rank the likelihood and assign nearest and near mvs. int32_t len = nearest_refmv_count[ref_frame]; while (len > 0) { int32_t nr_len = 0; for (int32_t idx = 1; idx < len; ++idx) { if (ref_mv_stack[ref_frame][idx - 1].weight < ref_mv_stack[ref_frame][idx].weight) { CandidateMv tmp_mv = ref_mv_stack[ref_frame][idx - 1]; ref_mv_stack[ref_frame][idx - 1] = ref_mv_stack[ref_frame][idx]; ref_mv_stack[ref_frame][idx] = tmp_mv; nr_len = idx; } } len = nr_len; } len = refmv_count[ref_frame]; while (len > nearest_refmv_count[ref_frame]) { int32_t nr_len = nearest_refmv_count[ref_frame]; for (int32_t idx = nearest_refmv_count[ref_frame] + 1; idx < len; ++idx) { if (ref_mv_stack[ref_frame][idx - 1].weight < ref_mv_stack[ref_frame][idx].weight) { CandidateMv tmp_mv = ref_mv_stack[ref_frame][idx - 1]; ref_mv_stack[ref_frame][idx - 1] = ref_mv_stack[ref_frame][idx]; ref_mv_stack[ref_frame][idx] = tmp_mv; nr_len = idx; } } len = nr_len; } //CHKN finish the Tables. if (rf[1] > NONE_FRAME) { //CHKN we get here only when refMVCount=0 or 1 if (refmv_count[ref_frame] < 2) { IntMv ref_id[2][2], ref_diff[2][2]; int32_t ref_id_count[2] = {0}, ref_diff_count[2] = {0}; int32_t mi_width = AOMMIN(mi_size_wide[BLOCK_64X64], xd->n8_w); mi_width = AOMMIN(mi_width, cm->mi_cols - mi_col); int32_t mi_height = AOMMIN(mi_size_high[BLOCK_64X64], xd->n8_h); mi_height = AOMMIN(mi_height, cm->mi_rows - mi_row); int32_t mi_size = AOMMIN(mi_width, mi_height); //CHKN scan ROW=-1 again but with more relaxed constraints for (int32_t idx = 0; abs(max_row_offset) >= 1 && idx < mi_size;) { const ModeInfo *const candidate_mi = xd->mi[-xd->mi_stride + idx]; const MbModeInfo *const candidate = &candidate_mi->mbmi; const int32_t candidate_bsize = candidate->block_mi.sb_type; for (int32_t rf_idx = 0; rf_idx < 2; ++rf_idx) { MvReferenceFrame can_rf = candidate->block_mi.ref_frame[rf_idx]; for (int32_t cmp_idx = 0; cmp_idx < 2; ++cmp_idx) { if (can_rf == rf[cmp_idx] && ref_id_count[cmp_idx] < 2) { ref_id[cmp_idx][ref_id_count[cmp_idx]] = candidate->block_mi.mv[rf_idx]; ++ref_id_count[cmp_idx]; } else if (can_rf > INTRA_FRAME && ref_diff_count[cmp_idx] < 2) { IntMv this_mv = candidate->block_mi.mv[rf_idx]; if (cm->ref_frame_sign_bias[can_rf] != cm->ref_frame_sign_bias[rf[cmp_idx]]) { this_mv.as_mv.row = -this_mv.as_mv.row; this_mv.as_mv.col = -this_mv.as_mv.col; } ref_diff[cmp_idx][ref_diff_count[cmp_idx]] = this_mv; ++ref_diff_count[cmp_idx]; } } } idx += mi_size_wide[candidate_bsize]; } //CHKN scan COL=-1 again but with more relaxed constraints for (int32_t idx = 0; abs(max_col_offset) >= 1 && idx < mi_size;) { const ModeInfo *const candidate_mi = xd->mi[idx * xd->mi_stride - 1]; const MbModeInfo *const candidate = &candidate_mi->mbmi; const int32_t candidate_bsize = candidate->block_mi.sb_type; for (int32_t rf_idx = 0; rf_idx < 2; ++rf_idx) { MvReferenceFrame can_rf = candidate->block_mi.ref_frame[rf_idx]; for (int32_t cmp_idx = 0; cmp_idx < 2; ++cmp_idx) { if (can_rf == rf[cmp_idx] && ref_id_count[cmp_idx] < 2) { ref_id[cmp_idx][ref_id_count[cmp_idx]] = candidate->block_mi.mv[rf_idx]; ++ref_id_count[cmp_idx]; } else if (can_rf > INTRA_FRAME && ref_diff_count[cmp_idx] < 2) { IntMv this_mv = candidate->block_mi.mv[rf_idx]; if (cm->ref_frame_sign_bias[can_rf] != cm->ref_frame_sign_bias[rf[cmp_idx]]) { this_mv.as_mv.row = -this_mv.as_mv.row; this_mv.as_mv.col = -this_mv.as_mv.col; } ref_diff[cmp_idx][ref_diff_count[cmp_idx]] = this_mv; ++ref_diff_count[cmp_idx]; } } } idx += mi_size_high[candidate_bsize]; } // Build up the compound mv predictor IntMv comp_list[MAX_MV_REF_CANDIDATES + 1][2]; for (int32_t idx = 0; idx < 2; ++idx) { int32_t comp_idx = 0; for (int32_t list_idx = 0; list_idx < ref_id_count[idx] && comp_idx < MAX_MV_REF_CANDIDATES; ++list_idx, ++comp_idx) comp_list[comp_idx][idx] = ref_id[idx][list_idx]; for (int32_t list_idx = 0; list_idx < ref_diff_count[idx] && comp_idx < MAX_MV_REF_CANDIDATES; ++list_idx, ++comp_idx) comp_list[comp_idx][idx] = ref_diff[idx][list_idx]; for (; comp_idx < MAX_MV_REF_CANDIDATES; ++comp_idx) comp_list[comp_idx][idx] = gm_mv_candidates[idx]; } //CHKN fill the stack, increment the counter if (refmv_count[ref_frame]) { //CHKN RefMvCount=1 assert(refmv_count[ref_frame] == 1); if (comp_list[0][0].as_int == ref_mv_stack[ref_frame][0].this_mv.as_int && comp_list[0][1].as_int == ref_mv_stack[ref_frame][0].comp_mv.as_int) { ref_mv_stack[ref_frame][refmv_count[ref_frame]].this_mv = comp_list[1][0]; ref_mv_stack[ref_frame][refmv_count[ref_frame]].comp_mv = comp_list[1][1]; } else { ref_mv_stack[ref_frame][refmv_count[ref_frame]].this_mv = comp_list[0][0]; ref_mv_stack[ref_frame][refmv_count[ref_frame]].comp_mv = comp_list[0][1]; } ref_mv_stack[ref_frame][refmv_count[ref_frame]].weight = 2; ++refmv_count[ref_frame]; } else { //CHKN RefMvCount=0 for (int32_t idx = 0; idx < MAX_MV_REF_CANDIDATES; ++idx) { ref_mv_stack[ref_frame][refmv_count[ref_frame]].this_mv = comp_list[idx][0]; ref_mv_stack[ref_frame][refmv_count[ref_frame]].comp_mv = comp_list[idx][1]; ref_mv_stack[ref_frame][refmv_count[ref_frame]].weight = 2; ++refmv_count[ref_frame]; } } } assert(refmv_count[ref_frame] >= 2); for (int32_t idx = 0; idx < refmv_count[ref_frame]; ++idx) { clamp_mv_ref(&ref_mv_stack[ref_frame][idx].this_mv.as_mv, xd->n8_w << MI_SIZE_LOG2, xd->n8_h << MI_SIZE_LOG2, xd); clamp_mv_ref(&ref_mv_stack[ref_frame][idx].comp_mv.as_mv, xd->n8_w << MI_SIZE_LOG2, xd->n8_h << MI_SIZE_LOG2, xd); } } else { // Handle single reference frame extension int32_t mi_width = AOMMIN(mi_size_wide[BLOCK_64X64], xd->n8_w); mi_width = AOMMIN(mi_width, cm->mi_cols - mi_col); int32_t mi_height = AOMMIN(mi_size_high[BLOCK_64X64], xd->n8_h); mi_height = AOMMIN(mi_height, cm->mi_rows - mi_row); int32_t mi_size = AOMMIN(mi_width, mi_height); //CHKn if count is still < 2, re-scan ROW=-1 with less constraints. // Order is already fixed. the added candidates are stored as we go at the bottom of the Stack. //CHKN TODO: confirm this could be avoided if we have already 2(DRL:OFF), or 4(DRL:ON) candidates for (int32_t idx = 0; abs(max_row_offset) >= 1 && idx < mi_size && refmv_count[ref_frame] < MAX_MV_REF_CANDIDATES;) { const ModeInfo *const candidate_mi = xd->mi[-xd->mi_stride + idx]; const MbModeInfo *const candidate = &candidate_mi->mbmi; const int32_t candidate_bsize = candidate->block_mi.sb_type; for (int32_t rf_idx = 0; rf_idx < 2; ++rf_idx) { if (candidate->block_mi.ref_frame[rf_idx] > INTRA_FRAME) { IntMv this_mv = candidate->block_mi.mv[rf_idx]; if (cm->ref_frame_sign_bias[candidate->block_mi.ref_frame[rf_idx]] != cm->ref_frame_sign_bias[ref_frame]) { this_mv.as_mv.row = -this_mv.as_mv.row; this_mv.as_mv.col = -this_mv.as_mv.col; } int32_t stack_idx; for (stack_idx = 0; stack_idx < refmv_count[ref_frame]; ++stack_idx) { IntMv stack_mv = ref_mv_stack[ref_frame][stack_idx].this_mv; if (this_mv.as_int == stack_mv.as_int) break; } if (stack_idx == refmv_count[ref_frame]) { ref_mv_stack[ref_frame][stack_idx].this_mv = this_mv; ref_mv_stack[ref_frame][stack_idx].weight = 2; ++refmv_count[ref_frame]; } } } idx += mi_size_wide[candidate_bsize]; } //CHKn if count is still < 2, re-scan COL=-1 with less constraints. the added candidates are stored as we go at the bottom of the Stack. for (int32_t idx = 0; abs(max_col_offset) >= 1 && idx < mi_size && refmv_count[ref_frame] < MAX_MV_REF_CANDIDATES;) { const ModeInfo *const candidate_mi = xd->mi[idx * xd->mi_stride - 1]; const MbModeInfo *const candidate = &candidate_mi->mbmi; const int32_t candidate_bsize = candidate->block_mi.sb_type; for (int32_t rf_idx = 0; rf_idx < 2; ++rf_idx) { if (candidate->block_mi.ref_frame[rf_idx] > INTRA_FRAME) { IntMv this_mv = candidate->block_mi.mv[rf_idx]; if (cm->ref_frame_sign_bias[candidate->block_mi.ref_frame[rf_idx]] != cm->ref_frame_sign_bias[ref_frame]) { this_mv.as_mv.row = -this_mv.as_mv.row; this_mv.as_mv.col = -this_mv.as_mv.col; } int32_t stack_idx; for (stack_idx = 0; stack_idx < refmv_count[ref_frame]; ++stack_idx) { IntMv stack_mv = ref_mv_stack[ref_frame][stack_idx].this_mv; if (this_mv.as_int == stack_mv.as_int) break; } if (stack_idx == refmv_count[ref_frame]) { ref_mv_stack[ref_frame][stack_idx].this_mv = this_mv; ref_mv_stack[ref_frame][stack_idx].weight = 2; ++refmv_count[ref_frame]; } } } idx += mi_size_high[candidate_bsize]; } //CHKN THIS IS a Single Reference case //CHKN if the stack has at least 2 cand, then copy the top 2 to the final mvp Table, // if the stack has less than 2, use Gm to fill the mvpTable. // the stack counter remains 0 or 1 in this case. for (int32_t idx = refmv_count[ref_frame]; idx < MAX_MV_REF_CANDIDATES; ++idx) mv_ref_list[rf[0]][idx].as_int = gm_mv_candidates[0].as_int; for (int32_t idx = 0; idx < refmv_count[ref_frame]; ++idx) { clamp_mv_ref(&ref_mv_stack[ref_frame][idx].this_mv.as_mv, xd->n8_w << MI_SIZE_LOG2, xd->n8_h << MI_SIZE_LOG2, xd); } for (int32_t idx = 0; idx < AOMMIN(MAX_MV_REF_CANDIDATES, refmv_count[ref_frame]); ++idx) { mv_ref_list[rf[0]][idx].as_int = ref_mv_stack[ref_frame][idx].this_mv.as_int; } } (void)nearest_match; } static INLINE int block_center_x(int mi_col, BlockSize bs) { const int bw = block_size_wide[bs]; return mi_col * MI_SIZE + bw / 2 - 1; } static INLINE int block_center_y(int mi_row, BlockSize bs) { const int bh = block_size_high[bs]; return mi_row * MI_SIZE + bh / 2 - 1; } IntMv gm_get_motion_vector_enc(const EbWarpedMotionParams *gm, int32_t allow_hp, BlockSize bsize, int32_t mi_col, int32_t mi_row, int32_t is_integer) { IntMv res; if (gm->wmtype == IDENTITY) { res.as_int = 0; return res; } const int32_t *mat = gm->wmmat; int x, y, tx, ty; if (gm->wmtype == TRANSLATION) { // All global motion vectors are stored with WARPEDMODEL_PREC_BITS (16) // bits of fractional precision. The offset for a translation is stored in // entries 0 and 1. For translations, all but the top three (two if // cm->allow_high_precision_mv is false) fractional bits are always zero. // // After the right shifts, there are 3 fractional bits of precision. If // allow_hp is false, the bottom bit is always zero (so we don't need a // call to convert_to_trans_prec here) res.as_mv.row = gm->wmmat[0] >> GM_TRANS_ONLY_PREC_DIFF; res.as_mv.col = gm->wmmat[1] >> GM_TRANS_ONLY_PREC_DIFF; assert(IMPLIES(1 & (res.as_mv.row | res.as_mv.col), allow_hp)); if (is_integer) { integer_mv_precision(&res.as_mv); } return res; } x = block_center_x(mi_col, bsize); y = block_center_y(mi_row, bsize); if (gm->wmtype == ROTZOOM) { assert(gm->wmmat[5] == gm->wmmat[2]); assert(gm->wmmat[4] == -gm->wmmat[3]); } const int xc = (mat[2] - (1 << WARPEDMODEL_PREC_BITS)) * x + mat[3] * y + mat[0]; const int yc = mat[4] * x + (mat[5] - (1 << WARPEDMODEL_PREC_BITS)) * y + mat[1]; tx = convert_to_trans_prec(allow_hp, xc); ty = convert_to_trans_prec(allow_hp, yc); res.as_mv.row = ty; res.as_mv.col = tx; if (is_integer) { integer_mv_precision(&res.as_mv); } return res; } void init_xd(PictureControlSet *pcs_ptr, ModeDecisionContext *context_ptr) { TileInfo *tile = &context_ptr->sb_ptr->tile_info; int32_t mi_row = context_ptr->blk_origin_y >> MI_SIZE_LOG2; int32_t mi_col = context_ptr->blk_origin_x >> MI_SIZE_LOG2; Av1Common * cm = pcs_ptr->parent_pcs_ptr->av1_cm; MacroBlockD * xd = context_ptr->blk_ptr->av1xd; BlockSize bsize = context_ptr->blk_geom->bsize; const int32_t bw = mi_size_wide[bsize]; const int32_t bh = mi_size_high[bsize]; xd->n4_w = context_ptr->blk_geom->bwidth >> MI_SIZE_LOG2; xd->n4_h = context_ptr->blk_geom->bheight >> MI_SIZE_LOG2; xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8); xd->mb_to_bottom_edge = ((cm->mi_rows - bh - mi_row) * MI_SIZE) * 8; xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8); xd->mb_to_right_edge = ((cm->mi_cols - bw - mi_col) * MI_SIZE) * 8; xd->mi_row = -xd->mb_to_top_edge / (8 * MI_SIZE); xd->mi_col = -xd->mb_to_left_edge / (8 * MI_SIZE); xd->up_available = (mi_row > tile->mi_row_start); xd->left_available = (mi_col > tile->mi_col_start); xd->n8_h = bh; xd->n8_w = bw; xd->is_sec_rect = 0; if (xd->n8_w < xd->n8_h) { // Only mark is_sec_rect as 1 for the last block. // For PARTITION_VERT_4, it would be (0, 0, 0, 1); // For other partitions, it would be (0, 1). if (!((mi_col + xd->n8_w) & (xd->n8_h - 1))) xd->is_sec_rect = 1; } if (xd->n8_w > xd->n8_h) if (mi_row & (xd->n8_w - 1)) xd->is_sec_rect = 1; xd->tile.mi_col_start = tile->mi_col_start; xd->tile.mi_col_end = tile->mi_col_end; xd->tile.mi_row_start = tile->mi_row_start; xd->tile.mi_row_end = tile->mi_row_end; xd->mi_stride = pcs_ptr->mi_stride; const int32_t offset = mi_row * xd->mi_stride + mi_col; pcs_ptr->mi_grid_base[offset] = pcs_ptr->mip + offset; xd->mi = pcs_ptr->mi_grid_base + offset; //ModeInfo *mi_ptr = xd->mi[-(xd->mi_stride)]; /*&xd->mi[-xd->mi_stride]->mbmi*/ xd->above_mbmi = (xd->up_available) ? &xd->mi[-(xd->mi_stride)]->mbmi : NULL; //mi_ptr = xd->mi[-1]; xd->left_mbmi = (xd->left_available) ? &xd->mi[-1]->mbmi : NULL; if (!context_ptr->skip_intra) { const uint8_t ss_x = 1, ss_y = 1; xd->chroma_up_available = bh < 2 /*mi_size_wide[BLOCK_8X8]*/ ? (mi_row - 1) > xd->tile.mi_row_start : xd->up_available; xd->chroma_left_available = bw < 2 /*mi_size_high[BLOCK_8X8]*/ ? (mi_col - 1) > xd->tile.mi_col_start : xd->left_available; const int chroma_ref = ((mi_row & 0x01) || !(bh & 0x01)) && ((mi_col & 0x01) || !(bw & 0x01)); // To help calculate the "above" and "left" chroma blocks, note that the // current block may cover multiple luma blocks (eg, if partitioned into // 4x4 luma blocks). // First, find the top-left-most luma block covered by this chroma block int32_t base_mbmi_offset = -(mi_row & ss_y) * xd->mi_stride - (mi_col & ss_x); // Then, we consider the luma region covered by the left or above 4x4 chroma // prediction. We want to point to the chroma reference block in that // region, which is the bottom-right-most mi unit. // This leads to the following offsets: xd->chroma_above_mbmi = (xd->chroma_up_available && chroma_ref) ? &xd->mi[base_mbmi_offset - xd->mi_stride + ss_x]->mbmi : NULL; xd->chroma_left_mbmi = (xd->chroma_left_available && chroma_ref) ? &xd->mi[base_mbmi_offset + ss_y * xd->mi_stride - 1]->mbmi : NULL; } xd->mi[0]->mbmi.block_mi.partition = from_shape_to_part[context_ptr->blk_geom->shape]; } void generate_av1_mvp_table(ModeDecisionContext *context_ptr, BlkStruct *blk_ptr, const BlockGeom *blk_geom, uint16_t blk_origin_x, uint16_t blk_origin_y, MvReferenceFrame *ref_frames, uint32_t tot_refs, PictureControlSet *pcs_ptr) { int32_t mi_row = blk_origin_y >> MI_SIZE_LOG2; int32_t mi_col = blk_origin_x >> MI_SIZE_LOG2; Av1Common * cm = pcs_ptr->parent_pcs_ptr->av1_cm; FrameHeader *frm_hdr = &pcs_ptr->parent_pcs_ptr->frm_hdr; MacroBlockD *xd = blk_ptr->av1xd; BlockSize bsize = blk_geom->bsize; uint8_t symteric_refs = 0; IntMv mv_ref0[64]; if (pcs_ptr->temporal_layer_index>0) if(tot_refs == 3 && ref_frames[0] == LAST_FRAME && ref_frames[1] == BWDREF_FRAME && ref_frames[2] == LAST_BWD_FRAME) symteric_refs = 1; //128x128 OFF, 4xN OFF, SQ only uint32_t ref_it; for (ref_it = 0; ref_it < tot_refs; ++ref_it) { MvReferenceFrame ref_frame = ref_frames[ref_it]; xd->ref_mv_count[ref_frame] = 0; memset(context_ptr->md_local_blk_unit[blk_geom->blkidx_mds].ed_ref_mv_stack[ref_frame], 0, sizeof(CandidateMv)*MAX_REF_MV_STACK_SIZE); MvReferenceFrame rf[2]; av1_set_ref_frame(rf, ref_frame); IntMv gm_mv[2]; if (ref_frame == INTRA_FRAME) { gm_mv[0].as_int = gm_mv[1].as_int = 0; } else { if (ref_frame < REF_FRAMES) { gm_mv[0] = gm_get_motion_vector_enc( &pcs_ptr->parent_pcs_ptr->global_motion[ref_frame], frm_hdr->allow_high_precision_mv, bsize, mi_col, mi_row, frm_hdr->force_integer_mv); gm_mv[1].as_int = 0; } else { gm_mv[0] = gm_get_motion_vector_enc(&pcs_ptr->parent_pcs_ptr->global_motion[rf[0]], frm_hdr->allow_high_precision_mv, bsize, mi_col, mi_row, frm_hdr->force_integer_mv); gm_mv[1] = gm_get_motion_vector_enc(&pcs_ptr->parent_pcs_ptr->global_motion[rf[1]], frm_hdr->allow_high_precision_mv, bsize, mi_col, mi_row, frm_hdr->force_integer_mv); } } setup_ref_mv_list(pcs_ptr, cm, xd, ref_frame, xd->ref_mv_count, context_ptr->md_local_blk_unit[blk_geom->blkidx_mds].ed_ref_mv_stack, context_ptr->md_local_blk_unit[context_ptr->blk_geom->blkidx_mds].ref_mvs, gm_mv, pcs_ptr->parent_pcs_ptr->global_motion, mi_row, mi_col, context_ptr, symteric_refs, mv_ref0, blk_ptr->inter_mode_ctx); } } void get_av1_mv_pred_drl(ModeDecisionContext *context_ptr, BlkStruct *blk_ptr, MvReferenceFrame ref_frame, uint8_t is_compound, PredictionMode mode, uint8_t drl_index, //valid value of drl_index IntMv nearestmv[2], IntMv nearmv[2], IntMv ref_mv[2]) { MacroBlockD *xd = blk_ptr->av1xd; if (!is_compound && mode != GLOBALMV) { //av1_find_best_ref_mvs(allow_hp, ref_mvs[mbmi->ref_frame[0]], &nearestmv[0], &nearmv[0], cm->cur_frame_force_integer_mv); nearestmv[0] = context_ptr->md_local_blk_unit[context_ptr->blk_geom->blkidx_mds].ref_mvs[ref_frame][0]; nearmv[0] = context_ptr->md_local_blk_unit[context_ptr->blk_geom->blkidx_mds].ref_mvs[ref_frame][1]; } if (is_compound && mode != GLOBAL_GLOBALMV) { int32_t ref_mv_idx = drl_index + 1; nearestmv[0] = context_ptr->md_local_blk_unit[blk_ptr->mds_idx].ed_ref_mv_stack[ref_frame][0].this_mv; nearestmv[1] = context_ptr->md_local_blk_unit[blk_ptr->mds_idx].ed_ref_mv_stack[ref_frame][0].comp_mv; nearmv[0] = context_ptr->md_local_blk_unit[blk_ptr->mds_idx] .ed_ref_mv_stack[ref_frame][ref_mv_idx] .this_mv; nearmv[1] = context_ptr->md_local_blk_unit[blk_ptr->mds_idx] .ed_ref_mv_stack[ref_frame][ref_mv_idx] .comp_mv; } else if (drl_index > 0 && mode == NEARMV) { assert((1 + drl_index) < MAX_REF_MV_STACK_SIZE); IntMv cur_mv = context_ptr->md_local_blk_unit[blk_ptr->mds_idx] .ed_ref_mv_stack[ref_frame][1 + drl_index] .this_mv; nearmv[0] = cur_mv; } ref_mv[0] = nearestmv[0]; ref_mv[1] = nearestmv[1]; if (is_compound) { int32_t ref_mv_idx = drl_index; // Special case: NEAR_NEWMV and NEW_NEARMV modes use // 1 + mbmi->ref_mv_idx (like NEARMV) instead of // mbmi->ref_mv_idx (like NEWMV) if (mode == NEAR_NEWMV || mode == NEW_NEARMV) ref_mv_idx = 1 + drl_index; if (compound_ref0_mode(mode) == NEWMV) ref_mv[0] = context_ptr->md_local_blk_unit[blk_ptr->mds_idx] .ed_ref_mv_stack[ref_frame][ref_mv_idx] .this_mv; if (compound_ref1_mode(mode) == NEWMV) ref_mv[1] = context_ptr->md_local_blk_unit[blk_ptr->mds_idx] .ed_ref_mv_stack[ref_frame][ref_mv_idx] .comp_mv; } else { if (mode == NEWMV) { if (xd->ref_mv_count[ref_frame] > 1) ref_mv[0] = context_ptr->md_local_blk_unit[blk_ptr->mds_idx] .ed_ref_mv_stack[ref_frame][drl_index] .this_mv; } } } void update_mi_map_skip_settings(BlkStruct *blk_ptr) { // Update only the data in the top left block of the partition, because all other mi_blocks // point to the top left mi block of the partition blk_ptr->av1xd->mi[0]->mbmi.block_mi.skip = blk_ptr->block_has_coeff ? EB_FALSE : EB_TRUE; blk_ptr->av1xd->mi[0]->mbmi.block_mi.skip_mode = (int8_t)blk_ptr->skip_flag; } void update_mi_map(BlkStruct* blk_ptr, uint32_t blk_origin_x, uint32_t blk_origin_y, const BlockGeom* blk_geom, uint8_t avail_blk_flag, PictureControlSet* pcs_ptr) { uint32_t mi_stride = pcs_ptr->mi_stride; int32_t mi_row = blk_origin_y >> MI_SIZE_LOG2; int32_t mi_col = blk_origin_x >> MI_SIZE_LOG2; const int32_t offset = mi_row * mi_stride + mi_col; // Reset the mi_grid (needs to be done here in case it was changed for NSQ blocks during MD - init_xd()) pcs_ptr->mi_grid_base[offset] = pcs_ptr->mip + offset; ModeInfo * mi_ptr = *(pcs_ptr->mi_grid_base + offset); MvReferenceFrame rf[2] = {0, 0}; if (avail_blk_flag) av1_set_ref_frame(rf, blk_ptr->prediction_unit_array->ref_frame_type); uint8_t mi_x, mi_y; for (mi_y = 0; mi_y < (blk_geom->bheight >> MI_SIZE_LOG2); mi_y++) { for (mi_x = 0; mi_x < (blk_geom->bwidth >> MI_SIZE_LOG2); mi_x++) { const int32_t mi_idx = mi_x + mi_y * mi_stride; if (mi_idx != 0) { pcs_ptr->mi_grid_base[offset + mi_idx] = pcs_ptr->mi_grid_base[offset]; continue; } MbModeInfo* mbmi = &mi_ptr[mi_idx].mbmi; BlockModeInfo* block_mi = &mi_ptr[mi_idx].mbmi.block_mi; // copy mbmi data mbmi->tx_size = (avail_blk_flag && blk_ptr->prediction_mode_flag == INTRA_MODE && blk_ptr->pred_mode == INTRA_MODE_4x4) ? 0 : blk_geom->txsize[blk_ptr->tx_depth][0]; // inherit tx_size from 1st transform block; mbmi->tx_depth = blk_ptr->tx_depth; mbmi->comp_group_idx = blk_ptr->comp_group_idx; if (pcs_ptr->parent_pcs_ptr->frm_hdr.allow_screen_content_tools) svt_memcpy(&mbmi->palette_mode_info, &blk_ptr->palette_info.pmi, sizeof(PaletteModeInfo)); // The data copied into each mi block is the same; therefore, copy the data from the blk_ptr only for the first block_mi // then use memcpy to copy the first block_mi into the rest (more efficient than assignments from blk_ptr). All data that // is used from block_mi should be updated here. if (mi_idx == 0){ block_mi->sb_type = (avail_blk_flag && blk_ptr->prediction_mode_flag == INTRA_MODE && blk_ptr->pred_mode == INTRA_MODE_4x4) ? BLOCK_4X4 : blk_geom->bsize; block_mi->mode = blk_ptr->pred_mode; block_mi->skip = (avail_blk_flag && blk_ptr->block_has_coeff) ? EB_FALSE : EB_TRUE; block_mi->partition = from_shape_to_part[blk_geom->shape]; block_mi->skip_mode = (int8_t)blk_ptr->skip_flag; block_mi->segment_id = blk_ptr->segment_id; block_mi->seg_id_predicted = blk_ptr->seg_id_predicted; block_mi->uv_mode = blk_ptr->prediction_unit_array->intra_chroma_mode; block_mi->use_intrabc = blk_ptr->use_intrabc; block_mi->ref_frame[0] = rf[0]; block_mi->ref_frame[1] = (avail_blk_flag && blk_ptr->is_interintra_used) ? INTRA_FRAME : rf[1]; if (avail_blk_flag) { if (blk_ptr->prediction_unit_array->inter_pred_direction_index == UNI_PRED_LIST_0) { block_mi->mv[0].as_mv.col = blk_ptr->prediction_unit_array->mv[0].x; block_mi->mv[0].as_mv.row = blk_ptr->prediction_unit_array->mv[0].y; } else if (blk_ptr->prediction_unit_array->inter_pred_direction_index == UNI_PRED_LIST_1) { block_mi->mv[0].as_mv.col = blk_ptr->prediction_unit_array->mv[1].x; block_mi->mv[0].as_mv.row = blk_ptr->prediction_unit_array->mv[1].y; } else { block_mi->mv[0].as_mv.col = blk_ptr->prediction_unit_array->mv[0].x; block_mi->mv[0].as_mv.row = blk_ptr->prediction_unit_array->mv[0].y; block_mi->mv[1].as_mv.col = blk_ptr->prediction_unit_array->mv[1].x; block_mi->mv[1].as_mv.row = blk_ptr->prediction_unit_array->mv[1].y; } } block_mi->ref_mv_idx = blk_ptr->drl_index; block_mi->interintra_mode_params.interintra_mode = blk_ptr->interintra_mode; block_mi->interintra_mode_params.wedge_interintra = blk_ptr->use_wedge_interintra; block_mi->interintra_mode_params.interintra_wedge_index = blk_ptr->interintra_wedge_index; block_mi->motion_mode = blk_ptr->prediction_unit_array[0].motion_mode; block_mi->compound_idx = blk_ptr->compound_idx; block_mi->interp_filters = blk_ptr->interp_filters; block_mi->cfl_alpha_idx = blk_ptr->prediction_unit_array->cfl_alpha_idx; block_mi->cfl_alpha_signs = blk_ptr->prediction_unit_array->cfl_alpha_signs; block_mi->angle_delta[PLANE_TYPE_Y] = blk_ptr->prediction_unit_array[0].angle_delta[PLANE_TYPE_Y]; block_mi->angle_delta[PLANE_TYPE_UV] = blk_ptr->prediction_unit_array[0].angle_delta[PLANE_TYPE_UV]; } else { BlockModeInfo* block_mi_idx0 = &mi_ptr[0].mbmi.block_mi; svt_memcpy(block_mi, block_mi_idx0, sizeof(BlockModeInfo)); } } } } static INLINE void record_samples(MbModeInfo *mbmi, int *pts, int *pts_inref, int row_offset, int sign_r, int col_offset, int sign_c) { uint8_t bw = block_size_wide[mbmi->block_mi.sb_type]; uint8_t bh = block_size_high[mbmi->block_mi.sb_type]; int x = col_offset * MI_SIZE + sign_c * AOMMAX(bw, MI_SIZE) / 2 - 1; int y = row_offset * MI_SIZE + sign_r * AOMMAX(bh, MI_SIZE) / 2 - 1; pts[0] = (x * 8); pts[1] = (y * 8); pts_inref[0] = (x * 8) + mbmi->block_mi.mv[0].as_mv.col; pts_inref[1] = (y * 8) + mbmi->block_mi.mv[0].as_mv.row; } // Note: Samples returned are at 1/8-pel precision // Sample are the neighbor block center point's coordinates relative to the // left-top pixel of current block. int av1_find_samples(const Av1Common *cm, const BlockSize sb_size, MacroBlockD *xd, int mi_row, int mi_col, MvReferenceFrame rf0, int *pts, int *pts_inref) { int up_available = xd->up_available; int left_available = xd->left_available; int i, mi_step = 1, np = 0; const TileInfo *const tile = &xd->tile; int do_tl = 1; int do_tr = 1; // scan the nearest above rows if (up_available) { int mi_row_offset = -1; MbModeInfo *mbmi = &xd->mi[mi_row_offset * xd->mi_stride]->mbmi; uint8_t n4_w = mi_size_wide[mbmi->block_mi.sb_type]; if (xd->n4_w <= n4_w) { // Handle "current block width <= above block width" case. int col_offset = -mi_col % n4_w; if (col_offset < 0) do_tl = 0; if (col_offset + n4_w > xd->n4_w) do_tr = 0; if (mbmi->block_mi.ref_frame[0] == rf0 && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { record_samples(mbmi, pts, pts_inref, 0, -1, col_offset, 1); pts += 2; pts_inref += 2; np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) return LEAST_SQUARES_SAMPLES_MAX; } } else { // Handle "current block width > above block width" case. for (i = 0; i < AOMMIN(xd->n4_w, cm->mi_cols - mi_col); i += mi_step) { int mi_col_offset = i; mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi; n4_w = mi_size_wide[mbmi->block_mi.sb_type]; mi_step = AOMMIN(xd->n4_w, n4_w); if (mbmi->block_mi.ref_frame[0] == rf0 && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { record_samples(mbmi, pts, pts_inref, 0, -1, i, 1); pts += 2; pts_inref += 2; np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) return LEAST_SQUARES_SAMPLES_MAX; } } } } // scan the nearest left columns if (left_available) { int mi_col_offset = -1; MbModeInfo *mbmi = &xd->mi[mi_col_offset]->mbmi; uint8_t n4_h = mi_size_high[mbmi->block_mi.sb_type]; if (xd->n4_h <= n4_h) { // Handle "current block height <= above block height" case. int row_offset = -mi_row % n4_h; if (row_offset < 0) do_tl = 0; if (mbmi->block_mi.ref_frame[0] == rf0 && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { record_samples(mbmi, pts, pts_inref, row_offset, 1, 0, -1); pts += 2; pts_inref += 2; np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) return LEAST_SQUARES_SAMPLES_MAX; } } else { // Handle "current block height > above block height" case. for (i = 0; i < AOMMIN(xd->n4_h, cm->mi_rows - mi_row); i += mi_step) { int mi_row_offset = i; mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi; n4_h = mi_size_high[mbmi->block_mi.sb_type]; mi_step = AOMMIN(xd->n4_h, n4_h); if (mbmi->block_mi.ref_frame[0] == rf0 && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { record_samples(mbmi, pts, pts_inref, i, 1, 0, -1); pts += 2; pts_inref += 2; np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) return LEAST_SQUARES_SAMPLES_MAX; } } } } // Top-left block if (do_tl && left_available && up_available) { int mi_row_offset = -1; int mi_col_offset = -1; MbModeInfo *mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi; if (mbmi->block_mi.ref_frame[0] == rf0 && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { record_samples(mbmi, pts, pts_inref, 0, -1, 0, -1); pts += 2; pts_inref += 2; np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) return LEAST_SQUARES_SAMPLES_MAX; } } // Top-right block if (do_tr && has_top_right(cm, sb_size, xd, mi_row, mi_col, AOMMAX(xd->n4_w, xd->n4_h))) { Position trb_pos = {-1, xd->n4_w}; if (is_inside(tile, mi_col, mi_row, &trb_pos)) { int mi_row_offset = -1; int mi_col_offset = xd->n4_w; MbModeInfo *mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi; if (mbmi->block_mi.ref_frame[0] == rf0 && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { record_samples(mbmi, pts, pts_inref, 0, -1, xd->n4_w, 1); np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) return LEAST_SQUARES_SAMPLES_MAX; } } } return np; } void wm_count_samples(BlkStruct *blk_ptr, const BlockSize sb_size, const BlockGeom *blk_geom, uint16_t blk_origin_x, uint16_t blk_origin_y, uint8_t ref_frame_type, PictureControlSet *pcs_ptr, uint16_t *num_samples) { Av1Common * cm = pcs_ptr->parent_pcs_ptr->av1_cm; MacroBlockD *xd = blk_ptr->av1xd; int32_t mi_row = blk_origin_y >> MI_SIZE_LOG2; int32_t mi_col = blk_origin_x >> MI_SIZE_LOG2; xd->n4_w = blk_geom->bwidth >> MI_SIZE_LOG2; xd->n4_h = blk_geom->bheight >> MI_SIZE_LOG2; int up_available = xd->up_available; int left_available = xd->left_available; int i, mi_step = 1, np = 0; const TileInfo *const tile = &xd->tile; int do_tl = 1; int do_tr = 1; MvReferenceFrame rf[2]; av1_set_ref_frame(rf, ref_frame_type); if (up_available) { int mi_row_offset = -1; MbModeInfo *mbmi = &xd->mi[mi_row_offset * xd->mi_stride]->mbmi; uint8_t n4_w = mi_size_wide[mbmi->block_mi.sb_type]; if (xd->n4_w <= n4_w) { int col_offset = -mi_col % n4_w; if (col_offset < 0) do_tl = 0; if (col_offset + n4_w > xd->n4_w) do_tr = 0; if (mbmi->block_mi.ref_frame[0] == rf[0] && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) { *num_samples = LEAST_SQUARES_SAMPLES_MAX; return; } } } else { for (i = 0; i < AOMMIN(xd->n4_w, cm->mi_cols - mi_col); i += mi_step) { int mi_col_offset = i; mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi; n4_w = mi_size_wide[mbmi->block_mi.sb_type]; mi_step = AOMMIN(xd->n4_w, n4_w); if (mbmi->block_mi.ref_frame[0] == rf[0] && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) { *num_samples = LEAST_SQUARES_SAMPLES_MAX; return; } } } } } if (left_available) { int mi_col_offset = -1; MbModeInfo *mbmi = &xd->mi[mi_col_offset]->mbmi; uint8_t n4_h = mi_size_high[mbmi->block_mi.sb_type]; if (xd->n4_h <= n4_h) { int row_offset = -mi_row % n4_h; if (row_offset < 0) do_tl = 0; if (mbmi->block_mi.ref_frame[0] == rf[0] && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) { *num_samples = LEAST_SQUARES_SAMPLES_MAX; return; } } } else { for (i = 0; i < AOMMIN(xd->n4_h, cm->mi_rows - mi_row); i += mi_step) { int mi_row_offset = i; mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi; n4_h = mi_size_high[mbmi->block_mi.sb_type]; mi_step = AOMMIN(xd->n4_h, n4_h); if (mbmi->block_mi.ref_frame[0] == rf[0] && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) { *num_samples = LEAST_SQUARES_SAMPLES_MAX; return; } } } } } if (do_tl && left_available && up_available) { int mi_row_offset = -1; int mi_col_offset = -1; MbModeInfo *mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi; if (mbmi->block_mi.ref_frame[0] == rf[0] && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) { *num_samples = LEAST_SQUARES_SAMPLES_MAX; return; } } } if (do_tr && has_top_right(cm, sb_size, xd, mi_row, mi_col, AOMMAX(xd->n4_w, xd->n4_h))) { Position trb_pos = {-1, xd->n4_w}; if (is_inside(tile, mi_col, mi_row, &trb_pos)) { int mi_row_offset = -1; int mi_col_offset = xd->n4_w; MbModeInfo *mbmi = &xd->mi[mi_col_offset + mi_row_offset * xd->mi_stride]->mbmi; if (mbmi->block_mi.ref_frame[0] == rf[0] && mbmi->block_mi.ref_frame[1] == NONE_FRAME) { np++; if (np >= LEAST_SQUARES_SAMPLES_MAX) { *num_samples = LEAST_SQUARES_SAMPLES_MAX; return; } } } } *num_samples = np; } uint16_t wm_find_samples(BlkStruct *blk_ptr, const BlockGeom *blk_geom, uint16_t blk_origin_x, uint16_t blk_origin_y, MvReferenceFrame rf0, PictureControlSet *pcs_ptr, int32_t *pts, int32_t *pts_inref) { Av1Common * cm = pcs_ptr->parent_pcs_ptr->av1_cm; MacroBlockD *xd = blk_ptr->av1xd; int32_t mi_row = blk_origin_y >> MI_SIZE_LOG2; int32_t mi_col = blk_origin_x >> MI_SIZE_LOG2; xd->n4_w = blk_geom->bwidth >> MI_SIZE_LOG2; xd->n4_h = blk_geom->bheight >> MI_SIZE_LOG2; return (uint16_t)av1_find_samples( cm, ((SequenceControlSet *)pcs_ptr->scs_wrapper_ptr->object_ptr)->seq_header.sb_size, xd, mi_row, mi_col, rf0, pts, pts_inref); } EbBool warped_motion_parameters(PictureControlSet *pcs_ptr, BlkStruct *blk_ptr, MvUnit *mv_unit, const BlockGeom *blk_geom, uint16_t blk_origin_x, uint16_t blk_origin_y, uint8_t ref_frame_type, EbWarpedMotionParams *wm_params, uint16_t *num_samples) { MacroBlockD *xd = blk_ptr->av1xd; BlockSize bsize = blk_geom->bsize; EbBool apply_wm = EB_FALSE; int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE]; int32_t mi_row = blk_origin_y >> MI_SIZE_LOG2; int32_t mi_col = blk_origin_x >> MI_SIZE_LOG2; xd->n4_w = blk_geom->bwidth >> MI_SIZE_LOG2; xd->n4_h = blk_geom->bheight >> MI_SIZE_LOG2; *num_samples = 0; if (blk_geom->bwidth < 8 || blk_geom->bheight < 8) return apply_wm; MvReferenceFrame rf[2]; av1_set_ref_frame(rf, ref_frame_type); uint16_t nsamples = wm_find_samples( blk_ptr, blk_geom, blk_origin_x, blk_origin_y, rf[0], pcs_ptr, pts, pts_inref); if (nsamples == 0) return apply_wm; MV mv; mv.col = mv_unit->mv[mv_unit->pred_direction % BI_PRED].x; mv.row = mv_unit->mv[mv_unit->pred_direction % BI_PRED].y; if (nsamples > 1) nsamples = select_samples(&mv, pts, pts_inref, nsamples, bsize); *num_samples = nsamples; apply_wm = !svt_find_projection( (int)nsamples, pts, pts_inref, bsize, mv.row, mv.col, wm_params, (int)mi_row, (int)mi_col); return apply_wm; } //foreach_overlappable_nb_above int count_overlappable_nb_above(const Av1Common *cm, MacroBlockD *xd, int32_t mi_col, int nb_max) { int nb_count = 0; if (!xd->up_available) return nb_count; // prev_row_mi points into the mi array, starting at the beginning of the // previous row. ModeInfo **prev_row_mi = xd->mi - mi_col - 1 * xd->mi_stride; const int end_col = MIN(mi_col + xd->n4_w, cm->mi_cols); uint8_t mi_step; for (int above_mi_col = mi_col; above_mi_col < end_col && nb_count < nb_max; above_mi_col += mi_step) { ModeInfo **above_mi = prev_row_mi + above_mi_col; mi_step = MIN(mi_size_wide[above_mi[0]->mbmi.block_mi.sb_type], mi_size_wide[BLOCK_64X64]); // If we're considering a block with width 4, it should be treated as // half of a pair of blocks with chroma information in the second. Move // above_mi_col back to the start of the pair if needed, set above_mbmi // to point at the block with chroma information, and set mi_step to 2 to // step over the entire pair at the end of the iteration. if (mi_step == 1) { above_mi_col &= ~1; above_mi = prev_row_mi + above_mi_col + 1; mi_step = 2; } if (is_neighbor_overlappable(&(*above_mi)->mbmi)) ++nb_count; } return nb_count; } int count_overlappable_nb_left(const Av1Common *cm, MacroBlockD *xd, int32_t mi_row, int nb_max) { int nb_count = 0; if (!xd->left_available) return nb_count; // prev_col_mi points into the mi array, starting at the top of the // previous column ModeInfo **prev_col_mi = xd->mi - 1 - mi_row * xd->mi_stride; const int end_row = MIN(mi_row + xd->n4_h, cm->mi_rows); uint8_t mi_step; for (int left_mi_row = mi_row; left_mi_row < end_row && nb_count < nb_max; left_mi_row += mi_step) { ModeInfo **left_mi = prev_col_mi + left_mi_row * xd->mi_stride; mi_step = MIN(mi_size_high[left_mi[0]->mbmi.block_mi.sb_type], mi_size_high[BLOCK_64X64]); if (mi_step == 1) { left_mi_row &= ~1; left_mi = prev_col_mi + (left_mi_row + 1) * xd->mi_stride; mi_step = 2; } if (is_neighbor_overlappable(&(*left_mi)->mbmi)) ++nb_count; } return nb_count; } void svt_av1_count_overlappable_neighbors(const PictureControlSet *pcs_ptr, BlkStruct *blk_ptr, const BlockSize bsize, int32_t mi_row, int32_t mi_col) { Av1Common * cm = pcs_ptr->parent_pcs_ptr->av1_cm; MacroBlockD *xd = blk_ptr->av1xd; blk_ptr->prediction_unit_array[0].overlappable_neighbors[0] = 0; blk_ptr->prediction_unit_array[0].overlappable_neighbors[1] = 0; if (!is_motion_variation_allowed_bsize(bsize)) return; blk_ptr->prediction_unit_array[0].overlappable_neighbors[0] = count_overlappable_nb_above( cm, xd, mi_col, MAX_SIGNED_VALUE); blk_ptr->prediction_unit_array[0].overlappable_neighbors[1] = count_overlappable_nb_left( cm, xd, mi_row, MAX_SIGNED_VALUE); } int av1_is_dv_valid(const MV dv, const MacroBlockD *xd, int mi_row, int mi_col, BlockSize bsize, int mib_size_log2) { const int bw = block_size_wide[bsize]; const int bh = block_size_high[bsize]; const int scale_px_to_mv = 8; // Disallow subpixel for now // SUBPEL_MASK is not the correct scale if (((dv.row & (scale_px_to_mv - 1)) || (dv.col & (scale_px_to_mv - 1)))) return 0; const TileInfo *const tile = &xd->tile; // Is the source top-left inside the current tile? const int src_top_edge = mi_row * MI_SIZE * scale_px_to_mv + dv.row; const int tile_top_edge = tile->mi_row_start * MI_SIZE * scale_px_to_mv; if (src_top_edge < tile_top_edge) return 0; const int src_left_edge = mi_col * MI_SIZE * scale_px_to_mv + dv.col; const int tile_left_edge = tile->mi_col_start * MI_SIZE * scale_px_to_mv; if (src_left_edge < tile_left_edge) return 0; // Is the bottom right inside the current tile? const int src_bottom_edge = (mi_row * MI_SIZE + bh) * scale_px_to_mv + dv.row; const int tile_bottom_edge = tile->mi_row_end * MI_SIZE * scale_px_to_mv; if (src_bottom_edge > tile_bottom_edge) return 0; const int src_right_edge = (mi_col * MI_SIZE + bw) * scale_px_to_mv + dv.col; const int tile_right_edge = tile->mi_col_end * MI_SIZE * scale_px_to_mv; if (src_right_edge > tile_right_edge) return 0; // Special case for sub 8x8 chroma cases, to prevent referring to chroma // pixels outside current tile. for (int plane = 1; plane < 3 /* av1_num_planes(cm)*/; ++plane) { //const struct MacroBlockDPlane *const pd = &xd->plane[plane]; if (is_chroma_reference(mi_row, mi_col, bsize, 1, 1/* pd->subsampling_x, pd->subsampling_y*/)) { if (bw < 8 /*&& pd->subsampling_x*/) if (src_left_edge < tile_left_edge + 4 * scale_px_to_mv) return 0; if (bh < 8 /* && pd->subsampling_y*/) if (src_top_edge < tile_top_edge + 4 * scale_px_to_mv) return 0; } } // Is the bottom right within an already coded SB? Also consider additional // constraints to facilitate HW decoder. const int max_mib_size = 1 << mib_size_log2; const int active_sb_row = mi_row >> mib_size_log2; const int active_sb64_col = (mi_col * MI_SIZE) >> 6; const int sb_size = max_mib_size * MI_SIZE; const int src_sb_row = ((src_bottom_edge >> 3) - 1) / sb_size; const int src_sb64_col = ((src_right_edge >> 3) - 1) >> 6; const int total_sb64_per_row = ((tile->mi_col_end - tile->mi_col_start - 1) >> 4) + 1; const int active_sb64 = active_sb_row * total_sb64_per_row + active_sb64_col; const int src_sb64 = src_sb_row * total_sb64_per_row + src_sb64_col; if (src_sb64 >= active_sb64 - INTRABC_DELAY_SB64) return 0; // Wavefront constraint: use only top left area of frame for reference. const int gradient = 1 + INTRABC_DELAY_SB64 + (sb_size > 64); const int wf_offset = gradient * (active_sb_row - src_sb_row); if (src_sb_row > active_sb_row || src_sb64_col >= active_sb64_col - INTRABC_DELAY_SB64 + wf_offset) return 0; //add a SW-Wavefront constraint if (sb_size == 64) { if (src_sb64_col > active_sb64_col + (active_sb_row - src_sb_row)) return 0; } else { const int src_sb128_col = ((src_right_edge >> 3) - 1) >> 7; const int active_sb128_col = (mi_col * MI_SIZE) >> 7; if (src_sb128_col > active_sb128_col + (active_sb_row - src_sb_row)) return 0; } return 1; } int is_inside_tile_boundary(TileInfo *tile, int16_t mvx, int16_t mvy, int mi_col, int mi_row, BlockSize bsize) { const int bw = block_size_wide[bsize]; const int bh = block_size_high[bsize]; const int scale_px_to_mv = 8; const int src_top_edge = mi_row * MI_SIZE * scale_px_to_mv + mvy; const int tile_top_edge = tile->mi_row_start * MI_SIZE * scale_px_to_mv; if (src_top_edge < tile_top_edge) return 0; const int src_left_edge = mi_col * MI_SIZE * scale_px_to_mv + mvx; const int tile_left_edge = tile->mi_col_start * MI_SIZE * scale_px_to_mv; if (src_left_edge < tile_left_edge) return 0; // Is the bottom right inside the current tile? const int src_bottom_edge = (mi_row * MI_SIZE + bh) * scale_px_to_mv + mvy; const int tile_bottom_edge = tile->mi_row_end * MI_SIZE * scale_px_to_mv; if (src_bottom_edge > tile_bottom_edge) return 0; const int src_right_edge = (mi_col * MI_SIZE + bw) * scale_px_to_mv + mvx; const int tile_right_edge = tile->mi_col_end * MI_SIZE * scale_px_to_mv; if (src_right_edge > tile_right_edge) return 0; return 1; } IntMv svt_av1_get_ref_mv_from_stack(int ref_idx, const MvReferenceFrame *ref_frame, int ref_mv_idx, CandidateMv ref_mv_stack[][MAX_REF_MV_STACK_SIZE], MacroBlockD *xd /*const MB_MODE_INFO_EXT *mbmi_ext*/) { const int8_t ref_frame_type = av1_ref_frame_type(ref_frame); const CandidateMv *curr_ref_mv_stack = /*mbmi_ext->*/ ref_mv_stack[ref_frame_type]; IntMv ref_mv; ref_mv.as_int = INVALID_MV; if (ref_frame[1] > INTRA_FRAME) { if (ref_idx == 0) ref_mv = curr_ref_mv_stack[ref_mv_idx].this_mv; else { assert(ref_idx == 1); ref_mv = curr_ref_mv_stack[ref_mv_idx].comp_mv; } } else { assert(ref_idx == 0); if (ref_mv_idx < /*mbmi_ext->*/ xd->ref_mv_count[ref_frame_type]) ref_mv = curr_ref_mv_stack[ref_mv_idx].this_mv; else { //CHKN got this from decoder read_intrabc_info global_mvs[ref_frame].as_int = INVALID_MV; ref_mv.as_int = INVALID_MV; // mbmi_ext->global_mvs[ref_frame_type]; } } return ref_mv; } void svt_av1_find_best_ref_mvs_from_stack(int allow_hp, //const MB_MODE_INFO_EXT *mbmi_ext, CandidateMv ref_mv_stack[][MAX_REF_MV_STACK_SIZE], MacroBlockD *xd, MvReferenceFrame ref_frame, IntMv *nearest_mv, IntMv *near_mv, int is_integer) { const int ref_idx = 0; MvReferenceFrame ref_frames[2] = {ref_frame, NONE_FRAME}; *nearest_mv = svt_av1_get_ref_mv_from_stack( ref_idx, ref_frames, 0, ref_mv_stack /*mbmi_ext*/, xd); lower_mv_precision(&nearest_mv->as_mv, allow_hp, is_integer); *near_mv = svt_av1_get_ref_mv_from_stack(ref_idx, ref_frames, 1, ref_mv_stack /*mbmi_ext*/, xd); lower_mv_precision(&near_mv->as_mv, allow_hp, is_integer); }