|  | /* | 
|  | * Copyright (c) 2023, 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 "config/aom_dsp_rtcd.h" | 
|  | #include "config/av1_rtcd.h" | 
|  |  | 
|  | #include "av1/common/reconinter.h" | 
|  |  | 
|  | #include "av1/encoder/encodemv.h" | 
|  | #include "av1/encoder/nonrd_opt.h" | 
|  | #include "av1/encoder/rdopt.h" | 
|  |  | 
|  | static const SCAN_ORDER av1_fast_idtx_scan_order_16x16 = { | 
|  | av1_fast_idtx_scan_16x16, av1_fast_idtx_iscan_16x16 | 
|  | }; | 
|  |  | 
|  | #define DECLARE_BLOCK_YRD_BUFFERS()                      \ | 
|  | DECLARE_ALIGNED(64, tran_low_t, dqcoeff_buf[16 * 16]); \ | 
|  | DECLARE_ALIGNED(64, tran_low_t, qcoeff_buf[16 * 16]);  \ | 
|  | DECLARE_ALIGNED(64, tran_low_t, coeff_buf[16 * 16]);   \ | 
|  | uint16_t eob[1]; | 
|  |  | 
|  | #define DECLARE_BLOCK_YRD_VARS()                                          \ | 
|  | /* When is_tx_8x8_dual_applicable is true, we compute the txfm for the  \ | 
|  | * entire bsize and write macroblock_plane::coeff. So low_coeff is kept \ | 
|  | * as a non-const so we can reassign it to macroblock_plane::coeff. */  \ | 
|  | int16_t *low_coeff = (int16_t *)coeff_buf;                              \ | 
|  | int16_t *const low_qcoeff = (int16_t *)qcoeff_buf;                      \ | 
|  | int16_t *const low_dqcoeff = (int16_t *)dqcoeff_buf;                    \ | 
|  | const int diff_stride = bw; | 
|  |  | 
|  | #define DECLARE_LOOP_VARS_BLOCK_YRD() \ | 
|  | const int16_t *src_diff = &p->src_diff[(r * diff_stride + c) << 2]; | 
|  |  | 
|  | static AOM_FORCE_INLINE void update_yrd_loop_vars( | 
|  | MACROBLOCK *x, int *skippable, int step, int ncoeffs, | 
|  | int16_t *const low_coeff, int16_t *const low_qcoeff, | 
|  | int16_t *const low_dqcoeff, RD_STATS *this_rdc, int *eob_cost, | 
|  | int tx_blk_id) { | 
|  | const int is_txfm_skip = (ncoeffs == 0); | 
|  | *skippable &= is_txfm_skip; | 
|  | x->txfm_search_info.blk_skip[tx_blk_id] = is_txfm_skip; | 
|  | *eob_cost += get_msb(ncoeffs + 1); | 
|  | if (ncoeffs == 1) | 
|  | this_rdc->rate += (int)abs(low_qcoeff[0]); | 
|  | else if (ncoeffs > 1) | 
|  | this_rdc->rate += aom_satd_lp(low_qcoeff, step << 4); | 
|  |  | 
|  | this_rdc->dist += av1_block_error_lp(low_coeff, low_dqcoeff, step << 4) >> 2; | 
|  | } | 
|  |  | 
|  | static inline void aom_process_hadamard_lp_8x16(MACROBLOCK *x, | 
|  | int max_blocks_high, | 
|  | int max_blocks_wide, | 
|  | int num_4x4_w, int step, | 
|  | int block_step) { | 
|  | struct macroblock_plane *const p = &x->plane[AOM_PLANE_Y]; | 
|  | const int bw = 4 * num_4x4_w; | 
|  | const int num_4x4 = AOMMIN(num_4x4_w, max_blocks_wide); | 
|  | int block = 0; | 
|  |  | 
|  | for (int r = 0; r < max_blocks_high; r += block_step) { | 
|  | for (int c = 0; c < num_4x4; c += 2 * block_step) { | 
|  | const int16_t *src_diff = &p->src_diff[(r * bw + c) << 2]; | 
|  | int16_t *low_coeff = (int16_t *)p->coeff + BLOCK_OFFSET(block); | 
|  | aom_hadamard_lp_8x8_dual(src_diff, (ptrdiff_t)bw, low_coeff); | 
|  | block += 2 * step; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #if CONFIG_AV1_HIGHBITDEPTH | 
|  | #define DECLARE_BLOCK_YRD_HBD_VARS()     \ | 
|  | tran_low_t *const coeff = coeff_buf;   \ | 
|  | tran_low_t *const qcoeff = qcoeff_buf; \ | 
|  | tran_low_t *const dqcoeff = dqcoeff_buf; | 
|  |  | 
|  | static AOM_FORCE_INLINE void update_yrd_loop_vars_hbd( | 
|  | MACROBLOCK *x, int *skippable, int step, int ncoeffs, | 
|  | tran_low_t *const coeff, tran_low_t *const qcoeff, | 
|  | tran_low_t *const dqcoeff, RD_STATS *this_rdc, int *eob_cost, | 
|  | int tx_blk_id) { | 
|  | const MACROBLOCKD *xd = &x->e_mbd; | 
|  | const int is_txfm_skip = (ncoeffs == 0); | 
|  | *skippable &= is_txfm_skip; | 
|  | x->txfm_search_info.blk_skip[tx_blk_id] = is_txfm_skip; | 
|  | *eob_cost += get_msb(ncoeffs + 1); | 
|  |  | 
|  | int64_t dummy; | 
|  | if (ncoeffs == 1) | 
|  | this_rdc->rate += (int)abs(qcoeff[0]); | 
|  | else if (ncoeffs > 1) | 
|  | this_rdc->rate += aom_satd(qcoeff, step << 4); | 
|  | this_rdc->dist += | 
|  | av1_highbd_block_error(coeff, dqcoeff, step << 4, &dummy, xd->bd) >> 2; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /*!\brief Calculates RD Cost using Hadamard transform. | 
|  | * | 
|  | * \ingroup nonrd_mode_search | 
|  | * \callgraph | 
|  | * \callergraph | 
|  | * Calculates RD Cost using Hadamard transform. For low bit depth this function | 
|  | * uses low-precision set of functions (16-bit) and 32 bit for high bit depth | 
|  | * \param[in]    x              Pointer to structure holding all the data for | 
|  | the current macroblock | 
|  | * \param[in]    this_rdc       Pointer to calculated RD Cost | 
|  | * \param[in]    skippable      Pointer to a flag indicating possible tx skip | 
|  | * \param[in]    bsize          Current block size | 
|  | * \param[in]    tx_size        Transform size | 
|  | * \param[in]    is_inter_mode  Flag to indicate inter mode | 
|  | * | 
|  | * \remark Nothing is returned. Instead, calculated RD cost is placed to | 
|  | * \c this_rdc. \c skippable flag is set if there is no non-zero quantized | 
|  | * coefficients for Hadamard transform | 
|  | */ | 
|  | void av1_block_yrd(MACROBLOCK *x, RD_STATS *this_rdc, int *skippable, | 
|  | BLOCK_SIZE bsize, TX_SIZE tx_size) { | 
|  | MACROBLOCKD *xd = &x->e_mbd; | 
|  | const struct macroblockd_plane *pd = &xd->plane[AOM_PLANE_Y]; | 
|  | struct macroblock_plane *const p = &x->plane[AOM_PLANE_Y]; | 
|  | assert(bsize < BLOCK_SIZES_ALL); | 
|  | const int num_4x4_w = mi_size_wide[bsize]; | 
|  | const int num_4x4_h = mi_size_high[bsize]; | 
|  | const int step = 1 << (tx_size << 1); | 
|  | const int block_step = (1 << tx_size); | 
|  | const int row_step = step * num_4x4_w >> tx_size; | 
|  | int block = 0; | 
|  | const int max_blocks_wide = | 
|  | num_4x4_w + (xd->mb_to_right_edge >= 0 ? 0 : xd->mb_to_right_edge >> 5); | 
|  | const int max_blocks_high = | 
|  | num_4x4_h + (xd->mb_to_bottom_edge >= 0 ? 0 : xd->mb_to_bottom_edge >> 5); | 
|  | int eob_cost = 0; | 
|  | const int bw = 4 * num_4x4_w; | 
|  | const int bh = 4 * num_4x4_h; | 
|  | const int use_hbd = is_cur_buf_hbd(xd); | 
|  | int num_blk_skip_w = num_4x4_w; | 
|  |  | 
|  | #if CONFIG_AV1_HIGHBITDEPTH | 
|  | if (use_hbd) { | 
|  | aom_highbd_subtract_block(bh, bw, p->src_diff, bw, p->src.buf, | 
|  | p->src.stride, pd->dst.buf, pd->dst.stride); | 
|  | } else { | 
|  | aom_subtract_block(bh, bw, p->src_diff, bw, p->src.buf, p->src.stride, | 
|  | pd->dst.buf, pd->dst.stride); | 
|  | } | 
|  | #else | 
|  | aom_subtract_block(bh, bw, p->src_diff, bw, p->src.buf, p->src.stride, | 
|  | pd->dst.buf, pd->dst.stride); | 
|  | #endif | 
|  |  | 
|  | // Keep the intermediate value on the stack here. Writing directly to | 
|  | // skippable causes speed regression due to load-and-store issues in | 
|  | // update_yrd_loop_vars. | 
|  | int temp_skippable = 1; | 
|  | this_rdc->dist = 0; | 
|  | this_rdc->rate = 0; | 
|  | // For block sizes 8x16 or above, Hadamard txfm of two adjacent 8x8 blocks | 
|  | // can be done per function call. Hence the call of Hadamard txfm is | 
|  | // abstracted here for the specified cases. | 
|  | int is_tx_8x8_dual_applicable = | 
|  | (tx_size == TX_8X8 && block_size_wide[bsize] >= 16 && | 
|  | block_size_high[bsize] >= 8); | 
|  |  | 
|  | #if CONFIG_AV1_HIGHBITDEPTH | 
|  | // As of now, dual implementation of hadamard txfm is available for low | 
|  | // bitdepth. | 
|  | if (use_hbd) is_tx_8x8_dual_applicable = 0; | 
|  | #endif | 
|  |  | 
|  | if (is_tx_8x8_dual_applicable) { | 
|  | aom_process_hadamard_lp_8x16(x, max_blocks_high, max_blocks_wide, num_4x4_w, | 
|  | step, block_step); | 
|  | } | 
|  |  | 
|  | const SCAN_ORDER *const scan_order = &av1_scan_orders[tx_size][DCT_DCT]; | 
|  | DECLARE_BLOCK_YRD_BUFFERS() | 
|  | DECLARE_BLOCK_YRD_VARS() | 
|  | #if CONFIG_AV1_HIGHBITDEPTH | 
|  | DECLARE_BLOCK_YRD_HBD_VARS() | 
|  | #else | 
|  | (void)use_hbd; | 
|  | #endif | 
|  |  | 
|  | // Keep track of the row and column of the blocks we use so that we know | 
|  | // if we are in the unrestricted motion border. | 
|  | for (int r = 0; r < max_blocks_high; r += block_step) { | 
|  | for (int c = 0, s = 0; c < max_blocks_wide; c += block_step, s += step) { | 
|  | DECLARE_LOOP_VARS_BLOCK_YRD() | 
|  |  | 
|  | switch (tx_size) { | 
|  | #if CONFIG_AV1_HIGHBITDEPTH | 
|  | case TX_16X16: | 
|  | if (use_hbd) { | 
|  | aom_hadamard_16x16(src_diff, diff_stride, coeff); | 
|  | av1_quantize_fp(coeff, 16 * 16, p->zbin_QTX, p->round_fp_QTX, | 
|  | p->quant_fp_QTX, p->quant_shift_QTX, qcoeff, | 
|  | dqcoeff, p->dequant_QTX, eob, | 
|  | // default_scan_fp_16x16_transpose and | 
|  | // av1_default_iscan_fp_16x16_transpose have to be | 
|  | // used together. | 
|  | default_scan_fp_16x16_transpose, | 
|  | av1_default_iscan_fp_16x16_transpose); | 
|  | } else { | 
|  | aom_hadamard_lp_16x16(src_diff, diff_stride, low_coeff); | 
|  | av1_quantize_lp(low_coeff, 16 * 16, p->round_fp_QTX, | 
|  | p->quant_fp_QTX, low_qcoeff, low_dqcoeff, | 
|  | p->dequant_QTX, eob, | 
|  | // default_scan_lp_16x16_transpose and | 
|  | // av1_default_iscan_lp_16x16_transpose have to be | 
|  | // used together. | 
|  | default_scan_lp_16x16_transpose, | 
|  | av1_default_iscan_lp_16x16_transpose); | 
|  | } | 
|  | break; | 
|  | case TX_8X8: | 
|  | if (use_hbd) { | 
|  | aom_hadamard_8x8(src_diff, diff_stride, coeff); | 
|  | av1_quantize_fp( | 
|  | coeff, 8 * 8, p->zbin_QTX, p->round_fp_QTX, p->quant_fp_QTX, | 
|  | p->quant_shift_QTX, qcoeff, dqcoeff, p->dequant_QTX, eob, | 
|  | default_scan_8x8_transpose, av1_default_iscan_8x8_transpose); | 
|  | } else { | 
|  | if (is_tx_8x8_dual_applicable) { | 
|  | // The coeffs are pre-computed for the whole block, so re-assign | 
|  | // low_coeff to the appropriate location. | 
|  | const int block_offset = BLOCK_OFFSET(block + s); | 
|  | low_coeff = (int16_t *)p->coeff + block_offset; | 
|  | } else { | 
|  | aom_hadamard_lp_8x8(src_diff, diff_stride, low_coeff); | 
|  | } | 
|  | av1_quantize_lp( | 
|  | low_coeff, 8 * 8, p->round_fp_QTX, p->quant_fp_QTX, low_qcoeff, | 
|  | low_dqcoeff, p->dequant_QTX, eob, | 
|  | // default_scan_8x8_transpose and | 
|  | // av1_default_iscan_8x8_transpose have to be used together. | 
|  | default_scan_8x8_transpose, av1_default_iscan_8x8_transpose); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | assert(tx_size == TX_4X4); | 
|  | // In tx_size=4x4 case, aom_fdct4x4 and aom_fdct4x4_lp generate | 
|  | // normal coefficients order, so we don't need to change the scan | 
|  | // order here. | 
|  | if (use_hbd) { | 
|  | aom_fdct4x4(src_diff, coeff, diff_stride); | 
|  | av1_quantize_fp(coeff, 4 * 4, p->zbin_QTX, p->round_fp_QTX, | 
|  | p->quant_fp_QTX, p->quant_shift_QTX, qcoeff, | 
|  | dqcoeff, p->dequant_QTX, eob, scan_order->scan, | 
|  | scan_order->iscan); | 
|  | } else { | 
|  | aom_fdct4x4_lp(src_diff, low_coeff, diff_stride); | 
|  | av1_quantize_lp(low_coeff, 4 * 4, p->round_fp_QTX, p->quant_fp_QTX, | 
|  | low_qcoeff, low_dqcoeff, p->dequant_QTX, eob, | 
|  | scan_order->scan, scan_order->iscan); | 
|  | } | 
|  | break; | 
|  | #else | 
|  | case TX_16X16: | 
|  | aom_hadamard_lp_16x16(src_diff, diff_stride, low_coeff); | 
|  | av1_quantize_lp(low_coeff, 16 * 16, p->round_fp_QTX, p->quant_fp_QTX, | 
|  | low_qcoeff, low_dqcoeff, p->dequant_QTX, eob, | 
|  | default_scan_lp_16x16_transpose, | 
|  | av1_default_iscan_lp_16x16_transpose); | 
|  | break; | 
|  | case TX_8X8: | 
|  | if (is_tx_8x8_dual_applicable) { | 
|  | // The coeffs are pre-computed for the whole block, so re-assign | 
|  | // low_coeff to the appropriate location. | 
|  | const int block_offset = BLOCK_OFFSET(block + s); | 
|  | low_coeff = (int16_t *)p->coeff + block_offset; | 
|  | } else { | 
|  | aom_hadamard_lp_8x8(src_diff, diff_stride, low_coeff); | 
|  | } | 
|  | av1_quantize_lp(low_coeff, 8 * 8, p->round_fp_QTX, p->quant_fp_QTX, | 
|  | low_qcoeff, low_dqcoeff, p->dequant_QTX, eob, | 
|  | default_scan_8x8_transpose, | 
|  | av1_default_iscan_8x8_transpose); | 
|  | break; | 
|  | default: | 
|  | aom_fdct4x4_lp(src_diff, low_coeff, diff_stride); | 
|  | av1_quantize_lp(low_coeff, 4 * 4, p->round_fp_QTX, p->quant_fp_QTX, | 
|  | low_qcoeff, low_dqcoeff, p->dequant_QTX, eob, | 
|  | scan_order->scan, scan_order->iscan); | 
|  | break; | 
|  | #endif | 
|  | } | 
|  | assert(*eob <= 1024); | 
|  | #if CONFIG_AV1_HIGHBITDEPTH | 
|  | if (use_hbd) | 
|  | update_yrd_loop_vars_hbd(x, &temp_skippable, step, *eob, coeff, qcoeff, | 
|  | dqcoeff, this_rdc, &eob_cost, | 
|  | r * num_blk_skip_w + c); | 
|  | else | 
|  | #endif | 
|  | update_yrd_loop_vars(x, &temp_skippable, step, *eob, low_coeff, | 
|  | low_qcoeff, low_dqcoeff, this_rdc, &eob_cost, | 
|  | r * num_blk_skip_w + c); | 
|  | } | 
|  | block += row_step; | 
|  | } | 
|  |  | 
|  | this_rdc->skip_txfm = *skippable = temp_skippable; | 
|  | if (this_rdc->sse < INT64_MAX) { | 
|  | this_rdc->sse = (this_rdc->sse << 6) >> 2; | 
|  | if (temp_skippable) { | 
|  | this_rdc->dist = 0; | 
|  | this_rdc->dist = this_rdc->sse; | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // If skippable is set, rate gets clobbered later. | 
|  | this_rdc->rate <<= (2 + AV1_PROB_COST_SHIFT); | 
|  | this_rdc->rate += (eob_cost << AV1_PROB_COST_SHIFT); | 
|  | } | 
|  |  | 
|  | // Explicitly enumerate the cases so the compiler can generate SIMD for the | 
|  | // function. According to the disassembler, gcc generates SSE codes for each of | 
|  | // the possible block sizes. The hottest case is tx_width 16, which takes up | 
|  | // about 8% of the self cycle of av1_nonrd_pick_inter_mode_sb. Since | 
|  | // av1_nonrd_pick_inter_mode_sb takes up about 3% of total encoding time, the | 
|  | // potential room of improvement for writing AVX2 optimization is only 3% * 8% = | 
|  | // 0.24% of total encoding time. | 
|  | static inline void scale_square_buf_vals(int16_t *dst, int tx_width, | 
|  | const int16_t *src, int src_stride) { | 
|  | #define DO_SCALING                                                   \ | 
|  | do {                                                               \ | 
|  | for (int idy = 0; idy < tx_width; ++idy) {                       \ | 
|  | for (int idx = 0; idx < tx_width; ++idx) {                     \ | 
|  | dst[idy * tx_width + idx] = src[idy * src_stride + idx] * 8; \ | 
|  | }                                                              \ | 
|  | }                                                                \ | 
|  | } while (0) | 
|  |  | 
|  | if (tx_width == 4) { | 
|  | DO_SCALING; | 
|  | } else if (tx_width == 8) { | 
|  | DO_SCALING; | 
|  | } else if (tx_width == 16) { | 
|  | DO_SCALING; | 
|  | } else { | 
|  | assert(0); | 
|  | } | 
|  |  | 
|  | #undef DO_SCALING | 
|  | } | 
|  |  | 
|  | /*!\brief Calculates RD Cost when the block uses Identity transform. | 
|  | * Note that this function is only for low bit depth encoding, since it | 
|  | * is called in real-time mode for now, which sets high bit depth to 0: | 
|  | * -DCONFIG_AV1_HIGHBITDEPTH=0 | 
|  | * | 
|  | * \ingroup nonrd_mode_search | 
|  | * \callgraph | 
|  | * \callergraph | 
|  | * Calculates RD Cost. For low bit depth this function | 
|  | * uses low-precision set of functions (16-bit) and 32 bit for high bit depth | 
|  | * \param[in]    x              Pointer to structure holding all the data for | 
|  | the current macroblock | 
|  | * \param[in]    pred_buf       Pointer to the prediction buffer | 
|  | * \param[in]    pred_stride    Stride for the prediction buffer | 
|  | * \param[in]    this_rdc       Pointer to calculated RD Cost | 
|  | * \param[in]    skippable      Pointer to a flag indicating possible tx skip | 
|  | * \param[in]    bsize          Current block size | 
|  | * \param[in]    tx_size        Transform size | 
|  | * | 
|  | * \remark Nothing is returned. Instead, calculated RD cost is placed to | 
|  | * \c this_rdc. \c skippable flag is set if all coefficients are zero. | 
|  | */ | 
|  | void av1_block_yrd_idtx(MACROBLOCK *x, const uint8_t *const pred_buf, | 
|  | int pred_stride, RD_STATS *this_rdc, int *skippable, | 
|  | BLOCK_SIZE bsize, TX_SIZE tx_size) { | 
|  | MACROBLOCKD *xd = &x->e_mbd; | 
|  | struct macroblock_plane *const p = &x->plane[AOM_PLANE_Y]; | 
|  | assert(bsize < BLOCK_SIZES_ALL); | 
|  | const int num_4x4_w = mi_size_wide[bsize]; | 
|  | const int num_4x4_h = mi_size_high[bsize]; | 
|  | const int step = 1 << (tx_size << 1); | 
|  | const int block_step = (1 << tx_size); | 
|  | const int max_blocks_wide = | 
|  | num_4x4_w + (xd->mb_to_right_edge >= 0 ? 0 : xd->mb_to_right_edge >> 5); | 
|  | const int max_blocks_high = | 
|  | num_4x4_h + (xd->mb_to_bottom_edge >= 0 ? 0 : xd->mb_to_bottom_edge >> 5); | 
|  | int eob_cost = 0; | 
|  | const int bw = 4 * num_4x4_w; | 
|  | const int bh = 4 * num_4x4_h; | 
|  | const int num_blk_skip_w = num_4x4_w; | 
|  | // Keep the intermediate value on the stack here. Writing directly to | 
|  | // skippable causes speed regression due to load-and-store issues in | 
|  | // update_yrd_loop_vars. | 
|  | int temp_skippable = 1; | 
|  | int tx_wd = 0; | 
|  | const SCAN_ORDER *scan_order = NULL; | 
|  | switch (tx_size) { | 
|  | case TX_64X64: | 
|  | assert(0);  // Not implemented | 
|  | break; | 
|  | case TX_32X32: | 
|  | assert(0);  // Not used | 
|  | break; | 
|  | case TX_16X16: | 
|  | scan_order = &av1_fast_idtx_scan_order_16x16; | 
|  | tx_wd = 16; | 
|  | break; | 
|  | case TX_8X8: | 
|  | scan_order = &av1_fast_idtx_scan_order_8x8; | 
|  | tx_wd = 8; | 
|  | break; | 
|  | default: | 
|  | assert(tx_size == TX_4X4); | 
|  | scan_order = &av1_fast_idtx_scan_order_4x4; | 
|  | tx_wd = 4; | 
|  | break; | 
|  | } | 
|  | assert(scan_order != NULL); | 
|  |  | 
|  | this_rdc->dist = 0; | 
|  | this_rdc->rate = 0; | 
|  | aom_subtract_block(bh, bw, p->src_diff, bw, p->src.buf, p->src.stride, | 
|  | pred_buf, pred_stride); | 
|  | // Keep track of the row and column of the blocks we use so that we know | 
|  | // if we are in the unrestricted motion border. | 
|  | DECLARE_BLOCK_YRD_BUFFERS() | 
|  | DECLARE_BLOCK_YRD_VARS() | 
|  | for (int r = 0; r < max_blocks_high; r += block_step) { | 
|  | for (int c = 0, s = 0; c < max_blocks_wide; c += block_step, s += step) { | 
|  | DECLARE_LOOP_VARS_BLOCK_YRD() | 
|  | scale_square_buf_vals(low_coeff, tx_wd, src_diff, diff_stride); | 
|  | av1_quantize_lp(low_coeff, tx_wd * tx_wd, p->round_fp_QTX, | 
|  | p->quant_fp_QTX, low_qcoeff, low_dqcoeff, p->dequant_QTX, | 
|  | eob, scan_order->scan, scan_order->iscan); | 
|  | assert(*eob <= 1024); | 
|  | update_yrd_loop_vars(x, &temp_skippable, step, *eob, low_coeff, | 
|  | low_qcoeff, low_dqcoeff, this_rdc, &eob_cost, | 
|  | r * num_blk_skip_w + c); | 
|  | } | 
|  | } | 
|  | this_rdc->skip_txfm = *skippable = temp_skippable; | 
|  | if (this_rdc->sse < INT64_MAX) { | 
|  | this_rdc->sse = (this_rdc->sse << 6) >> 2; | 
|  | if (temp_skippable) { | 
|  | this_rdc->dist = 0; | 
|  | this_rdc->dist = this_rdc->sse; | 
|  | return; | 
|  | } | 
|  | } | 
|  | // If skippable is set, rate gets clobbered later. | 
|  | this_rdc->rate <<= (2 + AV1_PROB_COST_SHIFT); | 
|  | this_rdc->rate += (eob_cost << AV1_PROB_COST_SHIFT); | 
|  | } | 
|  |  | 
|  | int64_t av1_model_rd_for_sb_uv(AV1_COMP *cpi, BLOCK_SIZE plane_bsize, | 
|  | MACROBLOCK *x, MACROBLOCKD *xd, | 
|  | RD_STATS *this_rdc, int start_plane, | 
|  | int stop_plane) { | 
|  | // Note our transform coeffs are 8 times an orthogonal transform. | 
|  | // Hence quantizer step is also 8 times. To get effective quantizer | 
|  | // we need to divide by 8 before sending to modeling function. | 
|  | unsigned int sse; | 
|  | int rate; | 
|  | int64_t dist; | 
|  | int plane; | 
|  | int64_t tot_sse = 0; | 
|  |  | 
|  | this_rdc->rate = 0; | 
|  | this_rdc->dist = 0; | 
|  | this_rdc->skip_txfm = 0; | 
|  |  | 
|  | for (plane = start_plane; plane <= stop_plane; ++plane) { | 
|  | struct macroblock_plane *const p = &x->plane[plane]; | 
|  | struct macroblockd_plane *const pd = &xd->plane[plane]; | 
|  | const uint32_t dc_quant = p->dequant_QTX[0]; | 
|  | const uint32_t ac_quant = p->dequant_QTX[1]; | 
|  | const BLOCK_SIZE bs = plane_bsize; | 
|  | unsigned int var; | 
|  | if (!x->color_sensitivity[COLOR_SENS_IDX(plane)]) continue; | 
|  |  | 
|  | var = cpi->ppi->fn_ptr[bs].vf(p->src.buf, p->src.stride, pd->dst.buf, | 
|  | pd->dst.stride, &sse); | 
|  | assert(sse >= var); | 
|  | tot_sse += sse; | 
|  |  | 
|  | av1_model_rd_from_var_lapndz(sse - var, num_pels_log2_lookup[bs], | 
|  | dc_quant >> 3, &rate, &dist); | 
|  |  | 
|  | this_rdc->rate += rate >> 1; | 
|  | this_rdc->dist += dist << 3; | 
|  |  | 
|  | av1_model_rd_from_var_lapndz(var, num_pels_log2_lookup[bs], ac_quant >> 3, | 
|  | &rate, &dist); | 
|  |  | 
|  | this_rdc->rate += rate; | 
|  | this_rdc->dist += dist << 4; | 
|  | } | 
|  |  | 
|  | if (this_rdc->rate == 0) { | 
|  | this_rdc->skip_txfm = 1; | 
|  | } | 
|  |  | 
|  | if (RDCOST(x->rdmult, this_rdc->rate, this_rdc->dist) >= | 
|  | RDCOST(x->rdmult, 0, tot_sse << 4)) { | 
|  | this_rdc->rate = 0; | 
|  | this_rdc->dist = tot_sse << 4; | 
|  | this_rdc->skip_txfm = 1; | 
|  | } | 
|  |  | 
|  | return tot_sse; | 
|  | } | 
|  |  | 
|  | static void compute_intra_yprediction(const AV1_COMMON *cm, | 
|  | PREDICTION_MODE mode, BLOCK_SIZE bsize, | 
|  | MACROBLOCK *x, MACROBLOCKD *xd) { | 
|  | const SequenceHeader *seq_params = cm->seq_params; | 
|  | struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; | 
|  | struct macroblock_plane *const p = &x->plane[AOM_PLANE_Y]; | 
|  | uint8_t *const src_buf_base = p->src.buf; | 
|  | uint8_t *const dst_buf_base = pd->dst.buf; | 
|  | const int src_stride = p->src.stride; | 
|  | const int dst_stride = pd->dst.stride; | 
|  | int plane = 0; | 
|  | int row, col; | 
|  | // block and transform sizes, in number of 4x4 blocks log 2 ("*_b") | 
|  | // 4x4=0, 8x8=2, 16x16=4, 32x32=6, 64x64=8 | 
|  | // transform size varies per plane, look it up in a common way. | 
|  | const TX_SIZE tx_size = max_txsize_lookup[bsize]; | 
|  | const BLOCK_SIZE plane_bsize = | 
|  | get_plane_block_size(bsize, pd->subsampling_x, pd->subsampling_y); | 
|  | // If mb_to_right_edge is < 0 we are in a situation in which | 
|  | // the current block size extends into the UMV and we won't | 
|  | // visit the sub blocks that are wholly within the UMV. | 
|  | const int max_blocks_wide = max_block_wide(xd, plane_bsize, plane); | 
|  | const int max_blocks_high = max_block_high(xd, plane_bsize, plane); | 
|  | // Keep track of the row and column of the blocks we use so that we know | 
|  | // if we are in the unrestricted motion border. | 
|  | for (row = 0; row < max_blocks_high; row += (1 << tx_size)) { | 
|  | // Skip visiting the sub blocks that are wholly within the UMV. | 
|  | for (col = 0; col < max_blocks_wide; col += (1 << tx_size)) { | 
|  | p->src.buf = &src_buf_base[4 * (row * (int64_t)src_stride + col)]; | 
|  | pd->dst.buf = &dst_buf_base[4 * (row * (int64_t)dst_stride + col)]; | 
|  | av1_predict_intra_block( | 
|  | xd, seq_params->sb_size, seq_params->enable_intra_edge_filter, | 
|  | block_size_wide[bsize], block_size_high[bsize], tx_size, mode, 0, 0, | 
|  | FILTER_INTRA_MODES, pd->dst.buf, dst_stride, pd->dst.buf, dst_stride, | 
|  | 0, 0, plane); | 
|  | } | 
|  | } | 
|  | p->src.buf = src_buf_base; | 
|  | pd->dst.buf = dst_buf_base; | 
|  | } | 
|  |  | 
|  | // Checks whether Intra mode needs to be pruned based on | 
|  | // 'intra_y_mode_bsize_mask_nrd' and 'prune_hv_pred_modes_using_blksad' | 
|  | // speed features. | 
|  | static inline bool is_prune_intra_mode( | 
|  | AV1_COMP *cpi, int mode_index, int force_intra_check, BLOCK_SIZE bsize, | 
|  | uint8_t segment_id, SOURCE_SAD source_sad_nonrd, | 
|  | uint8_t color_sensitivity[MAX_MB_PLANE - 1]) { | 
|  | const PREDICTION_MODE this_mode = intra_mode_list[mode_index]; | 
|  | if (mode_index > 2 || force_intra_check == 0) { | 
|  | if (!((1 << this_mode) & cpi->sf.rt_sf.intra_y_mode_bsize_mask_nrd[bsize])) | 
|  | return true; | 
|  |  | 
|  | if (this_mode == DC_PRED) return false; | 
|  |  | 
|  | if (!cpi->sf.rt_sf.prune_hv_pred_modes_using_src_sad) return false; | 
|  |  | 
|  | const bool has_color_sensitivity = | 
|  | color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] && | 
|  | color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)]; | 
|  | if (has_color_sensitivity && | 
|  | (cpi->rc.frame_source_sad > 1.1 * cpi->rc.avg_source_sad || | 
|  | cyclic_refresh_segment_id_boosted(segment_id) || | 
|  | source_sad_nonrd > kMedSad)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /*!\brief Estimation of RD cost of an intra mode for Non-RD optimized case. | 
|  | * | 
|  | * \ingroup nonrd_mode_search | 
|  | * \callgraph | 
|  | * \callergraph | 
|  | * Calculates RD Cost for an intra mode for a single TX block using Hadamard | 
|  | * transform. | 
|  | * \param[in]    plane          Color plane | 
|  | * \param[in]    block          Index of a TX block in a prediction block | 
|  | * \param[in]    row            Row of a current TX block | 
|  | * \param[in]    col            Column of a current TX block | 
|  | * \param[in]    plane_bsize    Block size of a current prediction block | 
|  | * \param[in]    tx_size        Transform size | 
|  | * \param[in]    arg            Pointer to a structure that holds parameters | 
|  | *                              for intra mode search | 
|  | * | 
|  | * \remark Nothing is returned. Instead, best mode and RD Cost of the best mode | 
|  | * are set in \c args->rdc and \c args->mode | 
|  | */ | 
|  | void av1_estimate_block_intra(int plane, int block, int row, int col, | 
|  | BLOCK_SIZE plane_bsize, TX_SIZE tx_size, | 
|  | void *arg) { | 
|  | struct estimate_block_intra_args *const args = arg; | 
|  | AV1_COMP *const cpi = args->cpi; | 
|  | AV1_COMMON *const cm = &cpi->common; | 
|  | MACROBLOCK *const x = args->x; | 
|  | MACROBLOCKD *const xd = &x->e_mbd; | 
|  | struct macroblock_plane *const p = &x->plane[plane]; | 
|  | struct macroblockd_plane *const pd = &xd->plane[plane]; | 
|  | const BLOCK_SIZE bsize_tx = txsize_to_bsize[tx_size]; | 
|  | uint8_t *const src_buf_base = p->src.buf; | 
|  | uint8_t *const dst_buf_base = pd->dst.buf; | 
|  | const int64_t src_stride = p->src.stride; | 
|  | const int64_t dst_stride = pd->dst.stride; | 
|  |  | 
|  | (void)block; | 
|  |  | 
|  | av1_predict_intra_block_facade(cm, xd, plane, col, row, tx_size); | 
|  |  | 
|  | if (args->prune_mode_based_on_sad || args->prune_palette_sad) { | 
|  | unsigned int this_sad = cpi->ppi->fn_ptr[plane_bsize].sdf( | 
|  | p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride); | 
|  | const unsigned int sad_threshold = | 
|  | args->best_sad != UINT_MAX ? args->best_sad + (args->best_sad >> 4) | 
|  | : UINT_MAX; | 
|  | // Skip the evaluation of current mode if its SAD is more than a threshold. | 
|  | if (args->prune_mode_based_on_sad && this_sad > sad_threshold) { | 
|  | // For the current mode, set rate and distortion to maximum possible | 
|  | // values and return. | 
|  | // Note: args->rdc->rate is checked in av1_nonrd_pick_intra_mode() to skip | 
|  | // the evaluation of the current mode. | 
|  | args->rdc->rate = INT_MAX; | 
|  | args->rdc->dist = INT64_MAX; | 
|  | return; | 
|  | } | 
|  | if (this_sad < args->best_sad) { | 
|  | args->best_sad = this_sad; | 
|  | } | 
|  | } | 
|  |  | 
|  | RD_STATS this_rdc; | 
|  | av1_invalid_rd_stats(&this_rdc); | 
|  |  | 
|  | p->src.buf = &src_buf_base[4 * (row * src_stride + col)]; | 
|  | pd->dst.buf = &dst_buf_base[4 * (row * dst_stride + col)]; | 
|  |  | 
|  | if (plane == 0) { | 
|  | av1_block_yrd(x, &this_rdc, &args->skippable, bsize_tx, | 
|  | AOMMIN(tx_size, TX_16X16)); | 
|  | } else { | 
|  | av1_model_rd_for_sb_uv(cpi, bsize_tx, x, xd, &this_rdc, plane, plane); | 
|  | } | 
|  |  | 
|  | p->src.buf = src_buf_base; | 
|  | pd->dst.buf = dst_buf_base; | 
|  | assert(args->rdc->rate != INT_MAX && args->rdc->dist != INT64_MAX); | 
|  | args->rdc->rate += this_rdc.rate; | 
|  | args->rdc->dist += this_rdc.dist; | 
|  | } | 
|  |  | 
|  | /*!\brief Estimates best intra mode for inter mode search | 
|  | * | 
|  | * \ingroup nonrd_mode_search | 
|  | * \callgraph | 
|  | * \callergraph | 
|  | * | 
|  | * Using heuristics based on best inter mode, block size, and other decides | 
|  | * whether to check intra modes. If so, estimates and selects best intra mode | 
|  | * from the reduced set of intra modes (max 4 intra modes checked) | 
|  | * | 
|  | * \param[in]    cpi                      Top-level encoder structure | 
|  | * \param[in]    x                        Pointer to structure holding all the | 
|  | *                                        data for the current macroblock | 
|  | * \param[in]    bsize                    Current block size | 
|  | * \param[in]    best_early_term          Flag, indicating that TX for the | 
|  | *                                        best inter mode was skipped | 
|  | * \param[in]    ref_cost_intra           Cost of signalling intra mode | 
|  | * \param[in]    reuse_prediction         Flag, indicating prediction re-use | 
|  | * \param[in]    orig_dst                 Original destination buffer | 
|  | * \param[in]    tmp_buffers              Pointer to a temporary buffers for | 
|  | *                                        prediction re-use | 
|  | * \param[out]   this_mode_pred           Pointer to store prediction buffer | 
|  | *                                        for prediction re-use | 
|  | * \param[in]    best_rdc                 Pointer to RD cost for the best | 
|  | *                                        selected intra mode | 
|  | * \param[in]    best_pickmode            Pointer to a structure containing | 
|  | *                                        best mode picked so far | 
|  | * \param[in]    ctx                      Pointer to structure holding coding | 
|  | *                                        contexts and modes for the block | 
|  | * | 
|  | * \remark Nothing is returned. Instead, calculated RD cost is placed to | 
|  | * \c best_rdc and best selected mode is placed to \c best_pickmode | 
|  | * | 
|  | */ | 
|  | void av1_estimate_intra_mode(AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, | 
|  | int best_early_term, unsigned int ref_cost_intra, | 
|  | int reuse_prediction, struct buf_2d *orig_dst, | 
|  | PRED_BUFFER *tmp_buffers, | 
|  | PRED_BUFFER **this_mode_pred, RD_STATS *best_rdc, | 
|  | BEST_PICKMODE *best_pickmode, | 
|  | PICK_MODE_CONTEXT *ctx, | 
|  | unsigned int *best_sad_norm) { | 
|  | AV1_COMMON *const cm = &cpi->common; | 
|  | MACROBLOCKD *const xd = &x->e_mbd; | 
|  | MB_MODE_INFO *const mi = xd->mi[0]; | 
|  | const TxfmSearchParams *txfm_params = &x->txfm_search_params; | 
|  | const unsigned char segment_id = mi->segment_id; | 
|  | const int *const rd_threshes = cpi->rd.threshes[segment_id][bsize]; | 
|  | const int *const rd_thresh_freq_fact = x->thresh_freq_fact[bsize]; | 
|  | const bool is_screen_content = | 
|  | cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN; | 
|  | struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; | 
|  | const REAL_TIME_SPEED_FEATURES *const rt_sf = &cpi->sf.rt_sf; | 
|  |  | 
|  | const CommonQuantParams *quant_params = &cm->quant_params; | 
|  |  | 
|  | RD_STATS this_rdc; | 
|  |  | 
|  | int intra_cost_penalty = av1_get_intra_cost_penalty( | 
|  | quant_params->base_qindex, quant_params->y_dc_delta_q, | 
|  | cm->seq_params->bit_depth); | 
|  | int64_t inter_mode_thresh = | 
|  | RDCOST(x->rdmult, ref_cost_intra + intra_cost_penalty, 0); | 
|  | int perform_intra_pred = rt_sf->check_intra_pred_nonrd; | 
|  | int force_intra_check = 0; | 
|  | // For spatial enhancement layer: turn off intra prediction if the | 
|  | // previous spatial layer as golden ref is not chosen as best reference. | 
|  | // only do this for temporal enhancement layer and on non-key frames. | 
|  | if (cpi->svc.spatial_layer_id > 0 && | 
|  | best_pickmode->best_ref_frame != GOLDEN_FRAME && | 
|  | cpi->svc.temporal_layer_id > 0 && | 
|  | !cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame) | 
|  | perform_intra_pred = 0; | 
|  |  | 
|  | int do_early_exit_rdthresh = 1; | 
|  |  | 
|  | uint32_t spatial_var_thresh = 50; | 
|  | int motion_thresh = 32; | 
|  | // Adjust thresholds to make intra mode likely tested if the other | 
|  | // references (golden, alt) are skipped/not checked. For now always | 
|  | // adjust for svc mode. | 
|  | if (cpi->ppi->use_svc || (rt_sf->use_nonrd_altref_frame == 0 && | 
|  | rt_sf->nonrd_prune_ref_frame_search > 0)) { | 
|  | spatial_var_thresh = 150; | 
|  | motion_thresh = 0; | 
|  | } | 
|  |  | 
|  | // Some adjustments to checking intra mode based on source variance. | 
|  | if (x->source_variance < spatial_var_thresh) { | 
|  | // If the best inter mode is large motion or non-LAST ref reduce intra cost | 
|  | // penalty, so intra mode is more likely tested. | 
|  | if (best_rdc->rdcost != INT64_MAX && | 
|  | (best_pickmode->best_ref_frame != LAST_FRAME || | 
|  | abs(mi->mv[0].as_mv.row) >= motion_thresh || | 
|  | abs(mi->mv[0].as_mv.col) >= motion_thresh)) { | 
|  | intra_cost_penalty = intra_cost_penalty >> 2; | 
|  | inter_mode_thresh = | 
|  | RDCOST(x->rdmult, ref_cost_intra + intra_cost_penalty, 0); | 
|  | do_early_exit_rdthresh = 0; | 
|  | } | 
|  | if ((x->source_variance < AOMMAX(50, (spatial_var_thresh >> 1)) && | 
|  | x->content_state_sb.source_sad_nonrd >= kHighSad) || | 
|  | (is_screen_content && x->source_variance < 50 && | 
|  | ((bsize >= BLOCK_32X32 && | 
|  | x->content_state_sb.source_sad_nonrd != kZeroSad) || | 
|  | x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] == 1 || | 
|  | x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)] == 1))) | 
|  | force_intra_check = 1; | 
|  | // For big blocks worth checking intra (since only DC will be checked), | 
|  | // even if best_early_term is set. | 
|  | if (bsize >= BLOCK_32X32) best_early_term = 0; | 
|  | } else if (rt_sf->source_metrics_sb_nonrd && | 
|  | x->content_state_sb.source_sad_nonrd <= kLowSad) { | 
|  | perform_intra_pred = 0; | 
|  | } | 
|  |  | 
|  | if (best_rdc->skip_txfm && best_pickmode->best_mode_initial_skip_flag) { | 
|  | if (rt_sf->skip_intra_pred == 1 && best_pickmode->best_mode != NEWMV) | 
|  | perform_intra_pred = 0; | 
|  | else if (rt_sf->skip_intra_pred == 2) | 
|  | perform_intra_pred = 0; | 
|  | } | 
|  |  | 
|  | if (!(best_rdc->rdcost == INT64_MAX || force_intra_check || | 
|  | (perform_intra_pred && !best_early_term && | 
|  | bsize <= cpi->sf.part_sf.max_intra_bsize))) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Early exit based on RD cost calculated using known rate. When | 
|  | // is_screen_content is true, more bias is given to intra modes. Hence, | 
|  | // considered conservative threshold in early exit for the same. | 
|  | const int64_t known_rd = is_screen_content | 
|  | ? CALC_BIASED_RDCOST(inter_mode_thresh) | 
|  | : inter_mode_thresh; | 
|  | if (known_rd > best_rdc->rdcost) return; | 
|  |  | 
|  | struct estimate_block_intra_args args; | 
|  | init_estimate_block_intra_args(&args, cpi, x); | 
|  | if (prune_palette_testing_inter(cpi, x->source_variance)) | 
|  | args.prune_palette_sad = true; | 
|  | TX_SIZE intra_tx_size = AOMMIN( | 
|  | AOMMIN(max_txsize_lookup[bsize], | 
|  | tx_mode_to_biggest_tx_size[txfm_params->tx_mode_search_type]), | 
|  | TX_16X16); | 
|  | if (is_screen_content && cpi->rc.high_source_sad && | 
|  | x->source_variance > spatial_var_thresh && bsize <= BLOCK_16X16) | 
|  | intra_tx_size = TX_4X4; | 
|  |  | 
|  | PRED_BUFFER *const best_pred = best_pickmode->best_pred; | 
|  | if (reuse_prediction && best_pred != NULL) { | 
|  | const int bh = block_size_high[bsize]; | 
|  | const int bw = block_size_wide[bsize]; | 
|  | if (best_pred->data == orig_dst->buf) { | 
|  | *this_mode_pred = &tmp_buffers[get_pred_buffer(tmp_buffers, 3)]; | 
|  | aom_convolve_copy(best_pred->data, best_pred->stride, | 
|  | (*this_mode_pred)->data, (*this_mode_pred)->stride, bw, | 
|  | bh); | 
|  | best_pickmode->best_pred = *this_mode_pred; | 
|  | } | 
|  | } | 
|  | pd->dst = *orig_dst; | 
|  |  | 
|  | for (int midx = 0; midx < RTC_INTRA_MODES; ++midx) { | 
|  | const PREDICTION_MODE this_mode = intra_mode_list[midx]; | 
|  | const THR_MODES mode_index = mode_idx[INTRA_FRAME][mode_offset(this_mode)]; | 
|  | const int64_t mode_rd_thresh = rd_threshes[mode_index]; | 
|  |  | 
|  | if (is_prune_intra_mode(cpi, midx, force_intra_check, bsize, segment_id, | 
|  | x->content_state_sb.source_sad_nonrd, | 
|  | x->color_sensitivity)) | 
|  | continue; | 
|  |  | 
|  | if (is_screen_content && rt_sf->source_metrics_sb_nonrd) { | 
|  | // For spatially flat blocks with zero motion only check | 
|  | // DC mode. | 
|  | if (x->content_state_sb.source_sad_nonrd == kZeroSad && | 
|  | x->source_variance == 0 && this_mode != DC_PRED) | 
|  | continue; | 
|  | // Only test Intra for big blocks if spatial_variance is small. | 
|  | else if (bsize > BLOCK_32X32 && x->source_variance > 50) | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (rd_less_than_thresh(best_rdc->rdcost, mode_rd_thresh, | 
|  | rd_thresh_freq_fact[mode_index]) && | 
|  | (do_early_exit_rdthresh || this_mode == SMOOTH_PRED)) { | 
|  | continue; | 
|  | } | 
|  | const BLOCK_SIZE uv_bsize = | 
|  | get_plane_block_size(bsize, xd->plane[AOM_PLANE_U].subsampling_x, | 
|  | xd->plane[AOM_PLANE_U].subsampling_y); | 
|  |  | 
|  | mi->mode = this_mode; | 
|  | mi->ref_frame[0] = INTRA_FRAME; | 
|  | mi->ref_frame[1] = NONE_FRAME; | 
|  |  | 
|  | av1_invalid_rd_stats(&this_rdc); | 
|  | args.mode = this_mode; | 
|  | args.skippable = 1; | 
|  | args.rdc = &this_rdc; | 
|  | mi->tx_size = intra_tx_size; | 
|  | compute_intra_yprediction(cm, this_mode, bsize, x, xd); | 
|  | // Look into selecting tx_size here, based on prediction residual. | 
|  | av1_block_yrd(x, &this_rdc, &args.skippable, bsize, mi->tx_size); | 
|  | // TODO(kyslov@) Need to account for skippable | 
|  | if (x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)]) { | 
|  | av1_foreach_transformed_block_in_plane(xd, uv_bsize, AOM_PLANE_U, | 
|  | av1_estimate_block_intra, &args); | 
|  | } | 
|  | if (x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)]) { | 
|  | av1_foreach_transformed_block_in_plane(xd, uv_bsize, AOM_PLANE_V, | 
|  | av1_estimate_block_intra, &args); | 
|  | } | 
|  |  | 
|  | int mode_cost = 0; | 
|  | if (av1_is_directional_mode(this_mode) && av1_use_angle_delta(bsize)) { | 
|  | mode_cost += | 
|  | x->mode_costs.angle_delta_cost[this_mode - V_PRED] | 
|  | [MAX_ANGLE_DELTA + | 
|  | mi->angle_delta[PLANE_TYPE_Y]]; | 
|  | } | 
|  | if (this_mode == DC_PRED && av1_filter_intra_allowed_bsize(cm, bsize)) { | 
|  | mode_cost += x->mode_costs.filter_intra_cost[bsize][0]; | 
|  | } | 
|  | this_rdc.rate += ref_cost_intra; | 
|  | this_rdc.rate += intra_cost_penalty; | 
|  | this_rdc.rate += mode_cost; | 
|  | this_rdc.rdcost = RDCOST(x->rdmult, this_rdc.rate, this_rdc.dist); | 
|  |  | 
|  | if (is_screen_content && rt_sf->source_metrics_sb_nonrd) { | 
|  | // For blocks with low spatial variance and color sad, | 
|  | // favor the intra-modes, only on scene/slide change. | 
|  | if (cpi->rc.high_source_sad && x->source_variance < 800 && | 
|  | (x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] || | 
|  | x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)])) | 
|  | this_rdc.rdcost = CALC_BIASED_RDCOST(this_rdc.rdcost); | 
|  | // Otherwise bias against intra for blocks with zero | 
|  | // motion and no color, on non-scene/slide changes. | 
|  | else if (!cpi->rc.high_source_sad && x->source_variance > 0 && | 
|  | x->content_state_sb.source_sad_nonrd == kZeroSad && | 
|  | x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] == 0 && | 
|  | x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)] == 0) | 
|  | this_rdc.rdcost = (3 * this_rdc.rdcost) >> 1; | 
|  | } | 
|  |  | 
|  | if (this_rdc.rdcost < best_rdc->rdcost) { | 
|  | *best_rdc = this_rdc; | 
|  | best_pickmode->best_mode = this_mode; | 
|  | best_pickmode->best_tx_size = mi->tx_size; | 
|  | best_pickmode->best_ref_frame = INTRA_FRAME; | 
|  | best_pickmode->best_second_ref_frame = NONE; | 
|  | best_pickmode->best_mode_skip_txfm = this_rdc.skip_txfm; | 
|  | mi->uv_mode = this_mode; | 
|  | mi->mv[0].as_int = INVALID_MV; | 
|  | mi->mv[1].as_int = INVALID_MV; | 
|  | if (!this_rdc.skip_txfm) | 
|  | memset(ctx->blk_skip, 0, | 
|  | sizeof(x->txfm_search_info.blk_skip[0]) * ctx->num_4x4_blk); | 
|  | } | 
|  | } | 
|  | if (best_pickmode->best_ref_frame == INTRA_FRAME) | 
|  | memset(ctx->blk_skip, 0, | 
|  | sizeof(x->txfm_search_info.blk_skip[0]) * ctx->num_4x4_blk); | 
|  | mi->tx_size = best_pickmode->best_tx_size; | 
|  |  | 
|  | *best_sad_norm = args.best_sad >> | 
|  | (b_width_log2_lookup[bsize] + b_height_log2_lookup[bsize]); | 
|  | } |