Coverage Report

Created: 2026-07-16 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/svt-av1/Source/Lib/Codec/mode_decision.c
Line
Count
Source
1
/*
2
* Copyright(c) 2019 Intel Corporation
3
* Copyright (c) 2016, Alliance for Open Media. All rights reserved
4
*
5
* This source code is subject to the terms of the BSD 3-Clause Clear License and
6
* the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear License
7
* was not distributed with this source code in the LICENSE file, you can
8
* obtain it at https://www.aomedia.org/license. If the Alliance for Open
9
* Media Patent License 1.0 was not distributed with this source code in the
10
* PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
11
*/
12
13
/***************************************
14
* Includes
15
***************************************/
16
#include <stdbool.h>
17
#include <stdio.h>
18
#include <stdlib.h>
19
#include <limits.h>
20
21
#include "common_utils.h"
22
#include "enc_dec_process.h"
23
#include "definitions.h"
24
#include "sequence_control_set.h"
25
#include "mode_decision.h"
26
#include "md_process.h"
27
#include "motion_estimation.h"
28
29
#include "av1me.h"
30
#include "hash.h"
31
#include "enc_inter_prediction.h"
32
#include "rd_cost.h"
33
#include "aom_dsp_rtcd.h"
34
#include "svt_log.h"
35
#include "resize.h"
36
#include "mcomp.h"
37
#include "ac_bias.h"
38
#include "src_ops_process.h"
39
#include "utility.h"
40
#include "adaptive_mv_pred.h"
41
#include "av1me.h"
42
static const uint32_t intra_luma_to_chroma[INTRA_MODES] = {
43
    UV_DC_PRED, // Average of above and left pixels
44
    UV_V_PRED, // Vertical
45
    UV_H_PRED, // Horizontal
46
    UV_D45_PRED, // Directional 45  degree
47
    UV_D135_PRED, // Directional 135 degree
48
    UV_D113_PRED, // Directional 113 degree
49
    UV_D157_PRED, // Directional 157 degree
50
    UV_D203_PRED, // Directional 203 degree
51
    UV_D67_PRED, // Directional 67  degree
52
    UV_SMOOTH_PRED, // Combination of horizontal and vertical interpolation
53
    UV_SMOOTH_V_PRED, // Vertical interpolation
54
    UV_SMOOTH_H_PRED, // Horizontal interpolation
55
    UV_PAETH_PRED, // Predict from the direction of smallest gradient
56
};
57
58
void calc_target_weighted_pred(PictureControlSet* pcs, ModeDecisionContext* ctx, const Av1Common* cm,
59
                               const MacroBlockD* xd, int mi_row, int mi_col, const uint8_t* above, int above_stride,
60
                               const uint8_t* left, int left_stride);
61
#define INC_MD_CAND_CNT(cnt, max_can_count)                  \
62
278k
    MULTI_LINE_MACRO_BEGIN                                   \
63
278k
    if (cnt + 1 < max_can_count)                             \
64
280k
        cnt++;                                               \
65
278k
    else                                                     \
66
18.4E
        SVT_ERROR("Mode decision candidate count exceeded"); \
67
278k
    MULTI_LINE_MACRO_END
68
69
0
#define SUPERRES_INVALID_STATE 0x7fffffff
70
71
2.64M
bool svt_av1_is_lossless_segment(PictureControlSet* pcs, int8_t segment_id) {
72
2.64M
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
73
2.64M
    if (frm_hdr->segmentation_params.segmentation_enabled) {
74
0
        return pcs->lossless[segment_id];
75
2.64M
    } else {
76
2.64M
        return pcs->lossless[0];
77
2.64M
    }
78
2.64M
}
79
80
0
static bool check_mv_validity(int16_t x_mv, int16_t y_mv, uint8_t need_shift) {
81
0
    Mv mv;
82
    //go to 1/8th if input is 1/4pel
83
0
    mv.y = y_mv << need_shift;
84
0
    mv.x = x_mv << need_shift;
85
    /* AV1 limits
86
      -16384 < MV_x_in_1/8 or MV_y_in_1/8 < 16384
87
      which means in full pel:
88
      -2048 < MV_x_in_full_pel or MV_y_in_full_pel < 2048
89
    */
90
0
    if (!is_mv_valid(&mv)) {
91
0
        return false;
92
0
    }
93
0
    return true;
94
0
}
95
96
int svt_is_interintra_allowed(uint8_t enable_inter_intra, BlockSize bsize, PredictionMode mode,
97
0
                              const MvReferenceFrame ref_frame[2]) {
98
0
    return enable_inter_intra && svt_aom_is_interintra_allowed_bsize((const BlockSize)bsize) &&
99
0
        svt_aom_is_interintra_allowed_mode(mode) && svt_aom_is_interintra_allowed_ref(ref_frame);
100
0
}
101
102
0
int svt_aom_filter_intra_allowed_bsize(BlockSize bs) {
103
0
    return block_size_wide[bs] <= 32 && block_size_high[bs] <= 32;
104
0
}
105
106
280k
int svt_aom_filter_intra_allowed(uint8_t enable_filter_intra, BlockSize bsize, uint8_t palette_size, uint32_t mode) {
107
280k
    return enable_filter_intra && mode == DC_PRED && palette_size == 0 && svt_aom_filter_intra_allowed_bsize(bsize);
108
280k
}
109
110
// returns the max inter-inter compound type based on settings and block size
111
0
static MD_COMP_TYPE get_tot_comp_types_bsize(MD_COMP_TYPE tot_comp_types, BlockSize bsize) {
112
0
    return (svt_aom_get_wedge_params_bits(bsize) == 0) ? MIN(tot_comp_types, MD_COMP_WEDGE) : tot_comp_types;
113
0
}
114
115
/*
116
Get the ME offset for a given block (the offset used to locate the PA MVs from the parent PCS).
117
*/
118
uint32_t svt_aom_get_me_block_offset(const uint32_t org_x, const uint32_t org_y, const BlockSize bsize,
119
139k
                                     const uint8_t enable_me_8x8, const uint8_t enable_me_16x16) {
120
139k
    const int      bwidth     = block_size_wide[bsize];
121
139k
    const int      bheight    = block_size_high[bsize];
122
139k
    const uint32_t max_length = MAX(bwidth, bheight);
123
124
139k
    uint32_t me_idx = 0;
125
139k
    switch (max_length) {
126
0
    case 4:
127
135k
    case 8:
128
135k
        me_idx++;
129
135k
        if (org_x & 8) { // (org_x % 16) / 8
130
65.6k
            me_idx += 1;
131
65.6k
        }
132
135k
        if (org_y & 8) { // (org_y % 16) / 8
133
65.7k
            me_idx += 2;
134
65.7k
        }
135
135k
        AOM_FALLTHROUGH_INTENDED;
136
136k
    case 16:
137
136k
        me_idx++;
138
136k
        if (org_x & 16) { // (org_x % 32) / 16
139
64.9k
            me_idx += 5;
140
64.9k
        }
141
136k
        if (org_y & 16) { // (org_y % 32) / 16
142
64.7k
            me_idx += 10;
143
64.7k
        }
144
136k
        AOM_FALLTHROUGH_INTENDED;
145
137k
    case 32:
146
137k
        me_idx++;
147
137k
        if (org_x & 32) { // (org_x % 64) / 32
148
63.8k
            me_idx += 21;
149
63.8k
        }
150
137k
        if (org_y & 32) { // (org_y % 64) / 32
151
63.3k
            me_idx += 42;
152
63.3k
        }
153
137k
        break;
154
2.33k
    default:
155
        // me_idx = 0;
156
2.33k
        break;
157
139k
    }
158
159
139k
    uint32_t me_block_offset = me_idx_85[me_idx]; // convert idx to me_idx
160
161
139k
    if (!enable_me_8x8) {
162
139k
        if (me_block_offset >= MAX_SB64_PU_COUNT_NO_8X8) {
163
135k
            me_block_offset = me_idx_85_8x8_to_16x16_conversion[me_block_offset - MAX_SB64_PU_COUNT_NO_8X8];
164
135k
        }
165
139k
        assert(me_block_offset < 21);
166
139k
        if (!enable_me_16x16) {
167
0
            if (me_block_offset >= MAX_SB64_PU_COUNT_WO_16X16) {
168
0
                assert(me_block_offset < 21);
169
0
                me_block_offset = me_idx_16x16_to_parent_32x32_conversion[me_block_offset - MAX_SB64_PU_COUNT_WO_16X16];
170
0
            }
171
0
        }
172
139k
    }
173
174
139k
    return me_block_offset;
175
139k
}
176
177
//Given one reference frame identified by the pair (list_index,ref_index)
178
//indicate if ME data is valid
179
uint8_t svt_aom_is_me_data_present(uint32_t me_block_offset, uint32_t me_cand_offset, const MeSbResults* me_results,
180
0
                                   uint8_t list_idx, uint8_t ref_idx) {
181
0
    uint8_t            total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
182
0
    const MeCandidate* me_block_results = &me_results->me_candidate_array[me_cand_offset];
183
0
    for (uint32_t me_cand_i = 0; me_cand_i < total_me_cnt; ++me_cand_i) {
184
0
        const MeCandidate* me_cand = &me_block_results[me_cand_i];
185
0
        assert(me_cand->direction <= 2);
186
0
        if (me_cand->direction == 0 || me_cand->direction == 2) {
187
0
            if (list_idx == me_cand->ref0_list && ref_idx == me_cand->ref_idx_l0) {
188
0
                return 1;
189
0
            }
190
0
        }
191
0
        if (me_cand->direction == 1 || me_cand->direction == 2) {
192
0
            if (list_idx == me_cand->ref1_list && ref_idx == me_cand->ref_idx_l1) {
193
0
                return 1;
194
0
            }
195
0
        }
196
0
    }
197
0
    return 0;
198
0
}
199
200
/********************************************
201
* Constants
202
********************************************/
203
// 1 - Regular uni-pred ,
204
// 2 - Regular uni-pred + Wedge compound Inter Intra
205
// 3 - Regular uni-pred + Wedge compound Inter Intra + Smooth compound Inter Intra
206
207
#if CONFIG_ENABLE_OBMC
208
0
static bool warped_motion_mode_allowed(PictureControlSet* pcs, ModeDecisionContext* ctx) {
209
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
210
0
    return frm_hdr->allow_warped_motion && has_overlappable_candidates(ctx->blk_ptr) && ctx->blk_geom->bwidth >= 8 &&
211
0
        ctx->blk_geom->bheight >= 8 && ctx->wm_ctrls.enabled;
212
0
}
213
#endif
214
MotionMode svt_aom_obmc_motion_mode_allowed(
215
    const PictureControlSet* pcs, ModeDecisionContext* ctx, const BlockSize bsize,
216
    uint8_t          situation, // 0: candidate(s) preparation, 1: data preparation, 2: simple translation face-off
217
0
    MvReferenceFrame rf0, MvReferenceFrame rf1, PredictionMode mode) {
218
0
    if (ctx->obmc_ctrls.trans_face_off && !situation) {
219
0
        return SIMPLE_TRANSLATION;
220
0
    }
221
    // check if should cap the max block size for obmc
222
223
0
    if (block_size_wide[bsize] > ctx->obmc_ctrls.max_blk_size ||
224
0
        block_size_high[bsize] > ctx->obmc_ctrls.max_blk_size) {
225
0
        return SIMPLE_TRANSLATION;
226
0
    }
227
0
    if (!ctx->obmc_ctrls.enabled) {
228
0
        return SIMPLE_TRANSLATION;
229
0
    }
230
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
231
232
0
    if (!frm_hdr->is_motion_mode_switchable) {
233
0
        return SIMPLE_TRANSLATION;
234
0
    }
235
236
0
    if (frm_hdr->force_integer_mv == 0) {
237
0
        const TransformationType gm_type = pcs->ppcs->global_motion[rf0].wmtype;
238
0
        if (is_global_mv_block(mode, bsize, gm_type)) {
239
0
            return SIMPLE_TRANSLATION;
240
0
        }
241
0
    }
242
0
    if (is_motion_variation_allowed_bsize(bsize) && is_inter_singleref_mode(mode) && rf1 != INTRA_FRAME &&
243
0
        !(rf1 > INTRA_FRAME)) // is_motion_variation_allowed_compound
244
0
    {
245
0
        if (!has_overlappable_candidates(ctx->blk_ptr)) { // check_num_overlappable_neighbors
246
0
            return SIMPLE_TRANSLATION;
247
0
        }
248
249
0
        return OBMC_CAUSAL;
250
0
    } else {
251
0
        return SIMPLE_TRANSLATION;
252
0
    }
253
0
}
254
255
//static uint32_t  AntiContouringIntraMode[11] = { EB_INTRA_PLANAR, EB_INTRA_DC, EB_INTRA_HORIZONTAL, EB_INTRA_VERTICAL,
256
//EB_INTRA_MODE_2, EB_INTRA_MODE_6, EB_INTRA_MODE_14, EB_INTRA_MODE_18, EB_INTRA_MODE_22, EB_INTRA_MODE_30, EB_INTRA_MODE_34 };
257
0
int32_t svt_aom_have_newmv_in_inter_mode(PredictionMode mode) {
258
0
    return (mode == NEWMV || mode == NEW_NEWMV || mode == NEAREST_NEWMV || mode == NEW_NEARESTMV ||
259
0
            mode == NEAR_NEWMV || mode == NEW_NEARMV);
260
0
}
261
262
static MvReferenceFrame to_ref_frame[2][4] = {{LAST_FRAME, LAST2_FRAME, LAST3_FRAME, GOLDEN_FRAME},
263
                                              {BWDREF_FRAME, ALTREF2_FRAME, ALTREF_FRAME, INVALID_REF}};
264
265
0
MvReferenceFrame svt_get_ref_frame_type(uint8_t list, uint8_t ref_idx) {
266
0
    return to_ref_frame[list][ref_idx];
267
0
};
268
269
0
uint8_t svt_aom_get_max_drl_index(uint8_t refmvCnt, PredictionMode mode) {
270
0
    uint8_t max_drl = 0;
271
272
0
    if (mode == NEWMV || mode == NEW_NEWMV) {
273
0
        if (refmvCnt < 2) {
274
0
            max_drl = 1;
275
0
        } else if (refmvCnt == 2) {
276
0
            max_drl = 2;
277
0
        } else {
278
0
            max_drl = 3;
279
0
        }
280
0
    }
281
282
0
    if (mode == NEARMV || mode == NEAR_NEARMV || mode == NEAR_NEWMV || mode == NEW_NEARMV) {
283
0
        if (refmvCnt < 3) {
284
0
            max_drl = 1;
285
0
        } else if (refmvCnt == 3) {
286
0
            max_drl = 2;
287
0
        } else {
288
0
            max_drl = 3;
289
0
        }
290
0
    }
291
292
0
    return max_drl;
293
0
}
294
295
0
#define MV_COST_WEIGHT 108
296
297
static int64_t pick_interintra_wedge(PictureControlSet* pcs, ModeDecisionContext* ctx, const BlockSize bsize,
298
                                     const uint8_t* const p0, const uint8_t* const p1, uint8_t* src_buf,
299
0
                                     uint32_t src_stride, int8_t* wedge_index_out) {
300
0
    assert(svt_aom_is_interintra_wedge_used(bsize));
301
    // assert(cpi->common.seq_params.enable_interintra_compound);
302
303
0
    const int bw = block_size_wide[bsize];
304
0
    const int bh = block_size_high[bsize];
305
0
    DECLARE_ALIGNED(32, int16_t, residual1[MAX_INTERINTRA_SB_SQUARE]); // src - pred1
306
0
    DECLARE_ALIGNED(32, int16_t, diff10[MAX_INTERINTRA_SB_SQUARE]); // pred1 - pred0
307
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
308
0
    if (ctx->hbd_md) {
309
0
        svt_aom_highbd_subtract_block(bh, bw, residual1, bw, src_buf, src_stride, p1, bw, EB_TEN_BIT);
310
0
        svt_aom_highbd_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw, EB_TEN_BIT);
311
312
0
    } else
313
0
#endif
314
0
    {
315
0
        svt_aom_subtract_block(bh, bw, residual1, bw, src_buf, src_stride, p1, bw);
316
0
        svt_aom_subtract_block(bh, bw, diff10, bw, p1, bw, p0, bw);
317
0
    }
318
319
0
    int8_t  wedge_index = -1;
320
0
    int64_t rd          = pick_wedge_fixed_sign(pcs, ctx, bsize, residual1, diff10, 0, &wedge_index);
321
0
    *wedge_index_out    = wedge_index;
322
323
0
    return rd;
324
0
}
325
326
0
static void inter_intra_search(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand) {
327
0
    SequenceControlSet* scs = pcs->scs;
328
0
    DECLARE_ALIGNED(16, uint8_t, tmp_buf[2 * MAX_INTERINTRA_SB_SQUARE]);
329
0
    DECLARE_ALIGNED(16, uint8_t, ii_pred_buf[2 * MAX_INTERINTRA_SB_SQUARE]);
330
    // get inter pred for ref0
331
0
    EbPictureBufferDesc* src_pic = ctx->hbd_md ? pcs->input_frame16bit : pcs->ppcs->enhanced_pic;
332
0
    uint16_t* src_buf_hbd = (uint16_t*)src_pic->y_buffer + (ctx->blk_org_x) + (ctx->blk_org_y) * src_pic->y_stride;
333
0
    uint8_t*  src_buf     = src_pic->y_buffer + (ctx->blk_org_x) + (ctx->blk_org_y) * src_pic->y_stride;
334
335
0
    uint8_t  bit_depth   = ctx->hbd_md ? EB_TEN_BIT : EB_EIGHT_BIT;
336
0
    uint32_t full_lambda = ctx->hbd_md ? ctx->full_lambda_md[EB_10_BIT_MD] : ctx->full_lambda_md[EB_8_BIT_MD];
337
338
0
    uint32_t            bwidth  = ctx->blk_geom->bwidth;
339
0
    uint32_t            bheight = ctx->blk_geom->bheight;
340
0
    EbPictureBufferDesc pred_desc;
341
0
    pred_desc.border   = 0;
342
0
    pred_desc.y_stride = bwidth;
343
344
0
    EbPictureBufferDesc* ref_pic_list0 = svt_aom_get_ref_pic_buffer(pcs, cand->block_mi.ref_frame[0]);
345
0
    EbPictureBufferDesc* ref_pic_list1 = NULL;
346
347
    // Use scaled references if resolution of the reference is different from that of the input
348
    // Only have one ref
349
0
    if (ref_pic_list0 != NULL) {
350
0
        uint8_t list_idx0  = get_list_idx(cand->block_mi.ref_frame[0]);
351
0
        int8_t  ref_idx_l0 = get_ref_frame_idx(cand->block_mi.ref_frame[0]);
352
0
        svt_aom_use_scaled_rec_refs_if_needed(
353
0
            pcs,
354
0
            pcs->ppcs->enhanced_pic,
355
0
            (EbReferenceObject*)pcs->ref_pic_ptr_array[list_idx0][ref_idx_l0]->object_ptr,
356
0
            &ref_pic_list0,
357
0
            ctx->hbd_md);
358
0
    }
359
0
    pred_desc.y_buffer = tmp_buf;
360
361
    //we call the regular inter prediction path here (no compound)
362
0
    cand->block_mi.interp_filters     = 0;
363
0
    cand->block_mi.is_interintra_used = 0;
364
0
    svt_aom_inter_prediction(scs,
365
0
                             pcs,
366
0
                             &cand->block_mi,
367
0
                             &cand->wm_params_l0,
368
0
                             &cand->wm_params_l1,
369
0
                             ctx->blk_ptr,
370
0
                             ctx->blk_geom->bsize,
371
0
                             ctx->shape,
372
0
                             false, // use_precomputed_obmc
373
0
                             false, // use_precomputed_ii - ii not performed here
374
0
                             ctx,
375
0
                             NULL,
376
0
                             NULL,
377
0
                             NULL,
378
0
                             ref_pic_list0,
379
0
                             ref_pic_list1,
380
0
                             ctx->blk_org_x,
381
0
                             ctx->blk_org_y,
382
0
                             &pred_desc, //output
383
0
                             0, //output org_x,
384
0
                             0, //output org_y,
385
0
                             PICTURE_BUFFER_DESC_LUMA_MASK,
386
0
                             ctx->hbd_md ? EB_TEN_BIT : EB_EIGHT_BIT,
387
0
                             0); // is_16bit_pipeline
388
389
0
    assert(svt_aom_is_interintra_wedge_used(ctx->blk_geom->bsize)); //if not I need to add nowedge path!!
390
391
0
    int64_t        best_interintra_rd   = INT64_MAX;
392
0
    InterIntraMode best_interintra_mode = INTERINTRA_MODES;
393
0
    for (int j = 0; j < INTERINTRA_MODES; ++j) {
394
        // if ((!cpi->oxcf.enable_smooth_intra || cpi->sf.disable_smooth_intra) &&
395
        //     (InterIntraMode)j == II_SMOOTH_PRED)
396
        //   continue;
397
0
        InterIntraMode interintra_mode = (InterIntraMode)j;
398
        // rmode = interintra_mode_cost[mbmi->interintra_mode];
399
0
        const int bsize_group = eb_size_group_lookup[ctx->blk_geom->bsize];
400
0
        const int rmode       = ctx->md_rate_est_ctx->inter_intra_mode_fac_bits[bsize_group][interintra_mode];
401
        // av1_combine_interintra(xd, bsize, 0, tmp_buf, bw, intrapred, bw);
402
0
        if (ctx->hbd_md) {
403
0
            svt_aom_combine_interintra_highbd(interintra_mode, // mode,
404
0
                                              0, // use_wedge_interintra,
405
0
                                              0, // cand->interintra_wedge_index,
406
0
                                              0, // int wedge_sign,
407
0
                                              ctx->blk_geom->bsize,
408
0
                                              ctx->blk_geom->bsize, // plane_bsize,
409
0
                                              ii_pred_buf,
410
0
                                              bwidth, /*uint8_t *comppred, int compstride,*/
411
0
                                              tmp_buf,
412
0
                                              bwidth, /*const uint8_t *interpred, int interstride,*/
413
0
                                              ctx->intrapred_buf[j],
414
0
                                              bwidth /*const uint8_t *intrapred,   int intrastride*/,
415
0
                                              bit_depth);
416
0
        } else {
417
0
            svt_aom_combine_interintra(interintra_mode, //mode,
418
0
                                       0, //use_wedge_interintra,
419
0
                                       0, //cand->interintra_wedge_index,
420
0
                                       0, //int wedge_sign,
421
0
                                       ctx->blk_geom->bsize,
422
0
                                       ctx->blk_geom->bsize, // plane_bsize,
423
0
                                       ii_pred_buf,
424
0
                                       bwidth, /*uint8_t *comppred, int compstride,*/
425
0
                                       tmp_buf,
426
0
                                       bwidth, /*const uint8_t *interpred, int interstride,*/
427
0
                                       ctx->intrapred_buf[j],
428
0
                                       bwidth /*const uint8_t *intrapred,   int intrastride*/);
429
0
        }
430
0
        int64_t rd;
431
0
        if (ctx->inter_intra_comp_ctrls.use_rd_model) {
432
0
            int     rate_sum;
433
0
            int64_t dist_sum;
434
0
            model_rd_for_sb_with_curvfit(pcs,
435
0
                                         ctx,
436
0
                                         ctx->blk_geom->bsize,
437
0
                                         bwidth,
438
0
                                         bheight,
439
0
                                         ctx->hbd_md ? (uint8_t*)src_buf_hbd : src_buf,
440
0
                                         src_pic->y_stride,
441
0
                                         ii_pred_buf,
442
0
                                         bwidth,
443
0
                                         0,
444
0
                                         0,
445
0
                                         0,
446
0
                                         0,
447
0
                                         &rate_sum,
448
0
                                         &dist_sum,
449
0
                                         NULL,
450
0
                                         NULL,
451
0
                                         NULL);
452
453
0
            rd = RDCOST(full_lambda, rate_sum + rmode, dist_sum);
454
0
        } else {
455
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
456
0
            if (ctx->hbd_md) {
457
0
                rd = svt_aom_highbd_sse((uint8_t*)src_buf_hbd, src_pic->y_stride, ii_pred_buf, bwidth, bwidth, bheight);
458
0
            } else
459
0
#endif
460
0
            {
461
0
                rd = svt_aom_sse(src_buf, src_pic->y_stride, ii_pred_buf, bwidth, bwidth, bheight);
462
0
            }
463
0
        }
464
0
        if (rd < best_interintra_rd) {
465
0
            best_interintra_rd             = rd;
466
0
            cand->block_mi.interintra_mode = best_interintra_mode = interintra_mode;
467
0
        }
468
0
    }
469
    // To test: Enable wedge search if source variance and edge strength are above the thresholds.
470
    //CHKN need to re-do intra pred using the winner, or have a separate intra serch for wedge
471
0
    int64_t       best_interintra_rd_wedge = INT64_MAX;
472
0
    const uint8_t ii_wedge_mode            = ctx->shape == PART_N ? ctx->inter_intra_comp_ctrls.wedge_mode_sq
473
0
                                                                  : ctx->inter_intra_comp_ctrls.wedge_mode_nsq;
474
0
    if (ii_wedge_mode) {
475
0
        best_interintra_rd_wedge = pick_interintra_wedge(pcs,
476
0
                                                         ctx,
477
0
                                                         ctx->blk_geom->bsize,
478
0
                                                         ctx->intrapred_buf[best_interintra_mode],
479
0
                                                         tmp_buf,
480
0
                                                         ctx->hbd_md ? (uint8_t*)src_buf_hbd : src_buf,
481
0
                                                         src_pic->y_stride,
482
0
                                                         &cand->block_mi.interintra_wedge_index);
483
0
    }
484
485
    // for ii_wedge_mode 1, always inject wedge as a separate candidate; for wedge mode 2 only inject
486
    // if wedge is better than non-wedge
487
0
    if (ii_wedge_mode == 1 || best_interintra_rd_wedge < best_interintra_rd) {
488
0
        cand->block_mi.use_wedge_interintra = 1;
489
0
    } else {
490
0
        cand->block_mi.use_wedge_interintra = 0;
491
0
    }
492
0
}
493
494
static COMPOUND_TYPE to_av1_compound_lut[] = {COMPOUND_AVERAGE, COMPOUND_DISTWTD, COMPOUND_DIFFWTD, COMPOUND_WEDGE};
495
496
static void determine_compound_mode(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
497
0
                                    MD_COMP_TYPE cur_type) {
498
0
    BlockModeInfo* block_mi        = &cand->block_mi;
499
0
    block_mi->interinter_comp.type = to_av1_compound_lut[cur_type];
500
0
    switch (cur_type) {
501
0
    case MD_COMP_AVG:
502
0
        block_mi->comp_group_idx = 0;
503
0
        block_mi->compound_idx   = 1;
504
0
        break;
505
0
    case MD_COMP_DIST:
506
0
        block_mi->comp_group_idx = 0;
507
0
        block_mi->compound_idx   = 0;
508
0
        break;
509
0
    case MD_COMP_DIFF0:
510
0
        block_mi->comp_group_idx            = 1;
511
0
        block_mi->compound_idx              = 1;
512
0
        block_mi->interinter_comp.mask_type = 55;
513
0
        svt_aom_search_compound_diff_wedge(pcs, ctx, cand);
514
0
        break;
515
0
    case MD_COMP_WEDGE:
516
0
        block_mi->comp_group_idx = 1;
517
0
        block_mi->compound_idx   = 1;
518
0
        svt_aom_search_compound_diff_wedge(pcs, ctx, cand);
519
0
        break;
520
0
    default:
521
0
        SVT_ERROR("not used comp type\n");
522
0
        assert(0);
523
0
        break;
524
0
    }
525
0
}
526
527
void svt_aom_choose_best_av1_mv_pred(ModeDecisionContext* ctx, MvReferenceFrame ref_frame,
528
                                     PredictionMode mode, // NEW or NEW_NEW
529
                                     Mv mv0, Mv mv1,
530
                                     uint8_t* bestDrlIndex, // output
531
                                     Mv       best_pred_mv[2] // output
532
0
) {
533
0
    if (ctx->shut_fast_rate) {
534
0
        return;
535
0
    }
536
0
    if (ctx->approx_inter_rate > 1) {
537
0
        *bestDrlIndex   = 0;
538
0
        best_pred_mv[0] = ctx->ref_mv_stack[ref_frame][0].this_mv;
539
0
        best_pred_mv[1] = ctx->ref_mv_stack[ref_frame][0].comp_mv;
540
0
        return;
541
0
    }
542
0
    int16_t mv0x = mv0.x;
543
0
    int16_t mv0y = mv0.y;
544
0
    int16_t mv1x = mv1.x;
545
0
    int16_t mv1y = mv1.y;
546
547
0
    uint8_t is_compound = is_inter_compound_mode(mode);
548
549
0
    struct MdRateEstimationContext* md_rate_est_ctx = ctx->md_rate_est_ctx;
550
0
    BlkStruct*                      blk_ptr         = ctx->blk_ptr;
551
0
    uint8_t                         max_drl_index;
552
0
    Mv                              nearestmv[2] = {{{0}}, {{0}}};
553
0
    Mv                              nearmv[2];
554
0
    Mv                              ref_mv[2];
555
0
    Mv                              mv;
556
557
0
    max_drl_index = svt_aom_get_max_drl_index(blk_ptr->av1xd->ref_mv_count[ref_frame], mode);
558
    // max_drl_index = 1;
559
560
0
    if (max_drl_index == 1) {
561
0
        *bestDrlIndex = 0;
562
563
0
        best_pred_mv[0] = ctx->ref_mv_stack[ref_frame][0].this_mv;
564
0
        best_pred_mv[1] = ctx->ref_mv_stack[ref_frame][0].comp_mv;
565
0
    } else {
566
0
        uint8_t  drli;
567
0
        uint32_t best_mv_cost = 0xFFFFFFFF;
568
0
        for (drli = 0; drli < max_drl_index; drli++) {
569
0
            svt_aom_get_av1_mv_pred_drl(ctx, blk_ptr, ref_frame, is_compound, mode, drli, nearestmv, nearmv, ref_mv);
570
571
            //compute the rate for this drli Cand
572
0
            mv.y             = mv0y;
573
0
            mv.x             = mv0x;
574
0
            uint32_t mv_rate = 0;
575
0
            if (ctx->approx_inter_rate) {
576
0
                mv_rate = (uint32_t)svt_av1_mv_bit_cost_light(&mv, &(ref_mv[0]));
577
0
            } else {
578
0
                mv_rate = (uint32_t)svt_av1_mv_bit_cost(
579
0
                    &mv, &(ref_mv[0]), md_rate_est_ctx->nmv_vec_cost, md_rate_est_ctx->nmvcoststack, MV_COST_WEIGHT);
580
0
            }
581
582
0
            if (is_compound) {
583
0
                mv.y = mv1y;
584
0
                mv.x = mv1x;
585
0
                if (ctx->approx_inter_rate) {
586
0
                    mv_rate += (uint32_t)svt_av1_mv_bit_cost_light(&mv, &(ref_mv[1]));
587
0
                } else {
588
0
                    mv_rate += (uint32_t)svt_av1_mv_bit_cost(&mv,
589
0
                                                             &(ref_mv[1]),
590
0
                                                             md_rate_est_ctx->nmv_vec_cost,
591
0
                                                             md_rate_est_ctx->nmvcoststack,
592
0
                                                             MV_COST_WEIGHT);
593
0
                }
594
0
            }
595
596
0
            const int32_t new_mv = (mode == NEWMV || mode == NEW_NEWMV);
597
0
            if (new_mv) {
598
0
                int32_t idx;
599
0
                for (idx = 0; idx < 2; ++idx) {
600
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame] > idx + 1) {
601
0
                        uint8_t drl_1_ctx = av1_drl_ctx(&(ctx->ref_mv_stack[ref_frame][0]), idx);
602
0
                        mv_rate += ctx->md_rate_est_ctx->drl_mode_fac_bits[drl_1_ctx][drli != idx];
603
0
                        if (drli == idx) {
604
0
                            break;
605
0
                        }
606
0
                    }
607
0
                }
608
0
            }
609
610
0
            if (mv_rate < best_mv_cost) {
611
0
                best_mv_cost    = mv_rate;
612
0
                *bestDrlIndex   = drli;
613
0
                best_pred_mv[0] = ref_mv[0];
614
0
                best_pred_mv[1] = ref_mv[1];
615
0
            }
616
0
        }
617
0
    }
618
0
}
619
620
0
static void mode_decision_cand_bf_dctor(EbPtr p) {
621
    // pred/rec_coeff/quant are borrowed from the MD-context pools; residual/recon are
622
    // shared (temp_*). Nothing is owned by the candidate buffer itself.
623
0
    (void)p;
624
0
}
625
626
2.82k
static void mode_decision_scratch_cand_bf_dctor(EbPtr p) {
627
2.82k
    ModeDecisionCandidateBuffer* obj = (ModeDecisionCandidateBuffer*)p;
628
2.82k
    EB_DELETE(obj->pred);
629
2.82k
    EB_DELETE(obj->residual);
630
2.82k
    EB_DELETE(obj->rec_coeff);
631
2.82k
    EB_DELETE(obj->recon);
632
2.82k
    EB_DELETE(obj->quant);
633
2.82k
}
634
635
/***************************************
636
* Mode Decision Candidate Ctor
637
***************************************/
638
EbErrorType svt_aom_mode_decision_cand_bf_ctor(ModeDecisionCandidateBuffer* buffer_ptr, EbPictureBufferDesc* pred,
639
                                               EbPictureBufferDesc* rec_coeff, EbPictureBufferDesc* quant,
640
                                               EbPictureBufferDesc* temp_residual, EbPictureBufferDesc* temp_recon_ptr,
641
14.1k
                                               uint64_t* fast_cost, uint64_t* full_cost, uint64_t* full_cost_ssim) {
642
14.1k
    buffer_ptr->dctor = mode_decision_cand_bf_dctor;
643
644
    // Candidate Ptr
645
14.1k
    buffer_ptr->cand = NULL;
646
647
    // Video Buffers — pred/rec_coeff/quant borrowed from MD-context pools; residual/recon
648
    // shared with the MD context.
649
14.1k
    buffer_ptr->pred      = pred;
650
14.1k
    buffer_ptr->residual  = temp_residual;
651
14.1k
    buffer_ptr->rec_coeff = rec_coeff;
652
14.1k
    buffer_ptr->quant     = quant;
653
14.1k
    buffer_ptr->recon     = temp_recon_ptr;
654
655
    // Costs
656
14.1k
    buffer_ptr->fast_cost      = fast_cost;
657
14.1k
    buffer_ptr->full_cost      = full_cost;
658
14.1k
    buffer_ptr->full_cost_ssim = full_cost_ssim;
659
14.1k
    return EB_ErrorNone;
660
14.1k
}
661
662
EbErrorType svt_aom_mode_decision_scratch_cand_bf_ctor(ModeDecisionCandidateBuffer* buffer_ptr, uint8_t sb_size,
663
2.82k
                                                       EbBitDepth max_bitdepth) {
664
2.82k
    EbPictureBufferDescInitData picture_buffer_desc_init_data;
665
2.82k
    EbPictureBufferDescInitData double_width_picture_buffer_desc_init_data;
666
2.82k
    EbPictureBufferDescInitData thirty_two_width_picture_buffer_desc_init_data;
667
668
2.82k
    buffer_ptr->dctor = mode_decision_scratch_cand_bf_dctor;
669
670
    // Init Picture Data
671
2.82k
    picture_buffer_desc_init_data.max_width                           = sb_size;
672
2.82k
    picture_buffer_desc_init_data.max_height                          = sb_size;
673
2.82k
    picture_buffer_desc_init_data.bit_depth                           = max_bitdepth;
674
2.82k
    picture_buffer_desc_init_data.color_format                        = EB_YUV420;
675
2.82k
    picture_buffer_desc_init_data.buffer_enable_mask                  = PICTURE_BUFFER_DESC_FULL_MASK;
676
2.82k
    picture_buffer_desc_init_data.border                              = 0;
677
2.82k
    picture_buffer_desc_init_data.split_mode                          = false;
678
2.82k
    picture_buffer_desc_init_data.is_16bit_pipeline                   = max_bitdepth > EB_EIGHT_BIT;
679
2.82k
    double_width_picture_buffer_desc_init_data.max_width              = sb_size;
680
2.82k
    double_width_picture_buffer_desc_init_data.max_height             = sb_size;
681
2.82k
    double_width_picture_buffer_desc_init_data.bit_depth              = EB_SIXTEEN_BIT;
682
2.82k
    double_width_picture_buffer_desc_init_data.color_format           = EB_YUV420;
683
2.82k
    double_width_picture_buffer_desc_init_data.buffer_enable_mask     = PICTURE_BUFFER_DESC_FULL_MASK;
684
2.82k
    double_width_picture_buffer_desc_init_data.border                 = 0;
685
2.82k
    double_width_picture_buffer_desc_init_data.split_mode             = false;
686
2.82k
    double_width_picture_buffer_desc_init_data.is_16bit_pipeline      = true;
687
2.82k
    thirty_two_width_picture_buffer_desc_init_data.max_width          = sb_size;
688
2.82k
    thirty_two_width_picture_buffer_desc_init_data.max_height         = sb_size;
689
2.82k
    thirty_two_width_picture_buffer_desc_init_data.bit_depth          = EB_THIRTYTWO_BIT;
690
2.82k
    thirty_two_width_picture_buffer_desc_init_data.color_format       = EB_YUV420;
691
2.82k
    thirty_two_width_picture_buffer_desc_init_data.buffer_enable_mask = PICTURE_BUFFER_DESC_FULL_MASK;
692
2.82k
    thirty_two_width_picture_buffer_desc_init_data.border             = 0;
693
2.82k
    thirty_two_width_picture_buffer_desc_init_data.split_mode         = false;
694
2.82k
    thirty_two_width_picture_buffer_desc_init_data.is_16bit_pipeline  = true;
695
696
    // Candidate Ptr
697
2.82k
    buffer_ptr->cand = NULL;
698
699
    // Video Buffers
700
2.82k
    EB_NEW(buffer_ptr->pred, svt_picture_buffer_desc_ctor, (EbPtr)&picture_buffer_desc_init_data);
701
2.82k
    EB_NEW(buffer_ptr->residual, svt_picture_buffer_desc_ctor, (EbPtr)&double_width_picture_buffer_desc_init_data);
702
2.82k
    EB_NEW(buffer_ptr->rec_coeff, svt_picture_buffer_desc_ctor, (EbPtr)&thirty_two_width_picture_buffer_desc_init_data);
703
2.82k
    EB_NEW(buffer_ptr->quant, svt_picture_buffer_desc_ctor, (EbPtr)&thirty_two_width_picture_buffer_desc_init_data);
704
705
2.82k
    EB_NEW(buffer_ptr->recon, svt_picture_buffer_desc_ctor, (EbPtr)&picture_buffer_desc_init_data);
706
2.82k
    return EB_ErrorNone;
707
2.82k
}
708
709
/***************************************
710
* return true if the MV candidate is already injected
711
***************************************/
712
0
static bool mv_is_already_injected(ModeDecisionContext* ctx, Mv mv0, Mv mv1, uint8_t ref_type) {
713
0
    MvReferenceFrame rf[2];
714
0
    av1_set_ref_frame(rf, ref_type);
715
716
    // Unipred Candidate
717
0
    if (rf[1] <= INTRA_FRAME) {
718
        // First check the validity of the candidate MV, and exit if invalid MV
719
0
        if (ctx->corrupted_mv_check && !check_mv_validity(mv0.x, mv0.y, 0)) {
720
0
            return true;
721
0
        }
722
723
0
        for (int cand_idx = 0; cand_idx < ctx->injected_mv_count; cand_idx++) {
724
0
            if (ctx->injected_ref_types[cand_idx] == ref_type && ctx->injected_mvs[cand_idx][0].as_int == mv0.as_int) {
725
0
                return true;
726
0
            }
727
0
        }
728
0
    } else { // Bipred Candidate
729
        // First check the validity of the candidate MV, and exit if invalid MV
730
0
        if (ctx->corrupted_mv_check && (!check_mv_validity(mv0.x, mv0.y, 0) || !check_mv_validity(mv1.x, mv1.y, 0))) {
731
0
            return true;
732
0
        }
733
734
0
        RedundantCandCtrls* redund_ctrls = &ctx->cand_reduction_ctrls.redundant_cand_ctrls;
735
0
        if (redund_ctrls->score_th) {
736
0
            uint8_t is_high_mag = (ABS(mv0.x) > redund_ctrls->mag_th) && (ABS(mv0.y) > redund_ctrls->mag_th) &&
737
0
                (ABS(mv1.x) > redund_ctrls->mag_th) && (ABS(mv1.y) > redund_ctrls->mag_th);
738
0
            for (int cand_idx = 0; cand_idx < ctx->injected_mv_count; cand_idx++) {
739
0
                if (ctx->injected_ref_types[cand_idx] == ref_type) {
740
0
                    int score = ABS(ctx->injected_mvs[cand_idx][0].x - mv0.x) +
741
0
                        ABS(ctx->injected_mvs[cand_idx][0].y - mv0.y) + ABS(ctx->injected_mvs[cand_idx][1].x - mv1.x) +
742
0
                        ABS(ctx->injected_mvs[cand_idx][1].y - mv1.y);
743
744
0
                    if (score == 0 || (score < redund_ctrls->score_th && is_high_mag)) {
745
0
                        return true;
746
0
                    }
747
0
                }
748
0
            }
749
0
        } else {
750
0
            for (int cand_idx = 0; cand_idx < ctx->injected_mv_count; cand_idx++) {
751
0
                if (ctx->injected_ref_types[cand_idx] == ref_type &&
752
0
                    ctx->injected_mvs[cand_idx][0].as_int == mv0.as_int &&
753
0
                    ctx->injected_mvs[cand_idx][1].as_int == mv1.as_int) {
754
0
                    return true;
755
0
                }
756
0
            }
757
0
        }
758
0
    }
759
0
    return false;
760
0
}
761
762
bool svt_aom_is_valid_unipred_ref(ModeDecisionContext* ctx, uint8_t inter_cand_group, uint8_t list_idx,
763
0
                                  uint8_t ref_idx) {
764
0
    if (!ctx->ref_pruning_ctrls.enabled) {
765
0
        return true;
766
0
    }
767
0
    if (!ctx->ref_filtering_res[inter_cand_group][list_idx][ref_idx].do_ref &&
768
0
        (ref_idx || !ctx->ref_pruning_ctrls.closest_refs[inter_cand_group])) {
769
0
        return false;
770
0
    } else {
771
0
        return true;
772
0
    }
773
0
}
774
775
// Determine if the MV-to-MVP difference satisfies the mv_diff restriction
776
0
static bool is_valid_mv_diff(Mv best_pred_mv[2], Mv mv0, Mv mv1, uint8_t is_compound) {
777
0
    const uint8_t mv_diff_max_bit = MV_IN_USE_BITS;
778
779
0
    if (abs(mv0.x - best_pred_mv[0].x) > (1 << mv_diff_max_bit) ||
780
0
        abs(mv0.y - best_pred_mv[0].y) > (1 << mv_diff_max_bit)) {
781
0
        return false;
782
0
    }
783
784
0
    if (is_compound) {
785
0
        if (abs(mv1.x - best_pred_mv[1].x) > (1 << mv_diff_max_bit) ||
786
0
            abs(mv1.y - best_pred_mv[1].y) > (1 << mv_diff_max_bit)) {
787
0
            return false;
788
0
        }
789
0
    }
790
0
    return true;
791
0
}
792
793
static bool is_valid_bipred_ref(ModeDecisionContext* ctx, uint8_t inter_cand_group, uint8_t list_idx_0,
794
0
                                uint8_t ref_idx_0, uint8_t list_idx_1, uint8_t ref_idx_1) {
795
0
    if (!ctx->ref_pruning_ctrls.enabled) {
796
0
        return true;
797
0
    }
798
    // Both ref should be 1 for bipred refs to be valid: if 1 is not best_refs then there is a chance to exit the injection
799
0
    if (!ctx->ref_filtering_res[inter_cand_group][list_idx_0][ref_idx_0].do_ref ||
800
0
        !ctx->ref_filtering_res[inter_cand_group][list_idx_1][ref_idx_1].do_ref) {
801
        // Check whether we should check the closest, if no then there no need to move forward and return false
802
0
        if (!ctx->ref_pruning_ctrls.closest_refs[inter_cand_group]) {
803
0
            return false;
804
0
        }
805
806
        // Else check if ref are LAST and BWD, if not then return false
807
0
        if (ref_idx_0 || ref_idx_1) {
808
0
            return false;
809
0
        }
810
0
    }
811
0
    return true;
812
0
}
813
814
0
#define BIPRED_3x3_REFINMENT_POSITIONS 8
815
816
static int8_t allow_refinement_flag[BIPRED_3x3_REFINMENT_POSITIONS] = {1, 0, 1, 0, 1, 0, 1, 0};
817
static int8_t bipred_3x3_x_pos[BIPRED_3x3_REFINMENT_POSITIONS]      = {-1, -1, 0, 1, 1, 1, 0, -1};
818
static int8_t bipred_3x3_y_pos[BIPRED_3x3_REFINMENT_POSITIONS]      = {0, 1, 1, 1, 0, -1, -1, -1};
819
820
138k
static INLINE uint8_t is_dc_only_safe(PictureControlSet* pcs, ModeDecisionContext* ctx) {
821
    // Early exit if pruning not enabled, SB-128, NSQ, or 4x4 (no variance available)
822
138k
    if (!ctx->intra_ctrls.prune_using_edge_info || pcs->scs->super_block_size == 128 || ctx->shape != PART_N ||
823
138k
        ctx->blk_geom->sq_size == 4) {
824
0
        return 0;
825
0
    }
826
827
    // Block variance lookup
828
138k
    int            blk_idx;
829
138k
    int            sub_idx[4];
830
138k
    const Position blk_org = {.x = ctx->blk_org_x - ctx->sb_origin_x, .y = ctx->blk_org_y - ctx->sb_origin_y};
831
138k
    svt_aom_get_blk_var_map(ctx->blk_geom->sq_size, blk_org.x, blk_org.y, &blk_idx, sub_idx);
832
833
138k
    uint16_t* sb_var  = pcs->ppcs->variance[ctx->sb_index];
834
138k
    uint32_t  blk_var = sb_var[blk_idx];
835
836
    // For 8x8, we do not have 4x4 sub-variance, skip spread check
837
138k
    if (ctx->blk_geom->sq_size == 8) {
838
136k
        return (blk_var < 2000);
839
136k
    }
840
841
    // For 16x16 and above, compute spread from sub-blocks
842
2.58k
    uint32_t min_var = UINT32_MAX;
843
2.58k
    uint32_t max_var = 0;
844
845
18.9k
    for (int i = 0; i < 4; i++) {
846
16.3k
        uint32_t v = sb_var[sub_idx[i]];
847
16.3k
        min_var    = MIN(min_var, v);
848
16.3k
        max_var    = MAX(max_var, v);
849
16.3k
    }
850
851
2.58k
    uint32_t spread_var = max_var - min_var;
852
853
4.09k
    return (blk_var < 2000 && spread_var < 4000);
854
138k
}
855
856
// Inject inter-intra, WM, OBMC for unipred simple-trans candidate
857
//
858
// total_cand_count is the index to ctx->fast_cand_array for the next candidate injected (which is the
859
// same as the number of candidates injected so far).  It is assumed the simple-trans candidate to base
860
// the other candidtes on is the previously injected candidate (at index total_cand_count - 1).
861
//
862
// enable_ii, enable_wm, and enable_obmc allow the caller to disable some modes explicitly; if enabled, the
863
// mode will be injected if the block size/candidate type supports the mode. The enable signals are left as
864
// arguments because some candidates do not inject all modes (e.g. unipred does not inject WM/OBMC).
865
static void inj_non_simple_modes(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* total_cand_count,
866
0
                                 const bool enable_ii, const bool enable_wm, const bool enable_obmc) {
867
    // index of simple translation candidate (to be used to copy cand info for other modes)
868
    // assumes the simple trans cand is the previously injected candidate
869
0
    const uint32_t                     simple_trans_cand_idx = *total_cand_count - 1;
870
0
    const ModeDecisionCandidate* const simple_trans_cand     = &ctx->fast_cand_array[simple_trans_cand_idx];
871
872
    // The candidate count to be used to track number of inj cands, and the index of fast_cand_array for new candidates
873
0
    uint32_t cand_count = *total_cand_count;
874
875
0
    assert(simple_trans_cand->block_mi.ref_frame[1] == NONE_FRAME);
876
0
    const uint8_t list_idx = get_list_idx(simple_trans_cand->block_mi.ref_frame[0]);
877
0
    const uint8_t ref_idx  = get_ref_frame_idx(simple_trans_cand->block_mi.ref_frame[0]);
878
879
    // INJECT INTER-INTRA
880
0
    const uint8_t is_ii_allowed = svt_aom_is_valid_unipred_ref(ctx, INTER_INTRA_GROUP, list_idx, ref_idx) &&
881
0
        svt_is_interintra_allowed(ctx->inter_intra_comp_ctrls.enabled,
882
0
                                  ctx->blk_geom->bsize,
883
0
                                  simple_trans_cand->block_mi.mode,
884
0
                                  simple_trans_cand->block_mi.ref_frame);
885
0
    if (enable_ii && is_ii_allowed) {
886
0
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_count];
887
0
        svt_memcpy(cand, simple_trans_cand, sizeof(ModeDecisionCandidate));
888
889
0
        inter_intra_search(pcs, ctx, cand);
890
0
        cand->block_mi.is_interintra_used = 1;
891
0
        cand->block_mi.ref_frame[1]       = INTRA_FRAME;
892
0
        const InterIntraMode ii_mode      = cand->block_mi.interintra_mode;
893
0
        INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
894
895
        // if ii_wedge_mode is 1, then inject wedge/non-wedge as separate candidates; OW, only inject the best (above)
896
0
        const uint8_t ii_wedge_mode = ctx->shape == PART_N ? ctx->inter_intra_comp_ctrls.wedge_mode_sq
897
0
                                                           : ctx->inter_intra_comp_ctrls.wedge_mode_nsq;
898
0
        if (ii_wedge_mode == 1) {
899
0
            cand = &ctx->fast_cand_array[cand_count];
900
0
            svt_memcpy(cand, simple_trans_cand, sizeof(ModeDecisionCandidate));
901
902
0
            cand->block_mi.is_interintra_used   = 1;
903
0
            cand->block_mi.ref_frame[1]         = INTRA_FRAME;
904
0
            cand->block_mi.interintra_mode      = ii_mode;
905
0
            cand->block_mi.use_wedge_interintra = 0;
906
0
            INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
907
0
        }
908
0
    }
909
910
0
#if CONFIG_ENABLE_OBMC
911
    // INJECT WARP
912
0
    const uint8_t is_warp_allowed = warped_motion_mode_allowed(pcs, ctx) &&
913
0
        svt_aom_is_valid_unipred_ref(ctx, WARP_GROUP, list_idx, ref_idx);
914
0
    if (enable_wm && is_warp_allowed) {
915
0
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_count];
916
0
        svt_memcpy(cand, simple_trans_cand, sizeof(ModeDecisionCandidate));
917
918
0
        cand->block_mi.is_interintra_used = 0;
919
0
        cand->block_mi.motion_mode        = WARPED_CAUSAL;
920
0
        cand->wm_params_l0.wmtype         = AFFINE;
921
922
0
        uint8_t motion_mode_valid = 1;
923
0
        if (cand->block_mi.mode == NEWMV && ctx->wm_ctrls.refinement_iterations && ctx->wm_ctrls.refine_level == 0) {
924
            // Perform refinement; if refinement is off, then MV is valid, since it's been checked above
925
0
            motion_mode_valid = svt_aom_wm_motion_refinement(pcs, ctx, cand, 0);
926
0
        }
927
928
0
        if (motion_mode_valid) {
929
0
            motion_mode_valid = svt_aom_warped_motion_parameters(ctx,
930
0
                                                                 cand->block_mi.mv[0],
931
0
                                                                 ctx->blk_geom,
932
0
                                                                 cand->block_mi.ref_frame[0],
933
0
                                                                 &cand->wm_params_l0,
934
0
                                                                 &cand->block_mi.num_proj_ref,
935
0
                                                                 ctx->wm_ctrls.lower_band_th,
936
0
                                                                 ctx->wm_ctrls.upper_band_th,
937
0
                                                                 0);
938
0
        }
939
940
0
        if (motion_mode_valid) {
941
0
            INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
942
0
        }
943
0
    }
944
945
    // INJECT OBMC
946
0
    const uint8_t is_obmc_allowed = svt_aom_is_valid_unipred_ref(ctx, OBMC_GROUP, list_idx, ref_idx) &&
947
0
        (svt_aom_obmc_motion_mode_allowed(pcs,
948
0
                                          ctx,
949
0
                                          ctx->blk_geom->bsize,
950
0
                                          0,
951
0
                                          simple_trans_cand->block_mi.ref_frame[0],
952
0
                                          simple_trans_cand->block_mi.ref_frame[1],
953
0
                                          simple_trans_cand->block_mi.mode) == OBMC_CAUSAL);
954
0
    if (enable_obmc && is_obmc_allowed) {
955
0
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_count];
956
0
        svt_memcpy(cand, simple_trans_cand, sizeof(ModeDecisionCandidate));
957
958
0
        cand->block_mi.is_interintra_used = 0;
959
0
        cand->block_mi.motion_mode        = OBMC_CAUSAL;
960
961
0
        uint8_t motion_mode_valid = 1;
962
0
        if (cand->block_mi.mode == NEWMV && ctx->obmc_ctrls.refine_level == 0) {
963
0
            assert(cand->block_mi.ref_frame[1] == NONE_FRAME);
964
0
            motion_mode_valid = svt_aom_obmc_motion_refinement(pcs, ctx, cand, ctx->obmc_ctrls.refine_level);
965
0
        }
966
967
0
        if (motion_mode_valid) {
968
0
            INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
969
0
        }
970
0
    }
971
#else
972
    UNUSED(enable_wm);
973
    UNUSED(enable_obmc);
974
#endif // CONFIG_ENABLE_OBMC
975
976
0
    *total_cand_count = cand_count;
977
0
}
978
979
// Determines if inter MVP compound modes should be skipped based on info from neighbouring blocks/ref frame types.
980
0
static bool skip_compound_on_ref_types(ModeDecisionContext* ctx, MvReferenceFrame rf[2]) {
981
0
    if (!ctx->inter_comp_ctrls.skip_on_ref_info) {
982
0
        return false;
983
0
    }
984
985
0
    MacroBlockD* xd = ctx->blk_ptr->av1xd;
986
987
    // If both references are from the same list, skip compound
988
0
    const uint8_t list_idx_0 = get_list_idx(rf[0]);
989
0
    const uint8_t list_idx_1 = get_list_idx(rf[1]);
990
0
    if (list_idx_0 == list_idx_1) {
991
0
        return true;
992
0
    }
993
994
    // Skip compound unless neighbours selected the ref frames
995
0
    bool skip_comp = true;
996
0
    if (!xd->left_available && !xd->up_available) {
997
0
        return false;
998
0
    }
999
1000
0
    if (xd->left_available) {
1001
0
        const BlockModeInfo* const left_mi = &xd->left_mbmi->block_mi;
1002
0
        if ((is_inter_singleref_mode(left_mi->mode) &&
1003
0
             (left_mi->ref_frame[0] == rf[0] || left_mi->ref_frame[0] == rf[1])) ||
1004
0
            (is_inter_compound_mode(left_mi->mode) &&
1005
0
             (left_mi->ref_frame[0] == rf[0] && left_mi->ref_frame[1] == rf[1]))) {
1006
0
            return false;
1007
0
        }
1008
0
    }
1009
0
    if (xd->up_available) {
1010
0
        const BlockModeInfo* const above_mi = &xd->above_mbmi->block_mi;
1011
0
        if ((is_inter_singleref_mode(above_mi->mode) &&
1012
0
             (above_mi->ref_frame[0] == rf[0] || above_mi->ref_frame[0] == rf[1])) ||
1013
0
            (is_inter_compound_mode(above_mi->mode) &&
1014
0
             (above_mi->ref_frame[0] == rf[0] && above_mi->ref_frame[1] == rf[1]))) {
1015
0
            return false;
1016
0
        }
1017
0
    }
1018
1019
0
    return skip_comp;
1020
0
}
1021
1022
// Inject inter-inter compound types (DIST, DIFF, WEDGE) for a bipred AVG candidate
1023
//
1024
// total_cand_count is the index to ctx->fast_cand_array for the next candidate injected (which is the
1025
// same as the number of candidates injected so far).  It is assumed the AVG candidate to base
1026
// the other candidtes on is the previously injected candidate (at index total_cand_count - 1).
1027
0
static void inj_comp_modes(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* total_cand_count) {
1028
    // index of MD_COMP_AVG candidate (to be used to copy cand info for other modes)
1029
    // assumes the avg cand is the previously injected candidate
1030
0
    const uint32_t         avg_cand_idx = *total_cand_count - 1;
1031
0
    ModeDecisionCandidate* avg_cand     = &ctx->fast_cand_array[avg_cand_idx];
1032
1033
    // Get allowable compound types based on settings and block size
1034
0
    MD_COMP_TYPE tot_comp_types = get_tot_comp_types_bsize(ctx->inter_comp_ctrls.tot_comp_types, ctx->blk_geom->bsize);
1035
0
    if (tot_comp_types == MD_COMP_DIST) {
1036
0
        return;
1037
0
    }
1038
1039
    // Distortion-based ref pruning for compound types
1040
0
    const uint8_t ref_idx_0  = get_ref_frame_idx(avg_cand->block_mi.ref_frame[0]);
1041
0
    const uint8_t ref_idx_1  = get_ref_frame_idx(avg_cand->block_mi.ref_frame[1]);
1042
0
    const uint8_t list_idx_0 = get_list_idx(avg_cand->block_mi.ref_frame[0]);
1043
0
    const uint8_t list_idx_1 = get_list_idx(avg_cand->block_mi.ref_frame[1]);
1044
0
    if (!is_valid_bipred_ref(ctx, INTER_COMP_GROUP, list_idx_0, ref_idx_0, list_idx_1, ref_idx_1)) {
1045
0
        return;
1046
0
    }
1047
1048
    // Skip compound on neighbour info
1049
0
    if (skip_compound_on_ref_types(ctx, avg_cand->block_mi.ref_frame)) {
1050
0
        return;
1051
0
    }
1052
1053
    // Skip compound on MV length
1054
0
    if (ctx->inter_comp_ctrls.max_mv_length) {
1055
0
        const uint16_t max_mv_length = ctx->inter_comp_ctrls.max_mv_length;
1056
0
        if (abs(avg_cand->block_mi.mv[0].x) > max_mv_length || abs(avg_cand->block_mi.mv[0].y) > max_mv_length ||
1057
0
            abs(avg_cand->block_mi.mv[1].x) > max_mv_length || abs(avg_cand->block_mi.mv[1].y) > max_mv_length) {
1058
0
            return;
1059
0
        }
1060
0
    }
1061
    // If compound modes are to be tested for this block, generate the buffers that will be used in the DIFF/WEDGE search.
1062
    // Even if DIFF/WEDGE are not used, still call the function because it is needed for pred0_to_pred1_mult to work.
1063
0
    if (tot_comp_types > MD_COMP_DIST) {
1064
0
        if (svt_aom_calc_pred_masked_compound(pcs, ctx, avg_cand)) {
1065
0
            return;
1066
0
        }
1067
0
    }
1068
1069
    // The candidate count to be used to track number of inj cands, and the index of fast_cand_array for new candidates
1070
0
    uint32_t cand_count = *total_cand_count;
1071
0
    for (MD_COMP_TYPE cur_type = MD_COMP_DIST; cur_type < tot_comp_types; cur_type++) {
1072
0
        if (ctx->inter_comp_ctrls.no_sym_dist && cur_type == MD_COMP_DIST && ref_idx_0 == 0 && ref_idx_1 == 0) {
1073
0
            continue;
1074
0
        }
1075
0
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_count];
1076
0
        svt_memcpy(cand, &ctx->fast_cand_array[avg_cand_idx], sizeof(ModeDecisionCandidate));
1077
0
        cand->skip_mode_allowed = false;
1078
0
        determine_compound_mode(pcs, ctx, cand, cur_type);
1079
0
        INC_MD_CAND_CNT(cand_count, pcs->ppcs->max_can_count);
1080
0
    }
1081
0
    *total_cand_count = cand_count;
1082
0
}
1083
1084
static void unipred_3x3_candidates_injection(PictureControlSet* pcs, ModeDecisionContext* ctx,
1085
0
                                             uint32_t* candidate_total_cnt) {
1086
0
    uint32_t               cand_total_cnt          = (*candidate_total_cnt);
1087
0
    const uint8_t          allow_high_precision_mv = pcs->ppcs->frm_hdr.allow_high_precision_mv;
1088
0
    MeSbResults*           me_results              = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1089
0
    const uint8_t          total_me_cnt            = me_results->total_me_candidate_index[ctx->me_block_offset];
1090
0
    const MeCandidate*     me_block_results        = &me_results->me_candidate_array[ctx->me_cand_offset];
1091
0
    ModeDecisionCandidate* cand_array              = ctx->fast_cand_array;
1092
1093
    // (8 Best_L0 neighbors)
1094
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
1095
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
1096
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
1097
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
1098
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
1099
0
        if (inter_direction == BI_PRED) {
1100
0
            continue;
1101
0
        }
1102
0
        assert(inter_direction == 0 || inter_direction == 1);
1103
0
        const uint8_t list_idx = inter_direction;
1104
0
        const uint8_t ref_idx  = list_idx == REF_LIST_0 ? list0_ref_index : list1_ref_index;
1105
0
        if (!svt_aom_is_valid_unipred_ref(ctx, MIN(TOT_INTER_GROUP - 1, UNI_3x3_GROUP), list_idx, ref_idx)) {
1106
0
            continue;
1107
0
        }
1108
0
        for (int unipred_index = 0; unipred_index < BIPRED_3x3_REFINMENT_POSITIONS; ++unipred_index) {
1109
            /**************
1110
            NEWMV L0
1111
            ************* */
1112
0
            if (ctx->unipred3x3_injection >= 2) {
1113
0
                if (allow_refinement_flag[unipred_index] == 0) {
1114
0
                    continue;
1115
0
                }
1116
0
            }
1117
0
            Mv to_inj_mv = ctx->sb_me_mv[list_idx][ref_idx];
1118
0
            to_inj_mv.x += (bipred_3x3_x_pos[unipred_index] << !allow_high_precision_mv);
1119
0
            to_inj_mv.y += (bipred_3x3_y_pos[unipred_index] << !allow_high_precision_mv);
1120
0
            const uint8_t    to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
1121
0
            MvReferenceFrame rf[2]              = {to_inject_ref_type, NONE_FRAME};
1122
0
            if ((ctx->injected_mv_count == 0 ||
1123
0
                 mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, to_inject_ref_type) == false)) {
1124
0
                uint8_t drl_index       = 0;
1125
0
                Mv      best_pred_mv[2] = {{{0}}, {{0}}};
1126
0
                svt_aom_choose_best_av1_mv_pred(
1127
0
                    ctx, to_inject_ref_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
1128
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
1129
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
1130
0
                    cand->block_mi.use_intrabc        = 0;
1131
0
                    cand->skip_mode_allowed           = false;
1132
0
                    cand->block_mi.mode               = NEWMV;
1133
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1134
0
                    cand->block_mi.is_interintra_used = 0;
1135
0
                    cand->drl_index                   = drl_index;
1136
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1137
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1138
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1139
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
1140
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[to_inject_ref_type].num;
1141
1142
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
1143
1144
0
                    const bool enable_ii = true;
1145
                    // OBMC and WM perform a refinement search around the ME MV, so they are not injected as unipred3x3 candidates,
1146
                    // since this is effectively a refinement search
1147
0
                    const bool enable_obmc = false;
1148
0
                    const bool enable_warp = false;
1149
0
                    inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
1150
1151
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1152
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
1153
0
                    ++ctx->injected_mv_count;
1154
0
                }
1155
0
            }
1156
0
        }
1157
0
    }
1158
1159
    // update the total number of candidates injected
1160
0
    (*candidate_total_cnt) = cand_total_cnt;
1161
1162
0
    return;
1163
0
}
1164
1165
static void bipred_3x3_candidates_injection(PictureControlSet* pcs, ModeDecisionContext* ctx,
1166
0
                                            uint32_t* candidate_total_cnt) {
1167
0
    uint32_t               cand_total_cnt          = (*candidate_total_cnt);
1168
0
    const uint8_t          allow_high_precision_mv = pcs->ppcs->frm_hdr.allow_high_precision_mv;
1169
0
    const MeSbResults*     me_results              = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1170
0
    const uint8_t          total_me_cnt            = me_results->total_me_candidate_index[ctx->me_block_offset];
1171
0
    const MeCandidate*     me_block_results        = &me_results->me_candidate_array[ctx->me_cand_offset];
1172
0
    ModeDecisionCandidate* cand_array              = ctx->fast_cand_array;
1173
0
    Mv                     best_pred_mv[2]         = {{{0}}, {{0}}};
1174
1175
    /**************
1176
    NEW_NEWMV
1177
    ************* */
1178
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
1179
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
1180
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
1181
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
1182
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
1183
0
        if (inter_direction < BI_PRED) {
1184
0
            continue;
1185
0
        }
1186
0
        assert(inter_direction == BI_PRED);
1187
1188
0
        const uint8_t ref0_list = me_block_results_ptr->ref0_list;
1189
0
        const uint8_t ref1_list = me_block_results_ptr->ref1_list;
1190
0
        if (!is_valid_bipred_ref(ctx, BI_3x3_GROUP, ref0_list, list0_ref_index, ref1_list, list1_ref_index)) {
1191
0
            continue;
1192
0
        }
1193
1194
0
        int8_t best_list = -1;
1195
0
        int    diff      = ((int)ctx->post_subpel_me_mv_cost[ref0_list][list0_ref_index] -
1196
0
                    (int)ctx->post_subpel_me_mv_cost[ref1_list][list1_ref_index]) *
1197
0
            100;
1198
1199
0
        if (ctx->bipred3x3_ctrls.use_l0_l1_dev != (uint8_t)~0) {
1200
0
            if (abs(diff) >
1201
0
                (ctx->bipred3x3_ctrls.use_l0_l1_dev * (int)ctx->post_subpel_me_mv_cost[ref0_list][list0_ref_index])) {
1202
0
                return;
1203
0
            }
1204
0
        }
1205
1206
        // Best list in terms of distortion reduction
1207
0
        if (ctx->bipred3x3_ctrls.use_best_list) {
1208
0
            best_list = ref0_list;
1209
0
            if (diff > 0) {
1210
0
                best_list = ref1_list;
1211
0
            }
1212
0
        }
1213
1214
0
        MvReferenceFrame rf[2]              = {svt_get_ref_frame_type(ref0_list, list0_ref_index),
1215
0
                                               svt_get_ref_frame_type(ref1_list, list1_ref_index)};
1216
0
        const uint8_t    to_inject_ref_type = av1_ref_frame_type(rf);
1217
0
        if (best_list == -1 || best_list == ref0_list) {
1218
            // (Best_L0, 8 Best_L1 neighbors)
1219
0
            for (uint32_t bipred_index = 0; bipred_index < BIPRED_3x3_REFINMENT_POSITIONS; ++bipred_index) {
1220
0
                if (!ctx->bipred3x3_ctrls.search_diag) {
1221
0
                    if (allow_refinement_flag[bipred_index] == 0) {
1222
0
                        continue;
1223
0
                    }
1224
0
                }
1225
0
                Mv to_inj_mv0 = ctx->sb_me_mv[ref0_list][list0_ref_index];
1226
0
                Mv to_inj_mv1 = ctx->sb_me_mv[ref1_list][list1_ref_index];
1227
0
                to_inj_mv1.x += (bipred_3x3_x_pos[bipred_index] << !allow_high_precision_mv);
1228
0
                to_inj_mv1.y += (bipred_3x3_y_pos[bipred_index] << !allow_high_precision_mv);
1229
0
                if ((ctx->injected_mv_count == 0 ||
1230
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
1231
0
                    uint8_t drl_index = 0;
1232
0
                    svt_aom_choose_best_av1_mv_pred(
1233
0
                        ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
1234
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
1235
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
1236
0
                        cand->block_mi.use_intrabc        = 0;
1237
0
                        cand->skip_mode_allowed           = false;
1238
0
                        cand->drl_index                   = drl_index;
1239
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1240
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1241
0
                        cand->block_mi.mode               = NEW_NEWMV;
1242
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1243
0
                        cand->block_mi.is_interintra_used = 0;
1244
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1245
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1246
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
1247
0
                        cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
1248
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1249
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
1250
1251
0
                        if (ctx->inter_comp_ctrls.do_3x3_bi) {
1252
0
                            ctx->cmp_store.pred0_cnt = 0;
1253
0
                            ctx->cmp_store.pred1_cnt = 0;
1254
0
                            inj_comp_modes(pcs, ctx, &cand_total_cnt);
1255
0
                        }
1256
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1257
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1258
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
1259
0
                        ++ctx->injected_mv_count;
1260
0
                    }
1261
0
                }
1262
0
            }
1263
0
        }
1264
0
        if (best_list == -1 || best_list == ref1_list) {
1265
            // (8 Best_L0 neighbors, Best_L1) :
1266
0
            for (uint32_t bipred_index = 0; bipred_index < BIPRED_3x3_REFINMENT_POSITIONS; ++bipred_index) {
1267
0
                if (!ctx->bipred3x3_ctrls.search_diag) {
1268
0
                    if (allow_refinement_flag[bipred_index] == 0) {
1269
0
                        continue;
1270
0
                    }
1271
0
                }
1272
0
                Mv to_inj_mv0 = ctx->sb_me_mv[ref0_list][list0_ref_index];
1273
0
                to_inj_mv0.x += (bipred_3x3_x_pos[bipred_index] << !allow_high_precision_mv);
1274
0
                to_inj_mv0.y += (bipred_3x3_y_pos[bipred_index] << !allow_high_precision_mv);
1275
0
                Mv to_inj_mv1 = ctx->sb_me_mv[ref1_list][list1_ref_index];
1276
0
                if ((ctx->injected_mv_count == 0 ||
1277
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
1278
0
                    uint8_t drl_index = 0;
1279
0
                    svt_aom_choose_best_av1_mv_pred(
1280
0
                        ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
1281
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
1282
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
1283
0
                        cand->block_mi.use_intrabc        = 0;
1284
0
                        cand->skip_mode_allowed           = false;
1285
0
                        cand->drl_index                   = drl_index;
1286
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1287
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1288
0
                        cand->block_mi.mode               = NEW_NEWMV;
1289
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1290
0
                        cand->block_mi.is_interintra_used = 0;
1291
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1292
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1293
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
1294
0
                        cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
1295
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1296
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
1297
1298
0
                        if (ctx->inter_comp_ctrls.do_3x3_bi) {
1299
0
                            ctx->cmp_store.pred0_cnt = 0;
1300
0
                            ctx->cmp_store.pred1_cnt = 0;
1301
0
                            inj_comp_modes(pcs, ctx, &cand_total_cnt);
1302
0
                        }
1303
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1304
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1305
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
1306
0
                        ++ctx->injected_mv_count;
1307
0
                    }
1308
0
                }
1309
0
            }
1310
0
        }
1311
0
    }
1312
1313
    // update the total number of candidates injected
1314
0
    (*candidate_total_cnt) = cand_total_cnt;
1315
1316
0
    return;
1317
0
}
1318
1319
/*********************************************************************
1320
**********************************************************************
1321
        Upto 12 inter Candidated injected
1322
        Min 6 inter Candidated injected
1323
UniPred L0 : NEARST         + upto 3x NEAR
1324
UniPred L1 : NEARST         + upto 3x NEAR
1325
BIPred     : NEARST_NEARST  + upto 3x NEAR_NEAR
1326
**********************************************************************
1327
**********************************************************************/
1328
static void inject_mvp_candidates_ii_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candTotCnt,
1329
0
                                               const bool allow_bipred) {
1330
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
1331
0
    uint32_t               cand_idx   = *candTotCnt;
1332
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
1333
0
    MacroBlockD*           xd         = ctx->blk_ptr->av1xd;
1334
1335
    //all of ref pairs: (1)single-ref List0  (2)single-ref List1  (3)compound Bi-Dir List0-List1
1336
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
1337
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
1338
0
        MvReferenceFrame rf[2];
1339
0
        av1_set_ref_frame(rf, ref_pair);
1340
1341
        //single ref/list
1342
0
        if (rf[1] == NONE_FRAME) {
1343
0
            MvReferenceFrame frame_type = rf[0];
1344
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
1345
0
            if (ctx->cand_reduction_ctrls.lpd1_mvp_best_me_list) {
1346
0
                const MeSbResults* me_results           = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1347
0
                const uint8_t      total_me_cnt         = me_results->total_me_candidate_index[ctx->me_block_offset];
1348
0
                const MeCandidate* me_block_results     = &me_results->me_candidate_array[ctx->me_cand_offset];
1349
0
                const MeCandidate* me_block_results_ptr = &me_block_results[0];
1350
0
                const uint8_t      inter_direction      = me_block_results_ptr->direction;
1351
0
                if (total_me_cnt && list_idx != inter_direction) {
1352
0
                    continue;
1353
0
                }
1354
0
            }
1355
            //NEAREST
1356
            // Don't check if MV is already injected b/c NEAREST is the first INTER MV injected
1357
0
            Mv to_inj_mv = {.as_int = ctx->ref_mv_stack[frame_type][0].this_mv.as_int};
1358
1359
0
            ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1360
0
            cand->block_mi.mode               = NEARESTMV;
1361
0
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1362
0
            cand->skip_mode_allowed           = false;
1363
0
            cand->drl_index                   = 0;
1364
0
            cand->block_mi.ref_frame[0]       = rf[0];
1365
0
            cand->block_mi.ref_frame[1]       = rf[1];
1366
0
            cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1367
0
            cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1368
0
            cand->block_mi.use_intrabc        = 0;
1369
0
            cand->block_mi.is_interintra_used = 0;
1370
0
            INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1371
1372
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1373
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1374
0
            ++ctx->injected_mv_count;
1375
            //NEAR
1376
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[frame_type], NEARMV);
1377
0
            uint8_t       cap_max_drl_index = 0;
1378
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1379
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_count, max_drl_index);
1380
0
            }
1381
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1382
0
                to_inj_mv.as_int = ctx->ref_mv_stack[frame_type][1 + drli].this_mv.as_int;
1383
1384
0
                if ((ctx->injected_mv_count == 0 ||
1385
0
                     mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
1386
0
                    cand                              = &cand_array[cand_idx];
1387
0
                    cand->block_mi.mode               = NEARMV;
1388
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1389
0
                    cand->skip_mode_allowed           = false;
1390
0
                    cand->drl_index                   = drli;
1391
0
                    cand->block_mi.use_intrabc        = 0;
1392
0
                    cand->block_mi.is_interintra_used = 0;
1393
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1394
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1395
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1396
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1397
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1398
1399
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1400
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1401
0
                    ++ctx->injected_mv_count;
1402
0
                }
1403
0
            }
1404
0
        } else if (allow_bipred) {
1405
            //NEAREST_NEAREST
1406
            // Don't check if MV is already injected b/c NEAREST_NEAREST is the first bipred INTER candidate injected
1407
0
            Mv         to_inj_mv0   = {.as_int = ctx->ref_mv_stack[ref_pair][0].this_mv.as_int};
1408
0
            Mv         to_inj_mv1   = {.as_int = ctx->ref_mv_stack[ref_pair][0].comp_mv.as_int};
1409
0
            const bool is_skip_mode = !svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) &&
1410
0
                frm_hdr->skip_mode_params.skip_mode_flag && (rf[0] == frm_hdr->skip_mode_params.ref_frame_idx_0) &&
1411
0
                (rf[1] == frm_hdr->skip_mode_params.ref_frame_idx_1);
1412
0
            ModeDecisionCandidate* cand         = &cand_array[cand_idx];
1413
0
            cand->block_mi.mode                 = NEAREST_NEARESTMV;
1414
0
            cand->block_mi.motion_mode          = SIMPLE_TRANSLATION;
1415
0
            cand->skip_mode_allowed             = is_skip_mode;
1416
0
            cand->block_mi.mv[0].as_int         = to_inj_mv0.as_int;
1417
0
            cand->block_mi.mv[1].as_int         = to_inj_mv1.as_int;
1418
0
            cand->drl_index                     = 0;
1419
0
            cand->block_mi.use_intrabc          = 0;
1420
0
            cand->block_mi.is_interintra_used   = 0;
1421
0
            cand->block_mi.ref_frame[0]         = rf[0];
1422
0
            cand->block_mi.ref_frame[1]         = rf[1];
1423
0
            cand->block_mi.comp_group_idx       = 0;
1424
0
            cand->block_mi.compound_idx         = 1;
1425
0
            cand->block_mi.interinter_comp.type = COMPOUND_AVERAGE;
1426
1427
0
            INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1428
1429
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1430
0
            ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1431
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1432
0
            ++ctx->injected_mv_count;
1433
1434
            //NEAR_NEAR
1435
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEAR_NEARMV);
1436
0
            uint8_t       cap_max_drl_index = 0;
1437
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1438
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_near_count, max_drl_index);
1439
0
            }
1440
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1441
0
                to_inj_mv0.as_int = ctx->ref_mv_stack[ref_pair][1 + drli].this_mv.as_int;
1442
0
                to_inj_mv1.as_int = ctx->ref_mv_stack[ref_pair][1 + drli].comp_mv.as_int;
1443
0
                if ((ctx->injected_mv_count == 0 ||
1444
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair) == false)) {
1445
0
                    cand                                = &cand_array[cand_idx];
1446
0
                    cand->block_mi.mode                 = NEAR_NEARMV;
1447
0
                    cand->block_mi.motion_mode          = SIMPLE_TRANSLATION;
1448
0
                    cand->skip_mode_allowed             = false;
1449
0
                    cand->block_mi.use_intrabc          = 0;
1450
0
                    cand->block_mi.is_interintra_used   = 0;
1451
0
                    cand->block_mi.mv[0].as_int         = to_inj_mv0.as_int;
1452
0
                    cand->block_mi.mv[1].as_int         = to_inj_mv1.as_int;
1453
0
                    cand->drl_index                     = drli;
1454
0
                    cand->block_mi.ref_frame[0]         = rf[0];
1455
0
                    cand->block_mi.ref_frame[1]         = rf[1];
1456
0
                    cand->block_mi.comp_group_idx       = 0;
1457
0
                    cand->block_mi.compound_idx         = 1;
1458
0
                    cand->block_mi.interinter_comp.type = COMPOUND_AVERAGE;
1459
1460
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1461
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1462
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1463
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1464
0
                    ++ctx->injected_mv_count;
1465
0
                }
1466
0
            }
1467
0
        }
1468
0
    }
1469
    //update tot Candidate count
1470
0
    *candTotCnt = cand_idx;
1471
0
}
1472
1473
/*********************************************************************
1474
**********************************************************************
1475
        Upto 12 inter Candidated injected
1476
        Min 6 inter Candidated injected
1477
UniPred L0 : NEARST         + upto 3x NEAR
1478
UniPred L1 : NEARST         + upto 3x NEAR
1479
BIPred     : NEARST_NEARST  + upto 3x NEAR_NEAR
1480
**********************************************************************
1481
**********************************************************************/
1482
static void inject_mvp_candidates_ii(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* cand_total_cnt,
1483
0
                                     const bool allow_bipred) {
1484
0
    BlkStruct*             blk_ptr    = ctx->blk_ptr;
1485
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
1486
0
    uint32_t               cand_idx   = *cand_total_cnt;
1487
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
1488
0
    MacroBlockD*           xd         = blk_ptr->av1xd;
1489
0
    Mv                     nearestmv[2], nearmv[2], ref_mv[2];
1490
1491
    //all of ref pairs: (1)single-ref List0  (2)single-ref List1  (3)compound Bi-Dir List0-List1  (4)compound Uni-Dir List0-List0  (5)compound Uni-Dir List1-List1
1492
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
1493
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
1494
0
        MvReferenceFrame rf[2];
1495
0
        av1_set_ref_frame(rf, ref_pair);
1496
        //single ref/list
1497
0
        if (rf[1] == NONE_FRAME) {
1498
0
            MvReferenceFrame frame_type = rf[0];
1499
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
1500
0
            uint8_t          ref_idx    = get_ref_frame_idx(rf[0]);
1501
            // Always consider the 2 closet ref frames (i.e. ref_idx=0) @ MVP cand generation
1502
0
            if (!svt_aom_is_valid_unipred_ref(ctx, MIN(TOT_INTER_GROUP - 1, NRST_NEAR_GROUP), list_idx, ref_idx)) {
1503
0
                continue;
1504
0
            }
1505
            //NEAREST
1506
0
            Mv to_inj_mv = {.as_int = ctx->ref_mv_stack[frame_type][0].this_mv.as_int};
1507
0
            if ((ctx->injected_mv_count == 0 ||
1508
0
                 mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
1509
0
                assert(list_idx == 0 || list_idx == 1);
1510
0
                ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1511
0
                cand->block_mi.mode               = NEARESTMV;
1512
0
                cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1513
0
                cand->block_mi.use_intrabc        = 0;
1514
0
                cand->skip_mode_allowed           = false;
1515
0
                cand->drl_index                   = 0;
1516
0
                cand->block_mi.ref_frame[0]       = rf[0];
1517
0
                cand->block_mi.ref_frame[1]       = rf[1];
1518
0
                cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1519
0
                cand->block_mi.is_interintra_used = 0;
1520
0
                cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1521
0
                INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1522
1523
0
                const bool enable_ii   = true;
1524
0
                const bool enable_obmc = true;
1525
0
                const bool enable_warp = ctx->wm_ctrls.use_wm_for_mvp ? true : false;
1526
0
                inj_non_simple_modes(pcs, ctx, &cand_idx, enable_ii, enable_warp, enable_obmc);
1527
0
                ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1528
0
                ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1529
0
                ++ctx->injected_mv_count;
1530
0
            }
1531
1532
            //NEAR
1533
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[frame_type], NEARMV);
1534
0
            uint8_t       cap_max_drl_index = 0;
1535
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1536
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_count, max_drl_index);
1537
0
            }
1538
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1539
0
                svt_aom_get_av1_mv_pred_drl(ctx, blk_ptr, frame_type, 0, NEARMV, drli, nearestmv, nearmv, ref_mv);
1540
1541
0
                to_inj_mv.as_int = nearmv[0].as_int;
1542
0
                if ((ctx->injected_mv_count == 0 ||
1543
0
                     mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
1544
0
                    assert(list_idx == 0 || list_idx == 1);
1545
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1546
0
                    cand->block_mi.mode               = NEARMV;
1547
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1548
0
                    cand->block_mi.use_intrabc        = 0;
1549
0
                    cand->skip_mode_allowed           = false;
1550
0
                    cand->drl_index                   = drli;
1551
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1552
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1553
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
1554
0
                    cand->block_mi.is_interintra_used = 0;
1555
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
1556
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1557
1558
0
                    const bool enable_ii   = true;
1559
0
                    const bool enable_obmc = true;
1560
0
                    const bool enable_warp = ctx->wm_ctrls.use_wm_for_mvp ? true : false;
1561
0
                    inj_non_simple_modes(pcs, ctx, &cand_idx, enable_ii, enable_warp, enable_obmc);
1562
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
1563
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
1564
0
                    ++ctx->injected_mv_count;
1565
0
                }
1566
0
            }
1567
0
        } else if (allow_bipred) {
1568
0
            const uint8_t ref_idx_0 = get_ref_frame_idx(rf[0]);
1569
0
            const uint8_t ref_idx_1 = get_ref_frame_idx(rf[1]);
1570
1571
0
            const uint8_t list_idx_0 = get_list_idx(rf[0]);
1572
0
            const uint8_t list_idx_1 = get_list_idx(rf[1]);
1573
1574
0
            ctx->cmp_store.pred0_cnt = 0;
1575
0
            ctx->cmp_store.pred1_cnt = 0;
1576
1577
            // Always consider the 2 closet ref frames (i.e. ref_idx=0) @ MVP cand generation
1578
0
            if (!is_valid_bipred_ref(ctx, NRST_NEAR_GROUP, list_idx_0, ref_idx_0, list_idx_1, ref_idx_1)) {
1579
0
                continue;
1580
0
            }
1581
1582
            //NEAREST_NEAREST
1583
0
            Mv to_inj_mv0 = {.as_int = ctx->ref_mv_stack[ref_pair][0].this_mv.as_int};
1584
0
            Mv to_inj_mv1 = {.as_int = ctx->ref_mv_stack[ref_pair][0].comp_mv.as_int};
1585
0
            if ((ctx->injected_mv_count == 0 ||
1586
0
                 mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair) == false)) {
1587
0
                const bool is_skip_mode = !svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) &&
1588
0
                    frm_hdr->skip_mode_params.skip_mode_flag && (rf[0] == frm_hdr->skip_mode_params.ref_frame_idx_0) &&
1589
0
                    (rf[1] == frm_hdr->skip_mode_params.ref_frame_idx_1);
1590
0
                ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1591
0
                cand->block_mi.mode               = NEAREST_NEARESTMV;
1592
0
                cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1593
0
                cand->block_mi.is_interintra_used = 0;
1594
0
                cand->block_mi.use_intrabc        = 0;
1595
0
                cand->skip_mode_allowed           = /*cur_type == MD_COMP_AVG &&*/ is_skip_mode ? true : false;
1596
0
                cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1597
0
                cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1598
0
                cand->drl_index                   = 0;
1599
0
                cand->block_mi.ref_frame[0]       = rf[0];
1600
0
                cand->block_mi.ref_frame[1]       = rf[1];
1601
0
                determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1602
0
                INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1603
1604
0
                if (ctx->inter_comp_ctrls.do_nearest_nearest) {
1605
                    // Don't reset ctx->cmp_store.pred0_cnt for MVP
1606
0
                    inj_comp_modes(pcs, ctx, &cand_idx);
1607
0
                }
1608
0
                ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1609
0
                ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1610
0
                ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1611
0
                ++ctx->injected_mv_count;
1612
0
            }
1613
1614
            //NEAR_NEAR
1615
0
            const uint8_t max_drl_index     = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEAR_NEARMV);
1616
0
            uint8_t       cap_max_drl_index = 0;
1617
0
            if (ctx->cand_reduction_ctrls.near_count_ctrls.enabled) {
1618
0
                cap_max_drl_index = MIN(ctx->cand_reduction_ctrls.near_count_ctrls.near_near_count, max_drl_index);
1619
0
            }
1620
0
            for (uint8_t drli = 0; drli < cap_max_drl_index; drli++) {
1621
0
                svt_aom_get_av1_mv_pred_drl(ctx, blk_ptr, ref_pair, 1, NEAR_NEARMV, drli, nearestmv, nearmv, ref_mv);
1622
1623
0
                to_inj_mv0.as_int = nearmv[0].as_int;
1624
0
                to_inj_mv1.as_int = nearmv[1].as_int;
1625
0
                if ((ctx->injected_mv_count == 0 ||
1626
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair) == false)) {
1627
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1628
0
                    cand->block_mi.mode               = NEAR_NEARMV;
1629
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1630
0
                    cand->block_mi.is_interintra_used = 0;
1631
0
                    cand->block_mi.use_intrabc        = 0;
1632
0
                    cand->skip_mode_allowed           = false;
1633
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1634
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1635
0
                    cand->drl_index                   = drli;
1636
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1637
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1638
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1639
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1640
1641
0
                    if (ctx->inter_comp_ctrls.do_near_near) {
1642
                        // Don't reset ctx->cmp_store.pred0_cnt for MVP
1643
0
                        inj_comp_modes(pcs, ctx, &cand_idx);
1644
0
                    }
1645
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1646
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1647
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1648
0
                    ++ctx->injected_mv_count;
1649
0
                }
1650
0
            }
1651
0
        }
1652
0
    }
1653
    //update tot Candidate count
1654
0
    *cand_total_cnt = cand_idx;
1655
0
}
1656
1657
static void inject_new_nearest_new_comb_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
1658
0
                                                   uint32_t* cand_tot_cnt) {
1659
0
    uint32_t               cand_idx   = *cand_tot_cnt;
1660
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
1661
0
    MacroBlockD*           xd         = ctx->blk_ptr->av1xd;
1662
0
    Mv                     nearestmv[2], nearmv[2], ref_mv[2];
1663
1664
    //all of ref pairs: (1)single-ref List0  (2)single-ref List1  (3)compound Bi-Dir List0-List1  (4)compound Uni-Dir List0-List0  (5)compound Uni-Dir List1-List1
1665
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
1666
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
1667
0
        MvReferenceFrame rf[2];
1668
0
        av1_set_ref_frame(rf, ref_pair);
1669
0
        if (rf[1] != NONE_FRAME) {
1670
0
            const uint8_t ref_idx_0  = get_ref_frame_idx(rf[0]);
1671
0
            const uint8_t ref_idx_1  = get_ref_frame_idx(rf[1]);
1672
0
            const uint8_t list_idx_0 = get_list_idx(rf[0]);
1673
0
            const uint8_t list_idx_1 = get_list_idx(rf[1]);
1674
0
            if (!svt_aom_is_valid_unipred_ref(
1675
0
                    ctx, MIN(TOT_INTER_GROUP - 1, NRST_NEW_NEAR_GROUP), list_idx_0, ref_idx_0) ||
1676
0
                !svt_aom_is_valid_unipred_ref(
1677
0
                    ctx, MIN(TOT_INTER_GROUP - 1, NRST_NEW_NEAR_GROUP), list_idx_1, ref_idx_1)) {
1678
0
                continue;
1679
0
            }
1680
1681
0
            {
1682
                //NEAREST_NEWMV
1683
0
                const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1684
0
                Mv                 to_inj_mv0 = {.as_int = ctx->ref_mv_stack[ref_pair][0].this_mv.as_int};
1685
0
                Mv                 to_inj_mv1 = ctx->sb_me_mv[list_idx_1][ref_idx_1];
1686
0
                bool               inj_mv =
1687
0
                    (ctx->injected_mv_count == 0 || !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1688
0
                    svt_aom_is_me_data_present(
1689
0
                        ctx->me_block_offset, ctx->me_cand_offset, me_results, get_list_idx(rf[1]), ref_idx_1);
1690
0
                if (inj_mv) {
1691
0
                    svt_aom_get_av1_mv_pred_drl(ctx,
1692
0
                                                ctx->blk_ptr,
1693
0
                                                ref_pair,
1694
0
                                                1, // is_compound
1695
0
                                                NEAREST_NEWMV,
1696
0
                                                0, //not needed drli,
1697
0
                                                nearestmv,
1698
0
                                                nearmv,
1699
0
                                                ref_mv);
1700
1701
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1702
0
                    cand->block_mi.mode               = NEAREST_NEWMV;
1703
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1704
0
                    cand->block_mi.is_interintra_used = 0;
1705
0
                    cand->block_mi.use_intrabc        = 0;
1706
0
                    cand->skip_mode_allowed           = false;
1707
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1708
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1709
0
                    cand->drl_index                   = 0;
1710
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1711
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1712
0
                    cand->pred_mv[1].as_int           = ref_mv[1].as_int;
1713
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1714
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1715
1716
0
                    if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1717
0
                        ctx->cmp_store.pred0_cnt = 0;
1718
0
                        ctx->cmp_store.pred1_cnt = 0;
1719
0
                        inj_comp_modes(pcs, ctx, &cand_idx);
1720
0
                    }
1721
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1722
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1723
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1724
0
                    ++ctx->injected_mv_count;
1725
0
                }
1726
0
            }
1727
1728
0
            {
1729
                //NEW_NEARESTMV
1730
0
                const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1731
0
                Mv                 to_inj_mv0 = ctx->sb_me_mv[list_idx_0][ref_idx_0];
1732
0
                Mv                 to_inj_mv1 = {.as_int = ctx->ref_mv_stack[ref_pair][0].comp_mv.as_int};
1733
0
                bool               inj_mv     = (ctx->injected_mv_count == 0 ||
1734
0
                               !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1735
0
                    svt_aom_is_me_data_present(ctx->me_block_offset, ctx->me_cand_offset, me_results, 0, ref_idx_0);
1736
0
                if (inj_mv) {
1737
0
                    svt_aom_get_av1_mv_pred_drl(ctx,
1738
0
                                                ctx->blk_ptr,
1739
0
                                                ref_pair,
1740
0
                                                1, // is_compound
1741
0
                                                NEW_NEARESTMV,
1742
0
                                                0, //not needed drli,
1743
0
                                                nearestmv,
1744
0
                                                nearmv,
1745
0
                                                ref_mv);
1746
1747
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1748
0
                    cand->block_mi.mode               = NEW_NEARESTMV;
1749
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1750
0
                    cand->block_mi.is_interintra_used = 0;
1751
0
                    cand->block_mi.use_intrabc        = 0;
1752
0
                    cand->skip_mode_allowed           = false;
1753
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1754
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1755
0
                    cand->drl_index                   = 0;
1756
0
                    cand->block_mi.ref_frame[0]       = rf[0];
1757
0
                    cand->block_mi.ref_frame[1]       = rf[1];
1758
0
                    cand->pred_mv[0].as_int           = ref_mv[0].as_int;
1759
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1760
0
                    INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1761
1762
0
                    if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1763
0
                        ctx->cmp_store.pred0_cnt = 0;
1764
0
                        ctx->cmp_store.pred1_cnt = 0;
1765
0
                        inj_comp_modes(pcs, ctx, &cand_idx);
1766
0
                    }
1767
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1768
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1769
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1770
0
                    ++ctx->injected_mv_count;
1771
0
                }
1772
0
            }
1773
            // For level 2, only inject NEAREST_NEW/NEW_NEAREST candidates
1774
0
            if (ctx->new_nearest_near_comb_injection >= 2) {
1775
0
                continue;
1776
0
            }
1777
1778
            //NEW_NEARMV
1779
0
            {
1780
0
                const uint8_t max_drl_index = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEW_NEARMV);
1781
1782
0
                for (uint8_t drli = 0; drli < max_drl_index; drli++) {
1783
0
                    svt_aom_get_av1_mv_pred_drl(
1784
0
                        ctx, ctx->blk_ptr, ref_pair, 1, NEW_NEARMV, drli, nearestmv, nearmv, ref_mv);
1785
1786
                    //NEW_NEARMV
1787
0
                    const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1788
0
                    Mv                 to_inj_mv0 = ctx->sb_me_mv[list_idx_0][ref_idx_0];
1789
0
                    Mv                 to_inj_mv1 = {.as_int = nearmv[1].as_int};
1790
0
                    bool               inj_mv     = (ctx->injected_mv_count == 0 ||
1791
0
                                   !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1792
0
                        svt_aom_is_me_data_present(ctx->me_block_offset, ctx->me_cand_offset, me_results, 0, ref_idx_0);
1793
0
                    if (inj_mv) {
1794
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1795
0
                        cand->block_mi.mode               = NEW_NEARMV;
1796
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1797
0
                        cand->block_mi.is_interintra_used = 0;
1798
0
                        cand->block_mi.use_intrabc        = 0;
1799
0
                        cand->skip_mode_allowed           = false;
1800
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1801
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1802
0
                        cand->drl_index                   = drli;
1803
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1804
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1805
0
                        cand->pred_mv[0].as_int           = ref_mv[0].as_int;
1806
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1807
0
                        INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1808
1809
0
                        if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1810
0
                            ctx->cmp_store.pred0_cnt = 0;
1811
0
                            ctx->cmp_store.pred1_cnt = 0;
1812
0
                            inj_comp_modes(pcs, ctx, &cand_idx);
1813
0
                        }
1814
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1815
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1816
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1817
0
                        ++ctx->injected_mv_count;
1818
0
                    }
1819
0
                }
1820
0
            }
1821
            //NEAR_NEWMV
1822
0
            {
1823
0
                uint8_t max_drl_index = svt_aom_get_max_drl_index(xd->ref_mv_count[ref_pair], NEAR_NEWMV);
1824
1825
0
                for (uint8_t drli = 0; drli < max_drl_index; drli++) {
1826
0
                    svt_aom_get_av1_mv_pred_drl(
1827
0
                        ctx, ctx->blk_ptr, ref_pair, 1, NEAR_NEWMV, drli, nearestmv, nearmv, ref_mv);
1828
1829
                    //NEAR_NEWMV
1830
0
                    const MeSbResults* me_results = pcs->ppcs->pa_me_data->me_results[ctx->me_sb_addr];
1831
0
                    Mv                 to_inj_mv0 = {.as_int = nearmv[0].as_int};
1832
0
                    Mv                 to_inj_mv1 = ctx->sb_me_mv[list_idx_1][ref_idx_1];
1833
0
                    bool               inj_mv     = (ctx->injected_mv_count == 0 ||
1834
0
                                   !mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, ref_pair)) &&
1835
0
                        svt_aom_is_me_data_present(
1836
0
                                      ctx->me_block_offset, ctx->me_cand_offset, me_results, list_idx_1, ref_idx_1);
1837
1838
0
                    if (inj_mv) {
1839
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_idx];
1840
0
                        cand->block_mi.mode               = NEAR_NEWMV;
1841
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
1842
0
                        cand->block_mi.is_interintra_used = 0;
1843
0
                        cand->block_mi.use_intrabc        = 0;
1844
0
                        cand->skip_mode_allowed           = false;
1845
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
1846
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
1847
0
                        cand->drl_index                   = drli;
1848
0
                        cand->block_mi.ref_frame[0]       = rf[0];
1849
0
                        cand->block_mi.ref_frame[1]       = rf[1];
1850
0
                        cand->pred_mv[1].as_int           = ref_mv[1].as_int;
1851
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
1852
0
                        INC_MD_CAND_CNT(cand_idx, pcs->ppcs->max_can_count);
1853
1854
0
                        if (ctx->inter_comp_ctrls.do_nearest_near_new) {
1855
0
                            ctx->cmp_store.pred0_cnt = 0;
1856
0
                            ctx->cmp_store.pred1_cnt = 0;
1857
0
                            inj_comp_modes(pcs, ctx, &cand_idx);
1858
0
                        }
1859
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
1860
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
1861
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = ref_pair;
1862
0
                        ++ctx->injected_mv_count;
1863
0
                    }
1864
0
                }
1865
0
            }
1866
0
        }
1867
0
    }
1868
    //update tot Candidate count
1869
0
    *cand_tot_cnt = cand_idx;
1870
0
}
1871
1872
// Refine the WM MV (8 bit search).  Return true if search found a valid MV; false otherwise
1873
uint8_t svt_aom_wm_motion_refinement(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
1874
0
                                     const bool shut_approx) {
1875
0
    PictureParentControlSet* ppcs         = pcs->ppcs;
1876
0
    const Mv                 neighbors[9] = {
1877
0
        {{0, 0}}, {{-1, 0}}, {{0, 1}}, {{1, 0}}, {{0, -1}}, {{1, -1}}, {{1, 1}}, {{-1, 1}}, {{-1, -1}}};
1878
1879
    // Set info used to get MV cost
1880
0
    int*        mvjcost       = ctx->md_rate_est_ctx->nmv_vec_cost;
1881
0
    const int** mvcost        = ctx->md_rate_est_ctx->nmvcoststack;
1882
0
    uint32_t    full_lambda   = ctx->full_lambda_md[EB_8_BIT_MD]; // 8bit only
1883
0
    int         error_per_bit = full_lambda >> RD_EPB_SHIFT;
1884
0
    error_per_bit += (error_per_bit == 0);
1885
0
    EbPictureBufferDesc*    input_pic          = ppcs->enhanced_pic; // 10BIT not supported
1886
0
    uint32_t                input_origin_index = (ctx->blk_org_y) * input_pic->y_stride + (ctx->blk_org_x);
1887
0
    const AomVarianceFnPtr* fn_ptr             = &svt_aom_mefn_ptr[ctx->blk_geom->bsize];
1888
0
    unsigned int            sse;
1889
0
    uint8_t*                src_y = input_pic->y_buffer + input_origin_index;
1890
1891
0
    int mv_prec_shift = ppcs->frm_hdr.allow_high_precision_mv ? 0 : 1;
1892
0
    int best_cost     = INT_MAX;
1893
    // local WM always uses one ref - MV for ref0 stored in idx0
1894
0
    assert(cand->block_mi.ref_frame[1] == NONE_FRAME);
1895
0
    Mv       search_centre_mv = {.as_int = cand->block_mi.mv[0].as_int};
1896
0
    Mv       best_mv          = {.as_int = cand->block_mi.mv[0].as_int};
1897
0
    Mv       prev_mv          = {.as_int = cand->block_mi.mv[0].as_int};
1898
0
    const Mv ref_mv           = {.as_int = cand->pred_mv[0].as_int};
1899
1900
0
    int      max_iterations  = ctx->wm_ctrls.refinement_iterations;
1901
0
    int      tot_checked_pos = 0;
1902
0
    uint32_t mv_record[256];
1903
0
    for (int iter = 0; iter < max_iterations; iter++) {
1904
        // search the (0,0) offset position only for the first search iteration
1905
0
        for (int i = (iter ? 1 : 0); i < (ctx->wm_ctrls.refine_diag ? 9 : 5); i++) {
1906
0
            const Mv test_mv = (Mv){{search_centre_mv.x + (neighbors[i].x * (1 << mv_prec_shift)),
1907
0
                                     search_centre_mv.y + (neighbors[i].y * (1 << mv_prec_shift))}};
1908
1909
            // Don't re-test previously tested positions
1910
0
            if (iter) {
1911
0
                if (prev_mv.as_int == test_mv.as_int) {
1912
0
                    continue;
1913
0
                }
1914
0
                int match_found = 0;
1915
0
                for (int j = 0; j < tot_checked_pos; j++) {
1916
0
                    if (test_mv.as_int == mv_record[j]) {
1917
0
                        match_found = 1;
1918
0
                    }
1919
0
                }
1920
0
                if (match_found) {
1921
0
                    continue;
1922
0
                }
1923
0
            }
1924
0
            mv_record[tot_checked_pos++] = test_mv.as_int;
1925
0
            uint8_t local_warp_valid     = svt_aom_warped_motion_parameters(ctx,
1926
0
                                                                        test_mv,
1927
0
                                                                        ctx->blk_geom,
1928
0
                                                                        cand->block_mi.ref_frame[0],
1929
0
                                                                        &cand->wm_params_l0,
1930
0
                                                                        &cand->block_mi.num_proj_ref,
1931
0
                                                                        ctx->wm_ctrls.lower_band_th,
1932
0
                                                                        ctx->wm_ctrls.upper_band_th,
1933
0
                                                                        shut_approx);
1934
0
            if (!local_warp_valid) {
1935
0
                continue;
1936
0
            }
1937
0
            assert(cand->block_mi.ref_frame[1] == NONE_FRAME);
1938
0
            EbPictureBufferDesc* ref_pic_0 = svt_aom_get_ref_pic_buffer(pcs, cand->block_mi.ref_frame[0]);
1939
0
            EbPictureBufferDesc* ref_pic_1 = NULL; // will stay NULL b/c this is unipred candidate
1940
1941
            // update MV to be testing MV before calling prediction function
1942
0
            cand->block_mi.mv[0].as_int = test_mv.as_int;
1943
0
            svt_aom_inter_prediction(pcs->scs,
1944
0
                                     pcs,
1945
0
                                     &cand->block_mi,
1946
0
                                     &cand->wm_params_l0,
1947
0
                                     &cand->wm_params_l1,
1948
0
                                     ctx->blk_ptr,
1949
0
                                     ctx->blk_geom->bsize,
1950
0
                                     ctx->shape,
1951
                                     // If using 8bit MD for HBD content, can't use pre-computed OBMC/II to
1952
                                     // generate conformant recon
1953
0
                                     true, //use_precomputed_obmc - not used here
1954
0
                                     true, //use_precomputed_ii - not used here
1955
0
                                     ctx,
1956
0
                                     ctx->recon_neigh_y,
1957
0
                                     ctx->recon_neigh_cb,
1958
0
                                     ctx->recon_neigh_cr,
1959
0
                                     ref_pic_0,
1960
0
                                     ref_pic_1, // this is NULL
1961
0
                                     ctx->blk_org_x,
1962
0
                                     ctx->blk_org_y,
1963
0
                                     ctx->scratch_prediction_ptr,
1964
0
                                     0,
1965
0
                                     0,
1966
0
                                     PICTURE_BUFFER_DESC_LUMA_MASK,
1967
0
                                     EB_EIGHT_BIT,
1968
0
                                     0); // is_16bit_pipeline
1969
1970
0
            int var = fn_ptr->vf(ctx->scratch_prediction_ptr->y_buffer,
1971
0
                                 ctx->scratch_prediction_ptr->y_stride,
1972
0
                                 src_y,
1973
0
                                 input_pic->y_stride,
1974
0
                                 &sse);
1975
0
            if (ctx->approx_inter_rate) {
1976
0
                var += svt_aom_mv_err_cost_light(&test_mv, &ref_mv);
1977
0
            } else {
1978
0
                var += svt_aom_mv_err_cost(&test_mv, &ref_mv, mvjcost, mvcost, error_per_bit);
1979
0
            }
1980
1981
0
            if (var < best_cost) {
1982
0
                best_mv.as_int = test_mv.as_int;
1983
0
                best_cost      = var;
1984
0
            }
1985
0
        }
1986
0
        prev_mv.as_int          = search_centre_mv.as_int;
1987
0
        search_centre_mv.as_int = best_mv.as_int;
1988
0
        if (prev_mv.as_int == best_mv.as_int) {
1989
0
            break;
1990
0
        }
1991
0
    }
1992
0
    cand->block_mi.mv[0].as_int = best_mv.as_int;
1993
1994
    // Derive pred MV for best WM position
1995
0
    Mv best_pred_mv[2] = {{{0}}, {{0}}};
1996
0
    svt_aom_choose_best_av1_mv_pred(ctx,
1997
0
                                    cand->block_mi.ref_frame[0], // WM only allowed for unipred cands
1998
0
                                    cand->block_mi.mode,
1999
0
                                    cand->block_mi.mv[0],
2000
0
                                    (Mv){{0}},
2001
0
                                    &cand->drl_index,
2002
0
                                    best_pred_mv);
2003
0
    cand->pred_mv[0].as_int = best_pred_mv[0].as_int;
2004
2005
    // Check that final chosen MV is valid
2006
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, best_mv, best_mv, 0)) {
2007
0
        return 1;
2008
0
    }
2009
2010
0
    return 0;
2011
0
}
2012
2013
static INLINE void setup_pred_plane(Buf2D* dst, BlockSize bsize, uint8_t* src, int width, int height, int stride,
2014
0
                                    int mi_row, int mi_col, int subsampling_x, int subsampling_y) {
2015
    // Offset the buffer pointer
2016
0
    if (subsampling_y && (mi_row & 0x01) && (mi_size_high[bsize] == 1)) {
2017
0
        mi_row -= 1;
2018
0
    }
2019
0
    if (subsampling_x && (mi_col & 0x01) && (mi_size_wide[bsize] == 1)) {
2020
0
        mi_col -= 1;
2021
0
    }
2022
2023
0
    const int x = (MI_SIZE * mi_col) >> subsampling_x;
2024
0
    const int y = (MI_SIZE * mi_row) >> subsampling_y;
2025
0
    dst->buf    = src + (y * stride + x); // scaled_buffer_offset(x, y, stride, scale);
2026
0
    dst->buf0   = src;
2027
0
    dst->width  = width;
2028
0
    dst->height = height;
2029
0
    dst->stride = stride;
2030
0
}
2031
2032
void svt_av1_setup_pred_block(BlockSize bsize, Buf2D dst[MAX_PLANES], const Yv12BufferConfig* src, int mi_row,
2033
0
                              int mi_col) {
2034
0
    dst[0].buf    = src->y_buffer;
2035
0
    dst[0].stride = src->y_stride;
2036
0
    dst[1].buf    = src->u_buffer;
2037
0
    dst[2].buf    = src->v_buffer;
2038
0
    dst[1].stride = dst[2].stride = src->uv_stride;
2039
2040
0
    setup_pred_plane(
2041
0
        dst, bsize, dst[0].buf, src->y_crop_width, src->y_crop_height, dst[0].stride, mi_row, mi_col, 0, 0);
2042
0
}
2043
2044
static int sad_per_bit_lut_8[QINDEX_RANGE];
2045
static int sad_per_bit_lut_10[QINDEX_RANGE];
2046
2047
// Get the sad per bit for the relevant qindex and bit depth
2048
0
int svt_aom_get_sad_per_bit(int qidx, EbBitDepth is_hbd) {
2049
0
    return is_hbd ? sad_per_bit_lut_10[qidx] : sad_per_bit_lut_8[qidx];
2050
0
}
2051
2052
2
static void init_me_luts_bd(int* bit16lut, int range, EbBitDepth bit_depth) {
2053
2
    int i;
2054
    // Initialize the sad lut tables using a formulaic calculation for now.
2055
    // This is to make it easier to resolve the impact of experimental changes
2056
    // to the quantizer tables.
2057
514
    for (i = 0; i < range; i++) {
2058
512
        const double q = svt_av1_convert_qindex_to_q(i, bit_depth);
2059
512
        bit16lut[i]    = (int)(0.0418 * q + 2.4107);
2060
512
    }
2061
2
}
2062
2063
1
void svt_av1_init_me_luts(void) {
2064
1
    init_me_luts_bd(sad_per_bit_lut_8, QINDEX_RANGE, EB_EIGHT_BIT);
2065
1
    init_me_luts_bd(sad_per_bit_lut_10, QINDEX_RANGE, EB_TEN_BIT);
2066
1
}
2067
2068
#if CONFIG_ENABLE_OBMC
2069
static void single_motion_search(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
2070
                                 Mv best_pred_mv, IntraBcContext* x, BlockSize bsize, Mv* ref_mv, int* rate_mv,
2071
0
                                 int refine_level) {
2072
0
    bool do_full_refine = 0;
2073
0
    bool do_frac_refine = 0;
2074
0
    switch (refine_level) {
2075
0
    case 0:
2076
0
    case 1:
2077
0
    case 3:
2078
0
        do_full_refine = 1;
2079
0
        do_frac_refine = 1;
2080
0
        break;
2081
0
    case 2:
2082
0
    case 4:
2083
0
        do_full_refine = 0;
2084
0
        do_frac_refine = 1;
2085
0
        break;
2086
0
    default:
2087
0
        break;
2088
0
    }
2089
0
    const Av1Common* const cm      = pcs->ppcs->av1_cm;
2090
0
    FrameHeader*           frm_hdr = &pcs->ppcs->frm_hdr;
2091
    // single_motion_search supports 8bit path only
2092
0
    uint32_t full_lambda = ctx->full_lambda_md[EB_8_BIT_MD];
2093
2094
0
    x->xd            = ctx->blk_ptr->av1xd;
2095
0
    const int mi_row = -x->xd->mb_to_top_edge / (8 * MI_SIZE);
2096
0
    const int mi_col = -x->xd->mb_to_left_edge / (8 * MI_SIZE);
2097
2098
0
    x->nmv_vec_cost  = ctx->md_rate_est_ctx->nmv_vec_cost;
2099
0
    x->mv_cost_stack = ctx->md_rate_est_ctx->nmvcoststack;
2100
    // Set up limit values for MV components.
2101
    // Mv beyond the range do not produce new/different prediction block.
2102
0
    const int mi_width   = mi_size_wide[bsize];
2103
0
    const int mi_height  = mi_size_high[bsize];
2104
0
    x->mv_limits.row_min = -(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
2105
0
    x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
2106
0
    x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND;
2107
0
    x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND;
2108
    //set search paramters
2109
0
    x->sadperbit16 = svt_aom_get_sad_per_bit(frm_hdr->quantization_params.base_q_idx, 0);
2110
0
    x->errorperbit = full_lambda >> RD_EPB_SHIFT;
2111
0
    x->errorperbit += (x->errorperbit == 0);
2112
0
    if (do_full_refine) {
2113
0
        int      sadpb         = x->sadperbit16;
2114
0
        MvLimits tmp_mv_limits = x->mv_limits;
2115
2116
        // Note: MV limits are modified here. Always restore the original values
2117
        // after full-pixel motion search.
2118
0
        svt_av1_set_mv_search_range(&x->mv_limits, ref_mv);
2119
2120
0
        Mv mvp_full = best_pred_mv; // mbmi->mv[0].as_mv;
2121
2122
        // TODO: should use get_fullmv_from_mv instead of shifting
2123
0
        mvp_full.x >>= 3;
2124
0
        mvp_full.y >>= 3;
2125
2126
0
        x->best_mv.as_int = x->second_best_mv.as_int = INVALID_MV; //D
2127
2128
0
        switch (cand->block_mi.motion_mode) {
2129
0
        case OBMC_CAUSAL:
2130
0
            svt_av1_obmc_full_pixel_search(
2131
0
                ctx, x, &mvp_full, sadpb, &svt_aom_mefn_ptr[bsize], ref_mv, &(x->best_mv), 0);
2132
0
            break;
2133
0
        default:
2134
0
            assert(0 && "Invalid motion mode!\n");
2135
0
        }
2136
2137
0
        x->mv_limits = tmp_mv_limits;
2138
0
    } else { // round-up the default
2139
0
        x->best_mv.x = best_pred_mv.x >> 3;
2140
0
        x->best_mv.y = best_pred_mv.y >> 3;
2141
0
    }
2142
2143
0
    if (do_frac_refine) {
2144
0
        int          dis; /* TODO: use dis in distortion calculation later. */
2145
0
        unsigned int sse1; //unused
2146
0
        switch (cand->block_mi.motion_mode) {
2147
0
        case OBMC_CAUSAL:
2148
0
            svt_av1_find_best_obmc_sub_pixel_tree_up(ctx,
2149
0
                                                     x,
2150
0
                                                     cm,
2151
0
                                                     mi_row,
2152
0
                                                     mi_col,
2153
0
                                                     &x->best_mv,
2154
0
                                                     ref_mv,
2155
0
                                                     frm_hdr->allow_high_precision_mv,
2156
0
                                                     x->errorperbit,
2157
0
                                                     &svt_aom_mefn_ptr[bsize],
2158
0
                                                     0, // mv.subpel_force_stop
2159
0
                                                     2, //  mv.subpel_iters_per_step
2160
0
                                                     x->nmv_vec_cost,
2161
0
                                                     x->mv_cost_stack,
2162
0
                                                     &dis,
2163
0
                                                     &sse1,
2164
0
                                                     0,
2165
0
                                                     USE_8_TAPS);
2166
2167
0
            break;
2168
0
        default:
2169
0
            assert(0 && "Invalid motion mode!\n");
2170
0
        }
2171
0
    } else {
2172
0
        x->best_mv.x *= 8;
2173
0
        x->best_mv.y *= 8;
2174
0
    }
2175
0
    if (ctx->approx_inter_rate) {
2176
0
        *rate_mv = svt_av1_mv_bit_cost_light(&x->best_mv, ref_mv);
2177
0
    } else {
2178
0
        *rate_mv = svt_av1_mv_bit_cost(&x->best_mv, ref_mv, x->nmv_vec_cost, x->mv_cost_stack, MV_COST_WEIGHT);
2179
0
    }
2180
0
}
2181
2182
// Refine the OBMC MV (8 bit search). Return true if search found a valid MV; false otherwise
2183
uint8_t svt_aom_obmc_motion_refinement(PictureControlSet* pcs, ModeDecisionContext* ctx, ModeDecisionCandidate* cand,
2184
0
                                       int refine_level) {
2185
0
    if (block_size_wide[ctx->blk_geom->bsize] > ctx->obmc_ctrls.max_blk_size_to_refine ||
2186
0
        block_size_high[ctx->blk_geom->bsize] > ctx->obmc_ctrls.max_blk_size_to_refine) {
2187
0
        return 1;
2188
0
    }
2189
2190
0
    if (ctx->obmc_weighted_pred_ready == false) {
2191
0
        int mi_row = ctx->blk_org_y >> 2;
2192
0
        int mi_col = ctx->blk_org_x >> 2;
2193
2194
0
        DECLARE_ALIGNED(16, uint8_t, dst_buf1_8b[4 * MAX_PLANES * MAX_SB_SQUARE]);
2195
2196
0
        uint8_t* dst_buf2_8b = dst_buf1_8b + 2 * MAX_PLANES * MAX_SB_SQUARE;
2197
0
        if (ctx->obmc_is_luma_neigh_10bit) {
2198
0
            svt_aom_un_pack2d((uint16_t*)ctx->obmc_buff_0,
2199
0
                              ctx->blk_geom->bwidth,
2200
0
                              dst_buf1_8b,
2201
0
                              ctx->blk_geom->bwidth,
2202
0
                              NULL,
2203
0
                              ctx->blk_geom->bwidth,
2204
0
                              ctx->blk_geom->bwidth,
2205
0
                              ctx->blk_geom->bheight);
2206
2207
0
            svt_aom_un_pack2d((uint16_t*)ctx->obmc_buff_1,
2208
0
                              ctx->blk_geom->bwidth,
2209
0
                              dst_buf2_8b,
2210
0
                              ctx->blk_geom->bwidth,
2211
0
                              NULL,
2212
0
                              ctx->blk_geom->bwidth,
2213
0
                              ctx->blk_geom->bwidth,
2214
0
                              ctx->blk_geom->bheight);
2215
0
        }
2216
2217
0
        calc_target_weighted_pred(pcs,
2218
0
                                  ctx,
2219
0
                                  pcs->ppcs->av1_cm,
2220
0
                                  ctx->blk_ptr->av1xd,
2221
0
                                  mi_row,
2222
0
                                  mi_col,
2223
0
                                  ctx->obmc_is_luma_neigh_10bit ? dst_buf1_8b : ctx->obmc_buff_0,
2224
0
                                  ctx->blk_geom->bwidth,
2225
0
                                  ctx->obmc_is_luma_neigh_10bit ? dst_buf2_8b : ctx->obmc_buff_1,
2226
0
                                  ctx->blk_geom->bwidth);
2227
2228
0
        ctx->obmc_weighted_pred_ready = true;
2229
0
    }
2230
0
    Mv              best_pred_mv[2] = {{{0}}, {{0}}};
2231
0
    IntraBcContext  x_st;
2232
0
    IntraBcContext* x = &x_st;
2233
2234
0
    MacroBlockD* xd;
2235
0
    xd = x->xd       = ctx->blk_ptr->av1xd;
2236
0
    const int mi_row = -xd->mb_to_top_edge / (8 * MI_SIZE);
2237
0
    const int mi_col = -xd->mb_to_left_edge / (8 * MI_SIZE);
2238
2239
0
    {
2240
0
        assert(cand->block_mi.ref_frame[1] == NONE_FRAME); // OBMC only allowed for unipred cands
2241
0
        uint8_t ref_idx  = get_ref_frame_idx(cand->block_mi.ref_frame[0]);
2242
0
        uint8_t list_idx = get_list_idx(cand->block_mi.ref_frame[0]);
2243
2244
0
        assert(list_idx < MAX_NUM_OF_REF_PIC_LIST);
2245
0
        EbPictureBufferDesc* reference_picture =
2246
0
            ((EbReferenceObject*)pcs->ref_pic_ptr_array[list_idx][ref_idx]->object_ptr)->reference_picture;
2247
2248
0
        svt_aom_use_scaled_rec_refs_if_needed(pcs,
2249
0
                                              pcs->ppcs->enhanced_pic,
2250
0
                                              (EbReferenceObject*)pcs->ref_pic_ptr_array[list_idx][ref_idx]->object_ptr,
2251
0
                                              &reference_picture,
2252
0
                                              EB_8_BIT_MD);
2253
0
        Yv12BufferConfig ref_buf;
2254
0
        svt_aom_link_eb_to_aom_buffer_desc_8bit(reference_picture, &ref_buf);
2255
2256
0
        Buf2D yv12_mb[MAX_PLANES];
2257
0
        svt_av1_setup_pred_block(ctx->blk_geom->bsize, yv12_mb, &ref_buf, mi_row, mi_col);
2258
0
        for (int i = 0; i < 1; ++i) {
2259
0
            x->xdplane[i].pre[0] = yv12_mb[i]; //ref in ME
2260
0
        }
2261
2262
0
        x->plane[0].src.buf  = 0; // x->xdplane[0].pre[0];
2263
0
        x->plane[0].src.buf0 = 0;
2264
0
    }
2265
2266
0
    Mv  best_mv = {.as_int = cand->block_mi.mv[0].as_int};
2267
0
    int tmp_rate_mv;
2268
2269
0
    Mv ref_mv = {.as_int = cand->pred_mv[0].as_int};
2270
2271
0
    single_motion_search(pcs, ctx, cand, best_mv, x, ctx->blk_geom->bsize, &ref_mv, &tmp_rate_mv, refine_level);
2272
0
    cand->block_mi.mv[0].as_int = x->best_mv.as_int;
2273
0
    svt_aom_choose_best_av1_mv_pred(ctx,
2274
0
                                    cand->block_mi.ref_frame[0], // OBMC only allowed for unipred candidtes
2275
0
                                    cand->block_mi.mode,
2276
0
                                    cand->block_mi.mv[0],
2277
0
                                    (Mv){{0}},
2278
0
                                    &cand->drl_index,
2279
0
                                    best_pred_mv);
2280
0
    cand->pred_mv[0].as_int = best_pred_mv[0].as_int;
2281
    // Check that final chosen MV is valid
2282
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, cand->block_mi.mv[0], cand->block_mi.mv[0], 0)) {
2283
0
        return 1;
2284
0
    }
2285
2286
0
    return 0;
2287
0
}
2288
#endif // CONFIG_ENABLE_OBMC
2289
2290
/*
2291
   inject ME candidates for Light PD0
2292
*/
2293
static void inject_new_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2294
0
                                      const bool allow_bipred) {
2295
0
    const uint32_t         me_sb_addr       = ctx->me_sb_addr;
2296
0
    const uint32_t         me_block_offset  = ctx->me_block_offset;
2297
0
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
2298
0
    uint32_t               cand_total_cnt   = (*candidate_total_cnt);
2299
0
    const MeSbResults*     me_results       = pcs->ppcs->pa_me_data->me_results[me_sb_addr];
2300
0
    const uint8_t          total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
2301
0
    const MeCandidate*     me_block_results = &me_results->me_candidate_array[ctx->me_cand_offset];
2302
2303
0
    const uint8_t max_refs = pcs->ppcs->pa_me_data->max_refs;
2304
0
    const uint8_t max_l0   = pcs->ppcs->pa_me_data->max_l0;
2305
2306
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
2307
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
2308
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
2309
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
2310
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
2311
2312
0
        if (ctx->pd0_ctrls.pd0_level == PD0_LVL_6 && inter_direction == BI_PRED) {
2313
0
            continue;
2314
0
        }
2315
2316
        /**************
2317
            NEWMV
2318
        ************* */
2319
0
        if (inter_direction < BI_PRED) {
2320
0
            const uint8_t list_idx = inter_direction;
2321
0
            const uint8_t ref_idx  = inter_direction ? list1_ref_index : list0_ref_index;
2322
0
            const int16_t to_inject_mv_x =
2323
0
                (me_results->me_mv_array[me_block_offset * max_refs + (inter_direction ? max_l0 : 0) + ref_idx].x) * 8;
2324
0
            const int16_t to_inject_mv_y =
2325
0
                (me_results->me_mv_array[me_block_offset * max_refs + (inter_direction ? max_l0 : 0) + ref_idx].y) * 8;
2326
0
            const uint8_t to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
2327
2328
0
            ModeDecisionCandidate* cand = &cand_array[cand_total_cnt];
2329
0
            cand->block_mi.mode         = NEWMV;
2330
0
            cand->block_mi.mv[0]        = (Mv){{to_inject_mv_x, to_inject_mv_y}};
2331
0
            cand->block_mi.ref_frame[0] = to_inject_ref_type;
2332
0
            cand->block_mi.ref_frame[1] = NONE_FRAME;
2333
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2334
0
            if (cand_total_cnt > 2) {
2335
0
                break;
2336
0
            }
2337
0
        } else if (allow_bipred) {
2338
0
            assert(inter_direction == BI_PRED);
2339
            /**************
2340
               NEW_NEWMV
2341
            ************* */
2342
0
            const uint32_t ref0_offset = me_block_offset * max_refs +
2343
0
                (me_block_results_ptr->ref0_list > 0 ? max_l0 : 0) + list0_ref_index;
2344
0
            const uint32_t ref1_offset = me_block_offset * max_refs +
2345
0
                (me_block_results_ptr->ref1_list > 0 ? max_l0 : 0) + list1_ref_index;
2346
0
            const int16_t to_inject_mv_x_l0 = (me_results->me_mv_array[ref0_offset].x) * 8;
2347
0
            const int16_t to_inject_mv_y_l0 = (me_results->me_mv_array[ref0_offset].y) * 8;
2348
0
            const int16_t to_inject_mv_x_l1 = (me_results->me_mv_array[ref1_offset].x) * 8;
2349
0
            const int16_t to_inject_mv_y_l1 = (me_results->me_mv_array[ref1_offset].y) * 8;
2350
2351
0
            MvReferenceFrame rf[2] = {svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2352
0
                                      svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)};
2353
2354
            // Inject AVG candidate only
2355
0
            ModeDecisionCandidate* cand   = &cand_array[cand_total_cnt];
2356
0
            cand->block_mi.mv[REF_LIST_0] = (Mv){{to_inject_mv_x_l0, to_inject_mv_y_l0}};
2357
0
            cand->block_mi.mv[REF_LIST_1] = (Mv){{to_inject_mv_x_l1, to_inject_mv_y_l1}};
2358
0
            cand->block_mi.mode           = NEW_NEWMV;
2359
0
            cand->block_mi.ref_frame[0]   = rf[0];
2360
0
            cand->block_mi.ref_frame[1]   = rf[1];
2361
0
            determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2362
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2363
0
            if (cand_total_cnt > 2) {
2364
0
                break;
2365
0
            }
2366
0
        }
2367
0
    }
2368
    // update the total number of candidates injected
2369
0
    (*candidate_total_cnt) = cand_total_cnt;
2370
0
}
2371
2372
static void inject_new_candidates_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
2373
0
                                            uint32_t* candidate_total_cnt, const bool allow_bipred) {
2374
0
    const uint32_t         me_sb_addr       = ctx->me_sb_addr;
2375
0
    const uint32_t         me_block_offset  = ctx->me_block_offset;
2376
0
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
2377
0
    Mv                     best_pred_mv[2]  = {{{0}}, {{0}}};
2378
0
    uint32_t               cand_total_cnt   = (*candidate_total_cnt);
2379
0
    const MeSbResults*     me_results       = pcs->ppcs->pa_me_data->me_results[me_sb_addr];
2380
0
    const uint8_t          total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
2381
0
    const MeCandidate*     me_block_results = &me_results->me_candidate_array[ctx->me_cand_offset];
2382
2383
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
2384
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
2385
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
2386
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
2387
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
2388
2389
0
        if (ctx->cand_reduction_ctrls.reduce_unipred_candidates >= 2) {
2390
0
            if ((total_me_cnt > 1) && (inter_direction != 2)) {
2391
0
                continue;
2392
0
            }
2393
0
        } else if (ctx->cand_reduction_ctrls.reduce_unipred_candidates) {
2394
0
            if ((total_me_cnt > 3) && (inter_direction != 2)) {
2395
0
                continue;
2396
0
            }
2397
0
        }
2398
2399
        /**************
2400
            NEWMV
2401
        ************* */
2402
0
        if (inter_direction < BI_PRED) {
2403
0
            const uint8_t list_idx           = inter_direction;
2404
0
            const uint8_t ref_idx            = inter_direction ? list1_ref_index : list0_ref_index;
2405
0
            Mv            to_inj_mv          = ctx->sb_me_mv[list_idx][ref_idx];
2406
0
            const uint8_t to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
2407
0
            if (ctx->injected_mv_count == 0 ||
2408
0
                mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, to_inject_ref_type) == false) {
2409
0
                uint8_t drl_index = 0;
2410
0
                svt_aom_choose_best_av1_mv_pred(
2411
0
                    ctx, to_inject_ref_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
2412
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
2413
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2414
0
                    cand->block_mi.use_intrabc        = 0;
2415
0
                    cand->block_mi.is_interintra_used = 0;
2416
0
                    cand->skip_mode_allowed           = false;
2417
0
                    cand->block_mi.mode               = NEWMV;
2418
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2419
0
                    cand->drl_index                   = drl_index;
2420
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2421
0
                    cand->block_mi.ref_frame[0]       = to_inject_ref_type;
2422
0
                    cand->block_mi.ref_frame[1]       = NONE_FRAME;
2423
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2424
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[to_inject_ref_type].num;
2425
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2426
                    // Add the injected MV to the list of injected MVs
2427
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2428
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2429
0
                    ++ctx->injected_mv_count;
2430
0
                }
2431
0
            }
2432
0
        } else if (allow_bipred && inter_direction == 2 &&
2433
0
                   !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2434
            /**************
2435
               NEW_NEWMV
2436
            ************* */
2437
0
            Mv               to_inj_mv0 = ctx->sb_me_mv[me_block_results_ptr->ref0_list][list0_ref_index];
2438
0
            Mv               to_inj_mv1 = ctx->sb_me_mv[me_block_results_ptr->ref1_list][list1_ref_index];
2439
0
            MvReferenceFrame rf[2]      = {svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2440
0
                                           svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)};
2441
0
            uint8_t          to_inject_ref_type = av1_ref_frame_type(rf);
2442
0
            if ((ctx->injected_mv_count == 0 ||
2443
0
                 mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
2444
0
                uint8_t drl_index = 0;
2445
0
                svt_aom_choose_best_av1_mv_pred(
2446
0
                    ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
2447
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
2448
0
                    ModeDecisionCandidate* cand         = &cand_array[cand_total_cnt];
2449
0
                    cand->block_mi.use_intrabc          = 0;
2450
0
                    cand->block_mi.is_interintra_used   = 0;
2451
0
                    cand->skip_mode_allowed             = false;
2452
0
                    cand->drl_index                     = drl_index;
2453
0
                    cand->block_mi.mv[0].as_int         = to_inj_mv0.as_int;
2454
0
                    cand->block_mi.mv[1].as_int         = to_inj_mv1.as_int;
2455
0
                    cand->block_mi.mode                 = NEW_NEWMV;
2456
0
                    cand->block_mi.motion_mode          = SIMPLE_TRANSLATION;
2457
0
                    cand->block_mi.ref_frame[0]         = rf[0];
2458
0
                    cand->block_mi.ref_frame[1]         = rf[1];
2459
0
                    cand->pred_mv[0].as_int             = best_pred_mv[0].as_int;
2460
0
                    cand->pred_mv[1].as_int             = best_pred_mv[1].as_int;
2461
0
                    cand->block_mi.comp_group_idx       = 0;
2462
0
                    cand->block_mi.compound_idx         = 1;
2463
0
                    cand->block_mi.interinter_comp.type = COMPOUND_AVERAGE;
2464
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2465
2466
                    // Add the injected MV to the list of injected MVs
2467
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2468
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2469
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2470
0
                    ++ctx->injected_mv_count;
2471
0
                }
2472
0
            }
2473
0
        }
2474
0
    }
2475
    // update the total number of candidates injected
2476
0
    (*candidate_total_cnt) = cand_total_cnt;
2477
0
}
2478
2479
static void inject_new_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2480
0
                                  const bool allow_bipred) {
2481
0
    const uint32_t         me_sb_addr       = ctx->me_sb_addr;
2482
0
    const uint32_t         me_block_offset  = ctx->me_block_offset;
2483
0
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
2484
0
    Mv                     best_pred_mv[2]  = {{{0}}, {{0}}};
2485
0
    uint32_t               cand_total_cnt   = (*candidate_total_cnt);
2486
0
    const MeSbResults*     me_results       = pcs->ppcs->pa_me_data->me_results[me_sb_addr];
2487
0
    const uint8_t          total_me_cnt     = me_results->total_me_candidate_index[me_block_offset];
2488
0
    const MeCandidate*     me_block_results = &me_results->me_candidate_array[ctx->me_cand_offset];
2489
2490
0
    for (uint8_t me_candidate_index = 0; me_candidate_index < total_me_cnt; ++me_candidate_index) {
2491
0
        const MeCandidate* me_block_results_ptr = &me_block_results[me_candidate_index];
2492
0
        const uint8_t      inter_direction      = me_block_results_ptr->direction;
2493
0
        const uint8_t      list0_ref_index      = me_block_results_ptr->ref_idx_l0;
2494
0
        const uint8_t      list1_ref_index      = me_block_results_ptr->ref_idx_l1;
2495
2496
0
        if (ctx->cand_reduction_ctrls.reduce_unipred_candidates) {
2497
0
            if ((total_me_cnt > 3) && (inter_direction != 2)) {
2498
0
                continue;
2499
0
            }
2500
0
        }
2501
2502
        /**************
2503
            NEWMV unipred
2504
        ************* */
2505
0
        if (inter_direction < BI_PRED) {
2506
0
            const uint8_t list_idx = inter_direction;
2507
0
            const uint8_t ref_idx  = list_idx == REF_LIST_0 ? list0_ref_index : list1_ref_index;
2508
0
            if (!svt_aom_is_valid_unipred_ref(ctx, MIN(TOT_INTER_GROUP - 1, PA_ME_GROUP), list_idx, ref_idx)) {
2509
0
                continue;
2510
0
            }
2511
0
            Mv      to_inj_mv          = ctx->sb_me_mv[list_idx][ref_idx];
2512
0
            uint8_t to_inject_ref_type = svt_get_ref_frame_type(list_idx, ref_idx);
2513
0
            if ((ctx->injected_mv_count == 0 ||
2514
0
                 mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, to_inject_ref_type) == false)) {
2515
0
                uint8_t drl_index = 0;
2516
0
                svt_aom_choose_best_av1_mv_pred(
2517
0
                    ctx, to_inject_ref_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
2518
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
2519
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2520
0
                    cand->block_mi.use_intrabc        = 0;
2521
0
                    cand->skip_mode_allowed           = false;
2522
0
                    cand->block_mi.mode               = NEWMV;
2523
0
                    cand->drl_index                   = drl_index;
2524
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2525
0
                    cand->block_mi.ref_frame[0]       = to_inject_ref_type;
2526
0
                    cand->block_mi.ref_frame[1]       = NONE_FRAME;
2527
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2528
0
                    cand->block_mi.is_interintra_used = 0;
2529
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2530
0
                    cand->block_mi.num_proj_ref       = ctx->wm_sample_info[to_inject_ref_type].num;
2531
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2532
2533
0
                    const bool enable_ii   = true;
2534
0
                    const bool enable_obmc = true;
2535
0
                    const bool enable_warp = true;
2536
0
                    inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
2537
2538
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2539
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2540
0
                    ++ctx->injected_mv_count;
2541
0
                }
2542
0
            }
2543
0
        } else if (allow_bipred &&
2544
0
                   !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2545
0
            assert(inter_direction == BI_PRED);
2546
            /**************
2547
               NEW_NEWMV
2548
            ************* */
2549
0
            if (!is_valid_bipred_ref(ctx,
2550
0
                                     PA_ME_GROUP,
2551
0
                                     me_block_results_ptr->ref0_list,
2552
0
                                     list0_ref_index,
2553
0
                                     me_block_results_ptr->ref1_list,
2554
0
                                     list1_ref_index)) {
2555
0
                continue;
2556
0
            }
2557
0
            Mv      to_inj_mv0         = ctx->sb_me_mv[me_block_results_ptr->ref0_list][list0_ref_index];
2558
0
            Mv      to_inj_mv1         = ctx->sb_me_mv[me_block_results_ptr->ref1_list][list1_ref_index];
2559
0
            uint8_t to_inject_ref_type = av1_ref_frame_type(
2560
0
                (const MvReferenceFrame[]){svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2561
0
                                           svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)});
2562
0
            if ((ctx->injected_mv_count == 0 ||
2563
0
                 mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
2564
0
                uint8_t drl_index = 0;
2565
0
                svt_aom_choose_best_av1_mv_pred(
2566
0
                    ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
2567
0
                if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
2568
0
                    MvReferenceFrame rf[2] = {svt_get_ref_frame_type(me_block_results_ptr->ref0_list, list0_ref_index),
2569
0
                                              svt_get_ref_frame_type(me_block_results_ptr->ref1_list, list1_ref_index)};
2570
0
                    ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2571
0
                    cand->block_mi.use_intrabc        = 0;
2572
0
                    cand->skip_mode_allowed           = false;
2573
0
                    cand->drl_index                   = drl_index;
2574
0
                    cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
2575
0
                    cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
2576
0
                    cand->block_mi.mode               = NEW_NEWMV;
2577
0
                    cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2578
0
                    cand->block_mi.is_interintra_used = 0;
2579
0
                    cand->block_mi.ref_frame[0]       = rf[0];
2580
0
                    cand->block_mi.ref_frame[1]       = rf[1];
2581
0
                    cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2582
0
                    cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
2583
0
                    determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2584
0
                    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2585
2586
0
                    if (ctx->inter_comp_ctrls.do_me) {
2587
0
                        ctx->cmp_store.pred0_cnt = 0;
2588
0
                        ctx->cmp_store.pred1_cnt = 0;
2589
0
                        inj_comp_modes(pcs, ctx, &cand_total_cnt);
2590
0
                    }
2591
0
                    ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2592
0
                    ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2593
0
                    ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2594
0
                    ++ctx->injected_mv_count;
2595
0
                }
2596
0
            }
2597
0
        }
2598
0
    }
2599
    // update the total number of candidates injected
2600
0
    (*candidate_total_cnt) = cand_total_cnt;
2601
0
}
2602
2603
static void inject_global_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2604
0
                                     const bool allow_bipred) {
2605
0
    ModeDecisionCandidate* cand_array     = ctx->fast_cand_array;
2606
0
    uint32_t               cand_total_cnt = (*candidate_total_cnt);
2607
0
    uint32_t               mi_row         = ctx->blk_org_y >> MI_SIZE_LOG2;
2608
0
    uint32_t               mi_col         = ctx->blk_org_x >> MI_SIZE_LOG2;
2609
2610
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
2611
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
2612
0
        MvReferenceFrame rf[2];
2613
0
        av1_set_ref_frame(rf, ref_pair);
2614
2615
        //single ref/list
2616
0
        if (rf[1] == NONE_FRAME) {
2617
0
            MvReferenceFrame frame_type = rf[0];
2618
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
2619
0
            uint8_t          ref_idx    = get_ref_frame_idx(rf[0]);
2620
2621
0
            if (!svt_aom_is_valid_unipred_ref(ctx, GLOBAL_GROUP, list_idx, ref_idx)) {
2622
0
                continue;
2623
0
            }
2624
            // Get gm params
2625
0
            WarpedMotionParams* gm_params = &pcs->ppcs->global_motion[frame_type];
2626
0
            if (pcs->ppcs->gm_ctrls.skip_identity && gm_params->wmtype == IDENTITY) {
2627
0
                continue;
2628
0
            }
2629
0
            Mv to_inj_mv = svt_aom_gm_get_motion_vector_enc(gm_params,
2630
0
                                                            pcs->ppcs->frm_hdr.allow_high_precision_mv,
2631
0
                                                            ctx->blk_geom->bsize,
2632
0
                                                            mi_col,
2633
0
                                                            mi_row,
2634
0
                                                            0 /* force_integer_mv */);
2635
2636
0
            assert(list_idx == 0 || list_idx == 1);
2637
0
            ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2638
0
            cand->block_mi.mode               = GLOBALMV;
2639
0
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2640
0
            cand->block_mi.is_interintra_used = 0;
2641
0
            cand->wm_params_l0                = *gm_params;
2642
0
            cand->wm_params_l1                = *gm_params;
2643
0
            cand->block_mi.use_intrabc        = 0;
2644
0
            cand->skip_mode_allowed           = false;
2645
0
            cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2646
0
            cand->drl_index                   = 0;
2647
0
            cand->block_mi.ref_frame[0]       = rf[0];
2648
0
            cand->block_mi.ref_frame[1]       = rf[1];
2649
0
            cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
2650
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2651
2652
0
            const bool enable_ii   = true;
2653
0
            const bool enable_obmc = false;
2654
0
            const bool enable_warp = false;
2655
0
            inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
2656
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2657
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
2658
0
            ++ctx->injected_mv_count;
2659
0
        } else if (allow_bipred) {
2660
0
            uint8_t ref_idx_0  = get_ref_frame_idx(rf[0]);
2661
0
            uint8_t ref_idx_1  = get_ref_frame_idx(rf[1]);
2662
0
            uint8_t list_idx_0 = get_list_idx(rf[0]);
2663
0
            uint8_t list_idx_1 = get_list_idx(rf[1]);
2664
2665
0
            if (!is_valid_bipred_ref(ctx, GLOBAL_GROUP, list_idx_0, ref_idx_0, list_idx_1, ref_idx_1)) {
2666
0
                return;
2667
0
            }
2668
            // Get gm params
2669
0
            WarpedMotionParams* gm_params_0 = &pcs->ppcs->global_motion[svt_get_ref_frame_type(list_idx_0, ref_idx_0)];
2670
2671
0
            WarpedMotionParams* gm_params_1 = &pcs->ppcs->global_motion[svt_get_ref_frame_type(list_idx_1, ref_idx_1)];
2672
2673
0
            if (pcs->ppcs->gm_ctrls.skip_identity &&
2674
0
                (gm_params_0->wmtype == IDENTITY || gm_params_1->wmtype == IDENTITY)) {
2675
0
                continue;
2676
0
            }
2677
0
            Mv to_inj_mv0 = svt_aom_gm_get_motion_vector_enc(gm_params_0,
2678
0
                                                             pcs->ppcs->frm_hdr.allow_high_precision_mv,
2679
0
                                                             ctx->blk_geom->bsize,
2680
0
                                                             mi_col,
2681
0
                                                             mi_row,
2682
0
                                                             0 /* force_integer_mv */);
2683
2684
0
            Mv      to_inj_mv1         = svt_aom_gm_get_motion_vector_enc(gm_params_1,
2685
0
                                                             pcs->ppcs->frm_hdr.allow_high_precision_mv,
2686
0
                                                             ctx->blk_geom->bsize,
2687
0
                                                             mi_col,
2688
0
                                                             mi_row,
2689
0
                                                             0 /* force_integer_mv */);
2690
0
            uint8_t to_inject_ref_type = av1_ref_frame_type(rf);
2691
2692
0
            ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2693
0
            cand->block_mi.use_intrabc        = 0;
2694
0
            cand->skip_mode_allowed           = false;
2695
0
            cand->block_mi.mode               = GLOBAL_GLOBALMV;
2696
0
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2697
0
            cand->wm_params_l0                = *gm_params_0;
2698
0
            cand->wm_params_l1                = *gm_params_1;
2699
0
            cand->block_mi.is_interintra_used = 0;
2700
0
            cand->drl_index                   = 0;
2701
0
            cand->block_mi.ref_frame[0]       = rf[0];
2702
0
            cand->block_mi.ref_frame[1]       = rf[1];
2703
0
            cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
2704
0
            cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
2705
0
            determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2706
0
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2707
2708
0
            if (ctx->inter_comp_ctrls.do_global) {
2709
0
                ctx->cmp_store.pred0_cnt = 0;
2710
0
                ctx->cmp_store.pred1_cnt = 0;
2711
0
                inj_comp_modes(pcs, ctx, &cand_total_cnt);
2712
0
            }
2713
0
            ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2714
0
            ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2715
0
            ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2716
0
            ++ctx->injected_mv_count;
2717
0
        }
2718
0
    }
2719
    // update the total number of candidates injected
2720
0
    (*candidate_total_cnt) = cand_total_cnt;
2721
0
}
2722
2723
static void inject_pme_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt,
2724
0
                                  const bool allow_bipred) {
2725
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
2726
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
2727
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
2728
0
    for (uint32_t ref_it = 0; ref_it < ctx->tot_ref_frame_types; ++ref_it) {
2729
0
        MvReferenceFrame ref_pair = ctx->ref_frame_type_arr[ref_it];
2730
0
        MvReferenceFrame rf[2];
2731
0
        av1_set_ref_frame(rf, ref_pair);
2732
2733
        //single ref/list
2734
0
        if (rf[1] == NONE_FRAME) {
2735
0
            MvReferenceFrame frame_type = rf[0];
2736
0
            uint8_t          list_idx   = get_list_idx(rf[0]);
2737
0
            uint8_t          ref_idx    = get_ref_frame_idx(rf[0]);
2738
2739
0
            if (ctx->valid_pme_mv[list_idx][ref_idx]) {
2740
0
                Mv to_inj_mv = ctx->best_pme_mv[list_idx][ref_idx];
2741
0
                if ((ctx->injected_mv_count == 0 ||
2742
0
                     mv_is_already_injected(ctx, to_inj_mv, to_inj_mv, frame_type) == false)) {
2743
0
                    uint8_t drl_index = 0;
2744
0
                    svt_aom_choose_best_av1_mv_pred(
2745
0
                        ctx, frame_type, NEWMV, to_inj_mv, (Mv){{0}}, &drl_index, best_pred_mv);
2746
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv, to_inj_mv, 0)) {
2747
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2748
0
                        cand->block_mi.use_intrabc        = 0;
2749
0
                        cand->skip_mode_allowed           = false;
2750
0
                        cand->block_mi.mode               = NEWMV;
2751
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2752
0
                        cand->block_mi.is_interintra_used = 0;
2753
0
                        cand->drl_index                   = drl_index;
2754
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv.as_int;
2755
0
                        cand->block_mi.ref_frame[0]       = rf[0];
2756
0
                        cand->block_mi.ref_frame[1]       = rf[1];
2757
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2758
0
                        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[frame_type].num;
2759
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2760
2761
0
                        const bool enable_ii   = true;
2762
0
                        const bool enable_obmc = true;
2763
0
                        const bool enable_warp = true;
2764
0
                        inj_non_simple_modes(pcs, ctx, &cand_total_cnt, enable_ii, enable_warp, enable_obmc);
2765
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv.as_int;
2766
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = frame_type;
2767
0
                        ++ctx->injected_mv_count;
2768
0
                    }
2769
0
                }
2770
0
            }
2771
0
        } else if (allow_bipred) {
2772
0
            uint8_t ref_idx_0  = get_ref_frame_idx(rf[0]);
2773
0
            uint8_t ref_idx_1  = get_ref_frame_idx(rf[1]);
2774
0
            uint8_t list_idx_0 = get_list_idx(rf[0]);
2775
0
            uint8_t list_idx_1 = get_list_idx(rf[1]);
2776
2777
0
            if (ctx->valid_pme_mv[list_idx_0][ref_idx_0] && ctx->valid_pme_mv[list_idx_1][ref_idx_1]) {
2778
0
                Mv            to_inj_mv0         = ctx->best_pme_mv[list_idx_0][ref_idx_0];
2779
0
                Mv            to_inj_mv1         = ctx->best_pme_mv[list_idx_1][ref_idx_1];
2780
0
                const uint8_t to_inject_ref_type = av1_ref_frame_type((const MvReferenceFrame[]){
2781
0
                    svt_get_ref_frame_type(list_idx_0, ref_idx_0),
2782
0
                    svt_get_ref_frame_type(list_idx_1, ref_idx_1),
2783
0
                });
2784
0
                if ((ctx->injected_mv_count == 0 ||
2785
0
                     mv_is_already_injected(ctx, to_inj_mv0, to_inj_mv1, to_inject_ref_type) == false)) {
2786
0
                    uint8_t drl_index = 0;
2787
0
                    svt_aom_choose_best_av1_mv_pred(
2788
0
                        ctx, to_inject_ref_type, NEW_NEWMV, to_inj_mv0, to_inj_mv1, &drl_index, best_pred_mv);
2789
0
                    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, to_inj_mv0, to_inj_mv1, 1)) {
2790
0
                        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
2791
0
                        cand->block_mi.use_intrabc        = 0;
2792
0
                        cand->skip_mode_allowed           = false;
2793
0
                        cand->drl_index                   = drl_index;
2794
0
                        cand->block_mi.mv[0].as_int       = to_inj_mv0.as_int;
2795
0
                        cand->block_mi.mv[1].as_int       = to_inj_mv1.as_int;
2796
0
                        cand->block_mi.mode               = NEW_NEWMV;
2797
0
                        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
2798
0
                        cand->block_mi.is_interintra_used = 0;
2799
0
                        cand->block_mi.ref_frame[0]       = rf[0];
2800
0
                        cand->block_mi.ref_frame[1]       = rf[1];
2801
0
                        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
2802
0
                        cand->pred_mv[1].as_int           = best_pred_mv[1].as_int;
2803
0
                        determine_compound_mode(pcs, ctx, cand, MD_COMP_AVG);
2804
0
                        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
2805
2806
0
                        if (ctx->inter_comp_ctrls.do_pme) {
2807
0
                            ctx->cmp_store.pred0_cnt = 0;
2808
0
                            ctx->cmp_store.pred1_cnt = 0;
2809
0
                            inj_comp_modes(pcs, ctx, &cand_total_cnt);
2810
0
                        }
2811
0
                        ctx->injected_mvs[ctx->injected_mv_count][0].as_int = to_inj_mv0.as_int;
2812
0
                        ctx->injected_mvs[ctx->injected_mv_count][1].as_int = to_inj_mv1.as_int;
2813
0
                        ctx->injected_ref_types[ctx->injected_mv_count]     = to_inject_ref_type;
2814
0
                        ++ctx->injected_mv_count;
2815
0
                    }
2816
0
                }
2817
0
            }
2818
0
        }
2819
0
    }
2820
0
    (*candidate_total_cnt) = cand_total_cnt;
2821
0
}
2822
2823
static void inject_inter_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx,
2824
0
                                        uint32_t* candidate_total_cnt) {
2825
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
2826
    // Bipred prediction is only allowed when both dimensions are > 4 and the frame-header reference mode allows it.
2827
    // See AV1 spec 5.11.25
2828
0
    const bool allow_bipred = (frm_hdr->reference_mode == SINGLE_REFERENCE || ctx->blk_geom->bwidth == 4 ||
2829
0
                               ctx->blk_geom->bheight == 4)
2830
0
        ? false
2831
0
        : true;
2832
2833
0
    inject_new_candidates_pd0(pcs, ctx, candidate_total_cnt, allow_bipred);
2834
0
}
2835
2836
static void inject_inter_candidates_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
2837
0
                                              uint32_t* cand_total_cnt) {
2838
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
2839
    // Bipred prediction is only allowed when both dimensions are > 4 and the frame-header reference mode allows it.
2840
    // See AV1 spec 5.11.25
2841
0
    const bool allow_bipred = (frm_hdr->reference_mode == SINGLE_REFERENCE || ctx->blk_geom->bwidth == 4 ||
2842
0
                               ctx->blk_geom->bheight == 4)
2843
0
        ? false
2844
0
        : true;
2845
    // Needed in case WM/OBMC is on at the frame level (even though not used in light-PD1 path)
2846
0
    if (frm_hdr->is_motion_mode_switchable) {
2847
0
        const uint16_t mi_row = ctx->blk_org_y >> MI_SIZE_LOG2;
2848
0
        const uint16_t mi_col = ctx->blk_org_x >> MI_SIZE_LOG2;
2849
0
        svt_av1_count_overlappable_neighbors(pcs, ctx->blk_ptr, ctx->blk_geom->bsize, mi_row, mi_col);
2850
0
    } else {
2851
        // Overlappable neighbours only needed for non-"SIMPLE_TRANSLATION" candidates
2852
0
        ctx->blk_ptr->overlappable_neighbors = 0;
2853
0
    }
2854
0
    svt_aom_init_wm_samples(pcs, ctx);
2855
    // Inject MVP candidates
2856
0
    if (ctx->new_nearest_injection &&
2857
0
        !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2858
0
        inject_mvp_candidates_ii_light_pd1(pcs, ctx, cand_total_cnt, allow_bipred);
2859
0
    }
2860
2861
    // Inject ME candidates
2862
0
    if (ctx->inject_new_me) {
2863
0
        inject_new_candidates_light_pd1(pcs, ctx, cand_total_cnt, allow_bipred);
2864
0
    }
2865
0
}
2866
2867
static void svt_aom_inject_inter_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
2868
0
                                            uint32_t* cand_total_cnt) {
2869
0
    FrameHeader* frm_hdr = &pcs->ppcs->frm_hdr;
2870
    // Bipred prediction is only allowed when both dimensions are > 4 and the frame-header reference mode allows it.
2871
    // See AV1 spec 5.11.25
2872
0
    const bool allow_bipred = (frm_hdr->reference_mode == SINGLE_REFERENCE || ctx->blk_geom->bwidth == 4 ||
2873
0
                               ctx->blk_geom->bheight == 4)
2874
0
        ? false
2875
0
        : true;
2876
2877
0
    const uint32_t mi_row = ctx->blk_org_y >> MI_SIZE_LOG2;
2878
0
    const uint32_t mi_col = ctx->blk_org_x >> MI_SIZE_LOG2;
2879
2880
0
    svt_av1_count_overlappable_neighbors(pcs, ctx->blk_ptr, ctx->blk_geom->bsize, mi_row, mi_col);
2881
0
    svt_aom_init_wm_samples(pcs, ctx);
2882
0
#if CONFIG_ENABLE_OBMC
2883
0
    if (ctx->obmc_ctrls.enabled && ctx->obmc_ctrls.refine_level == 0) {
2884
0
        const uint8_t is_obmc_allowed = svt_aom_obmc_motion_mode_allowed(
2885
0
                                            pcs, ctx, ctx->blk_geom->bsize, 1, LAST_FRAME, -1, NEWMV) == OBMC_CAUSAL;
2886
0
        if (is_obmc_allowed) {
2887
0
            svt_aom_precompute_obmc_data(pcs, ctx, PICTURE_BUFFER_DESC_LUMA_MASK);
2888
0
        }
2889
0
    }
2890
0
#endif
2891
    /**************
2892
         MVP
2893
    ************* */
2894
0
    if (ctx->new_nearest_injection &&
2895
0
        !(ctx->is_intra_bordered && ctx->cand_reduction_ctrls.use_neighbouring_mode_ctrls.enabled)) {
2896
0
        inject_mvp_candidates_ii(pcs, ctx, cand_total_cnt, allow_bipred);
2897
0
    }
2898
    //----------------------
2899
    //    NEAREST_NEWMV, NEW_NEARESTMV, NEAR_NEWMV, NEW_NEARMV.
2900
    //----------------------
2901
0
    if (ctx->new_nearest_near_comb_injection && allow_bipred) {
2902
0
        inject_new_nearest_new_comb_candidates(pcs, ctx, cand_total_cnt);
2903
0
    }
2904
0
    if (ctx->inject_new_me) {
2905
0
        inject_new_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2906
0
    }
2907
0
    if (ctx->global_mv_injection) {
2908
0
        inject_global_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2909
0
    }
2910
0
    if (ctx->bipred3x3_ctrls.enabled && allow_bipred) {
2911
0
        bipred_3x3_candidates_injection(pcs, ctx, cand_total_cnt);
2912
0
    }
2913
2914
0
    if (ctx->unipred3x3_injection) {
2915
0
        unipred_3x3_candidates_injection(pcs, ctx, cand_total_cnt);
2916
0
    }
2917
2918
    // determine when to inject pme candidates based on size and resolution of block
2919
0
    if (ctx->inject_new_pme && ctx->updated_enable_pme) {
2920
0
        inject_pme_candidates(pcs, ctx, cand_total_cnt, allow_bipred);
2921
0
    }
2922
0
}
2923
2924
static const TxType g_intra_mode_to_tx_type[INTRA_MODES] = {
2925
    DCT_DCT, // DC
2926
    ADST_DCT, // V
2927
    DCT_ADST, // H
2928
    DCT_DCT, // D45
2929
    ADST_ADST, // D135
2930
    ADST_DCT, // D117
2931
    DCT_ADST, // D153
2932
    DCT_ADST, // D207
2933
    ADST_DCT, // D63
2934
    ADST_ADST, // SMOOTH
2935
    ADST_DCT, // SMOOTH_V
2936
    DCT_ADST, // SMOOTH_H
2937
    ADST_ADST, // PAETH
2938
};
2939
2940
static INLINE TxType intra_mode_to_tx_type(PredictionMode pred_mode, UvPredictionMode pred_mode_uv,
2941
138k
                                           PlaneType plane_type) {
2942
138k
    const PredictionMode mode = (plane_type == PLANE_TYPE_Y) ? pred_mode : get_uv_mode(pred_mode_uv);
2943
138k
    assert(mode < INTRA_MODES);
2944
138k
    return g_intra_mode_to_tx_type[mode];
2945
138k
}
2946
2947
/* For intra prediction, the chroma transform type may not follow the luma type.
2948
This function will return the intra chroma TX type to be used, which is based on TX size and chroma mode.
2949
Refer to section 5.11.40 of the AV1 spec (compute_tx_type). */
2950
138k
TxType svt_aom_get_intra_uv_tx_type(UvPredictionMode pred_mode_uv, TxSize tx_size, int32_t reduced_tx_set) {
2951
138k
    if (txsize_sqr_up_map[tx_size] > TX_32X32) {
2952
0
        return DCT_DCT;
2953
0
    }
2954
2955
    // In intra mode, uv planes don't share the same prediction mode as y
2956
    // plane, so the tx_type should not be shared. Pass DC_PRED as luma mode because the argument
2957
    // will not be used.
2958
138k
    TxType tx_type = intra_mode_to_tx_type(DC_PRED, pred_mode_uv, PLANE_TYPE_UV);
2959
138k
    assert(tx_type < TX_TYPES);
2960
138k
    const TxSetType tx_set_type = get_ext_tx_set_type(tx_size, /*is_inter*/ 0, reduced_tx_set);
2961
138k
    return !av1_ext_tx_used[tx_set_type][tx_type] ? DCT_DCT : tx_type;
2962
138k
}
2963
2964
// Values are now correlated to quantizer.
2965
0
static INLINE int mv_check_bounds(const MvLimits* mv_limits, const Mv* mv) {
2966
0
    return (mv->y >> 3) < mv_limits->row_min || (mv->y >> 3) > mv_limits->row_max ||
2967
0
        (mv->x >> 3) < mv_limits->col_min || (mv->x >> 3) > mv_limits->col_max;
2968
0
}
2969
2970
0
static void assert_release(int statement) {
2971
0
    if (statement == 0) {
2972
0
        SVT_LOG("ASSERT_ERRRR\n");
2973
0
    }
2974
0
}
2975
2976
static void intra_bc_search(PictureControlSet* pcs, ModeDecisionContext* ctx, const SequenceControlSet* scs,
2977
0
                            BlkStruct* blk_ptr, Mv* dv_cand, uint8_t* num_dv_cand) {
2978
0
    IntraBcContext  x_st;
2979
0
    IntraBcContext* x           = &x_st;
2980
0
    uint32_t        full_lambda = ctx->hbd_md ? ctx->full_lambda_md[EB_10_BIT_MD] : ctx->full_lambda_md[EB_8_BIT_MD];
2981
2982
0
    x->approx_inter_rate = ctx->approx_inter_rate;
2983
0
    x->xd                = blk_ptr->av1xd;
2984
0
    x->nmv_vec_cost      = ctx->md_rate_est_ctx->nmv_vec_cost;
2985
0
    x->mv_cost_stack     = ctx->md_rate_est_ctx->nmvcoststack;
2986
0
    BlockSize bsize      = ctx->blk_geom->bsize;
2987
0
    assert(bsize < BLOCK_SIZES_ALL);
2988
0
    FrameHeader*           frm_hdr    = &pcs->ppcs->frm_hdr;
2989
0
    const Av1Common* const cm         = pcs->ppcs->av1_cm;
2990
0
    MvReferenceFrame       ref_frame  = INTRA_FRAME;
2991
0
    const int              num_planes = 3;
2992
0
    MacroBlockD*           xd         = blk_ptr->av1xd;
2993
0
    const TileInfo*        tile       = &xd->tile;
2994
0
    const int              mi_row     = -xd->mb_to_top_edge / (8 * MI_SIZE);
2995
0
    const int              mi_col     = -xd->mb_to_left_edge / (8 * MI_SIZE);
2996
0
    const int              w          = block_size_wide[bsize];
2997
0
    const int              h          = block_size_high[bsize];
2998
0
    const int              sb_row     = mi_row >> scs->seq_header.sb_size_log2;
2999
0
    const int              sb_col     = mi_col >> scs->seq_header.sb_size_log2;
3000
3001
    // Set up limit values for MV components.
3002
    // Mv beyond the range do not produce new/different prediction block.
3003
0
    const int mi_width   = mi_size_wide[bsize];
3004
0
    const int mi_height  = mi_size_high[bsize];
3005
0
    x->mv_limits.row_min = -(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
3006
0
    x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
3007
0
    x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND;
3008
0
    x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND;
3009
    //set search paramters
3010
0
    x->sadperbit16 = svt_aom_get_sad_per_bit(frm_hdr->quantization_params.base_q_idx, 0);
3011
0
    x->errorperbit = full_lambda >> RD_EPB_SHIFT;
3012
0
    x->errorperbit += (x->errorperbit == 0);
3013
    //temp buffer for hash me
3014
0
    for (int i = 0; i < 2; i++) {
3015
0
        EB_MALLOC_ARRAY_NO_CHECK(x->hash_value_buffer[i], AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
3016
0
    }
3017
3018
0
    Mv nearestmv, nearmv;
3019
0
    svt_av1_find_best_ref_mvs_from_stack(0, ctx->ref_mv_stack /*mbmi_ext*/, xd, ref_frame, &nearestmv, &nearmv, 0);
3020
0
    if (nearestmv.as_int == INVALID_MV) {
3021
0
        nearestmv.as_int = 0;
3022
0
    }
3023
0
    if (nearmv.as_int == INVALID_MV) {
3024
0
        nearmv.as_int = 0;
3025
0
    }
3026
0
    Mv dv_ref = nearestmv.as_int == 0 ? nearmv : nearestmv;
3027
0
    if (dv_ref.as_int == 0) {
3028
0
        svt_aom_find_ref_dv(&dv_ref, tile, scs->seq_header.sb_mi_size, mi_row, mi_col);
3029
0
    }
3030
    // Ref DV should not have sub-pel.
3031
0
    assert((dv_ref.x & 7) == 0);
3032
0
    assert((dv_ref.y & 7) == 0);
3033
0
    ctx->ref_mv_stack[INTRA_FRAME][0].this_mv = dv_ref;
3034
3035
    /* pointer to current frame */
3036
0
    Yv12BufferConfig cur_buf;
3037
0
    svt_aom_link_eb_to_aom_buffer_desc_8bit(pcs->ppcs->enhanced_pic, &cur_buf);
3038
0
    struct Buf2D yv12_mb[MAX_PLANES];
3039
0
    svt_av1_setup_pred_block(bsize, yv12_mb, &cur_buf, mi_row, mi_col);
3040
0
    for (int i = 0; i < num_planes; ++i) {
3041
0
        x->xdplane[i].pre[0] = yv12_mb[i]; // ref in ME
3042
0
    }
3043
    // setup src for DV search same as ref
3044
0
    x->plane[0].src = x->xdplane[0].pre[0];
3045
3046
0
    enum IntrabcMotionDirection max_dir = pcs->ppcs->intrabc_ctrls.search_dir ? IBC_MOTION_LEFT : IBC_MOTION_DIRECTIONS;
3047
3048
0
    for (enum IntrabcMotionDirection dir = IBC_MOTION_ABOVE; dir < max_dir; ++dir) {
3049
0
        const MvLimits tmp_mv_limits = x->mv_limits;
3050
3051
0
        switch (dir) {
3052
0
        case IBC_MOTION_ABOVE:
3053
0
            x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE;
3054
0
            x->mv_limits.col_max = (tile->mi_col_end - mi_col) * MI_SIZE - w;
3055
0
            x->mv_limits.row_min = (tile->mi_row_start - mi_row) * MI_SIZE;
3056
0
            x->mv_limits.row_max = (sb_row * scs->seq_header.sb_mi_size - mi_row) * MI_SIZE - h;
3057
0
            break;
3058
0
        case IBC_MOTION_LEFT:
3059
0
            x->mv_limits.col_min = (tile->mi_col_start - mi_col) * MI_SIZE;
3060
0
            x->mv_limits.col_max = (sb_col * scs->seq_header.sb_mi_size - mi_col) * MI_SIZE - w;
3061
            // TODO: Minimize the overlap between above and
3062
            // left areas.
3063
0
            x->mv_limits.row_min     = (tile->mi_row_start - mi_row) * MI_SIZE;
3064
0
            int bottom_coded_mi_edge = AOMMIN((sb_row + 1) * scs->seq_header.sb_mi_size, tile->mi_row_end);
3065
0
            x->mv_limits.row_max     = (bottom_coded_mi_edge - mi_row) * MI_SIZE - h;
3066
0
            break;
3067
0
        default:
3068
0
            assert(0);
3069
0
        }
3070
0
        assert_release(x->mv_limits.col_min >= tmp_mv_limits.col_min);
3071
0
        assert_release(x->mv_limits.col_max <= tmp_mv_limits.col_max);
3072
0
        assert_release(x->mv_limits.row_min >= tmp_mv_limits.row_min);
3073
0
        assert_release(x->mv_limits.row_max <= tmp_mv_limits.row_max);
3074
3075
0
        svt_av1_set_mv_search_range(&x->mv_limits, &dv_ref);
3076
3077
0
        if (x->mv_limits.col_max < x->mv_limits.col_min || x->mv_limits.row_max < x->mv_limits.row_min) {
3078
0
            x->mv_limits = tmp_mv_limits;
3079
0
            continue;
3080
0
        }
3081
0
        Mv mvp_full = dv_ref;
3082
0
        mvp_full.x >>= 3;
3083
0
        mvp_full.y >>= 3;
3084
0
        x->best_mv.as_int = 0;
3085
3086
        // Hash Search
3087
0
        const AomVarianceFnPtr* fn_ptr = &svt_aom_mefn_ptr[bsize];
3088
3089
0
        int best_hash_cost = INT_MAX;
3090
0
        Mv  best_hash_mv   = {{0, 0}};
3091
3092
0
        svt_av1_intrabc_hash_search(
3093
0
            pcs, x, bsize, mi_col * MI_SIZE, mi_row * MI_SIZE, &dv_ref, 1, fn_ptr, &best_hash_cost, &best_hash_mv);
3094
3095
        // Hash produced a candidate
3096
0
        if (best_hash_cost < INT_MAX) {
3097
0
            Mv dv;
3098
0
            dv.x = best_hash_mv.x * 8;
3099
0
            dv.y = best_hash_mv.y * 8;
3100
3101
0
            dv_cand[*num_dv_cand] = dv;
3102
0
            (*num_dv_cand)++;
3103
3104
0
            x->best_mv = best_hash_mv;
3105
0
        }
3106
        // Full-pixel fallback if hash didn't produce a candidate
3107
0
        else {
3108
0
            svt_av1_full_pixel_search(pcs, x, bsize, &mvp_full, 0, x->sadperbit16, NULL, &dv_ref);
3109
3110
0
            Mv dv = {{x->best_mv.x * 8, x->best_mv.y * 8}};
3111
3112
0
            if (!mv_check_bounds(&x->mv_limits, &dv) &&
3113
0
                svt_aom_is_dv_valid(dv, xd, mi_row, mi_col, bsize, scs->seq_header.sb_size_log2)) {
3114
0
                dv_cand[*num_dv_cand] = dv;
3115
0
                (*num_dv_cand)++;
3116
0
            }
3117
0
        }
3118
3119
0
        x->mv_limits = tmp_mv_limits;
3120
0
    }
3121
3122
0
    for (int i = 0; i < 2; i++) {
3123
0
        EB_FREE_ARRAY(x->hash_value_buffer[i]);
3124
0
    }
3125
0
}
3126
3127
static void inject_intra_bc_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, const SequenceControlSet* scs,
3128
0
                                       BlkStruct* blk_ptr, uint32_t* cand_cnt) {
3129
0
    Mv      dv_cand[2];
3130
0
    uint8_t num_dv_cand = 0;
3131
3132
    //perform dv-pred + search up to 2 dv(s)
3133
0
    intra_bc_search(pcs, ctx, scs, blk_ptr, dv_cand, &num_dv_cand);
3134
3135
0
    ModeDecisionCandidate* cand_array = ctx->fast_cand_array;
3136
3137
0
    for (uint32_t dv_i = 0; dv_i < num_dv_cand; dv_i++) {
3138
0
        ModeDecisionCandidate* cand               = &cand_array[*cand_cnt];
3139
0
        cand->palette_info                        = NULL;
3140
0
        cand->block_mi.use_intrabc                = 1;
3141
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y]  = 0;
3142
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = 0;
3143
0
        cand->block_mi.uv_mode                    = UV_DC_PRED;
3144
0
        cand->block_mi.cfl_alpha_signs            = 0;
3145
0
        cand->block_mi.cfl_alpha_idx              = 0;
3146
0
        cand->transform_type[0]                   = DCT_DCT;
3147
0
        cand->transform_type_uv                   = DCT_DCT;
3148
0
        cand->block_mi.ref_frame[0]               = INTRA_FRAME;
3149
0
        cand->block_mi.ref_frame[1]               = NONE_FRAME;
3150
0
        cand->block_mi.mode                       = DC_PRED;
3151
0
        cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3152
        //inter ralated
3153
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3154
0
        cand->block_mi.is_interintra_used = 0;
3155
0
        cand->skip_mode_allowed           = false;
3156
0
        cand->block_mi.mv[0].as_int       = dv_cand[dv_i].as_int;
3157
0
        cand->pred_mv[0].as_int           = ctx->ref_mv_stack[INTRA_FRAME][0].this_mv.as_int;
3158
0
        cand->drl_index                   = 0;
3159
0
        cand->block_mi.interp_filters     = av1_broadcast_interp_filter(BILINEAR);
3160
0
        INC_MD_CAND_CNT((*cand_cnt), pcs->ppcs->max_can_count);
3161
0
    }
3162
0
}
3163
3164
static void inject_intra_candidates_pd0(PictureControlSet* pcs, ModeDecisionContext* ctx,
3165
140k
                                        uint32_t* candidate_total_cnt) {
3166
140k
    uint32_t               cand_total_cnt     = 0;
3167
140k
    ModeDecisionCandidate* cand               = &ctx->fast_cand_array[cand_total_cnt];
3168
140k
    cand->skip_mode_allowed                   = false;
3169
140k
    cand->palette_info                        = NULL;
3170
140k
    cand->block_mi.use_intrabc                = 0;
3171
140k
    cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3172
140k
    cand->block_mi.angle_delta[PLANE_TYPE_Y]  = 0;
3173
140k
    cand->block_mi.uv_mode                    = UV_DC_PRED;
3174
140k
    cand->block_mi.angle_delta[PLANE_TYPE_UV] = 0;
3175
140k
    cand->block_mi.cfl_alpha_signs            = 0;
3176
140k
    cand->block_mi.cfl_alpha_idx              = 0;
3177
140k
    cand->transform_type[0]                   = DCT_DCT;
3178
140k
    cand->transform_type_uv                   = DCT_DCT;
3179
140k
    cand->block_mi.ref_frame[0]               = INTRA_FRAME;
3180
140k
    cand->block_mi.ref_frame[1]               = NONE_FRAME;
3181
140k
    cand->block_mi.mode                       = DC_PRED;
3182
140k
    cand->block_mi.motion_mode                = SIMPLE_TRANSLATION;
3183
140k
    cand->block_mi.is_interintra_used         = 0;
3184
140k
    cand->block_mi.tx_depth                   = 0;
3185
140k
    INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3186
    // update the total number of candidates injected
3187
140k
    (*candidate_total_cnt) = cand_total_cnt;
3188
140k
    return;
3189
140k
}
3190
3191
static void inject_intra_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, const bool dc_cand_only_flag,
3192
139k
                                    uint32_t* candidate_total_cnt) {
3193
139k
    FrameHeader*           frm_hdr          = &pcs->ppcs->frm_hdr;
3194
139k
    PredictionMode         intra_mode_start = DC_PRED;
3195
139k
    PredictionMode         intra_mode_end   = dc_cand_only_flag ? DC_PRED : ctx->intra_ctrls.intra_mode_end;
3196
139k
    uint32_t               cand_total_cnt   = *candidate_total_cnt;
3197
139k
    ModeDecisionCandidate* cand_array       = ctx->fast_cand_array;
3198
139k
    const bool    use_angle_delta = ctx->intra_ctrls.angular_pred_level ? av1_use_angle_delta(ctx->blk_geom->bsize) : 0;
3199
139k
    const uint8_t disable_angle_prediction                = (ctx->intra_ctrls.angular_pred_level == 0);
3200
139k
    uint8_t       directional_mode_skip_mask[INTRA_MODES] = {0};
3201
139k
    if (ctx->intra_ctrls.angular_pred_level >= 4) {
3202
1.51M
        for (uint8_t i = D45_PRED; i < INTRA_MODE_END; i++) {
3203
1.37M
            directional_mode_skip_mask[i] = 1;
3204
1.37M
        }
3205
137k
    }
3206
139k
    const TxSize tx_size_uv = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3207
3208
277k
    for (PredictionMode intra_mode = intra_mode_start; intra_mode <= intra_mode_end; ++intra_mode) {
3209
138k
        if (av1_is_directional_mode(intra_mode) &&
3210
0
            (disable_angle_prediction || directional_mode_skip_mask[intra_mode])) {
3211
0
            continue;
3212
0
        }
3213
3214
138k
        const uint8_t angle_delta_count = av1_is_directional_mode(intra_mode) &&
3215
0
                ctx->intra_ctrls.angular_pred_level <= 2 && use_angle_delta
3216
138k
            ? 7
3217
138k
            : 1;
3218
3219
275k
        for (uint8_t angle_delta_counter = 0; angle_delta_counter < angle_delta_count; ++angle_delta_counter) {
3220
137k
            int32_t angle_delta = CLIP((angle_delta_count == 1 ? 0 : angle_delta_counter - MAX_ANGLE_DELTA),
3221
137k
                                       -MAX_ANGLE_DELTA,
3222
137k
                                       MAX_ANGLE_DELTA);
3223
137k
            if ((ctx->intra_ctrls.angular_pred_level >= 2 &&
3224
137k
                 (angle_delta == -1 || angle_delta == 1 || angle_delta == -2 || angle_delta == 2)) ||
3225
137k
                (ctx->intra_ctrls.angular_pred_level >= 3 && angle_delta != 0)) {
3226
0
                continue;
3227
0
            }
3228
137k
            ModeDecisionCandidate* cand               = &cand_array[cand_total_cnt];
3229
137k
            cand->skip_mode_allowed                   = false;
3230
137k
            cand->palette_info                        = NULL;
3231
137k
            cand->block_mi.mode                       = intra_mode;
3232
137k
            cand->block_mi.use_intrabc                = 0;
3233
137k
            cand->block_mi.filter_intra_mode          = FILTER_INTRA_MODES;
3234
137k
            cand->block_mi.angle_delta[PLANE_TYPE_Y]  = angle_delta;
3235
137k
            cand->block_mi.uv_mode                    = ctx->ind_uv_avail ? ctx->best_uv_mode[intra_mode]
3236
137k
                                                                          : intra_luma_to_chroma[intra_mode];
3237
137k
            cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail ? ctx->best_uv_angle[intra_mode]
3238
137k
                                                                          : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3239
137k
            cand->block_mi.cfl_alpha_signs            = 0;
3240
137k
            cand->block_mi.cfl_alpha_idx              = 0;
3241
137k
            cand->transform_type[0]                   = DCT_DCT;
3242
137k
            cand->transform_type_uv                   = svt_aom_get_intra_uv_tx_type(
3243
137k
                cand->block_mi.uv_mode, tx_size_uv, frm_hdr->reduced_tx_set);
3244
3245
137k
            if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3246
0
                continue;
3247
0
            }
3248
137k
            cand->block_mi.ref_frame[0]       = INTRA_FRAME;
3249
137k
            cand->block_mi.ref_frame[1]       = NONE_FRAME;
3250
137k
            cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3251
137k
            cand->block_mi.is_interintra_used = 0;
3252
137k
            INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3253
137k
        }
3254
138k
    }
3255
3256
    // update the total number of candidates injected
3257
139k
    (*candidate_total_cnt) = cand_total_cnt;
3258
3259
139k
    return;
3260
139k
}
3261
3262
static void inject_filter_intra_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx,
3263
0
                                           uint32_t* candidate_total_cnt) {
3264
0
    FilterIntraMode intra_mode_start = FILTER_DC_PRED;
3265
0
    FilterIntraMode intra_mode_end   = ctx->intra_ctrls.intra_mode_end == PAETH_PRED ? FILTER_PAETH_PRED
3266
0
          : ctx->intra_ctrls.intra_mode_end >= D157_PRED                             ? FILTER_D157_PRED
3267
0
          : ctx->intra_ctrls.intra_mode_end >= H_PRED                                ? FILTER_H_PRED
3268
0
          : ctx->intra_ctrls.intra_mode_end >= V_PRED                                ? FILTER_V_PRED
3269
0
                                                                                     : FILTER_DC_PRED;
3270
0
    intra_mode_end                   = MIN(intra_mode_end, ctx->filter_intra_ctrls.max_filter_intra_mode);
3271
3272
0
    const TxSize           tx_size_uv     = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3273
0
    uint32_t               cand_total_cnt = *candidate_total_cnt;
3274
0
    ModeDecisionCandidate* cand_array     = ctx->fast_cand_array;
3275
0
    FrameHeader*           frm_hdr        = &pcs->ppcs->frm_hdr;
3276
3277
0
    for (FilterIntraMode filter_intra_mode = intra_mode_start; filter_intra_mode <= intra_mode_end;
3278
0
         filter_intra_mode++) {
3279
0
        ModeDecisionCandidate* cand              = &cand_array[cand_total_cnt];
3280
0
        cand->skip_mode_allowed                  = false;
3281
0
        cand->block_mi.mode                      = DC_PRED;
3282
0
        cand->block_mi.use_intrabc               = 0;
3283
0
        cand->block_mi.filter_intra_mode         = filter_intra_mode;
3284
0
        cand->palette_info                       = NULL;
3285
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y] = 0;
3286
3287
0
        cand->block_mi.uv_mode = ctx->ind_uv_avail ? ctx->best_uv_mode[fimode_to_intramode[filter_intra_mode]]
3288
0
                                                   : intra_luma_to_chroma[fimode_to_intramode[filter_intra_mode]];
3289
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail
3290
0
            ? ctx->best_uv_angle[fimode_to_intramode[filter_intra_mode]]
3291
0
            : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3292
3293
0
        cand->block_mi.cfl_alpha_signs = 0;
3294
0
        cand->block_mi.cfl_alpha_idx   = 0;
3295
0
        cand->transform_type[0]        = DCT_DCT;
3296
0
        cand->transform_type_uv        = svt_aom_get_intra_uv_tx_type(
3297
0
            cand->block_mi.uv_mode, tx_size_uv, frm_hdr->reduced_tx_set);
3298
0
        if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3299
0
            continue;
3300
0
        }
3301
0
        cand->block_mi.ref_frame[0]       = INTRA_FRAME;
3302
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3303
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3304
0
        cand->block_mi.is_interintra_used = 0;
3305
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3306
0
    }
3307
3308
    // update the total number of candidates injected
3309
0
    (*candidate_total_cnt) = cand_total_cnt;
3310
3311
0
    return;
3312
0
}
3313
3314
static void inject_zz_backup_candidate(PictureControlSet* pcs, ModeDecisionContext* ctx,
3315
0
                                       uint32_t* candidate_total_cnt) {
3316
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
3317
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
3318
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
3319
0
    cand_array[cand_total_cnt].drl_index   = 0;
3320
0
    svt_aom_choose_best_av1_mv_pred(ctx,
3321
0
                                    svt_get_ref_frame_type(REF_LIST_0, 0),
3322
0
                                    NEWMV,
3323
0
                                    (Mv){{0}},
3324
0
                                    (Mv){{0}},
3325
0
                                    &cand_array[cand_total_cnt].drl_index,
3326
0
                                    best_pred_mv);
3327
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, (Mv){{0, 0}}, (Mv){{0, 0}}, 0)) {
3328
0
        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
3329
0
        cand->block_mi.use_intrabc        = 0;
3330
0
        cand->skip_mode_allowed           = false;
3331
0
        cand->block_mi.mode               = NEWMV;
3332
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3333
0
        cand->block_mi.mv[0]              = (Mv){{0, 0}};
3334
0
        cand->block_mi.ref_frame[0]       = svt_get_ref_frame_type(REF_LIST_0, 0);
3335
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3336
0
        cand->transform_type[0]           = DCT_DCT;
3337
0
        cand->transform_type_uv           = DCT_DCT;
3338
0
        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
3339
0
        cand->block_mi.is_interintra_used = 0;
3340
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3341
0
        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[svt_get_ref_frame_type(REF_LIST_0, 0)].num;
3342
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3343
        // update the total number of candidates injected
3344
0
        (*candidate_total_cnt) = cand_total_cnt;
3345
0
    }
3346
0
}
3347
3348
982k
int svt_av1_allow_palette(int allow_palette, BlockSize bsize) {
3349
982k
    assert(bsize < BLOCK_SIZES_ALL);
3350
982k
    return allow_palette && block_size_wide[bsize] <= 64 && block_size_high[bsize] <= 64 && bsize >= BLOCK_8X8;
3351
982k
}
3352
3353
void search_palette_luma(PictureControlSet* pcs, ModeDecisionContext* ctx, PaletteInfo* palette_cand,
3354
                         uint8_t* palette_size_array, uint32_t* tot_palette_cands);
3355
3356
0
static void inject_palette_candidates(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t* candidate_total_cnt) {
3357
0
    uint32_t               can_total_cnt      = *candidate_total_cnt;
3358
0
    ModeDecisionCandidate* cand_array         = ctx->fast_cand_array;
3359
0
    const TxSize           tx_size_uv         = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3360
0
    uint32_t               tot_palette_cands  = 0;
3361
0
    PaletteInfo*           palette_cand_array = ctx->palette_cand_array;
3362
    // MD palette search
3363
0
    uint8_t* palette_size_array_0 = ctx->palette_size_array_0;
3364
3365
0
    search_palette_luma(pcs, ctx, palette_cand_array, palette_size_array_0, &tot_palette_cands);
3366
3367
0
    for (uint32_t cand_i = 0; cand_i < tot_palette_cands; ++cand_i) {
3368
0
        ModeDecisionCandidate* cand       = &cand_array[can_total_cnt];
3369
0
        cand->block_mi.is_interintra_used = 0;
3370
0
        cand->palette_size[0]             = palette_size_array_0[cand_i];
3371
        // Palette is not supported for chroma
3372
0
        cand->palette_size[1] = 0;
3373
0
        cand->palette_info    = &palette_cand_array[cand_i];
3374
0
        assert(palette_size_array_0[cand_i] < 9);
3375
        //to re check these fields
3376
0
        cand->skip_mode_allowed    = false;
3377
0
        cand->block_mi.mode        = DC_PRED;
3378
0
        cand->block_mi.use_intrabc = 0;
3379
3380
0
        cand->block_mi.filter_intra_mode         = FILTER_INTRA_MODES;
3381
0
        cand->block_mi.angle_delta[PLANE_TYPE_Y] = 0;
3382
        // Palette is not supported for chroma mode, so we can set the intra chroma mode to anything. To use palette
3383
        // for chroma, we must force DC_PRED to be used for the intra chroma mode
3384
0
        assert(cand_array[can_total_cnt].palette_size[1] == 0);
3385
0
        cand->block_mi.uv_mode = ctx->ind_uv_avail ? ctx->best_uv_mode[DC_PRED] : intra_luma_to_chroma[DC_PRED];
3386
0
        cand->block_mi.angle_delta[PLANE_TYPE_UV] = ctx->ind_uv_avail ? ctx->best_uv_angle[DC_PRED]
3387
0
                                                                      : cand->block_mi.angle_delta[PLANE_TYPE_Y];
3388
0
        cand->block_mi.cfl_alpha_signs            = 0;
3389
0
        cand->block_mi.cfl_alpha_idx              = 0;
3390
0
        cand->transform_type[0]                   = DCT_DCT;
3391
0
        cand->transform_type_uv                   = svt_aom_get_intra_uv_tx_type(
3392
0
            cand->block_mi.uv_mode, tx_size_uv, pcs->ppcs->frm_hdr.reduced_tx_set);
3393
0
        if (svt_av1_is_lossless_segment(pcs, ctx->blk_ptr->segment_id) && cand->transform_type_uv != DCT_DCT) {
3394
0
            continue;
3395
0
        }
3396
0
        cand->block_mi.ref_frame[0] = INTRA_FRAME;
3397
0
        cand->block_mi.ref_frame[1] = NONE_FRAME;
3398
0
        cand->block_mi.motion_mode  = SIMPLE_TRANSLATION;
3399
0
        INC_MD_CAND_CNT(can_total_cnt, pcs->ppcs->max_can_count);
3400
0
    }
3401
3402
    // update the total number of candidates injected
3403
0
    (*candidate_total_cnt) = can_total_cnt;
3404
3405
0
    return;
3406
0
}
3407
3408
0
static INLINE void eliminate_candidate_based_on_pme_me_results(ModeDecisionContext* ctx, uint8_t* dc_cand_only_flag) {
3409
0
    if (ctx->md_pme_dist != (uint32_t)~0 || ctx->md_me_dist != (uint32_t)~0) {
3410
0
        uint32_t th = ctx->cand_reduction_ctrls.cand_elimination_ctrls.dc_only_th;
3411
0
        th *= ctx->blk_geom->bheight * ctx->blk_geom->bwidth;
3412
0
        const uint32_t best_me_distotion = MIN(ctx->md_pme_dist, ctx->md_me_dist);
3413
0
        if (best_me_distotion < th) {
3414
0
            *dc_cand_only_flag = 1;
3415
0
        }
3416
0
    }
3417
0
}
3418
3419
static bool valid_ref_frame_type(MvReferenceFrame rf[2], const MvReferenceFrame ref_frame_type_arr[],
3420
0
                                 uint8_t tot_ref_frame_types) {
3421
    // INTRA_FRAME is added in candidates sometimes, skip validation
3422
0
    if (rf[0] == INTRA_FRAME) {
3423
0
        return true;
3424
0
    }
3425
3426
0
    for (uint8_t i = 0; i < tot_ref_frame_types; i++) {
3427
0
        MvReferenceFrame rf_in_arr[2];
3428
0
        av1_set_ref_frame(rf_in_arr, ref_frame_type_arr[i]);
3429
0
        if (rf[0] == rf_in_arr[0] && rf[1] == rf_in_arr[1]) {
3430
0
            return true;
3431
0
        }
3432
0
    }
3433
0
    return false;
3434
0
}
3435
3436
// refer to inject_zz_backup_candidate, but use BWD ref instead of LAST
3437
static void inject_sframe_backup_candidate(PictureControlSet* pcs, ModeDecisionContext* ctx,
3438
0
                                           uint32_t* candidate_total_cnt) {
3439
0
    ModeDecisionCandidate* cand_array      = ctx->fast_cand_array;
3440
0
    Mv                     best_pred_mv[2] = {{{0}}, {{0}}};
3441
0
    uint32_t               cand_total_cnt  = (*candidate_total_cnt);
3442
0
    cand_array[cand_total_cnt].drl_index   = 0;
3443
0
    svt_aom_choose_best_av1_mv_pred(ctx,
3444
0
                                    svt_get_ref_frame_type(REF_LIST_1, 0),
3445
0
                                    NEWMV,
3446
0
                                    (Mv){{0}},
3447
0
                                    (Mv){{0}},
3448
0
                                    &cand_array[cand_total_cnt].drl_index,
3449
0
                                    best_pred_mv);
3450
0
    if (!ctx->corrupted_mv_check || is_valid_mv_diff(best_pred_mv, (Mv){{0, 0}}, (Mv){{0, 0}}, 0)) {
3451
0
        ModeDecisionCandidate* cand       = &cand_array[cand_total_cnt];
3452
0
        cand->block_mi.use_intrabc        = 0;
3453
0
        cand->skip_mode_allowed           = false;
3454
0
        cand->block_mi.mode               = NEWMV;
3455
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3456
0
        cand->block_mi.mv[0]              = (Mv){{0, 0}};
3457
0
        cand->block_mi.ref_frame[0]       = svt_get_ref_frame_type(REF_LIST_1, 0);
3458
0
        cand->block_mi.ref_frame[1]       = NONE_FRAME;
3459
0
        cand->transform_type[0]           = DCT_DCT;
3460
0
        cand->transform_type_uv           = DCT_DCT;
3461
0
        cand->pred_mv[0].as_int           = best_pred_mv[0].as_int;
3462
0
        cand->block_mi.is_interintra_used = 0;
3463
0
        cand->block_mi.motion_mode        = SIMPLE_TRANSLATION;
3464
0
        cand->block_mi.num_proj_ref       = ctx->wm_sample_info[svt_get_ref_frame_type(REF_LIST_1, 0)].num;
3465
0
        INC_MD_CAND_CNT(cand_total_cnt, pcs->ppcs->max_can_count);
3466
        // update the total number of candidates injected
3467
0
        (*candidate_total_cnt) = cand_total_cnt;
3468
0
    }
3469
0
}
3470
3471
// in MD stage 0, candidates are injected by different tools, but for S-Frame in RA mode
3472
// the ref frame types in ref_list0 has be pruned in PD for the reversed direction of ref MVs
3473
// here to check and reject the candidates if mismatches the available frame types array
3474
0
static uint32_t reject_candidate_sframe(PictureControlSet* pcs, ModeDecisionContext* ctx, uint32_t cand_total_cnt) {
3475
0
    for (uint32_t i = 0; i < cand_total_cnt;) {
3476
0
        if (!valid_ref_frame_type(
3477
0
                ctx->fast_cand_array[i].block_mi.ref_frame, ctx->ref_frame_type_arr, ctx->tot_ref_frame_types)) {
3478
0
            for (uint32_t j = i; j < cand_total_cnt; j++) {
3479
0
                memcpy(&ctx->fast_cand_array[j], &ctx->fast_cand_array[j + 1], sizeof(ModeDecisionCandidate));
3480
0
            }
3481
0
            cand_total_cnt--;
3482
0
            continue;
3483
0
        }
3484
0
        i++;
3485
0
    }
3486
    // zero candidate in fast cand array risks in md stage 0, add a candidate from ref list1 as backup
3487
0
    if (cand_total_cnt == 0) {
3488
0
        inject_sframe_backup_candidate(pcs, ctx, &cand_total_cnt);
3489
0
    }
3490
0
    assert(cand_total_cnt > 0);
3491
0
    return cand_total_cnt;
3492
0
}
3493
3494
EbErrorType generate_md_stage_0_cand_pd0(ModeDecisionContext* ctx, uint32_t* candidate_total_count_ptr,
3495
140k
                                         PictureControlSet* pcs) {
3496
140k
    const SliceType slice_type     = pcs->slice_type;
3497
140k
    uint32_t        cand_total_cnt = 0;
3498
    //----------------------
3499
    // Intra
3500
140k
    if (ctx->blk_geom->sq_size < 128 && ctx->intra_ctrls.enable_intra) {
3501
140k
        inject_intra_candidates_pd0(pcs, ctx, &cand_total_cnt);
3502
140k
    }
3503
3504
140k
    if (slice_type != I_SLICE) {
3505
0
        inject_inter_candidates_pd0(pcs, ctx, &cand_total_cnt);
3506
0
    }
3507
3508
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_stage_0()
3509
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3510
140k
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3511
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3512
0
    }
3513
3514
140k
    if (pcs->ppcs->sframe_ref_pruned) {
3515
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3516
0
    }
3517
3518
140k
    *candidate_total_count_ptr = cand_total_cnt;
3519
3520
140k
    return EB_ErrorNone;
3521
140k
}
3522
3523
/*
3524
   generate candidates for light pd1
3525
*/
3526
void generate_md_stage_0_cand_light_pd1(ModeDecisionContext* ctx, uint32_t* candidate_total_count_ptr,
3527
0
                                        PictureControlSet* pcs) {
3528
0
    const SliceType slice_type     = pcs->slice_type;
3529
0
    uint32_t        cand_total_cnt = 0;
3530
    // Reset duplicates variables
3531
0
    ctx->injected_mv_count = 0;
3532
0
    ctx->inject_new_me     = 1;
3533
0
    if (slice_type != I_SLICE) {
3534
0
        inject_inter_candidates_light_pd1(pcs, ctx, &cand_total_cnt);
3535
0
    }
3536
    //----------------------
3537
    // Intra
3538
0
    if (ctx->intra_ctrls.enable_intra && ctx->blk_geom->sq_size < 128) {
3539
0
        uint8_t dc_cand_only_flag = ctx->intra_ctrls.intra_mode_end == DC_PRED || is_dc_only_safe(pcs, ctx);
3540
0
        if (ctx->cand_reduction_ctrls.cand_elimination_ctrls.enabled && !dc_cand_only_flag &&
3541
0
            ctx->md_me_dist != (uint32_t)~0) {
3542
0
            uint32_t th = ctx->cand_reduction_ctrls.cand_elimination_ctrls.dc_only_th;
3543
0
            th *= (ctx->blk_geom->bheight * ctx->blk_geom->bwidth);
3544
0
            if (ctx->md_me_dist < th) {
3545
0
                dc_cand_only_flag = 1;
3546
0
            }
3547
0
        }
3548
0
        inject_intra_candidates(pcs, ctx, dc_cand_only_flag, &cand_total_cnt);
3549
0
    }
3550
3551
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_syage_0()
3552
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3553
0
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3554
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3555
0
    }
3556
3557
0
    if (pcs->ppcs->sframe_ref_pruned) {
3558
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3559
0
    }
3560
3561
0
    *candidate_total_count_ptr = cand_total_cnt;
3562
0
}
3563
3564
EbErrorType generate_md_stage_0_cand(PictureControlSet* pcs, ModeDecisionContext* ctx, const PC_TREE* const pc_tree,
3565
138k
                                     uint32_t* candidate_total_count_ptr) {
3566
138k
    const SequenceControlSet* scs            = pcs->scs;
3567
138k
    const SliceType           slice_type     = pcs->slice_type;
3568
138k
    uint32_t                  cand_total_cnt = 0;
3569
    // Reset duplicates variables
3570
138k
    ctx->injected_mv_count = 0;
3571
138k
    ctx->inject_new_me     = 1;
3572
138k
    ctx->inject_new_pme    = 1;
3573
    //----------------------
3574
    // Intra
3575
138k
    if (ctx->intra_ctrls.enable_intra) {
3576
138k
        uint8_t dc_cand_only_flag = ctx->intra_ctrls.intra_mode_end == DC_PRED || is_dc_only_safe(pcs, ctx);
3577
138k
        if (ctx->cand_reduction_ctrls.cand_elimination_ctrls.enabled) {
3578
0
            eliminate_candidate_based_on_pme_me_results(ctx, &dc_cand_only_flag);
3579
0
        }
3580
139k
        if (ctx->blk_geom->sq_size < 128) {
3581
139k
            inject_intra_candidates(pcs, ctx, dc_cand_only_flag, &cand_total_cnt);
3582
139k
        }
3583
138k
        if (ctx->filter_intra_ctrls.enabled && svt_aom_filter_intra_allowed_bsize(ctx->blk_geom->bsize)) {
3584
0
            inject_filter_intra_candidates(pcs, ctx, &cand_total_cnt);
3585
0
        }
3586
3587
138k
        bool eval_intrabc = true;
3588
3589
138k
        if (svt_av1_allow_palette(ctx->md_palette_level, ctx->blk_geom->bsize)) {
3590
0
            uint32_t palette_start_cnt = cand_total_cnt;
3591
3592
0
            inject_palette_candidates(pcs, ctx, &cand_total_cnt);
3593
3594
0
            eval_intrabc = cand_total_cnt > palette_start_cnt;
3595
0
        }
3596
3597
138k
        if (ctx->md_allow_intrabc) {
3598
0
            if (!pcs->ppcs->intrabc_ctrls.palette_hint || eval_intrabc) {
3599
0
                bool do_intra_bc = true;
3600
3601
0
                if (ctx->shape == PART_N) {
3602
0
                    if (pcs->ppcs->intrabc_ctrls.b4_parent_gating && ctx->blk_geom->sq_size == 4 &&
3603
0
                        pc_tree->parent->tested_blk[PART_N][0]) {
3604
0
                        if (pc_tree->parent->block_data[PART_N][0]->block_mi.use_intrabc == 0) {
3605
0
                            do_intra_bc = false;
3606
0
                        }
3607
0
                    }
3608
0
                } else {
3609
0
                    if (pcs->ppcs->intrabc_ctrls.nsq_parent_gating && pc_tree->tested_blk[PART_N][0]) {
3610
0
                        if (pc_tree->block_data[PART_N][0]->block_mi.use_intrabc == 0) {
3611
0
                            do_intra_bc = false;
3612
0
                        }
3613
0
                    }
3614
0
                }
3615
3616
0
                if (do_intra_bc) {
3617
0
                    inject_intra_bc_candidates(pcs, ctx, scs, ctx->blk_ptr, &cand_total_cnt);
3618
0
                }
3619
0
            }
3620
0
        }
3621
138k
    }
3622
138k
    if (slice_type != I_SLICE) {
3623
0
        svt_aom_inject_inter_candidates(pcs, ctx, &cand_total_cnt);
3624
0
    }
3625
    // For I_SLICE, DC is always injected, and therefore there is no a risk of no candidates @ md_syage_0()
3626
    // For non I_SLICE, there is a risk of no candidates @ md_stage_0() because of the INTER candidates pruning techniques
3627
138k
    if (slice_type != I_SLICE && cand_total_cnt == 0) {
3628
0
        inject_zz_backup_candidate(pcs, ctx, &cand_total_cnt);
3629
0
    }
3630
3631
138k
    if (pcs->ppcs->sframe_ref_pruned) {
3632
0
        cand_total_cnt = reject_candidate_sframe(pcs, ctx, cand_total_cnt);
3633
0
    }
3634
3635
138k
    *candidate_total_count_ptr = cand_total_cnt;
3636
3637
138k
    memset(ctx->md_stage_0_count, 0, CAND_CLASS_TOTAL * sizeof(uint32_t));
3638
138k
    bool merge_inter_cands = 0;
3639
139k
    if (ctx->nic_ctrls.pruning_ctrls.merge_inter_cands_mult != (uint8_t)~0) {
3640
139k
        uint16_t th = (ctx->nic_ctrls.pruning_ctrls.merge_inter_cands_mult * (63 - pcs->scs->static_config.qp)) >> 1;
3641
139k
        if ((MIN(ctx->md_me_dist, ctx->md_pme_dist) / (ctx->blk_geom->bwidth * ctx->blk_geom->bheight)) < th) {
3642
135k
            merge_inter_cands = 1;
3643
135k
        }
3644
139k
    }
3645
3646
278k
    for (uint32_t cand_i = 0; cand_i < cand_total_cnt; cand_i++) {
3647
139k
        ModeDecisionCandidate* cand = &ctx->fast_cand_array[cand_i];
3648
139k
        if (is_intra_mode(cand->block_mi.mode)) {
3649
            // Intra prediction
3650
139k
            if ((cand->palette_info == NULL || cand->palette_size[0] == 0) && cand->block_mi.use_intrabc == 0) {
3651
139k
                cand->cand_class = CAND_CLASS_0;
3652
139k
                ctx->md_stage_0_count[CAND_CLASS_0]++;
3653
139k
            } else if (cand->block_mi.use_intrabc == 0) {
3654
                // Palette Prediction
3655
0
                cand->cand_class = CAND_CLASS_3;
3656
0
                ctx->md_stage_0_count[CAND_CLASS_3]++;
3657
37
            } else {
3658
                // Intra-BC Prediction
3659
37
                cand->cand_class = CAND_CLASS_4;
3660
37
                ctx->md_stage_0_count[CAND_CLASS_4]++;
3661
37
            }
3662
18.4E
        } else { // INTER
3663
18.4E
            if (cand->block_mi.mode == NEWMV || cand->block_mi.mode == NEW_NEWMV || merge_inter_cands) {
3664
                // MV Prediction
3665
0
                cand->cand_class = CAND_CLASS_2;
3666
0
                ctx->md_stage_0_count[CAND_CLASS_2]++;
3667
18.4E
            } else {
3668
                //MVP Prediction
3669
18.4E
                cand->cand_class = CAND_CLASS_1;
3670
18.4E
                ctx->md_stage_0_count[CAND_CLASS_1]++;
3671
18.4E
            }
3672
18.4E
        }
3673
139k
    }
3674
138k
    return EB_ErrorNone;
3675
138k
}
3676
3677
uint8_t av1_drl_ctx(const CandidateMv* ref_mv_stack, int32_t ref_idx);
3678
3679
/***************************************
3680
* Update symbols for light-PD1 path
3681
***************************************/
3682
void svt_aom_product_full_mode_decision_light_pd1(PictureControlSet* pcs, ModeDecisionContext* ctx,
3683
0
                                                  ModeDecisionCandidateBuffer* cand_bf) {
3684
0
    BlkStruct*             blk_ptr = ctx->blk_ptr;
3685
0
    ModeDecisionCandidate* cand    = cand_bf->cand;
3686
0
    blk_ptr->total_rate            = cand_bf->total_rate;
3687
3688
    // Set common signals (INTER/INTRA)
3689
0
    svt_memcpy(&blk_ptr->block_mi, &cand->block_mi, sizeof(BlockModeInfo));
3690
0
    blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
3691
3692
    // Set INTER mode signals
3693
0
    if (is_inter_mode(cand->block_mi.mode)) {
3694
0
        blk_ptr->drl_index = cand->drl_index;
3695
0
        assert(IMPLIES(
3696
0
            is_inter_compound_mode(cand->block_mi.mode) && blk_ptr->block_mi.interinter_comp.type == COMPOUND_AVERAGE,
3697
0
            (blk_ptr->block_mi.comp_group_idx == 0 && blk_ptr->block_mi.compound_idx == 1)));
3698
3699
        // Set MVs
3700
0
        blk_ptr->predmv[0].as_int = cand->pred_mv[0].as_int;
3701
0
        if (has_second_ref(&blk_ptr->block_mi)) {
3702
0
            blk_ptr->predmv[1].as_int = cand->pred_mv[1].as_int;
3703
0
        }
3704
3705
0
        const int8_t ref_frame_type = av1_ref_frame_type(blk_ptr->block_mi.ref_frame);
3706
        // Store winning inter_mode_ctx in blk to avoid storing for all ref frames for EC
3707
0
        blk_ptr->inter_mode_ctx = ctx->inter_mode_ctx[ref_frame_type];
3708
        // Store drl_ctx in blk to avoid storing final_ref_mv_stack for EC
3709
0
        if (blk_ptr->block_mi.mode == NEWMV || blk_ptr->block_mi.mode == NEW_NEWMV) {
3710
0
            for (uint8_t idx = 0; idx < 2; ++idx) {
3711
0
                if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3712
0
                    blk_ptr->drl_ctx[idx] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3713
0
                } else {
3714
0
                    blk_ptr->drl_ctx[idx] = -1;
3715
0
                }
3716
0
            }
3717
0
        }
3718
3719
0
        if (have_nearmv_in_inter_mode(blk_ptr->block_mi.mode)) {
3720
            // TODO(jingning): Temporary solution to compensate the NEARESTMV offset.
3721
0
            for (uint8_t idx = 1; idx < 3; ++idx) {
3722
0
                if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3723
0
                    blk_ptr->drl_ctx_near[idx - 1] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3724
0
                } else {
3725
0
                    blk_ptr->drl_ctx_near[idx - 1] = -1;
3726
0
                }
3727
0
            }
3728
0
        }
3729
0
    } else { // Set INTRA mode signals
3730
0
        cand->skip_mode_allowed = false;
3731
0
    }
3732
    // Set TX and coeff-related data
3733
0
    blk_ptr->block_has_coeff   = ((cand_bf->block_has_coeff) > 0) ? true : false;
3734
0
    ctx->blk_ptr->cnt_nz_coeff = cand_bf->cnt_nz_coeff;
3735
3736
    // If skip_mode is allowed, and block has no coeffs, use skip_mode
3737
0
    if (cand->skip_mode_allowed == true) {
3738
0
        blk_ptr->block_mi.skip_mode |= !blk_ptr->block_has_coeff;
3739
0
    }
3740
3741
0
    assert(IMPLIES(pcs->ppcs->frm_hdr.interpolation_filter == SWITCHABLE && blk_ptr->block_mi.skip_mode,
3742
0
                   cand->block_mi.interp_filters == 0));
3743
0
    if (blk_ptr->block_mi.skip_mode) {
3744
0
        blk_ptr->block_has_coeff = 0;
3745
0
        cand_bf->y_has_coeff     = 0;
3746
0
        cand_bf->u_has_coeff     = 0;
3747
0
        cand_bf->v_has_coeff     = 0;
3748
0
    }
3749
0
    blk_ptr->block_mi.skip = !blk_ptr->block_has_coeff;
3750
3751
0
    const uint16_t txb_itr       = 0;
3752
0
    const int32_t  txb_1d_offset = 0, txb_1d_offset_uv = 0;
3753
0
    blk_ptr->y_has_coeff         = cand_bf->y_has_coeff;
3754
0
    blk_ptr->u_has_coeff         = cand_bf->u_has_coeff;
3755
0
    blk_ptr->v_has_coeff         = cand_bf->v_has_coeff;
3756
0
    blk_ptr->tx_type[txb_itr]    = cand->transform_type[txb_itr];
3757
0
    blk_ptr->tx_type_uv          = cand->transform_type_uv;
3758
0
    blk_ptr->quant_dc.y[txb_itr] = cand_bf->quant_dc.y[txb_itr];
3759
0
    blk_ptr->quant_dc.u[txb_itr] = cand_bf->quant_dc.u[txb_itr];
3760
0
    blk_ptr->quant_dc.v[txb_itr] = cand_bf->quant_dc.v[txb_itr];
3761
3762
0
    if (ctx->bypass_encdec) {
3763
0
        blk_ptr->eob.y[txb_itr] = cand_bf->eob.y[txb_itr];
3764
0
        blk_ptr->eob.u[txb_itr] = cand_bf->eob.u[txb_itr];
3765
0
        blk_ptr->eob.v[txb_itr] = cand_bf->eob.v[txb_itr];
3766
0
        int32_t* src_ptr;
3767
0
        int32_t* dst_ptr;
3768
3769
0
        const TxSize tx_size   = tx_depth_to_tx_size[blk_ptr->block_mi.tx_depth][ctx->blk_geom->bsize];
3770
0
        const int    tx_width  = tx_size_wide[tx_size];
3771
0
        const int    tx_height = tx_size_high[tx_size];
3772
3773
        // only one TX unit, so no need to bitmask
3774
0
        if (blk_ptr->y_has_coeff) {
3775
0
            src_ptr = &(((int32_t*)cand_bf->quant->y_buffer)[txb_1d_offset]);
3776
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->y_buffer) + ctx->coded_area_sb;
3777
0
            svt_memcpy(dst_ptr, src_ptr, tx_width * tx_height * sizeof(int32_t));
3778
0
        }
3779
0
        ctx->coded_area_sb += tx_width * tx_height;
3780
3781
0
        const TxSize tx_size_uv   = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3782
0
        const int    tx_width_uv  = tx_size_wide[tx_size_uv];
3783
0
        const int    tx_height_uv = tx_size_high[tx_size_uv];
3784
        // Cb
3785
        // only one TX unit, so no need to bitmask
3786
0
        if (blk_ptr->u_has_coeff) {
3787
0
            src_ptr = &(((int32_t*)cand_bf->quant->u_buffer)[txb_1d_offset_uv]);
3788
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->u_buffer) +
3789
0
                ctx->coded_area_sb_uv;
3790
0
            svt_memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
3791
0
        }
3792
3793
        // Cr
3794
        // only one TX unit, so no need to bitmask
3795
0
        if (blk_ptr->v_has_coeff) {
3796
0
            src_ptr = &(((int32_t*)cand_bf->quant->v_buffer)[txb_1d_offset_uv]);
3797
0
            dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->v_buffer) +
3798
0
                ctx->coded_area_sb_uv;
3799
0
            svt_memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
3800
0
        }
3801
0
        ctx->coded_area_sb_uv += tx_width_uv * tx_height_uv;
3802
0
    }
3803
0
}
3804
3805
0
static INLINE double derive_ssim_threshold_factor_for_full_md(SequenceControlSet* scs) {
3806
0
    return scs->input_resolution >= INPUT_SIZE_1080p_RANGE ? 1.02 : 1.03;
3807
0
}
3808
3809
/***************************************
3810
* Full Mode Decision
3811
***************************************/
3812
uint32_t svt_aom_product_full_mode_decision(PictureControlSet* pcs, ModeDecisionContext* ctx,
3813
                                            ModeDecisionCandidateBuffer** buffer_ptr_array,
3814
140k
                                            uint32_t candidate_total_count, uint32_t* best_candidate_index_array) {
3815
140k
    SequenceControlSet* scs                = pcs->scs;
3816
140k
    BlkStruct*          blk_ptr            = ctx->blk_ptr;
3817
140k
    uint32_t            lowest_cost_index  = best_candidate_index_array[0];
3818
140k
    const bool          use_ssim_full_cost = ctx->tune_ssim_level > SSIM_LVL_0 ? true : false;
3819
3820
    // Find the candidate with the lowest cost
3821
    // Only need to sort if have multiple candidates
3822
140k
    if (ctx->md_stage_3_total_count > 1) {
3823
0
        if (use_ssim_full_cost) {
3824
            // Pass one: find candidate with the lowest SSD cost
3825
0
            uint64_t ssd_lowest_cost = 0xFFFFFFFFFFFFFFFFull;
3826
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3827
0
                uint32_t cand_index = best_candidate_index_array[i];
3828
0
                uint64_t cost       = *(buffer_ptr_array[cand_index]->full_cost);
3829
0
                if (cost < ssd_lowest_cost) {
3830
0
                    lowest_cost_index = cand_index;
3831
0
                    ssd_lowest_cost   = cost;
3832
0
                }
3833
0
            }
3834
3835
            // Pass two: among the candidates with SSD cost not greater than the threshold, find the one with the lowest SSIM cost
3836
0
            const double   threshold_factor   = derive_ssim_threshold_factor_for_full_md(scs);
3837
0
            const uint64_t ssd_cost_threshold = (uint64_t)(threshold_factor * ssd_lowest_cost);
3838
0
            uint64_t       ssim_lowest_cost   = 0xFFFFFFFFFFFFFFFFull;
3839
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3840
0
                uint32_t cand_index = best_candidate_index_array[i];
3841
3842
0
                uint64_t ssim_cost = *(buffer_ptr_array[cand_index]->full_cost_ssim);
3843
0
                uint64_t ssd_cost  = *(buffer_ptr_array[cand_index]->full_cost);
3844
0
                if (ssim_cost < ssim_lowest_cost) {
3845
0
                    if (ssd_cost <= ssd_cost_threshold) {
3846
0
                        lowest_cost_index = cand_index;
3847
0
                        ssim_lowest_cost  = ssim_cost;
3848
0
                        ssd_lowest_cost   = ssd_cost;
3849
0
                    }
3850
0
                } else if (ssim_cost == ssim_lowest_cost) {
3851
                    // if two candidates have the same ssim cost, choose the one with lower ssd cost
3852
0
                    if (ssd_cost < ssd_lowest_cost) {
3853
0
                        lowest_cost_index = cand_index;
3854
0
                        ssd_lowest_cost   = ssd_cost;
3855
0
                    }
3856
0
                }
3857
0
            }
3858
0
        } else { // fallback to SSD based RD cost
3859
0
            uint64_t lowest_cost = 0xFFFFFFFFFFFFFFFFull;
3860
0
            for (uint32_t i = 0; i < candidate_total_count; ++i) {
3861
0
                uint32_t cand_index = best_candidate_index_array[i];
3862
3863
0
                uint64_t cost = *(buffer_ptr_array[cand_index]->full_cost);
3864
0
                if (scs->vq_ctrls.sharpness_ctrls.unipred_bias && pcs->ppcs->is_noise_level &&
3865
0
                    is_inter_singleref_mode(buffer_ptr_array[cand_index]->cand->block_mi.mode)) {
3866
0
                    cost = (cost * uni_psy_bias[pcs->ppcs->picture_qp]) / 100;
3867
0
                }
3868
3869
0
                if (cost < lowest_cost) {
3870
0
                    lowest_cost_index = cand_index;
3871
0
                    lowest_cost       = cost;
3872
0
                }
3873
0
            }
3874
0
        }
3875
0
    }
3876
140k
    ModeDecisionCandidateBuffer* cand_bf = buffer_ptr_array[lowest_cost_index];
3877
140k
    ModeDecisionCandidate*       cand    = cand_bf->cand;
3878
140k
    blk_ptr->total_rate                  = cand_bf->total_rate;
3879
140k
    if (!(ctx->pd_pass == PD_PASS_1 && ctx->fixed_partition)) {
3880
        // When lambda tuning is on, lambda of each block is set separately, however at interdepth decision the sb lambda is used
3881
133k
        uint32_t full_lambda = ctx->hbd_md ? ctx->full_sb_lambda_md[EB_10_BIT_MD] : ctx->full_sb_lambda_md[EB_8_BIT_MD];
3882
133k
        ctx->blk_ptr->cost   = RDCOST(full_lambda, cand_bf->total_rate, cand_bf->full_dist);
3883
133k
        ctx->blk_ptr->full_dist = cand_bf->full_dist;
3884
133k
    }
3885
3886
    // Set common signals (INTER/INTRA)
3887
140k
    svt_memcpy(&blk_ptr->block_mi, &cand->block_mi, sizeof(BlockModeInfo));
3888
    // Set INTER mode signals
3889
    // INTER signals set first b/c INTER shuts Palette, so INTRA must overwrite if Palette + intrabc is used
3890
140k
    if (is_inter_block(&blk_ptr->block_mi)) {
3891
0
        blk_ptr->drl_index = cand->drl_index;
3892
0
        assert(IMPLIES(
3893
0
            is_inter_compound_mode(cand->block_mi.mode) && blk_ptr->block_mi.interinter_comp.type == COMPOUND_AVERAGE,
3894
0
            (blk_ptr->block_mi.comp_group_idx == 0 && blk_ptr->block_mi.compound_idx == 1)));
3895
3896
0
        blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
3897
        // Set MVs
3898
0
        blk_ptr->predmv[0].as_int = cand->pred_mv[0].as_int;
3899
0
        if (has_second_ref(&blk_ptr->block_mi)) {
3900
0
            blk_ptr->predmv[1].as_int = cand->pred_mv[1].as_int;
3901
0
        }
3902
0
        if (blk_ptr->block_mi.motion_mode == WARPED_CAUSAL ||
3903
0
            (cand->block_mi.mode == GLOBALMV || cand->block_mi.mode == GLOBAL_GLOBALMV)) {
3904
0
            svt_memcpy(&ctx->blk_ptr->wm_params_l0, &cand->wm_params_l0, sizeof(WarpedMotionParams));
3905
0
            svt_memcpy(&ctx->blk_ptr->wm_params_l1, &cand->wm_params_l1, sizeof(WarpedMotionParams));
3906
0
        }
3907
3908
0
        if (ctx->pd_pass == PD_PASS_1) {
3909
0
            const int8_t ref_frame_type = av1_ref_frame_type(blk_ptr->block_mi.ref_frame);
3910
            // Store winning inter_mode_ctx in blk to avoid storing for all ref frames for EC
3911
0
            blk_ptr->inter_mode_ctx = ctx->inter_mode_ctx[ref_frame_type];
3912
            // Store drl_ctx in blk to avoid storing final_ref_mv_stack for EC
3913
0
            if (blk_ptr->block_mi.mode == NEWMV || blk_ptr->block_mi.mode == NEW_NEWMV) {
3914
0
                for (uint8_t idx = 0; idx < 2; ++idx) {
3915
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3916
0
                        blk_ptr->drl_ctx[idx] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3917
0
                    } else {
3918
0
                        blk_ptr->drl_ctx[idx] = -1;
3919
0
                    }
3920
0
                }
3921
0
            }
3922
3923
0
            if (have_nearmv_in_inter_mode(blk_ptr->block_mi.mode)) {
3924
                // TODO(jingning): Temporary solution to compensate the NEARESTMV offset.
3925
0
                for (uint8_t idx = 1; idx < 3; ++idx) {
3926
0
                    if (blk_ptr->av1xd->ref_mv_count[ref_frame_type] > idx + 1) {
3927
0
                        blk_ptr->drl_ctx_near[idx - 1] = av1_drl_ctx(ctx->ref_mv_stack[ref_frame_type], idx);
3928
0
                    } else {
3929
0
                        blk_ptr->drl_ctx_near[idx - 1] = -1;
3930
0
                    }
3931
0
                }
3932
0
            }
3933
0
        }
3934
0
    }
3935
3936
    // Set INTRA mode signals
3937
140k
    if (is_intra_mode(blk_ptr->block_mi.mode)) {
3938
139k
        if (!cand->palette_info) {
3939
139k
            blk_ptr->palette_size[0] = blk_ptr->palette_size[1] = 0;
3940
139k
        } else if (svt_av1_allow_palette(ctx->md_palette_level, ctx->blk_geom->bsize)) {
3941
0
            memcpy(&blk_ptr->palette_info->pmi, &cand->palette_info->pmi, sizeof(PaletteModeInfo));
3942
0
            memcpy(blk_ptr->palette_info->color_idx_map, cand->palette_info->color_idx_map, MAX_PALETTE_SQUARE);
3943
0
            blk_ptr->palette_size[0] = cand->palette_size[0];
3944
0
            blk_ptr->palette_size[1] = cand->palette_size[1];
3945
0
        }
3946
3947
139k
        if (blk_ptr->block_mi.use_intrabc == 0) {
3948
139k
            cand->skip_mode_allowed = false;
3949
139k
        }
3950
139k
    }
3951
3952
    // Set TX and coeff-related data
3953
140k
    blk_ptr->block_has_coeff   = ((cand_bf->block_has_coeff) > 0) ? true : false;
3954
140k
    ctx->blk_ptr->cnt_nz_coeff = cand_bf->cnt_nz_coeff;
3955
3956
    // If skip_mode is allowed, and block has no coeffs, use skip_mode
3957
140k
    if (cand->skip_mode_allowed == true) {
3958
0
        blk_ptr->block_mi.skip_mode |= !blk_ptr->block_has_coeff;
3959
0
    }
3960
3961
140k
    assert(IMPLIES(pcs->ppcs->frm_hdr.interpolation_filter == SWITCHABLE && blk_ptr->block_mi.skip_mode,
3962
140k
                   cand->block_mi.interp_filters == 0));
3963
140k
    if (blk_ptr->block_mi.skip_mode) {
3964
0
        blk_ptr->block_has_coeff = 0;
3965
0
        cand_bf->y_has_coeff     = 0;
3966
0
        cand_bf->u_has_coeff     = 0;
3967
0
        cand_bf->v_has_coeff     = 0;
3968
0
    }
3969
3970
140k
    blk_ptr->block_mi.skip = !blk_ptr->block_has_coeff;
3971
140k
    blk_ptr->y_has_coeff   = cand_bf->y_has_coeff;
3972
140k
    blk_ptr->u_has_coeff   = cand_bf->u_has_coeff;
3973
140k
    blk_ptr->v_has_coeff   = cand_bf->v_has_coeff;
3974
140k
    svt_memcpy(blk_ptr->tx_type, cand->transform_type, sizeof(TxType) * MAX_TXB_COUNT);
3975
140k
    blk_ptr->tx_type_uv = cand->transform_type_uv;
3976
140k
    svt_memcpy(&blk_ptr->quant_dc, &cand_bf->quant_dc, sizeof(QuantDcData));
3977
140k
    svt_memcpy(&blk_ptr->eob, &cand_bf->eob, sizeof(EobData));
3978
3979
    // If bypassing EncDec, save recon/coeff
3980
140k
    if (ctx->bypass_encdec && ctx->pd_pass == PD_PASS_1) {
3981
137k
        const uint16_t tu_total_count = tx_blocks_per_depth[ctx->blk_geom->bsize][blk_ptr->block_mi.tx_depth];
3982
137k
        int32_t        txb_1d_offset = 0, txb_1d_offset_uv = 0;
3983
137k
        const TxSize   tx_size      = tx_depth_to_tx_size[blk_ptr->block_mi.tx_depth][ctx->blk_geom->bsize];
3984
137k
        const int      tx_width     = tx_size_wide[tx_size];
3985
137k
        const int      tx_height    = tx_size_high[tx_size];
3986
137k
        const TxSize   tx_size_uv   = av1_get_max_uv_txsize(ctx->blk_geom->bsize, 1, 1);
3987
137k
        const int      tx_width_uv  = tx_size_wide[tx_size_uv];
3988
137k
        const int      tx_height_uv = tx_size_high[tx_size_uv];
3989
660k
        for (uint16_t txb_itr = 0; txb_itr < tu_total_count; txb_itr++) {
3990
522k
            const bool uv_pass = (blk_ptr->block_mi.tx_depth == 0 || txb_itr == 0);
3991
3992
522k
            int32_t* src_ptr = &(((int32_t*)cand_bf->quant->y_buffer)[txb_1d_offset]);
3993
522k
            int32_t* dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->y_buffer)[txb_1d_offset]);
3994
3995
522k
            if (ctx->fixed_partition) {
3996
6.60k
                dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->y_buffer) +
3997
6.60k
                    ctx->coded_area_sb;
3998
6.60k
                ctx->coded_area_sb += tx_width * tx_height;
3999
6.60k
            }
4000
4001
522k
            if (blk_ptr->y_has_coeff & (1 << txb_itr)) {
4002
5.39k
                svt_memcpy(dst_ptr, src_ptr, tx_width * tx_height * sizeof(int32_t));
4003
5.39k
            }
4004
4005
522k
            txb_1d_offset += tx_width * tx_height;
4006
4007
522k
            if (ctx->has_uv && uv_pass) {
4008
                // Cb
4009
138k
                src_ptr = &(((int32_t*)cand_bf->quant->u_buffer)[txb_1d_offset_uv]);
4010
138k
                dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->u_buffer)[txb_1d_offset_uv]);
4011
4012
138k
                if (ctx->fixed_partition) {
4013
6.61k
                    dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->u_buffer) +
4014
6.61k
                        ctx->coded_area_sb_uv;
4015
6.61k
                }
4016
4017
138k
                if (blk_ptr->u_has_coeff & (1 << txb_itr)) {
4018
5.22k
                    svt_memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
4019
5.22k
                }
4020
4021
                // Cr
4022
138k
                src_ptr = &(((int32_t*)cand_bf->quant->v_buffer)[txb_1d_offset_uv]);
4023
138k
                dst_ptr = &(((int32_t*)ctx->blk_ptr->coeff_tmp->v_buffer)[txb_1d_offset_uv]);
4024
4025
138k
                if (ctx->fixed_partition) {
4026
6.61k
                    dst_ptr = ((int32_t*)pcs->ppcs->enc_dec_ptr->quantized_coeff[ctx->sb_index]->v_buffer) +
4027
6.61k
                        ctx->coded_area_sb_uv;
4028
6.61k
                    ctx->coded_area_sb_uv += tx_width_uv * tx_height_uv;
4029
6.61k
                }
4030
4031
138k
                if (blk_ptr->v_has_coeff & (1 << txb_itr)) {
4032
5.22k
                    svt_memcpy(dst_ptr, src_ptr, tx_width_uv * tx_height_uv * sizeof(int32_t));
4033
5.22k
                }
4034
4035
138k
                txb_1d_offset_uv += tx_width_uv * tx_height_uv;
4036
138k
            }
4037
522k
        }
4038
137k
    }
4039
4040
140k
    return lowest_cost_index;
4041
140k
}
4042
4043
// Return the end column for the current superblock, in unit of TPL blocks.
4044
0
static int get_superblock_tpl_column_end(PictureParentControlSet* ppcs, int mi_col, int num_mi_w) {
4045
0
    const int mib_size_log2 = ppcs->scs->seq_header.sb_size == BLOCK_128X128 ? 5 : 4;
4046
    // Find the start column of this superblock.
4047
0
    const int sb_mi_col_start = (mi_col >> mib_size_log2) << mib_size_log2;
4048
    // Same but in superres upscaled dimension.
4049
0
    const int sb_mi_col_start_sr = coded_to_superres_mi(sb_mi_col_start, ppcs->superres_denom);
4050
    // Width of this superblock in mi units.
4051
0
    const int sb_mi_width = mi_size_wide[ppcs->scs->seq_header.sb_size];
4052
    // Same but in superres upscaled dimension.
4053
0
    const int sb_mi_width_sr = coded_to_superres_mi(sb_mi_width, ppcs->superres_denom);
4054
    // Superblock end in mi units.
4055
0
    const int sb_mi_end = sb_mi_col_start_sr + sb_mi_width_sr;
4056
    // Superblock end in TPL units.
4057
0
    return (sb_mi_end + num_mi_w - 1) / num_mi_w;
4058
0
}
4059
4060
0
void aom_av1_set_ssim_rdmult(ModeDecisionContext* ctx, PictureControlSet* pcs, const int mi_row, const int mi_col) {
4061
0
    const Av1Common* const cm    = pcs->ppcs->av1_cm;
4062
0
    BlockSize              bsize = ctx->blk_geom->bsize;
4063
4064
0
    const int bsize_base = BLOCK_16X16;
4065
0
    const int num_mi_w   = mi_size_wide[bsize_base];
4066
0
    const int num_mi_h   = mi_size_high[bsize_base];
4067
0
    const int num_cols   = (cm->mi_cols + num_mi_w - 1) / num_mi_w;
4068
0
    const int num_rows   = (cm->mi_rows + num_mi_h - 1) / num_mi_h;
4069
0
    const int num_bcols  = (mi_size_wide[bsize] + num_mi_w - 1) / num_mi_w;
4070
0
    const int num_brows  = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h;
4071
0
    int       row, col;
4072
0
    double    num_of_mi          = 0.0;
4073
0
    double    geom_mean_of_scale = 1.0;
4074
0
    for (row = mi_row / num_mi_w; row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
4075
0
        for (col = mi_col / num_mi_h; col < num_cols && col < mi_col / num_mi_h + num_bcols; ++col) {
4076
0
            const int index = row * num_cols + col;
4077
0
            geom_mean_of_scale *= pcs->ppcs->pa_me_data->ssim_rdmult_scaling_factors[index];
4078
0
            num_of_mi += 1.0;
4079
0
        }
4080
0
    }
4081
0
    geom_mean_of_scale = pow(geom_mean_of_scale, (1.0 / num_of_mi));
4082
0
    if (!pcs->ppcs->blk_lambda_tuning) {
4083
0
        ctx->full_lambda_md[EB_8_BIT_MD] =
4084
0
            (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4085
0
        ctx->full_lambda_md[EB_10_BIT_MD] =
4086
0
            (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4087
4088
0
        ctx->fast_lambda_md[EB_8_BIT_MD] =
4089
0
            (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4090
0
        ctx->fast_lambda_md[EB_10_BIT_MD] =
4091
0
            (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4092
0
    } else {
4093
0
        ctx->full_lambda_md[EB_8_BIT_MD]  = (uint32_t)((double)ctx->full_lambda_md[EB_8_BIT_MD] * geom_mean_of_scale +
4094
0
                                                      0.5);
4095
0
        ctx->full_lambda_md[EB_10_BIT_MD] = (uint32_t)((double)ctx->full_lambda_md[EB_10_BIT_MD] * geom_mean_of_scale +
4096
0
                                                       0.5);
4097
4098
0
        ctx->fast_lambda_md[EB_8_BIT_MD]  = (uint32_t)((double)ctx->fast_lambda_md[EB_8_BIT_MD] * geom_mean_of_scale +
4099
0
                                                      0.5);
4100
0
        ctx->fast_lambda_md[EB_10_BIT_MD] = (uint32_t)((double)ctx->fast_lambda_md[EB_10_BIT_MD] * geom_mean_of_scale +
4101
0
                                                       0.5);
4102
0
    }
4103
0
}
4104
4105
0
void svt_aom_set_tuned_blk_lambda(ModeDecisionContext* ctx, PictureControlSet* pcs) {
4106
0
    PictureParentControlSet* ppcs = pcs->ppcs;
4107
0
    Av1Common*               cm   = ppcs->av1_cm;
4108
4109
0
    BlockSize bsize  = ctx->blk_geom->bsize;
4110
0
    int       mi_row = ctx->blk_org_y / 4;
4111
0
    int       mi_col = ctx->blk_org_x / 4;
4112
4113
0
    const int mi_col_sr         = coded_to_superres_mi(mi_col, ppcs->superres_denom);
4114
0
    const int mi_cols_sr        = ((ppcs->enhanced_unscaled_pic->width + 15) / 16) << 2; // picture column boundary
4115
0
    const int block_mi_width_sr = coded_to_superres_mi(mi_size_wide[bsize], ppcs->superres_denom);
4116
0
    const int bsize_base        = ppcs->tpl_ctrls.synth_blk_size == 32 ? BLOCK_32X32 : BLOCK_16X16;
4117
0
    const int num_mi_w          = mi_size_wide[bsize_base];
4118
0
    const int num_mi_h          = mi_size_high[bsize_base];
4119
0
    const int num_cols          = (mi_cols_sr + num_mi_w - 1) / num_mi_w;
4120
0
    const int num_rows          = (cm->mi_rows + num_mi_h - 1) / num_mi_h;
4121
0
    const int num_bcols         = (block_mi_width_sr + num_mi_w - 1) / num_mi_w;
4122
0
    const int num_brows         = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h;
4123
4124
    // This is required because the end col of superblock may be off by 1 in case
4125
    // of superres.
4126
0
    const int sb_bcol_end = get_superblock_tpl_column_end(ppcs, mi_col, num_mi_w);
4127
0
    int       row, col;
4128
0
    int32_t   base_block_count   = 0;
4129
0
    double    geom_mean_of_scale = 0.0;
4130
0
    for (row = mi_row / num_mi_w; row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
4131
0
        for (col = mi_col_sr / num_mi_h; col < num_cols && col < mi_col_sr / num_mi_h + num_bcols && col < sb_bcol_end;
4132
0
             ++col) {
4133
0
            const int index = row * num_cols + col;
4134
0
            geom_mean_of_scale += log(ppcs->pa_me_data->tpl_sb_rdmult_scaling_factors[index]);
4135
0
            ++base_block_count;
4136
0
        }
4137
0
    }
4138
    // When superres is on, base_block_count could be zero.
4139
    // This function's counterpart in AOM, av1_get_hier_tpl_rdmult, will encounter division by zero
4140
0
    if (base_block_count == 0) {
4141
        // return a large number to indicate invalid state
4142
0
        ctx->full_lambda_md[EB_8_BIT_MD]  = SUPERRES_INVALID_STATE;
4143
0
        ctx->full_lambda_md[EB_10_BIT_MD] = SUPERRES_INVALID_STATE;
4144
4145
0
        ctx->fast_lambda_md[EB_8_BIT_MD]  = SUPERRES_INVALID_STATE;
4146
0
        ctx->fast_lambda_md[EB_10_BIT_MD] = SUPERRES_INVALID_STATE;
4147
0
        return;
4148
0
    }
4149
4150
0
    geom_mean_of_scale = exp(geom_mean_of_scale / base_block_count);
4151
4152
0
    ctx->full_lambda_md[EB_8_BIT_MD] =
4153
0
        (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4154
0
    ctx->full_lambda_md[EB_10_BIT_MD] =
4155
0
        (uint32_t)((double)ctx->ed_ctx->pic_full_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4156
4157
0
    ctx->fast_lambda_md[EB_8_BIT_MD] =
4158
0
        (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_8_BIT_MD] * geom_mean_of_scale + 0.5);
4159
0
    ctx->fast_lambda_md[EB_10_BIT_MD] =
4160
0
        (uint32_t)((double)ctx->ed_ctx->pic_fast_lambda[EB_10_BIT_MD] * geom_mean_of_scale + 0.5);
4161
0
    if (ppcs->scs->static_config.tune == TUNE_SSIM || ppcs->scs->static_config.tune == TUNE_IQ ||
4162
0
        ppcs->scs->static_config.tune == TUNE_MS_SSIM) {
4163
0
        aom_av1_set_ssim_rdmult(ctx, pcs, mi_row, mi_col);
4164
0
    }
4165
0
}
4166
4167
0
double svt_ssim_4x4_c(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp) {
4168
0
    const int32_t count = 4 * 4;
4169
4170
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4171
0
    uint32_t i, j;
4172
0
    for (i = 0; i < 4; i++) {
4173
0
        for (j = 0; j < 4; j++) {
4174
0
            sum_s += s[j];
4175
0
            sum_r += r[j];
4176
0
            sum_sq_s += s[j] * s[j];
4177
0
            sum_sq_r += r[j] * r[j];
4178
0
            sum_sxr += s[j] * r[j];
4179
0
        }
4180
4181
0
        s += sp;
4182
0
        r += rp;
4183
0
    }
4184
4185
    //
4186
    // similarity
4187
    //
4188
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 8);
4189
0
    return score;
4190
0
}
4191
4192
0
double svt_ssim_8x8_c(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp) {
4193
0
    const int32_t count = 8 * 8;
4194
4195
    //
4196
    // is similar to svt_aom_ssim_parms_8x8_c, but supports MxN block size
4197
    //
4198
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4199
0
    uint32_t i, j;
4200
0
    for (i = 0; i < 8; i++) {
4201
0
        for (j = 0; j < 8; j++) {
4202
0
            sum_s += s[j];
4203
0
            sum_r += r[j];
4204
0
            sum_sq_s += s[j] * s[j];
4205
0
            sum_sq_r += r[j] * r[j];
4206
0
            sum_sxr += s[j] * r[j];
4207
0
        }
4208
4209
0
        s += sp;
4210
0
        r += rp;
4211
0
    }
4212
4213
    //
4214
    // similarity
4215
    //
4216
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 8);
4217
0
    return score;
4218
0
}
4219
4220
0
double svt_ssim_4x4_hbd_c(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp) {
4221
0
    const int32_t count = 4 * 4;
4222
4223
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4224
0
    uint32_t i, j;
4225
0
    for (i = 0; i < 4; i++) {
4226
0
        for (j = 0; j < 4; j++) {
4227
0
            sum_s += s[j];
4228
0
            sum_r += r[j];
4229
0
            sum_sq_s += s[j] * s[j];
4230
0
            sum_sq_r += r[j] * r[j];
4231
0
            sum_sxr += s[j] * r[j];
4232
0
        }
4233
4234
0
        s += sp;
4235
0
        r += rp;
4236
0
    }
4237
4238
    //
4239
    // similarity
4240
    //
4241
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 10);
4242
0
    return score;
4243
0
}
4244
4245
0
double svt_ssim_8x8_hbd_c(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp) {
4246
0
    const int32_t count = 8 * 8;
4247
4248
0
    uint32_t sum_s = 0, sum_r = 0, sum_sq_s = 0, sum_sq_r = 0, sum_sxr = 0;
4249
0
    uint32_t i, j;
4250
0
    for (i = 0; i < 8; i++) {
4251
0
        for (j = 0; j < 8; j++) {
4252
0
            sum_s += s[j];
4253
0
            sum_r += r[j];
4254
0
            sum_sq_s += s[j] * s[j];
4255
0
            sum_sq_r += r[j] * r[j];
4256
0
            sum_sxr += s[j] * r[j];
4257
0
        }
4258
4259
0
        s += sp;
4260
0
        r += rp;
4261
0
    }
4262
4263
    //
4264
    // similarity
4265
    //
4266
0
    double score = svt_aom_similarity(sum_s, sum_r, sum_sq_s, sum_sq_r, sum_sxr, count, 10);
4267
0
    return score;
4268
0
}
4269
4270
static double ssim_8x8_blocks(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width,
4271
0
                              uint32_t height) {
4272
0
    uint32_t i, j;
4273
0
    int      samples    = 0;
4274
0
    double   ssim_total = 0;
4275
4276
    // sample point start with each 4x4 location
4277
0
    for (i = 0; i <= height - 8; i += 8, s += sp * 8, r += rp * 8) {
4278
0
        for (j = 0; j <= width - 8; j += 8) {
4279
0
            double v = svt_ssim_8x8(s + j, sp, r + j, rp);
4280
0
            v        = CLIP3(0, 1, v);
4281
0
            ssim_total += v;
4282
0
            samples++;
4283
0
        }
4284
0
    }
4285
0
    assert(samples > 0);
4286
0
    ssim_total /= samples;
4287
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4288
0
    return ssim_total;
4289
0
}
4290
4291
static double ssim_4x4_blocks(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width,
4292
0
                              uint32_t height) {
4293
0
    uint32_t i, j;
4294
0
    int      samples    = 0;
4295
0
    double   ssim_total = 0;
4296
4297
    // sample point start with each 2x2 location
4298
0
    for (i = 0; i <= height - 4; i += 4, s += sp * 4, r += rp * 4) {
4299
0
        for (j = 0; j <= width - 4; j += 4) {
4300
0
            double v = svt_ssim_4x4(s + j, sp, r + j, rp);
4301
0
            v        = CLIP3(0, 1, v);
4302
0
            ssim_total += v;
4303
0
            samples++;
4304
0
        }
4305
0
    }
4306
0
    assert(samples > 0);
4307
0
    ssim_total /= samples;
4308
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4309
0
    return ssim_total;
4310
0
}
4311
4312
0
static double ssim(const uint8_t* s, uint32_t sp, const uint8_t* r, uint32_t rp, uint32_t width, uint32_t height) {
4313
0
    assert((width % 4) == 0 && (height % 4) == 0);
4314
0
    if ((width % 8) == 0 && (height % 8) == 0) {
4315
0
        return ssim_8x8_blocks(s, sp, r, rp, width, height);
4316
0
    } else {
4317
0
        return ssim_4x4_blocks(s, sp, r, rp, width, height);
4318
0
    }
4319
0
}
4320
4321
static double ssim_8x8_blocks_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4322
0
                                  uint32_t height) {
4323
0
    uint32_t i, j;
4324
0
    int      samples    = 0;
4325
0
    double   ssim_total = 0;
4326
4327
    // sample point start with each 4x4 location
4328
0
    for (i = 0; i <= height - 8; i += 8, s += sp * 8, r += rp * 8) {
4329
0
        for (j = 0; j <= width - 8; j += 8) {
4330
0
            double v = svt_ssim_8x8_hbd(s + j, sp, r + j, rp);
4331
0
            v        = CLIP3(0, 1, v);
4332
0
            ssim_total += v;
4333
0
            samples++;
4334
0
        }
4335
0
    }
4336
0
    assert(samples > 0);
4337
0
    ssim_total /= samples;
4338
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4339
0
    return ssim_total;
4340
0
}
4341
4342
static double ssim_4x4_blocks_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4343
0
                                  uint32_t height) {
4344
0
    uint32_t i, j;
4345
0
    int      samples    = 0;
4346
0
    double   ssim_total = 0;
4347
4348
    // sample point start with each 2x2 location
4349
0
    for (i = 0; i <= height - 4; i += 4, s += sp * 4, r += rp * 4) {
4350
0
        for (j = 0; j <= width - 4; j += 4) {
4351
0
            double v = svt_ssim_4x4_hbd(s + j, sp, r + j, rp);
4352
0
            v        = CLIP3(0, 1, v);
4353
0
            ssim_total += v;
4354
0
            samples++;
4355
0
        }
4356
0
    }
4357
0
    assert(samples > 0);
4358
0
    ssim_total /= samples;
4359
0
    assert(ssim_total <= 1.0 && ssim_total >= 0);
4360
0
    return ssim_total;
4361
0
}
4362
4363
static double ssim_hbd(const uint16_t* s, uint32_t sp, const uint16_t* r, uint32_t rp, uint32_t width,
4364
0
                       uint32_t height) {
4365
0
    assert((width % 4) == 0 && (height % 4) == 0);
4366
0
    if ((width % 8) == 0 && (height % 8) == 0) {
4367
0
        return ssim_8x8_blocks_hbd(s, sp, r, rp, width, height);
4368
0
    } else {
4369
0
        return ssim_4x4_blocks_hbd(s, sp, r, rp, width, height);
4370
0
    }
4371
0
}
4372
4373
uint64_t svt_spatial_full_distortion_ssim_kernel(uint8_t* input, uint32_t input_offset, uint32_t input_stride,
4374
                                                 uint8_t* recon, int32_t recon_offset, uint32_t recon_stride,
4375
0
                                                 uint32_t area_width, uint32_t area_height, bool hbd, double ac_bias) {
4376
0
    uint8_t        m     = 1;
4377
0
    const uint32_t count = area_width * area_height;
4378
4379
    // SSIM
4380
0
    uint64_t spatial_distortion;
4381
0
    double   ssim_score;
4382
4383
    // AC SAD
4384
0
    uint64_t psy_distortion = 0;
4385
4386
0
    if (!hbd) {
4387
0
        ssim_score = ssim(
4388
0
            input + input_offset, input_stride, recon + recon_offset, recon_stride, area_width, area_height);
4389
0
        if (ac_bias) {
4390
0
            uint64_t ac_distortion = svt_psy_distortion(
4391
0
                input + input_offset, input_stride, recon + recon_offset, recon_stride, area_width, area_height);
4392
0
            psy_distortion = (uint64_t)(ac_distortion * ac_bias);
4393
0
        }
4394
0
    } else {
4395
0
        m          = 8;
4396
0
        ssim_score = ssim_hbd((uint16_t*)input + input_offset,
4397
0
                              input_stride,
4398
0
                              (uint16_t*)recon + recon_offset,
4399
0
                              recon_stride,
4400
0
                              area_width,
4401
0
                              area_height);
4402
0
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
4403
0
        if (ac_bias) {
4404
0
            uint64_t ac_distortion = svt_psy_distortion_hbd((uint16_t*)input + input_offset,
4405
0
                                                            input_stride,
4406
0
                                                            (uint16_t*)recon + recon_offset,
4407
0
                                                            recon_stride,
4408
0
                                                            area_width,
4409
0
                                                            area_height);
4410
0
            psy_distortion         = (uint64_t)(ac_distortion * ac_bias);
4411
0
        }
4412
0
#endif
4413
0
    }
4414
4415
0
    spatial_distortion        = (uint64_t)((1 - ssim_score) * count * 100 * 7 * m);
4416
0
    uint64_t total_distortion = spatial_distortion + psy_distortion;
4417
4418
0
    return total_distortion;
4419
0
}