Coverage Report

Created: 2026-08-31 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/svt-av1/Source/Lib/Codec/av1me.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3
 *
4
 * This source code is subject to the terms of the BSD 2 Clause License and
5
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
 * was not distributed with this source code in the LICENSE file, you can
7
 * obtain it at https://www.aomedia.org/license/software-license. If the Alliance for Open
8
 * Media Patent License 1.0 was not distributed with this source code in the
9
 * PATENTS file, you can obtain it at https://www.aomedia.org/license/patent-license.
10
 */
11
12
#include <limits.h>
13
#include <math.h>
14
#include <stdio.h>
15
#include "av1me.h"
16
#include "mcomp.h"
17
#include "utility.h"
18
#include "pcs.h"
19
#include "sequence_control_set.h"
20
#include "aom_dsp_rtcd.h"
21
#include "md_process.h"
22
#include "adaptive_mv_pred.h"
23
24
AomVarianceFnPtr svt_aom_mefn_ptr[BLOCK_SIZES_ALL];
25
26
1
void init_fn_ptr(void) {
27
1
#if CONFIG_ENABLE_HIGH_BIT_DEPTH
28
1
#define BFP0(w, h)                                                                     \
29
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].sdf       = svt_aom_sad##w##x##h;                \
30
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].vf        = svt_aom_variance##w##x##h;           \
31
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].vf_hbd_10 = svt_aom_highbd_10_variance##w##x##h; \
32
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].svf       = svt_aom_sub_pixel_variance##w##x##h; \
33
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].sdx4df    = svt_aom_sad##w##x##h##x4d;
34
#else
35
#define BFP0(w, h)                                                                  \
36
    svt_aom_mefn_ptr[BLOCK_##w##X##h].sdf    = svt_aom_sad##w##x##h;                \
37
    svt_aom_mefn_ptr[BLOCK_##w##X##h].vf     = svt_aom_variance##w##x##h;           \
38
    svt_aom_mefn_ptr[BLOCK_##w##X##h].svf    = svt_aom_sub_pixel_variance##w##x##h; \
39
    svt_aom_mefn_ptr[BLOCK_##w##X##h].sdx4df = svt_aom_sad##w##x##h##x4d;
40
#endif
41
1
    BFP0(4, 16)
42
1
    BFP0(16, 4)
43
1
    BFP0(8, 32)
44
1
    BFP0(32, 8)
45
1
    BFP0(16, 64)
46
1
    BFP0(64, 16)
47
1
    BFP0(128, 128)
48
1
    BFP0(128, 64)
49
1
    BFP0(64, 128)
50
1
    BFP0(32, 16)
51
1
    BFP0(16, 32)
52
1
    BFP0(64, 32)
53
1
    BFP0(32, 64)
54
1
    BFP0(32, 32)
55
1
    BFP0(64, 64)
56
1
    BFP0(16, 16)
57
1
    BFP0(16, 8)
58
1
    BFP0(8, 16)
59
1
    BFP0(8, 8)
60
1
    BFP0(8, 4)
61
1
    BFP0(4, 8)
62
1
    BFP0(4, 4)
63
1
#if CONFIG_ENABLE_OBMC
64
1
#define OBFP(w, h)                                                           \
65
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].osdf = svt_aom_obmc_sad##w##x##h;      \
66
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].ovf  = svt_aom_obmc_variance##w##x##h; \
67
22
    svt_aom_mefn_ptr[BLOCK_##w##X##h].osvf = svt_aom_obmc_sub_pixel_variance##w##x##h;
68
1
    OBFP(128, 128)
69
1
    OBFP(128, 64)
70
1
    OBFP(64, 128)
71
1
    OBFP(64, 64)
72
1
    OBFP(64, 32)
73
1
    OBFP(32, 64)
74
1
    OBFP(32, 32)
75
1
    OBFP(32, 16)
76
1
    OBFP(16, 32)
77
1
    OBFP(16, 16)
78
1
    OBFP(16, 8)
79
1
    OBFP(8, 16)
80
1
    OBFP(8, 8)
81
1
    OBFP(4, 8)
82
1
    OBFP(8, 4)
83
1
    OBFP(4, 4)
84
1
    OBFP(4, 16)
85
1
    OBFP(16, 4)
86
1
    OBFP(8, 32)
87
1
    OBFP(32, 8)
88
1
    OBFP(16, 64)
89
1
    OBFP(64, 16)
90
1
#endif
91
1
}
92
93
0
static INLINE const uint8_t* get_buf_from_mv(const Buf2D* buf, const Mv mv) {
94
0
    return &buf->buf[mv.y * buf->stride + mv.x];
95
0
}
96
97
0
void svt_av1_set_mv_search_range(MvLimits* mv_limits, const Mv mv) {
98
0
    int col_min = (mv.x >> 3) - MAX_FULL_PEL_VAL + !!(mv.x & 7);
99
0
    int row_min = (mv.y >> 3) - MAX_FULL_PEL_VAL + !!(mv.y & 7);
100
0
    int col_max = (mv.x >> 3) + MAX_FULL_PEL_VAL;
101
0
    int row_max = (mv.y >> 3) + MAX_FULL_PEL_VAL;
102
103
0
    col_min = AOMMAX(col_min, (MV_LOW >> 3) + 1);
104
0
    row_min = AOMMAX(row_min, (MV_LOW >> 3) + 1);
105
0
    col_max = AOMMIN(col_max, (MV_UPP >> 3) - 1);
106
0
    row_max = AOMMIN(row_max, (MV_UPP >> 3) - 1);
107
108
    // Get intersection of UMV window and valid MV window to reduce # of checks
109
    // in diamond search.
110
0
    if (mv_limits->col_min < col_min) {
111
0
        mv_limits->col_min = col_min;
112
0
    }
113
0
    if (mv_limits->col_max > col_max) {
114
0
        mv_limits->col_max = col_max;
115
0
    }
116
0
    if (mv_limits->row_min < row_min) {
117
0
        mv_limits->row_min = row_min;
118
0
    }
119
0
    if (mv_limits->row_max > row_max) {
120
0
        mv_limits->row_max = row_max;
121
0
    }
122
0
}
123
124
0
int svt_aom_mv_err_cost_light(const Mv mv, const Mv ref) {
125
0
    const uint32_t factor     = 50;
126
0
    const uint32_t absmvdiffx = ABS(mv.x - ref.x);
127
0
    const uint32_t absmvdiffy = ABS(mv.y - ref.y);
128
0
    const uint32_t mv_rate    = 1296 + (factor * (absmvdiffx + absmvdiffy));
129
0
    return mv_rate;
130
0
}
131
132
0
static int mvsad_err_cost_light(const Mv mv, const Mv ref) {
133
0
    const uint32_t factor     = 50;
134
0
    const uint32_t absmvdiffx = ABS(mv.x - ref.x) * 8;
135
0
    const uint32_t absmvdiffy = ABS(mv.y - ref.y) * 8;
136
0
    const uint32_t mv_rate    = 1296 + (factor * (absmvdiffx + absmvdiffy));
137
0
    return mv_rate;
138
0
}
139
140
0
int svt_aom_mv_err_cost(const Mv mv, const Mv ref, const int* mvjcost, const int* mvcost[2], int error_per_bit) {
141
0
    if (mvcost) {
142
0
        const Mv diff = (Mv){{mv.x - ref.x, mv.y - ref.y}};
143
0
        return (int)ROUND_POWER_OF_TWO_64(
144
0
            (int64_t)svt_mv_cost(diff, mvjcost, mvcost) * error_per_bit,
145
0
            RDDIV_BITS + AV1_PROB_COST_SHIFT - RD_EPB_SHIFT + PIXEL_TRANSFORM_ERROR_SCALE);
146
0
    }
147
0
    return 0;
148
0
}
149
150
0
static int mvsad_err_cost(const IntraBcContext* x, const Mv mv, const Mv ref, int sad_per_bit) {
151
0
    if (x->approx_inter_rate) {
152
0
        return mvsad_err_cost_light(mv, ref);
153
0
    }
154
0
    const Mv diff = (Mv){{(mv.x - ref.x) * 8, (mv.y - ref.y) * 8}};
155
0
    return ROUND_POWER_OF_TWO(
156
0
        (unsigned)svt_mv_cost(diff, x->nmv_vec_cost, (const int* const*)x->mv_cost_stack) * sad_per_bit,
157
0
        AV1_PROB_COST_SHIFT);
158
0
}
159
160
0
void svt_av1_init3smotion_compensation(SearchSiteConfig* cfg, int stride) {
161
0
    int len, ss_count = 1;
162
163
0
    cfg->ss[0].mv.as_int = 0;
164
0
    cfg->ss[0].offset    = 0;
165
166
0
    for (len = MAX_FIRST_STEP; len > 0; len /= 2) {
167
        // Generate offsets for 8 search sites per step.
168
0
        const Mv ss_mvs[8] = {{{0, -len}},
169
0
                              {{0, len}},
170
0
                              {{-len, 0}},
171
0
                              {{len, 0}},
172
0
                              {{-len, -len}},
173
0
                              {{len, -len}},
174
0
                              {{-len, len}},
175
0
                              {{len, len}}};
176
0
        int      i;
177
0
        for (i = 0; i < 8; ++i) {
178
0
            SearchSite* const ss = &cfg->ss[ss_count++];
179
0
            ss->mv               = ss_mvs[i];
180
0
            ss->offset           = ss->mv.y * stride + ss->mv.x;
181
0
        }
182
0
    }
183
184
0
    cfg->ss_count          = ss_count;
185
0
    cfg->searches_per_step = 8;
186
0
}
187
188
0
static INLINE int is_mv_in(const MvLimits* mv_limits, const Mv mv) {
189
0
    return (mv.x >= mv_limits->col_min) && (mv.x <= mv_limits->col_max) && (mv.y >= mv_limits->row_min) &&
190
0
        (mv.y <= mv_limits->row_max);
191
0
}
192
193
int svt_av1_get_mvpred_var(const IntraBcContext* x, const Mv best_mv, const Mv center_mv, const AomVarianceFnPtr* vfp,
194
0
                           int use_mvcost) {
195
0
    const Buf2D* const what    = &x->plane[0].src;
196
0
    const Buf2D* const in_what = &x->xdplane[0].pre[0];
197
0
    const Mv           mv      = {{best_mv.x * 8, best_mv.y * 8}};
198
0
    unsigned int       unused;
199
0
    if (x->approx_inter_rate) {
200
0
        return vfp->vf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv), in_what->stride, &unused) +
201
0
            (use_mvcost ? svt_aom_mv_err_cost_light(mv, center_mv) : 0);
202
0
    } else {
203
0
        return vfp->vf(what->buf, what->stride, get_buf_from_mv(in_what, best_mv), in_what->stride, &unused) +
204
0
            (use_mvcost ? svt_aom_mv_err_cost(mv, center_mv, x->nmv_vec_cost, x->mv_cost_stack, x->errorperbit) : 0);
205
0
    }
206
0
}
207
208
// Exhaustive motion search around a given centre position with a given
209
// step size.
210
static int exhaustive_mesh_search(IntraBcContext* x, Mv* ref_mv, Mv* best_mv, int range, int step, int sad_per_bit,
211
0
                                  const AomVarianceFnPtr* fn_ptr, const Mv center_mv) {
212
0
    const Buf2D* const what       = &x->plane[0].src;
213
0
    const Buf2D* const in_what    = &x->xdplane[0].pre[0];
214
0
    Mv                 fcenter_mv = {.as_int = center_mv.as_int};
215
0
    unsigned int       best_sad   = INT_MAX;
216
0
    int                r, c, i;
217
0
    int                start_col, end_col, start_row, end_row;
218
0
    int                col_step = (step > 1) ? step : 4;
219
220
0
    assert(step >= 1);
221
222
0
    clamp_mv(&fcenter_mv, x->mv_limits.col_min, x->mv_limits.col_max, x->mv_limits.row_min, x->mv_limits.row_max);
223
0
    *best_mv = fcenter_mv;
224
0
    best_sad = fn_ptr->sdf(what->buf, what->stride, get_buf_from_mv(in_what, fcenter_mv), in_what->stride) +
225
0
        mvsad_err_cost(x, fcenter_mv, *ref_mv, sad_per_bit);
226
0
    start_row = AOMMAX(-range, x->mv_limits.row_min - fcenter_mv.y);
227
0
    start_col = AOMMAX(-range, x->mv_limits.col_min - fcenter_mv.x);
228
0
    end_row   = AOMMIN(range, x->mv_limits.row_max - fcenter_mv.y);
229
0
    end_col   = AOMMIN(range, x->mv_limits.col_max - fcenter_mv.x);
230
231
0
    for (r = start_row; r <= end_row; r += step) {
232
0
        for (c = start_col; c <= end_col; c += col_step) {
233
            // Step > 1 means we are not checking every location in this pass.
234
0
            if (step > 1) {
235
0
                const Mv     mv  = {{fcenter_mv.x + c, fcenter_mv.y + r}};
236
0
                unsigned int sad = fn_ptr->sdf(what->buf, what->stride, get_buf_from_mv(in_what, mv), in_what->stride);
237
0
                if (sad < best_sad) {
238
0
                    sad += mvsad_err_cost(x, mv, *ref_mv, sad_per_bit);
239
0
                    if (sad < best_sad) {
240
0
                        best_sad          = sad;
241
0
                        x->second_best_mv = *best_mv;
242
0
                        *best_mv          = mv;
243
0
                    }
244
0
                }
245
0
            } else {
246
                // 4 sads in a single call if we are checking every location
247
0
                if (c + 3 <= end_col) {
248
0
                    unsigned int   sads[4];
249
0
                    const uint8_t* addrs[4];
250
0
                    for (i = 0; i < 4; ++i) {
251
0
                        const Mv mv = {{fcenter_mv.x + c + i, fcenter_mv.y + r}};
252
0
                        addrs[i]    = get_buf_from_mv(in_what, mv);
253
0
                    }
254
0
                    fn_ptr->sdx4df(what->buf, what->stride, addrs, in_what->stride, sads);
255
256
0
                    for (i = 0; i < 4; ++i) {
257
0
                        if (sads[i] < best_sad) {
258
0
                            const Mv           mv  = {{fcenter_mv.x + c + i, fcenter_mv.y + r}};
259
0
                            const unsigned int sad = sads[i] + mvsad_err_cost(x, mv, *ref_mv, sad_per_bit);
260
0
                            if (sad < best_sad) {
261
0
                                best_sad          = sad;
262
0
                                x->second_best_mv = *best_mv;
263
0
                                *best_mv          = mv;
264
0
                            }
265
0
                        }
266
0
                    }
267
0
                } else {
268
0
                    for (i = 0; i < end_col - c; ++i) {
269
0
                        const Mv     mv  = {{fcenter_mv.x + c + i, fcenter_mv.y + r}};
270
0
                        unsigned int sad = fn_ptr->sdf(
271
0
                            what->buf, what->stride, get_buf_from_mv(in_what, mv), in_what->stride);
272
0
                        if (sad < best_sad) {
273
0
                            sad += mvsad_err_cost(x, mv, *ref_mv, sad_per_bit);
274
0
                            if (sad < best_sad) {
275
0
                                best_sad          = sad;
276
0
                                x->second_best_mv = *best_mv;
277
0
                                *best_mv          = mv;
278
0
                            }
279
0
                        }
280
0
                    }
281
0
                }
282
0
            }
283
0
        }
284
0
    }
285
286
0
    return best_sad;
287
0
}
288
289
int svt_av1_diamond_search_sad_c(IntraBcContext* x, const SearchSiteConfig* cfg, Mv* ref_mv, Mv* best_mv,
290
                                 int search_param, int sad_per_bit, int* num00, const AomVarianceFnPtr* fn_ptr,
291
0
                                 const Mv center_mv) {
292
0
    int i, j, step;
293
294
0
    uint8_t*       what        = x->plane[0].src.buf;
295
0
    const int      what_stride = x->plane[0].src.stride;
296
0
    const uint8_t* in_what;
297
0
    const int      in_what_stride = x->xdplane[0].pre[0].stride;
298
0
    const uint8_t* best_address;
299
300
0
    unsigned int bestsad;
301
0
    int          best_site = 0;
302
0
    int          last_site = 0;
303
304
0
    int ref_row;
305
0
    int ref_col;
306
307
    // search_param determines the length of the initial step and hence the number
308
    // of iterations.
309
    // 0 = initial step (MAX_FIRST_STEP) pel
310
    // 1 = (MAX_FIRST_STEP/2) pel,
311
    // 2 = (MAX_FIRST_STEP/4) pel...
312
0
    const SearchSite* ss        = &cfg->ss[search_param * cfg->searches_per_step];
313
0
    const int         tot_steps = (cfg->ss_count / cfg->searches_per_step) - search_param;
314
315
0
    const Mv fcenter_mv = {{center_mv.x >> 3, center_mv.y >> 3}};
316
0
    clamp_mv(ref_mv, x->mv_limits.col_min, x->mv_limits.col_max, x->mv_limits.row_min, x->mv_limits.row_max);
317
0
    ref_row    = ref_mv->y;
318
0
    ref_col    = ref_mv->x;
319
0
    *num00     = 0;
320
0
    best_mv->y = ref_row;
321
0
    best_mv->x = ref_col;
322
323
    // Work out the start point for the search
324
0
    in_what      = x->xdplane[0].pre[0].buf + ref_row * in_what_stride + ref_col;
325
0
    best_address = in_what;
326
327
    // Check the starting position
328
0
    bestsad = fn_ptr->sdf(what, what_stride, in_what, in_what_stride) +
329
0
        mvsad_err_cost(x, *best_mv, fcenter_mv, sad_per_bit);
330
331
0
    i = 1;
332
333
0
    for (step = 0; step < tot_steps; step++) {
334
0
        int all_in = 1;
335
336
        // All_in is true if every one of the points we are checking are within
337
        // the bounds of the image.
338
0
        all_in &= ((best_mv->y + ss[i].mv.y) > x->mv_limits.row_min);
339
0
        all_in &= ((best_mv->y + ss[i + 1].mv.y) < x->mv_limits.row_max);
340
0
        all_in &= ((best_mv->x + ss[i + 2].mv.x) > x->mv_limits.col_min);
341
0
        all_in &= ((best_mv->x + ss[i + 3].mv.x) < x->mv_limits.col_max);
342
343
        // If all the pixels are within the bounds we don't check whether the
344
        // search point is valid in this loop,  otherwise we check each point
345
        // for validity..
346
0
        if (all_in) {
347
0
            unsigned int sad_array[4];
348
349
0
            for (j = 0; j < cfg->searches_per_step; j += 4) {
350
0
                unsigned char const* block_offset[4];
351
352
0
                for (int t = 0; t < 4; t++) {
353
0
                    block_offset[t] = ss[i + t].offset + best_address;
354
0
                }
355
356
0
                fn_ptr->sdx4df(what, what_stride, block_offset, in_what_stride, sad_array);
357
358
0
                for (int t = 0; t < 4; t++, i++) {
359
0
                    if (sad_array[t] < bestsad) {
360
0
                        const Mv this_mv = {{best_mv->x + ss[i].mv.x, best_mv->y + ss[i].mv.y}};
361
0
                        sad_array[t] += mvsad_err_cost(x, this_mv, fcenter_mv, sad_per_bit);
362
0
                        if (sad_array[t] < bestsad) {
363
0
                            bestsad   = sad_array[t];
364
0
                            best_site = i;
365
0
                        }
366
0
                    }
367
0
                }
368
0
            }
369
0
        } else {
370
0
            for (j = 0; j < cfg->searches_per_step; j++) {
371
                // Trap illegal vectors
372
0
                const Mv this_mv = {{best_mv->x + ss[i].mv.x, best_mv->y + ss[i].mv.y}};
373
374
0
                if (is_mv_in(&x->mv_limits, this_mv)) {
375
0
                    const uint8_t* const check_here = ss[i].offset + best_address;
376
0
                    unsigned int         thissad    = fn_ptr->sdf(what, what_stride, check_here, in_what_stride);
377
378
0
                    if (thissad < bestsad) {
379
0
                        thissad += mvsad_err_cost(x, this_mv, fcenter_mv, sad_per_bit);
380
0
                        if (thissad < bestsad) {
381
0
                            bestsad   = thissad;
382
0
                            best_site = i;
383
0
                        }
384
0
                    }
385
0
                }
386
0
                i++;
387
0
            }
388
0
        }
389
0
        if (best_site != last_site) {
390
0
            x->second_best_mv = *best_mv;
391
0
            best_mv->y += ss[best_site].mv.y;
392
0
            best_mv->x += ss[best_site].mv.x;
393
0
            best_address += ss[best_site].offset;
394
0
            last_site = best_site;
395
#if defined(NEW_DIAMOND_SEARCH)
396
            while (1) {
397
                const Mv this_mv = {{best_mv->x + ss[best_site].mv.x, best_mv->y + ss[best_site].mv.y}};
398
                if (is_mv_in(&x->mv_limits, &this_mv)) {
399
                    const uint8_t* const check_here = ss[best_site].offset + best_address;
400
                    unsigned int         thissad    = fn_ptr->sdf(what, what_stride, check_here, in_what_stride);
401
                    if (thissad < bestsad) {
402
                        thissad += mvsad_err_cost(x, this_mv, fcenter_mv, sad_per_bit);
403
                        if (thissad < bestsad) {
404
                            bestsad = thissad;
405
                            best_mv->y += ss[best_site].mv.y;
406
                            best_mv->x += ss[best_site].mv.x;
407
                            best_address += ss[best_site].offset;
408
                            continue;
409
                        }
410
                    }
411
                }
412
                break;
413
            }
414
#endif
415
0
        } else if (best_address == in_what) {
416
0
            (*num00)++;
417
0
        }
418
0
    }
419
0
    return bestsad;
420
0
}
421
422
static int svt_av1_refining_search_sad(IntraBcContext* x, Mv* ref_mv, int error_per_bit, int search_range,
423
0
                                       const AomVarianceFnPtr* fn_ptr, const Mv center_mv) {
424
0
    const Mv           neighbors[4] = {{{0, -1}}, {{-1, 0}}, {{1, 0}}, {{0, 1}}};
425
0
    const Buf2D* const what         = &x->plane[0].src;
426
0
    const Buf2D* const in_what      = &x->xdplane[0].pre[0];
427
0
    const Mv           fcenter_mv   = {{center_mv.x >> 3, center_mv.y >> 3}};
428
0
    const uint8_t*     best_address = get_buf_from_mv(in_what, *ref_mv);
429
0
    unsigned int       best_sad     = fn_ptr->sdf(what->buf, what->stride, best_address, in_what->stride) +
430
0
        mvsad_err_cost(x, *ref_mv, fcenter_mv, error_per_bit);
431
0
    for (int i = 0; i < search_range; i++) {
432
0
        int       best_site = -1;
433
0
        const int all_in    = (ref_mv->y - 1) > x->mv_limits.row_min && (ref_mv->y + 1) < x->mv_limits.row_max &&
434
0
            (ref_mv->x - 1) > x->mv_limits.col_min && (ref_mv->x + 1) < x->mv_limits.col_max;
435
436
0
        if (all_in) {
437
0
            unsigned int         sads[4];
438
0
            const uint8_t* const positions[4] = {
439
0
                best_address - in_what->stride, best_address - 1, best_address + 1, best_address + in_what->stride};
440
441
0
            fn_ptr->sdx4df(what->buf, what->stride, positions, in_what->stride, sads);
442
443
0
            for (int j = 0; j < 4; ++j) {
444
0
                if (sads[j] < best_sad) {
445
0
                    const Mv mv = {{ref_mv->x + neighbors[j].x, ref_mv->y + neighbors[j].y}};
446
0
                    sads[j] += mvsad_err_cost(x, mv, fcenter_mv, error_per_bit);
447
0
                    if (sads[j] < best_sad) {
448
0
                        best_sad  = sads[j];
449
0
                        best_site = j;
450
0
                    }
451
0
                }
452
0
            }
453
0
        } else {
454
0
            for (int j = 0; j < 4; ++j) {
455
0
                const Mv mv = {{ref_mv->x + neighbors[j].x, ref_mv->y + neighbors[j].y}};
456
457
0
                if (is_mv_in(&x->mv_limits, mv)) {
458
0
                    unsigned int sad = fn_ptr->sdf(
459
0
                        what->buf, what->stride, get_buf_from_mv(in_what, mv), in_what->stride);
460
0
                    if (sad < best_sad) {
461
0
                        sad += mvsad_err_cost(x, mv, fcenter_mv, error_per_bit);
462
0
                        if (sad < best_sad) {
463
0
                            best_sad  = sad;
464
0
                            best_site = j;
465
0
                        }
466
0
                    }
467
0
                }
468
0
            }
469
0
        }
470
471
0
        if (best_site == -1) {
472
0
            break;
473
0
        } else {
474
0
            x->second_best_mv = *ref_mv;
475
0
            ref_mv->y += neighbors[best_site].y;
476
0
            ref_mv->x += neighbors[best_site].x;
477
0
            best_address = get_buf_from_mv(in_what, *ref_mv);
478
0
        }
479
0
    }
480
481
0
    return best_sad;
482
0
}
483
484
/* do_refine: If last step (1-away) of n-step search doesn't pick the center
485
              point as the best match, we will do a final 1-away diamond
486
              refining search  */
487
static int full_pixel_diamond(PictureControlSet* pcs, IntraBcContext /*MACROBLOCK*/* x, Mv* mvp_full, int step_param,
488
                              int sadpb, int further_steps, int do_refine, int* cost_list,
489
0
                              const AomVarianceFnPtr* fn_ptr, const Mv ref_mv) {
490
0
    Mv  temp_mv;
491
0
    int thissme, n, num00 = 0;
492
0
    (void)cost_list;
493
    /*int bestsme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv,
494
                                        step_param, sadpb, &n, fn_ptr, ref_mv);*/
495
0
    int bestsme = svt_av1_diamond_search_sad_c(
496
0
        x, &pcs->ss_cfg, mvp_full, &temp_mv, step_param, sadpb, &n, fn_ptr, ref_mv);
497
498
0
    if (bestsme < INT_MAX) {
499
0
        bestsme = svt_av1_get_mvpred_var(x, temp_mv, ref_mv, fn_ptr, 1);
500
0
    }
501
0
    x->best_mv = temp_mv;
502
503
    // If there won't be more n-step search, check to see if refining search is
504
    // needed.
505
0
    if (n > further_steps) {
506
0
        do_refine = 0;
507
0
    }
508
509
0
    while (n < further_steps) {
510
0
        ++n;
511
512
0
        if (num00) {
513
0
            num00--;
514
0
        } else {
515
            /*thissme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv,
516
                                        step_param + n, sadpb, &num00, fn_ptr,
517
                                        ref_mv);*/
518
0
            thissme = svt_av1_diamond_search_sad_c(
519
0
                x, &pcs->ss_cfg, mvp_full, &temp_mv, step_param + n, sadpb, &num00, fn_ptr, ref_mv);
520
521
0
            if (thissme < INT_MAX) {
522
0
                thissme = svt_av1_get_mvpred_var(x, temp_mv, ref_mv, fn_ptr, 1);
523
0
            }
524
525
            // check to see if refining search is needed.
526
0
            if (num00 > further_steps - n) {
527
0
                do_refine = 0;
528
0
            }
529
530
0
            if (thissme < bestsme) {
531
0
                bestsme    = thissme;
532
0
                x->best_mv = temp_mv;
533
0
            }
534
0
        }
535
0
    }
536
537
    // final 1-away diamond refining search
538
0
    if (do_refine) {
539
0
        const int search_range = 8;
540
0
        Mv        best_mv      = x->best_mv;
541
0
        thissme                = svt_av1_refining_search_sad(x, &best_mv, sadpb, search_range, fn_ptr, ref_mv);
542
0
        if (thissme < INT_MAX) {
543
0
            thissme = svt_av1_get_mvpred_var(x, best_mv, ref_mv, fn_ptr, 1);
544
0
        }
545
0
        if (thissme < bestsme) {
546
0
            bestsme    = thissme;
547
0
            x->best_mv = best_mv;
548
0
        }
549
0
    }
550
551
    // Return cost list.
552
    /* if (cost_list) {
553
    calc_int_cost_list(x, ref_mv, sadpb, fn_ptr, &x->best_mv.as_mv, cost_list);
554
  }*/
555
0
    return bestsme;
556
0
}
557
558
0
#define MIN_RANGE 7
559
0
#define MAX_RANGE 256
560
0
#define MIN_INTERVAL 1
561
562
// Runs an limited range exhaustive mesh search using a pattern set
563
// according to the encode speed profile.
564
static int intrabc_full_pixel_exhaustive(PictureControlSet* pcs, IntraBcContext* x, const Mv center_mv, int sadpb,
565
0
                                         const AomVarianceFnPtr* fn_ptr, const Mv ref_mv, Mv* dst_mv) {
566
0
    const IntrabcCtrls* ctrls = &pcs->ppcs->intrabc_ctrls;
567
568
0
    Mv search_mv = center_mv;
569
0
    Mv ref_mv_fp = {{ref_mv.x >> 3, ref_mv.y >> 3}};
570
571
0
    int range     = ctrls->mesh_patterns[0].range;
572
0
    int interval  = ctrls->mesh_patterns[0].interval;
573
0
    int best_cost = INT_MAX;
574
575
    // Validate parameters
576
0
    if (range < MIN_RANGE || range > MAX_RANGE || interval < MIN_INTERVAL || interval > range) {
577
0
        return INT_MAX;
578
0
    }
579
580
0
    const int base_interval_div = range / interval;
581
582
    // Adapt search range based on center MV magnitude
583
0
    int mv_mag = AOMMAX(abs(search_mv.x), abs(search_mv.y));
584
0
    range      = AOMMAX(range, (5 * mv_mag) / 4);
585
0
    range      = AOMMIN(range, MAX_RANGE);
586
0
    interval   = AOMMAX(interval, range / base_interval_div);
587
588
    // Initial coarse search
589
0
    best_cost = exhaustive_mesh_search(x, &ref_mv_fp, &search_mv, range, interval, sadpb, fn_ptr, search_mv);
590
591
    // Progressive refinement
592
0
    if (interval > MIN_INTERVAL && range > MIN_RANGE) {
593
0
        for (int i = 1; i < MAX_MESH_STEP; i++) {
594
0
            const MeshPattern* pattern = &ctrls->mesh_patterns[i];
595
596
0
            if (pattern->range == 0) {
597
0
                break;
598
0
            }
599
600
0
            best_cost = exhaustive_mesh_search(
601
0
                x, &ref_mv_fp, &search_mv, pattern->range, pattern->interval, sadpb, fn_ptr, search_mv);
602
603
0
            if (pattern->interval == 1) {
604
0
                break;
605
0
            }
606
0
        }
607
0
    }
608
609
    // Final cost evaluation
610
0
    if (best_cost < INT_MAX) {
611
0
        best_cost = svt_av1_get_mvpred_var(x, search_mv, ref_mv, fn_ptr, 1);
612
0
    }
613
614
0
    *dst_mv = search_mv;
615
616
0
    return best_cost;
617
0
}
618
#if CONFIG_ENABLE_OBMC
619
static int get_obmc_mvpred_var(const IntraBcContext* x, const int32_t* wsrc, const int32_t* mask, const Mv best_mv,
620
0
                               const Mv center_mv, const AomVarianceFnPtr* vfp, int use_mvcost, int is_second) {
621
0
    const Buf2D* in_what = (const Buf2D*)(&x->xdplane[0].pre[is_second]);
622
0
    const Mv     mv      = {{best_mv.x * 8, best_mv.y * 8}};
623
0
    unsigned int unused;
624
0
    if (x->approx_inter_rate) {
625
0
        return vfp->ovf(get_buf_from_mv((const Buf2D*)in_what, best_mv), in_what->stride, wsrc, mask, &unused) +
626
0
            (use_mvcost ? svt_aom_mv_err_cost_light(mv, center_mv) : 0);
627
0
    } else {
628
0
        return vfp->ovf(get_buf_from_mv((const Buf2D*)in_what, best_mv), in_what->stride, wsrc, mask, &unused) +
629
0
            (use_mvcost ? svt_aom_mv_err_cost(mv, center_mv, x->nmv_vec_cost, x->mv_cost_stack, x->errorperbit) : 0);
630
0
    }
631
0
}
632
633
static int obmc_refining_search_sad(const IntraBcContext* x, const int32_t* wsrc, const int32_t* mask, Mv* ref_mv,
634
                                    int error_per_bit, int search_range, const AomVarianceFnPtr* fn_ptr,
635
0
                                    const Mv center_mv, int is_second, uint8_t search_diag) {
636
0
    const Mv     neighbors[8] = {{{0, -1}}, {{-1, 0}}, {{1, 0}}, {{0, 1}}, {{1, -1}}, {{1, 1}}, {{-1, 1}}, {{-1, -1}}};
637
0
    const Buf2D* in_what      = (const Buf2D*)(&x->xdplane[0].pre[is_second]);
638
0
    const Mv     fcenter_mv   = {{center_mv.x >> 3, center_mv.y >> 3}};
639
0
    unsigned int best_sad = fn_ptr->osdf(get_buf_from_mv((const Buf2D*)in_what, *ref_mv), in_what->stride, wsrc, mask) +
640
0
        mvsad_err_cost(x, *ref_mv, fcenter_mv, error_per_bit);
641
0
    int i, j;
642
643
0
    for (i = 0; i < search_range; i++) {
644
0
        int best_site = -1;
645
646
0
        for (j = 0; j < (search_diag ? 8 : 4); j++) {
647
0
            const Mv mv = {{ref_mv->x + neighbors[j].x, ref_mv->y + neighbors[j].y}};
648
0
            if (is_mv_in(&x->mv_limits, mv)) {
649
0
                unsigned int sad = fn_ptr->osdf(
650
0
                    get_buf_from_mv((const Buf2D*)in_what, mv), in_what->stride, wsrc, mask);
651
0
                if (sad < best_sad) {
652
0
                    sad += mvsad_err_cost(x, mv, fcenter_mv, error_per_bit);
653
0
                    if (sad < best_sad) {
654
0
                        best_sad  = sad;
655
0
                        best_site = j;
656
0
                    }
657
0
                }
658
0
            }
659
0
        }
660
661
0
        if (best_site == -1) {
662
0
            break;
663
0
        } else {
664
0
            ref_mv->y += neighbors[best_site].y;
665
0
            ref_mv->x += neighbors[best_site].x;
666
0
        }
667
0
    }
668
0
    return best_sad;
669
0
}
670
671
int svt_av1_obmc_full_pixel_search(ModeDecisionContext* ctx, IntraBcContext* x, const Mv mvp_full, int sadpb,
672
0
                                   const AomVarianceFnPtr* fn_ptr, const Mv ref_mv, Mv* dst_mv, int is_second) {
673
    // obmc_full_pixel_diamond does not provide BDR gain on 360p
674
0
    const int32_t* wsrc         = ctx->wsrc_buf;
675
0
    const int32_t* mask         = ctx->mask_buf;
676
0
    const int      search_range = ctx->obmc_ctrls.fpel_search_range;
677
0
    *dst_mv                     = mvp_full;
678
0
    x->approx_inter_rate        = ctx->approx_inter_rate;
679
0
    clamp_mv(dst_mv, x->mv_limits.col_min, x->mv_limits.col_max, x->mv_limits.row_min, x->mv_limits.row_max);
680
0
    clamp_mv(dst_mv, x->mv_limits.col_min, x->mv_limits.col_max, x->mv_limits.row_min, x->mv_limits.row_max);
681
0
    int thissme = obmc_refining_search_sad(
682
0
        x, wsrc, mask, dst_mv, sadpb, search_range, fn_ptr, ref_mv, is_second, ctx->obmc_ctrls.fpel_search_diag);
683
0
    if (thissme < INT_MAX) {
684
0
        thissme = get_obmc_mvpred_var(x, wsrc, mask, *dst_mv, ref_mv, fn_ptr, 1, is_second);
685
0
    }
686
687
0
    return thissme;
688
0
}
689
#endif
690
691
#if CONFIG_ENABLE_OBMC
692
static INLINE void set_subpel_mv_search_range(const MvLimits* mv_limits, int* col_min, int* col_max, int* row_min,
693
0
                                              int* row_max, const Mv ref_mv) {
694
0
    const int max_mv = MAX_FULL_PEL_VAL * 8;
695
0
    const int minc   = AOMMAX(mv_limits->col_min * 8, ref_mv.x - max_mv);
696
0
    const int maxc   = AOMMIN(mv_limits->col_max * 8, ref_mv.x + max_mv);
697
0
    const int minr   = AOMMAX(mv_limits->row_min * 8, ref_mv.y - max_mv);
698
0
    const int maxr   = AOMMIN(mv_limits->row_max * 8, ref_mv.y + max_mv);
699
700
0
    *col_min = AOMMAX(MV_LOW + 1, minc);
701
0
    *col_max = AOMMIN(MV_UPP - 1, maxc);
702
0
    *row_min = AOMMAX(MV_LOW + 1, minr);
703
0
    *row_max = AOMMIN(MV_UPP - 1, maxr);
704
0
}
705
706
static const Mv search_step_table[12] = {
707
    // left, right, up, down
708
    {{-4, 0}},
709
    {{4, 0}},
710
    {{0, -4}},
711
    {{0, 4}},
712
    {{-2, 0}},
713
    {{2, 0}},
714
    {{0, -2}},
715
    {{0, 2}},
716
    {{-1, 0}},
717
    {{1, 0}},
718
    {{0, -1}},
719
    {{0, 1}}};
720
721
static unsigned int setup_obmc_center_error(const int32_t* mask, const Mv bestmv, const Mv ref_mv, int error_per_bit,
722
                                            const AomVarianceFnPtr* vfp, const int32_t* const wsrc,
723
                                            const uint8_t* const y, int y_stride, int offset, int* mvjcost,
724
                                            const int* mvcost[2], unsigned int* sse1,
725
0
                                            uint8_t use_low_precision_cost_estimation, int* distortion) {
726
0
    unsigned int besterr;
727
0
    besterr     = vfp->ovf(y + offset, y_stride, wsrc, mask, sse1);
728
0
    *distortion = besterr;
729
0
    if (use_low_precision_cost_estimation) {
730
0
        besterr += svt_aom_mv_err_cost_light(bestmv, ref_mv);
731
0
    } else {
732
0
        besterr += svt_aom_mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit);
733
0
    }
734
0
    return besterr;
735
0
}
736
737
/* returns subpixel variance error function */
738
0
#define DIST(r, c) vfp->osvf(pre(y, y_stride, r, c), y_stride, sp(c), sp(r), z, mask, &sse)
739
#define CHECK_BETTER(v, r, c, lp)                                                                    \
740
0
    do {                                                                                             \
741
0
        if (c >= minc && c <= maxc && r >= minr && r <= maxr) {                                      \
742
0
            thismse = (DIST(r, c));                                                                  \
743
0
                                                                                                     \
744
0
            if (lp)                                                                                  \
745
0
                v = svt_aom_mv_err_cost_light((const Mv){{c, r}}, ref_mv);                           \
746
0
            else                                                                                     \
747
0
                v = svt_aom_mv_err_cost((const Mv){{c, r}}, ref_mv, mvjcost, mvcost, error_per_bit); \
748
0
            if ((v + thismse) < besterr) {                                                           \
749
0
                besterr     = v + thismse;                                                           \
750
0
                br          = r;                                                                     \
751
0
                bc          = c;                                                                     \
752
0
                *distortion = thismse;                                                               \
753
0
                *sse1       = sse;                                                                   \
754
0
            }                                                                                        \
755
0
        } else                                                                                       \
756
0
            v = INT_MAX;                                                                             \
757
0
    } while (0)
758
0
#define CHECK_BETTER0(v, r, c, lp) CHECK_BETTER(v, r, c, lp)
759
#define CHECK_BETTER1(v, r, c, lp)                                                        \
760
0
    do {                                                                                  \
761
0
        if (c >= minc && c <= maxc && r >= minr && r <= maxr) {                           \
762
0
            Mv this_mv = {{c, r}};                                                        \
763
0
            thismse    = upsampled_obmc_pref_error(xd,                                    \
764
0
                                                cm,                                    \
765
0
                                                mi_row,                                \
766
0
                                                mi_col,                                \
767
0
                                                mask,                                  \
768
0
                                                vfp,                                   \
769
0
                                                z,                                     \
770
0
                                                pre(y, y_stride, r, c),                \
771
0
                                                y_stride,                              \
772
0
                                                sp(c),                                 \
773
0
                                                sp(r),                                 \
774
0
                                                w,                                     \
775
0
                                                h,                                     \
776
0
                                                &sse,                                  \
777
0
                                                use_accurate_subpel_search);           \
778
0
            if (lp)                                                                       \
779
0
                v = svt_aom_mv_err_cost_light(this_mv, ref_mv);                           \
780
0
            else                                                                          \
781
0
                v = svt_aom_mv_err_cost(this_mv, ref_mv, mvjcost, mvcost, error_per_bit); \
782
0
            if ((v + thismse) < besterr) {                                                \
783
0
                besterr     = v + thismse;                                                \
784
0
                br          = r;                                                          \
785
0
                bc          = c;                                                          \
786
0
                *distortion = thismse;                                                    \
787
0
                *sse1       = sse;                                                        \
788
0
            }                                                                             \
789
0
        } else                                                                            \
790
0
            v = INT_MAX;                                                                  \
791
0
    } while (0)
792
#define SECOND_LEVEL_CHECKS_BEST(k)                          \
793
0
    do {                                                     \
794
0
        unsigned int second;                                 \
795
0
        int          br0 = br;                               \
796
0
        int          bc0 = bc;                               \
797
0
        assert(tr == br || tc == bc);                        \
798
0
        if (tr == br && tc != bc)                            \
799
0
            kc = bc - tc;                                    \
800
0
        else if (tr != br && tc == bc)                       \
801
0
            kr = br - tr;                                    \
802
0
        CHECK_BETTER##k(second, br0 + kr, bc0, lp);          \
803
0
        CHECK_BETTER##k(second, br0, bc0 + kc, lp);          \
804
0
        if (br0 != br || bc0 != bc)                          \
805
0
            CHECK_BETTER##k(second, br0 + kr, bc0 + kc, lp); \
806
0
    } while (0)
807
808
static int upsampled_obmc_pref_error(MacroBlockD* xd, const Av1Common* const cm, int mi_row, int mi_col,
809
                                     const int32_t* mask, const AomVarianceFnPtr* vfp, const int32_t* const wsrc,
810
                                     const uint8_t* const y, int y_stride, int subpel_x_q3, int subpel_y_q3, int w,
811
0
                                     int h, unsigned int* sse, int subpel_search) {
812
0
    unsigned int besterr;
813
814
0
    DECLARE_ALIGNED(16, uint8_t, pred[2 * MAX_SB_SQUARE]);
815
0
    svt_aom_upsampled_pred(xd,
816
0
                           (const struct AV1Common* const)cm,
817
0
                           mi_row,
818
0
                           mi_col,
819
0
                           pred,
820
0
                           w,
821
0
                           h,
822
0
                           subpel_x_q3,
823
0
                           subpel_y_q3,
824
0
                           y,
825
0
                           y_stride,
826
0
                           subpel_search);
827
828
0
    besterr = vfp->ovf(pred, w, wsrc, mask, sse);
829
0
    return besterr;
830
0
}
831
832
static unsigned int upsampled_setup_obmc_center_error(MacroBlockD* xd, const Av1Common* const cm, int mi_row,
833
                                                      int mi_col, const int32_t* mask, const Mv bestmv, const Mv ref_mv,
834
                                                      int error_per_bit, const AomVarianceFnPtr* vfp,
835
                                                      const int32_t* const wsrc, const uint8_t* const y, int y_stride,
836
                                                      int w, int h, int offset, int* mvjcost, const int* mvcost[2],
837
                                                      unsigned int* sse1, int* distortion,
838
0
                                                      uint8_t use_low_precision_cost_estimation, int subpel_search) {
839
0
    unsigned int besterr = upsampled_obmc_pref_error(
840
0
        xd, cm, mi_row, mi_col, mask, vfp, wsrc, y + offset, y_stride, 0, 0, w, h, sse1, subpel_search);
841
0
    *distortion = besterr;
842
0
    if (use_low_precision_cost_estimation) {
843
0
        besterr += svt_aom_mv_err_cost_light(bestmv, ref_mv);
844
0
    } else {
845
0
        besterr += svt_aom_mv_err_cost(bestmv, ref_mv, mvjcost, mvcost, error_per_bit);
846
0
    }
847
0
    return besterr;
848
0
}
849
850
// convert motion vector component to offset for sv[a]f calc
851
0
static INLINE int sp(int x) {
852
0
    return x & 7;
853
0
}
854
855
0
static INLINE const uint8_t* pre(const uint8_t* buf, int stride, int r, int c) {
856
0
    const int offset = (r >> 3) * stride + (c >> 3);
857
0
    return buf + offset;
858
0
}
859
860
int svt_av1_find_best_obmc_sub_pixel_tree_up(ModeDecisionContext* ctx, IntraBcContext* x,
861
                                             const struct Av1Common* const cm, int mi_row, int mi_col, Mv* bestmv,
862
                                             const Mv ref_mv, int allow_hp, int error_per_bit,
863
                                             const AomVarianceFnPtr* vfp, int forced_stop, int iters_per_step,
864
                                             int* mvjcost, const int* mvcost[2], int* distortion, unsigned int* sse1,
865
0
                                             int is_second, int use_accurate_subpel_search) {
866
0
    const int32_t*                 wsrc        = ctx->wsrc_buf;
867
0
    const int32_t*                 mask        = ctx->mask_buf;
868
0
    const int* const               z           = wsrc;
869
0
    const int* const               src_address = z;
870
0
    MacroBlockD*                   xd          = x->xd;
871
0
    struct MacroBlockDPlane* const pd          = &x->xdplane[0];
872
0
    unsigned int                   besterr     = INT_MAX;
873
0
    unsigned int                   sse;
874
0
    unsigned int                   thismse;
875
0
    int                            br    = bestmv->y * 8;
876
0
    int                            bc    = bestmv->x * 8;
877
0
    int                            hstep = 4;
878
0
    int                            round = 3 - forced_stop;
879
0
    int                            tr;
880
0
    int                            tc;
881
0
    const Mv*                      search_step = search_step_table;
882
0
    int                            best_idx    = -1;
883
0
    unsigned int                   cost_array[5];
884
0
    const int                      w  = block_size_wide[ctx->blk_geom->bsize];
885
0
    const int                      h  = block_size_high[ctx->blk_geom->bsize];
886
0
    const uint8_t                  lp = ctx->approx_inter_rate;
887
0
    int                            minc, maxc, minr, maxr;
888
889
0
    set_subpel_mv_search_range(&x->mv_limits, &minc, &maxc, &minr, &maxr, ref_mv);
890
891
0
    const uint8_t* y        = pd->pre[is_second].buf;
892
0
    int            y_stride = pd->pre[is_second].stride;
893
0
    int            offset   = bestmv->y * y_stride + bestmv->x;
894
895
0
    if (!allow_hp && round == 3) {
896
0
        round = 2;
897
0
    }
898
899
0
    bestmv->y *= 8;
900
0
    bestmv->x *= 8;
901
    // use_accurate_subpel_search can be 0 or 1 or 2
902
0
    besterr = use_accurate_subpel_search
903
0
        ? upsampled_setup_obmc_center_error(xd,
904
0
                                            cm,
905
0
                                            mi_row,
906
0
                                            mi_col,
907
0
                                            mask,
908
0
                                            *bestmv,
909
0
                                            ref_mv,
910
0
                                            error_per_bit,
911
0
                                            vfp,
912
0
                                            z,
913
0
                                            y,
914
0
                                            y_stride,
915
0
                                            w,
916
0
                                            h,
917
0
                                            offset,
918
0
                                            mvjcost,
919
0
                                            mvcost,
920
0
                                            sse1,
921
0
                                            distortion,
922
0
                                            lp,
923
0
                                            use_accurate_subpel_search)
924
0
        : setup_obmc_center_error(
925
0
              mask, *bestmv, ref_mv, error_per_bit, vfp, z, y, y_stride, offset, mvjcost, mvcost, sse1, lp, distortion);
926
927
0
    for (int iter = 0; iter < round; ++iter) {
928
        // Check vertical and horizontal sub-pixel positions.
929
0
        int idx = 0;
930
0
        for (; idx < 4; ++idx) {
931
0
            tr = br + search_step[idx].y;
932
0
            tc = bc + search_step[idx].x;
933
0
            if (tc >= minc && tc <= maxc && tr >= minr && tr <= maxr) {
934
0
                Mv this_mv = {{tc, tr}};
935
0
                thismse    = use_accurate_subpel_search
936
0
                       ? (unsigned)upsampled_obmc_pref_error(xd,
937
0
                                                          cm,
938
0
                                                          mi_row,
939
0
                                                          mi_col,
940
0
                                                          mask,
941
0
                                                          vfp,
942
0
                                                          src_address,
943
0
                                                          pre(y, y_stride, tr, tc),
944
0
                                                          y_stride,
945
0
                                                          sp(tc),
946
0
                                                          sp(tr),
947
0
                                                          w,
948
0
                                                          h,
949
0
                                                          &sse,
950
0
                                                          use_accurate_subpel_search)
951
0
                       : vfp->osvf(pre(y, y_stride, tr, tc), y_stride, sp(tc), sp(tr), src_address, mask, &sse);
952
0
                if (lp) {
953
0
                    cost_array[idx] = thismse + svt_aom_mv_err_cost_light(this_mv, ref_mv);
954
0
                } else {
955
0
                    cost_array[idx] = thismse + svt_aom_mv_err_cost(this_mv, ref_mv, mvjcost, mvcost, error_per_bit);
956
0
                }
957
0
                if (cost_array[idx] < besterr) {
958
0
                    best_idx    = idx;
959
0
                    besterr     = cost_array[idx];
960
0
                    *distortion = thismse;
961
0
                    *sse1       = sse;
962
0
                }
963
0
            } else {
964
0
                cost_array[idx] = INT_MAX;
965
0
            }
966
0
        }
967
968
        // Check diagonal sub-pixel position
969
0
        int kc = (cost_array[0] <= cost_array[1] ? -hstep : hstep);
970
0
        int kr = (cost_array[2] <= cost_array[3] ? -hstep : hstep);
971
972
0
        tc = bc + kc;
973
0
        tr = br + kr;
974
0
        if (tc >= minc && tc <= maxc && tr >= minr && tr <= maxr) {
975
0
            Mv this_mv = {{tc, tr}};
976
0
            thismse    = use_accurate_subpel_search
977
0
                   ? (unsigned)upsampled_obmc_pref_error(xd,
978
0
                                                      cm,
979
0
                                                      mi_row,
980
0
                                                      mi_col,
981
0
                                                      mask,
982
0
                                                      vfp,
983
0
                                                      src_address,
984
0
                                                      pre(y, y_stride, tr, tc),
985
0
                                                      y_stride,
986
0
                                                      sp(tc),
987
0
                                                      sp(tr),
988
0
                                                      w,
989
0
                                                      h,
990
0
                                                      &sse,
991
0
                                                      use_accurate_subpel_search)
992
0
                   : vfp->osvf(pre(y, y_stride, tr, tc), y_stride, sp(tc), sp(tr), src_address, mask, &sse);
993
0
            if (lp) {
994
0
                cost_array[4] = thismse + svt_aom_mv_err_cost_light(this_mv, ref_mv);
995
0
            } else {
996
0
                cost_array[4] = thismse + svt_aom_mv_err_cost(this_mv, ref_mv, mvjcost, mvcost, error_per_bit);
997
0
            }
998
999
0
            if (cost_array[4] < besterr) {
1000
0
                best_idx    = 4;
1001
0
                besterr     = cost_array[4];
1002
0
                *distortion = thismse;
1003
0
                *sse1       = sse;
1004
0
            }
1005
0
        } else {
1006
0
            cost_array[idx] = INT_MAX;
1007
0
        }
1008
1009
0
        if (best_idx < 4 && best_idx >= 0) {
1010
0
            br += search_step[best_idx].y;
1011
0
            bc += search_step[best_idx].x;
1012
0
        } else if (best_idx == 4) {
1013
0
            br = tr;
1014
0
            bc = tc;
1015
0
        }
1016
1017
0
        if (iters_per_step > 1 && best_idx != -1) {
1018
0
            if (use_accurate_subpel_search) {
1019
0
                SECOND_LEVEL_CHECKS_BEST(1);
1020
0
            } else {
1021
0
                SECOND_LEVEL_CHECKS_BEST(0);
1022
0
            }
1023
0
        }
1024
1025
0
        search_step += 4;
1026
0
        hstep >>= 1;
1027
0
        best_idx = -1;
1028
0
    }
1029
1030
0
    bestmv->y = br;
1031
0
    bestmv->x = bc;
1032
1033
0
    return besterr;
1034
0
}
1035
#endif
1036
void svt_av1_intrabc_hash_search(PictureControlSet* pcs, IntraBcContext* x, BlockSize bsize, int x_pos, int y_pos,
1037
                                 const Mv ref_mv, int intra, const AomVarianceFnPtr* fn_ptr, int* best_hash_cost,
1038
0
                                 Mv* best_hash_mv) {
1039
0
    const int block_width  = block_size_wide[bsize];
1040
0
    const int block_height = block_size_high[bsize];
1041
1042
0
    if (block_width != block_height || block_width > pcs->ppcs->intrabc_ctrls.max_block_size_hash) {
1043
0
        return;
1044
0
    }
1045
1046
0
    uint8_t* src_buf    = x->plane[0].src.buf;
1047
0
    int      src_stride = x->plane[0].src.stride;
1048
1049
0
    uint32_t hash_value1, hash_value2;
1050
1051
0
    svt_av1_get_block_hash_value(src_buf, src_stride, block_width, &hash_value1, &hash_value2, 0, x);
1052
1053
0
    HashTable* ref_frame_hash = &pcs->hash_table;
1054
0
    int        count          = svt_av1_hash_table_count(ref_frame_hash, hash_value1);
1055
1056
0
    if (count <= (intra ? 1 : 0)) {
1057
0
        return;
1058
0
    }
1059
1060
0
    Iterator iterator = svt_av1_hash_get_first_iterator(ref_frame_hash, hash_value1);
1061
1062
0
    const int mi_col = x_pos / MI_SIZE;
1063
0
    const int mi_row = y_pos / MI_SIZE;
1064
1065
0
    for (int i = 0; i < count; i++, svt_aom_iterator_increment(&iterator)) {
1066
0
        BlockHash ref_block_hash = *(BlockHash*)(svt_aom_iterator_get(&iterator));
1067
1068
0
        if (hash_value2 != ref_block_hash.hash_value2) {
1069
0
            continue;
1070
0
        }
1071
1072
0
        if (intra) {
1073
0
            Mv dv = {{8 * (ref_block_hash.x - x_pos), 8 * (ref_block_hash.y - y_pos)}};
1074
1075
0
            if (!svt_aom_is_dv_valid(dv, x->xd, mi_row, mi_col, bsize, pcs->ppcs->scs->seq_header.sb_size_log2)) {
1076
0
                continue;
1077
0
            }
1078
0
        }
1079
1080
0
        Mv hash_mv = {{ref_block_hash.x - x_pos, ref_block_hash.y - y_pos}};
1081
1082
0
        if (!is_mv_in(&x->mv_limits, hash_mv)) {
1083
0
            continue;
1084
0
        }
1085
1086
0
        int ref_cost = svt_av1_get_mvpred_var(x, hash_mv, ref_mv, fn_ptr, 1);
1087
1088
0
        if (ref_cost < *best_hash_cost) {
1089
0
            *best_hash_cost = ref_cost;
1090
0
            *best_hash_mv   = hash_mv;
1091
0
        }
1092
0
    }
1093
0
}
1094
1095
int svt_av1_full_pixel_search(PictureControlSet* pcs, IntraBcContext* x, BlockSize bsize, Mv* mvp_full, int step_param,
1096
0
                              int error_per_bit, int* cost_list, const Mv ref_mv) {
1097
0
    const AomVarianceFnPtr* fn_ptr = &svt_aom_mefn_ptr[bsize];
1098
0
    int                     var    = 0;
1099
1100
    // Initialize cost list if requested
1101
0
    if (cost_list) {
1102
0
        for (int i = 0; i < 5; i++) {
1103
0
            cost_list[i] = INT_MAX;
1104
0
        }
1105
0
    }
1106
1107
    // Primary diamond search
1108
0
    var = full_pixel_diamond(
1109
0
        pcs, x, mvp_full, step_param, error_per_bit, MAX_MVSEARCH_STEPS - 1 - step_param, 1, cost_list, fn_ptr, ref_mv);
1110
1111
    // Decide whether to run exhaustive refinement
1112
0
    bool run_mesh_search = 0;
1113
1114
0
    int exhaustive_mesh_thresh = (int)pcs->ppcs->intrabc_ctrls.exhaustive_mesh_thresh;
1115
1116
    // Scale threshold by block size
1117
0
    exhaustive_mesh_thresh >>= 10 - (mi_size_wide_log2[bsize] + mi_size_high_log2[bsize]);
1118
1119
0
    if (var > exhaustive_mesh_thresh) {
1120
0
        run_mesh_search = 1;
1121
0
    }
1122
0
    const int32_t full_pel_mv_diff = MAX(abs(mvp_full->x - x->best_mv.x), abs(mvp_full->y - x->best_mv.y));
1123
0
    if (full_pel_mv_diff <= pcs->ppcs->intrabc_ctrls.mesh_search_mv_diff_threshold) {
1124
0
        run_mesh_search = 0;
1125
0
    }
1126
    // Exhaustive (Mesh) Search
1127
0
    if (run_mesh_search) {
1128
0
        int var_ex;
1129
0
        Mv  mv_ex;
1130
1131
0
        var_ex = intrabc_full_pixel_exhaustive(pcs, x, x->best_mv, error_per_bit, fn_ptr, ref_mv, &mv_ex);
1132
1133
0
        if (var_ex < var) {
1134
0
            x->best_mv = mv_ex;
1135
0
        }
1136
0
    }
1137
1138
0
    return 0;
1139
0
}