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/motion_estimation.c
Line
Count
Source
1
/*
2
* Copyright(c) 2019 Intel Corporation
3
* Copyright(c) 2019 Netflix, Inc.
4
*
5
* This source code is subject to the terms of the BSD 2 Clause License and
6
* the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
7
* was not distributed with this source code in the LICENSE file, you can
8
* obtain it at https://www.aomedia.org/license/software-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
#include <stdio.h>
14
#include <inttypes.h>
15
16
#include "aom_dsp_rtcd.h"
17
#include "pcs.h"
18
#include "sequence_control_set.h"
19
#include "motion_estimation.h"
20
#include "utility.h"
21
22
#include "compute_sad.h"
23
#include "reference_object.h"
24
25
#include "enc_intra_prediction.h"
26
#include "lambda_rate_tables.h"
27
#include "transforms.h"
28
29
#include "svt_log.h"
30
#include "resize.h"
31
#include "enc_mode_config.h"
32
33
/********************************************
34
 * Constants
35
 ********************************************/
36
0
#define REFERENCE_PIC_LIST_0 0
37
0
#define REFERENCE_PIC_LIST_1 1
38
39
/*******************************************
40
 * Compute8x4SAD_Default
41
 *   Unoptimized 8x4 SAD
42
 *******************************************/
43
uint32_t svt_aom_compute8x4_sad_kernel_c(uint8_t* src, // input parameter, source samples Ptr
44
                                         uint32_t src_stride, // input parameter, source stride
45
                                         uint8_t* ref, // input parameter, reference samples Ptr
46
                                         uint32_t ref_stride) // input parameter, reference stride
47
0
{
48
0
    uint32_t row_number_in_blocks_8x4;
49
0
    uint32_t sad_block_8x4 = 0;
50
51
0
    for (row_number_in_blocks_8x4 = 0; row_number_in_blocks_8x4 < 4; ++row_number_in_blocks_8x4) {
52
0
        sad_block_8x4 += EB_ABS_DIFF(src[0x00], ref[0x00]);
53
0
        sad_block_8x4 += EB_ABS_DIFF(src[0x01], ref[0x01]);
54
0
        sad_block_8x4 += EB_ABS_DIFF(src[0x02], ref[0x02]);
55
0
        sad_block_8x4 += EB_ABS_DIFF(src[0x03], ref[0x03]);
56
0
        sad_block_8x4 += EB_ABS_DIFF(src[0x04], ref[0x04]);
57
0
        sad_block_8x4 += EB_ABS_DIFF(src[0x05], ref[0x05]);
58
0
        sad_block_8x4 += EB_ABS_DIFF(src[0x06], ref[0x06]);
59
0
        sad_block_8x4 += EB_ABS_DIFF(src[0x07], ref[0x07]);
60
0
        src += src_stride;
61
0
        ref += ref_stride;
62
0
    }
63
64
0
    return sad_block_8x4;
65
0
}
66
67
/*******************************************
68
 * Compute8x8SAD_Default
69
 *   Unoptimized 8x8 SAD
70
 *******************************************/
71
static uint32_t compute8x8_sad_kernel_c(uint8_t* src, // input parameter, source samples Ptr
72
                                        uint32_t src_stride, // input parameter, source stride
73
                                        uint8_t* ref, // input parameter, reference samples Ptr
74
                                        uint32_t ref_stride) // input parameter, reference stride
75
0
{
76
0
    uint32_t row_number_in_blocks_8x8;
77
0
    uint32_t sad_block_8x8 = 0;
78
79
0
    for (row_number_in_blocks_8x8 = 0; row_number_in_blocks_8x8 < 8; ++row_number_in_blocks_8x8) {
80
0
        sad_block_8x8 += EB_ABS_DIFF(src[0x00], ref[0x00]);
81
0
        sad_block_8x8 += EB_ABS_DIFF(src[0x01], ref[0x01]);
82
0
        sad_block_8x8 += EB_ABS_DIFF(src[0x02], ref[0x02]);
83
0
        sad_block_8x8 += EB_ABS_DIFF(src[0x03], ref[0x03]);
84
0
        sad_block_8x8 += EB_ABS_DIFF(src[0x04], ref[0x04]);
85
0
        sad_block_8x8 += EB_ABS_DIFF(src[0x05], ref[0x05]);
86
0
        sad_block_8x8 += EB_ABS_DIFF(src[0x06], ref[0x06]);
87
0
        sad_block_8x8 += EB_ABS_DIFF(src[0x07], ref[0x07]);
88
0
        src += src_stride;
89
0
        ref += ref_stride;
90
0
    }
91
92
0
    return sad_block_8x8;
93
0
}
94
95
/*******************************************
96
Calculate SAD for 16x16 and its 8x8 sublcoks
97
and check if there is improvment, if yes keep
98
the best SAD+MV
99
*******************************************/
100
void svt_ext_sad_calculation_8x8_16x16_c(uint8_t* src, uint32_t src_stride, uint8_t* ref, uint32_t ref_stride,
101
                                         uint32_t* p_best_sad_8x8, uint32_t* p_best_sad_16x16, uint32_t* p_best_mv8x8,
102
                                         uint32_t* p_best_mv16x16, uint32_t mv, uint32_t* p_sad16x16,
103
0
                                         uint32_t* p_sad8x8, bool sub_sad) {
104
0
    uint32_t sad16x16;
105
106
0
    if (sub_sad) {
107
0
        p_sad8x8[0] = (svt_aom_compute8x4_sad_kernel_c(
108
0
                          src + 0 * src_stride + 0, 2 * src_stride, ref + 0 * ref_stride + 0, 2 * ref_stride))
109
0
            << 1;
110
0
        p_sad8x8[1] = (svt_aom_compute8x4_sad_kernel_c(
111
0
                          src + 0 * src_stride + 8, 2 * src_stride, ref + 0 * ref_stride + 8, 2 * ref_stride))
112
0
            << 1;
113
0
        p_sad8x8[2] = (svt_aom_compute8x4_sad_kernel_c(
114
0
                          src + 8 * src_stride + 0, 2 * src_stride, ref + 8 * ref_stride + 0, 2 * ref_stride))
115
0
            << 1;
116
0
        p_sad8x8[3] = (svt_aom_compute8x4_sad_kernel_c(
117
0
                          src + 8 * src_stride + 8, 2 * src_stride, ref + 8 * ref_stride + 8, 2 * ref_stride))
118
0
            << 1;
119
0
    } else {
120
0
        p_sad8x8[0] = compute8x8_sad_kernel_c(
121
0
            src + 0 * src_stride + 0, src_stride, ref + 0 * ref_stride + 0, ref_stride);
122
0
        p_sad8x8[1] = compute8x8_sad_kernel_c(
123
0
            src + 0 * src_stride + 8, src_stride, ref + 0 * ref_stride + 8, ref_stride);
124
0
        p_sad8x8[2] = compute8x8_sad_kernel_c(
125
0
            src + 8 * src_stride + 0, src_stride, ref + 8 * ref_stride + 0, ref_stride);
126
0
        p_sad8x8[3] = compute8x8_sad_kernel_c(
127
0
            src + 8 * src_stride + 8, src_stride, ref + 8 * ref_stride + 8, ref_stride);
128
0
    }
129
130
0
    if (p_sad8x8[0] < p_best_sad_8x8[0]) {
131
0
        p_best_sad_8x8[0] = (uint32_t)p_sad8x8[0];
132
0
        p_best_mv8x8[0]   = mv;
133
0
    }
134
135
0
    if (p_sad8x8[1] < p_best_sad_8x8[1]) {
136
0
        p_best_sad_8x8[1] = (uint32_t)p_sad8x8[1];
137
0
        p_best_mv8x8[1]   = mv;
138
0
    }
139
140
0
    if (p_sad8x8[2] < p_best_sad_8x8[2]) {
141
0
        p_best_sad_8x8[2] = (uint32_t)p_sad8x8[2];
142
0
        p_best_mv8x8[2]   = mv;
143
0
    }
144
145
0
    if (p_sad8x8[3] < p_best_sad_8x8[3]) {
146
0
        p_best_sad_8x8[3] = (uint32_t)p_sad8x8[3];
147
0
        p_best_mv8x8[3]   = mv;
148
0
    }
149
150
0
    sad16x16 = p_sad8x8[0] + p_sad8x8[1] + p_sad8x8[2] + p_sad8x8[3];
151
0
    if (sad16x16 < p_best_sad_16x16[0]) {
152
0
        p_best_sad_16x16[0] = (uint32_t)sad16x16;
153
0
        p_best_mv16x16[0]   = mv;
154
0
    }
155
156
0
    *p_sad16x16 = (uint32_t)sad16x16;
157
0
}
158
159
/*******************************************
160
Calculate SAD for 32x32,64x64 from 16x16
161
and check if there is improvment, if yes keep
162
the best SAD+MV
163
*******************************************/
164
void svt_ext_sad_calculation_32x32_64x64_c(uint32_t* p_sad16x16, uint32_t* p_best_sad_32x32, uint32_t* p_best_sad_64x64,
165
                                           uint32_t* p_best_mv32x32, uint32_t* p_best_mv64x64, uint32_t mv,
166
0
                                           uint32_t* p_sad32x32) {
167
0
    uint32_t sad32x32_0, sad32x32_1, sad32x32_2, sad32x32_3, sad64x64;
168
169
0
    p_sad32x32[0] = sad32x32_0 = p_sad16x16[0] + p_sad16x16[1] + p_sad16x16[2] + p_sad16x16[3];
170
0
    if (sad32x32_0 < p_best_sad_32x32[0]) {
171
0
        p_best_sad_32x32[0] = sad32x32_0;
172
0
        p_best_mv32x32[0]   = mv;
173
0
    }
174
175
0
    p_sad32x32[1] = sad32x32_1 = p_sad16x16[4] + p_sad16x16[5] + p_sad16x16[6] + p_sad16x16[7];
176
0
    if (sad32x32_1 < p_best_sad_32x32[1]) {
177
0
        p_best_sad_32x32[1] = sad32x32_1;
178
0
        p_best_mv32x32[1]   = mv;
179
0
    }
180
181
0
    p_sad32x32[2] = sad32x32_2 = p_sad16x16[8] + p_sad16x16[9] + p_sad16x16[10] + p_sad16x16[11];
182
0
    if (sad32x32_2 < p_best_sad_32x32[2]) {
183
0
        p_best_sad_32x32[2] = sad32x32_2;
184
0
        p_best_mv32x32[2]   = mv;
185
0
    }
186
187
0
    p_sad32x32[3] = sad32x32_3 = p_sad16x16[12] + p_sad16x16[13] + p_sad16x16[14] + p_sad16x16[15];
188
0
    if (sad32x32_3 < p_best_sad_32x32[3]) {
189
0
        p_best_sad_32x32[3] = sad32x32_3;
190
0
        p_best_mv32x32[3]   = mv;
191
0
    }
192
0
    sad64x64 = sad32x32_0 + sad32x32_1 + sad32x32_2 + sad32x32_3;
193
0
    if (sad64x64 < p_best_sad_64x64[0]) {
194
0
        p_best_sad_64x64[0] = sad64x64;
195
0
        p_best_mv64x64[0]   = mv;
196
0
    }
197
0
}
198
199
/*******************************************
200
 * svt_ext_eight_sad_calculation_8x8_16x16
201
 *******************************************/
202
static void svt_ext_eight_sad_calculation_8x8_16x16(uint8_t* src, uint32_t src_stride, uint8_t* ref,
203
                                                    uint32_t ref_stride, uint32_t mv, uint32_t start_16x16_pos,
204
                                                    uint32_t* p_best_sad_8x8, uint32_t* p_best_sad_16x16,
205
                                                    uint32_t* p_best_mv8x8, uint32_t* p_best_mv16x16,
206
                                                    uint32_t p_eight_sad16x16[16][8], uint32_t p_eight_sad8x8[64][8],
207
0
                                                    bool sub_sad) {
208
0
    const uint32_t start_8x8_pos = 4 * start_16x16_pos;
209
0
    int16_t        x_mv, y_mv;
210
211
0
    (void)p_eight_sad8x8;
212
213
0
    p_best_sad_8x8 += start_8x8_pos;
214
0
    p_best_mv8x8 += start_8x8_pos;
215
0
    p_best_sad_16x16 += start_16x16_pos;
216
0
    p_best_mv16x16 += start_16x16_pos;
217
0
    if (sub_sad) {
218
0
        uint32_t src_stride_sub = (src_stride << 1);
219
0
        uint32_t ref_stride_sub = (ref_stride << 1);
220
0
        for (int search_index = 0; search_index < 8; search_index++) {
221
0
            uint32_t sad8x8_0 =
222
0
                (svt_aom_compute8x4_sad_kernel_c(src, src_stride_sub, ref + search_index, ref_stride_sub)) << 1;
223
0
            if (sad8x8_0 < p_best_sad_8x8[0]) {
224
0
                p_best_sad_8x8[0] = (uint32_t)sad8x8_0;
225
0
                x_mv              = _MVXT(mv) + (int16_t)search_index;
226
0
                y_mv              = _MVYT(mv);
227
0
                p_best_mv8x8[0]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
228
0
            }
229
230
0
            uint32_t sad8x8_1 =
231
0
                (svt_aom_compute8x4_sad_kernel_c(src + 8, src_stride_sub, ref + 8 + search_index, ref_stride_sub)) << 1;
232
0
            if (sad8x8_1 < p_best_sad_8x8[1]) {
233
0
                p_best_sad_8x8[1] = (uint32_t)sad8x8_1;
234
0
                x_mv              = _MVXT(mv) + (int16_t)search_index;
235
0
                y_mv              = _MVYT(mv);
236
0
                p_best_mv8x8[1]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
237
0
            }
238
239
0
            uint32_t sad8x8_2 = (svt_aom_compute8x4_sad_kernel_c(src + (src_stride << 3),
240
0
                                                                 src_stride_sub,
241
0
                                                                 ref + (ref_stride << 3) + search_index,
242
0
                                                                 ref_stride_sub))
243
0
                << 1;
244
0
            if (sad8x8_2 < p_best_sad_8x8[2]) {
245
0
                p_best_sad_8x8[2] = (uint32_t)sad8x8_2;
246
0
                x_mv              = _MVXT(mv) + (int16_t)search_index;
247
0
                y_mv              = _MVYT(mv);
248
0
                p_best_mv8x8[2]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
249
0
            }
250
251
0
            uint32_t sad8x8_3 = (svt_aom_compute8x4_sad_kernel_c(src + (src_stride << 3) + 8,
252
0
                                                                 src_stride_sub,
253
0
                                                                 ref + (ref_stride << 3) + 8 + search_index,
254
0
                                                                 ref_stride_sub))
255
0
                << 1;
256
0
            if (sad8x8_3 < p_best_sad_8x8[3]) {
257
0
                p_best_sad_8x8[3] = (uint32_t)sad8x8_3;
258
0
                x_mv              = _MVXT(mv) + (int16_t)search_index;
259
0
                y_mv              = _MVYT(mv);
260
0
                p_best_mv8x8[3]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
261
0
            }
262
0
            uint32_t sad16x16 = p_eight_sad16x16[start_16x16_pos][search_index] = sad8x8_0 + sad8x8_1 + sad8x8_2 +
263
0
                sad8x8_3;
264
0
            if (sad16x16 < p_best_sad_16x16[0]) {
265
0
                p_best_sad_16x16[0] = (uint32_t)sad16x16;
266
0
                x_mv                = _MVXT(mv) + (int16_t)search_index;
267
0
                y_mv                = _MVYT(mv);
268
0
                p_best_mv16x16[0]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
269
0
            }
270
0
        }
271
0
    } else {
272
0
        for (int search_index = 0; search_index < 8; search_index++) {
273
0
            uint32_t sad8x8_0 = compute8x8_sad_kernel_c(src, src_stride, ref + search_index, ref_stride);
274
0
            if (sad8x8_0 < p_best_sad_8x8[0]) {
275
0
                p_best_sad_8x8[0] = (uint32_t)sad8x8_0;
276
0
                x_mv              = _MVXT(mv) + (int16_t)search_index;
277
0
                y_mv              = _MVYT(mv);
278
0
                p_best_mv8x8[0]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
279
0
            }
280
281
0
            uint32_t sad8x8_1 = (compute8x8_sad_kernel_c(src + 8, src_stride, ref + 8 + search_index, ref_stride));
282
0
            if (sad8x8_1 < p_best_sad_8x8[1]) {
283
0
                p_best_sad_8x8[1] = (uint32_t)sad8x8_1;
284
0
                x_mv              = _MVXT(mv) + (int16_t)search_index;
285
0
                y_mv              = _MVYT(mv);
286
0
                p_best_mv8x8[1]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
287
0
            }
288
289
0
            uint32_t sad8x8_2 = (compute8x8_sad_kernel_c(
290
0
                src + (src_stride << 3), src_stride, ref + (ref_stride << 3) + search_index, ref_stride));
291
0
            if (sad8x8_2 < p_best_sad_8x8[2]) {
292
0
                p_best_sad_8x8[2] = (uint32_t)sad8x8_2;
293
0
                x_mv              = _MVXT(mv) + (int16_t)search_index;
294
0
                y_mv              = _MVYT(mv);
295
0
                p_best_mv8x8[2]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
296
0
            }
297
298
0
            uint32_t sad8x8_3 = (compute8x8_sad_kernel_c(
299
0
                src + (src_stride << 3) + 8, src_stride, ref + (ref_stride << 3) + 8 + search_index, ref_stride));
300
0
            if (sad8x8_3 < p_best_sad_8x8[3]) {
301
0
                p_best_sad_8x8[3] = (uint32_t)sad8x8_3;
302
0
                x_mv              = _MVXT(mv) + (int16_t)search_index;
303
0
                y_mv              = _MVYT(mv);
304
0
                p_best_mv8x8[3]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
305
0
            }
306
0
            uint32_t sad16x16 = p_eight_sad16x16[start_16x16_pos][search_index] = sad8x8_0 + sad8x8_1 + sad8x8_2 +
307
0
                sad8x8_3;
308
0
            if (sad16x16 < p_best_sad_16x16[0]) {
309
0
                p_best_sad_16x16[0] = (uint32_t)sad16x16;
310
0
                x_mv                = _MVXT(mv) + (int16_t)search_index;
311
0
                y_mv                = _MVYT(mv);
312
0
                p_best_mv16x16[0]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
313
0
            }
314
0
        }
315
0
    }
316
0
}
317
318
void svt_ext_all_sad_calculation_8x8_16x16_c(uint8_t* src, uint32_t src_stride, uint8_t* ref, uint32_t ref_stride,
319
                                             uint32_t mv, uint32_t* p_best_sad_8x8, uint32_t* p_best_sad_16x16,
320
                                             uint32_t* p_best_mv8x8, uint32_t* p_best_mv16x16,
321
                                             uint32_t p_eight_sad16x16[16][8], uint32_t p_eight_sad8x8[64][8],
322
0
                                             bool sub_sad) {
323
0
    static const char offsets[16] = {0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15};
324
    //---- 16x16 : 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15
325
0
    for (int y = 0; y < 4; y++) {
326
0
        for (int x = 0; x < 4; x++) {
327
0
            const uint32_t block_index           = 16 * y * src_stride + 16 * x;
328
0
            const uint32_t search_position_index = 16 * y * ref_stride + 16 * x;
329
0
            svt_ext_eight_sad_calculation_8x8_16x16(src + block_index,
330
0
                                                    src_stride,
331
0
                                                    ref + search_position_index,
332
0
                                                    ref_stride,
333
0
                                                    mv,
334
0
                                                    offsets[4 * y + x],
335
0
                                                    p_best_sad_8x8,
336
0
                                                    p_best_sad_16x16,
337
0
                                                    p_best_mv8x8,
338
0
                                                    p_best_mv16x16,
339
0
                                                    p_eight_sad16x16,
340
0
                                                    p_eight_sad8x8,
341
0
                                                    sub_sad);
342
0
        }
343
0
    }
344
0
}
345
346
/*******************************************
347
Calculate SAD for 32x32,64x64 from 16x16
348
and check if there is improvment, if yes keep
349
the best SAD+MV
350
*******************************************/
351
void svt_ext_eight_sad_calculation_32x32_64x64_c(const uint32_t p_sad16x16[16][8], uint32_t* p_best_sad_32x32,
352
                                                 uint32_t* p_best_sad_64x64, uint32_t* p_best_mv32x32,
353
0
                                                 uint32_t* p_best_mv64x64, uint32_t mv, uint32_t p_sad32x32[4][8]) {
354
0
    uint32_t search_index;
355
0
    int16_t  x_mv, y_mv;
356
0
    for (search_index = 0; search_index < 8; search_index++) {
357
0
        uint32_t sad32x32_0, sad32x32_1, sad32x32_2, sad32x32_3, sad64x64;
358
359
0
        p_sad32x32[0][search_index] = sad32x32_0 = p_sad16x16[0][search_index] + p_sad16x16[1][search_index] +
360
0
            p_sad16x16[2][search_index] + p_sad16x16[3][search_index];
361
0
        if (sad32x32_0 < p_best_sad_32x32[0]) {
362
0
            p_best_sad_32x32[0] = sad32x32_0;
363
0
            x_mv                = _MVXT(mv) + (int16_t)search_index;
364
0
            y_mv                = _MVYT(mv);
365
0
            p_best_mv32x32[0]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
366
0
        }
367
368
0
        p_sad32x32[1][search_index] = sad32x32_1 = p_sad16x16[4][search_index] + p_sad16x16[5][search_index] +
369
0
            p_sad16x16[6][search_index] + p_sad16x16[7][search_index];
370
0
        if (sad32x32_1 < p_best_sad_32x32[1]) {
371
0
            p_best_sad_32x32[1] = sad32x32_1;
372
0
            x_mv                = _MVXT(mv) + (int16_t)search_index;
373
0
            y_mv                = _MVYT(mv);
374
0
            p_best_mv32x32[1]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
375
0
        }
376
377
0
        p_sad32x32[2][search_index] = sad32x32_2 = p_sad16x16[8][search_index] + p_sad16x16[9][search_index] +
378
0
            p_sad16x16[10][search_index] + p_sad16x16[11][search_index];
379
0
        if (sad32x32_2 < p_best_sad_32x32[2]) {
380
0
            p_best_sad_32x32[2] = sad32x32_2;
381
0
            x_mv                = _MVXT(mv) + (int16_t)search_index;
382
0
            y_mv                = _MVYT(mv);
383
0
            p_best_mv32x32[2]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
384
0
        }
385
386
0
        p_sad32x32[3][search_index] = sad32x32_3 = p_sad16x16[12][search_index] + p_sad16x16[13][search_index] +
387
0
            p_sad16x16[14][search_index] + p_sad16x16[15][search_index];
388
0
        if (sad32x32_3 < p_best_sad_32x32[3]) {
389
0
            p_best_sad_32x32[3] = sad32x32_3;
390
0
            x_mv                = _MVXT(mv) + (int16_t)search_index;
391
0
            y_mv                = _MVYT(mv);
392
0
            p_best_mv32x32[3]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
393
0
        }
394
395
0
        sad64x64 = sad32x32_0 + sad32x32_1 + sad32x32_2 + sad32x32_3;
396
0
        if (sad64x64 < p_best_sad_64x64[0]) {
397
0
            p_best_sad_64x64[0] = sad64x64;
398
0
            x_mv                = _MVXT(mv) + (int16_t)search_index;
399
0
            y_mv                = _MVYT(mv);
400
0
            p_best_mv64x64[0]   = ((uint32_t)y_mv << 16) | ((uint16_t)x_mv);
401
0
        }
402
0
    }
403
0
}
404
405
/*******************************************
406
 * open_loop_me_get_search_point_results_block
407
 *******************************************/
408
static void open_loop_me_get_eight_search_point_results_block(
409
    MeContext* me_ctx, // input parameter, ME context Ptr, used to get SB Ptr
410
    uint32_t   list_index, // input parameter, reference list index
411
    uint32_t   ref_pic_index,
412
    int32_t    search_region_index, // input parameter, search area origin, used to
413
    // point to reference samples
414
    int32_t x_search_index, // input parameter, search region position in the
415
    // horizontal direction, used to derive xMV
416
    int32_t y_search_index // input parameter, search region position in the
417
    // vertical direction, used to derive yMV
418
0
) {
419
    // uint32_t ref_luma_stride = ref_pic_ptr->y_stride; // NADER
420
    // uint8_t  *ref_ptr = ref_pic_ptr->y_buffer; // NADER
421
0
    const bool sub_sad         = (me_ctx->me_search_method == SUB_SAD_SEARCH);
422
0
    uint32_t   ref_luma_stride = me_ctx->interpolated_full_stride[list_index][ref_pic_index];
423
0
    uint8_t*   ref_ptr         = me_ctx->integer_buffer_ptr[list_index][ref_pic_index] +
424
0
        ((ME_FILTER_TAP >> 1) * me_ctx->interpolated_full_stride[list_index][ref_pic_index]) + (ME_FILTER_TAP >> 1) +
425
0
        search_region_index;
426
427
0
    uint32_t curr_mv_1 = (((uint32_t)y_search_index) << 16);
428
0
    uint16_t curr_mv_2 = ((uint16_t)x_search_index);
429
0
    uint32_t curr_mv   = curr_mv_1 | curr_mv_2;
430
431
0
    svt_ext_all_sad_calculation_8x8_16x16(me_ctx->b64_src_ptr,
432
0
                                          me_ctx->b64_src_stride,
433
0
                                          ref_ptr,
434
0
                                          ref_luma_stride,
435
0
                                          curr_mv,
436
0
                                          me_ctx->p_best_sad_8x8,
437
0
                                          me_ctx->p_best_sad_16x16,
438
0
                                          me_ctx->p_best_mv8x8,
439
0
                                          me_ctx->p_best_mv16x16,
440
0
                                          me_ctx->p_eight_sad16x16,
441
0
                                          me_ctx->p_eight_sad8x8,
442
0
                                          sub_sad);
443
444
0
    svt_ext_eight_sad_calculation_32x32_64x64(me_ctx->p_eight_sad16x16,
445
0
                                              me_ctx->p_best_sad_32x32,
446
0
                                              me_ctx->p_best_sad_64x64,
447
0
                                              me_ctx->p_best_mv32x32,
448
0
                                              me_ctx->p_best_mv64x64,
449
0
                                              curr_mv,
450
0
                                              me_ctx->p_eight_sad32x32);
451
0
}
452
453
/*******************************************
454
 * open_loop_me_get_search_point_results_block
455
 *******************************************/
456
static void open_loop_me_get_search_point_results_block(
457
    MeContext* me_ctx, // input parameter, ME context Ptr, used to get SB Ptr
458
    uint32_t   list_index, // input parameter, reference list index
459
    uint32_t   ref_pic_index,
460
    int32_t    search_region_index, // input parameter, search area origin, used to
461
    // point to reference samples
462
    int32_t x_search_index, // input parameter, search region position in the
463
    // horizontal direction, used to derive xMV
464
    int32_t y_search_index) // input parameter, search region position in the
465
// vertical direction, used to derive yMV
466
0
{
467
0
    const bool sub_sad = (me_ctx->me_search_method == SUB_SAD_SEARCH);
468
0
    uint8_t*   src_ptr = me_ctx->b64_src_ptr;
469
470
    // uint8_t  *ref_ptr = ref_pic_ptr->y_buffer; // NADER
471
0
    uint8_t* ref_ptr = me_ctx->integer_buffer_ptr[list_index][ref_pic_index] + (ME_FILTER_TAP >> 1) +
472
0
        ((ME_FILTER_TAP >> 1) * me_ctx->interpolated_full_stride[list_index][ref_pic_index]);
473
    // uint32_t ref_luma_stride = ref_pic_ptr->y_stride; // NADER
474
0
    uint32_t ref_luma_stride          = me_ctx->interpolated_full_stride[list_index][ref_pic_index];
475
0
    int32_t  search_position_tl_index = search_region_index;
476
0
    int32_t  search_position_index;
477
0
    int32_t  block_index;
478
0
    int32_t  src_next_16x16_offset;
479
    // uint32_t ref_next_16x16_offset = (ref_pic_ptr->y_stride << 4); // NADER
480
0
    uint32_t  ref_next_16x16_offset = (ref_luma_stride << 4);
481
0
    uint32_t  curr_mv_1             = (((uint32_t)y_search_index) << 16);
482
0
    uint16_t  curr_mv_2             = ((uint16_t)x_search_index);
483
0
    uint32_t  curr_mv               = curr_mv_1 | curr_mv_2;
484
0
    uint32_t* p_best_sad_8x8        = me_ctx->p_best_sad_8x8;
485
0
    uint32_t* p_best_sad_16x16      = me_ctx->p_best_sad_16x16;
486
0
    uint32_t* p_best_sad_32x32      = me_ctx->p_best_sad_32x32;
487
0
    uint32_t* p_best_sad_64x64      = me_ctx->p_best_sad_64x64;
488
0
    uint32_t* p_best_mv8x8          = me_ctx->p_best_mv8x8;
489
0
    uint32_t* p_best_mv16x16        = me_ctx->p_best_mv16x16;
490
0
    uint32_t* p_best_mv32x32        = me_ctx->p_best_mv32x32;
491
0
    uint32_t* p_best_mv64x64        = me_ctx->p_best_mv64x64;
492
0
    uint32_t* p_sad32x32            = me_ctx->p_sad32x32;
493
0
    uint32_t* p_sad16x16            = me_ctx->p_sad16x16;
494
0
    uint32_t* p_sad8x8              = me_ctx->p_sad8x8;
495
496
    // TODO: block_index search_position_index could be removed
497
0
    const uint32_t src_stride = me_ctx->b64_src_stride;
498
0
    src_next_16x16_offset     = src_stride << 4;
499
500
    //---- 16x16 : 0
501
0
    block_index           = 0;
502
0
    search_position_index = search_position_tl_index;
503
504
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
505
0
                                      src_stride,
506
0
                                      ref_ptr + search_position_index,
507
0
                                      ref_luma_stride,
508
0
                                      &p_best_sad_8x8[0],
509
0
                                      &p_best_sad_16x16[0],
510
0
                                      &p_best_mv8x8[0],
511
0
                                      &p_best_mv16x16[0],
512
0
                                      curr_mv,
513
0
                                      &p_sad16x16[0],
514
0
                                      &p_sad8x8[0],
515
0
                                      sub_sad);
516
517
    //---- 16x16 : 1
518
0
    block_index           = block_index + 16;
519
0
    search_position_index = search_position_tl_index + 16;
520
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
521
0
                                      src_stride,
522
0
                                      ref_ptr + search_position_index,
523
0
                                      ref_luma_stride,
524
0
                                      &p_best_sad_8x8[4],
525
0
                                      &p_best_sad_16x16[1],
526
0
                                      &p_best_mv8x8[4],
527
0
                                      &p_best_mv16x16[1],
528
0
                                      curr_mv,
529
0
                                      &p_sad16x16[1],
530
0
                                      &p_sad8x8[4],
531
0
                                      sub_sad);
532
    //---- 16x16 : 4
533
0
    block_index           = block_index + 16;
534
0
    search_position_index = search_position_index + 16;
535
536
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
537
0
                                      src_stride,
538
0
                                      ref_ptr + search_position_index,
539
0
                                      ref_luma_stride,
540
0
                                      &p_best_sad_8x8[16],
541
0
                                      &p_best_sad_16x16[4],
542
0
                                      &p_best_mv8x8[16],
543
0
                                      &p_best_mv16x16[4],
544
0
                                      curr_mv,
545
0
                                      &p_sad16x16[4],
546
0
                                      &p_sad8x8[16],
547
0
                                      sub_sad);
548
549
    //---- 16x16 : 5
550
0
    block_index           = block_index + 16;
551
0
    search_position_index = search_position_index + 16;
552
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
553
0
                                      src_stride,
554
0
                                      ref_ptr + search_position_index,
555
0
                                      ref_luma_stride,
556
0
                                      &p_best_sad_8x8[20],
557
0
                                      &p_best_sad_16x16[5],
558
0
                                      &p_best_mv8x8[20],
559
0
                                      &p_best_mv16x16[5],
560
0
                                      curr_mv,
561
0
                                      &p_sad16x16[5],
562
0
                                      &p_sad8x8[20],
563
0
                                      sub_sad);
564
565
    //---- 16x16 : 2
566
0
    block_index           = src_next_16x16_offset;
567
0
    search_position_index = search_position_tl_index + ref_next_16x16_offset;
568
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
569
0
                                      src_stride,
570
0
                                      ref_ptr + search_position_index,
571
0
                                      ref_luma_stride,
572
0
                                      &p_best_sad_8x8[8],
573
0
                                      &p_best_sad_16x16[2],
574
0
                                      &p_best_mv8x8[8],
575
0
                                      &p_best_mv16x16[2],
576
0
                                      curr_mv,
577
0
                                      &p_sad16x16[2],
578
0
                                      &p_sad8x8[8],
579
0
                                      sub_sad);
580
    //---- 16x16 : 3
581
0
    block_index           = block_index + 16;
582
0
    search_position_index = search_position_index + 16;
583
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
584
0
                                      src_stride,
585
0
                                      ref_ptr + search_position_index,
586
0
                                      ref_luma_stride,
587
0
                                      &p_best_sad_8x8[12],
588
0
                                      &p_best_sad_16x16[3],
589
0
                                      &p_best_mv8x8[12],
590
0
                                      &p_best_mv16x16[3],
591
0
                                      curr_mv,
592
0
                                      &p_sad16x16[3],
593
0
                                      &p_sad8x8[12],
594
0
                                      sub_sad);
595
    //---- 16x16 : 6
596
0
    block_index           = block_index + 16;
597
0
    search_position_index = search_position_index + 16;
598
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
599
0
                                      src_stride,
600
0
                                      ref_ptr + search_position_index,
601
0
                                      ref_luma_stride,
602
0
                                      &p_best_sad_8x8[24],
603
0
                                      &p_best_sad_16x16[6],
604
0
                                      &p_best_mv8x8[24],
605
0
                                      &p_best_mv16x16[6],
606
0
                                      curr_mv,
607
0
                                      &p_sad16x16[6],
608
0
                                      &p_sad8x8[24],
609
0
                                      sub_sad);
610
    //---- 16x16 : 7
611
0
    block_index           = block_index + 16;
612
0
    search_position_index = search_position_index + 16;
613
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
614
0
                                      src_stride,
615
0
                                      ref_ptr + search_position_index,
616
0
                                      ref_luma_stride,
617
0
                                      &p_best_sad_8x8[28],
618
0
                                      &p_best_sad_16x16[7],
619
0
                                      &p_best_mv8x8[28],
620
0
                                      &p_best_mv16x16[7],
621
0
                                      curr_mv,
622
0
                                      &p_sad16x16[7],
623
0
                                      &p_sad8x8[28],
624
0
                                      sub_sad);
625
626
    //---- 16x16 : 8
627
0
    block_index           = (src_next_16x16_offset << 1);
628
0
    search_position_index = search_position_tl_index + (ref_next_16x16_offset << 1);
629
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
630
0
                                      src_stride,
631
0
                                      ref_ptr + search_position_index,
632
0
                                      ref_luma_stride,
633
0
                                      &p_best_sad_8x8[32],
634
0
                                      &p_best_sad_16x16[8],
635
0
                                      &p_best_mv8x8[32],
636
0
                                      &p_best_mv16x16[8],
637
0
                                      curr_mv,
638
0
                                      &p_sad16x16[8],
639
0
                                      &p_sad8x8[32],
640
0
                                      sub_sad);
641
    //---- 16x16 : 9
642
0
    block_index           = block_index + 16;
643
0
    search_position_index = search_position_index + 16;
644
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
645
0
                                      src_stride,
646
0
                                      ref_ptr + search_position_index,
647
0
                                      ref_luma_stride,
648
0
                                      &p_best_sad_8x8[36],
649
0
                                      &p_best_sad_16x16[9],
650
0
                                      &p_best_mv8x8[36],
651
0
                                      &p_best_mv16x16[9],
652
0
                                      curr_mv,
653
0
                                      &p_sad16x16[9],
654
0
                                      &p_sad8x8[36],
655
0
                                      sub_sad);
656
    //---- 16x16 : 12
657
0
    block_index           = block_index + 16;
658
0
    search_position_index = search_position_index + 16;
659
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
660
0
                                      src_stride,
661
0
                                      ref_ptr + search_position_index,
662
0
                                      ref_luma_stride,
663
0
                                      &p_best_sad_8x8[48],
664
0
                                      &p_best_sad_16x16[12],
665
0
                                      &p_best_mv8x8[48],
666
0
                                      &p_best_mv16x16[12],
667
0
                                      curr_mv,
668
0
                                      &p_sad16x16[12],
669
0
                                      &p_sad8x8[48],
670
0
                                      sub_sad);
671
    //---- 16x16 : 13
672
0
    block_index           = block_index + 16;
673
0
    search_position_index = search_position_index + 16;
674
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
675
0
                                      src_stride,
676
0
                                      ref_ptr + search_position_index,
677
0
                                      ref_luma_stride,
678
0
                                      &p_best_sad_8x8[52],
679
0
                                      &p_best_sad_16x16[13],
680
0
                                      &p_best_mv8x8[52],
681
0
                                      &p_best_mv16x16[13],
682
0
                                      curr_mv,
683
0
                                      &p_sad16x16[13],
684
0
                                      &p_sad8x8[52],
685
0
                                      sub_sad);
686
687
    //---- 16x16 : 10
688
0
    block_index           = (src_next_16x16_offset * 3);
689
0
    search_position_index = search_position_tl_index + (ref_next_16x16_offset * 3);
690
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
691
0
                                      src_stride,
692
0
                                      ref_ptr + search_position_index,
693
0
                                      ref_luma_stride,
694
0
                                      &p_best_sad_8x8[40],
695
0
                                      &p_best_sad_16x16[10],
696
0
                                      &p_best_mv8x8[40],
697
0
                                      &p_best_mv16x16[10],
698
0
                                      curr_mv,
699
0
                                      &p_sad16x16[10],
700
0
                                      &p_sad8x8[40],
701
0
                                      sub_sad);
702
    //---- 16x16 : 11
703
0
    block_index           = block_index + 16;
704
0
    search_position_index = search_position_index + 16;
705
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
706
0
                                      src_stride,
707
0
                                      ref_ptr + search_position_index,
708
0
                                      ref_luma_stride,
709
0
                                      &p_best_sad_8x8[44],
710
0
                                      &p_best_sad_16x16[11],
711
0
                                      &p_best_mv8x8[44],
712
0
                                      &p_best_mv16x16[11],
713
0
                                      curr_mv,
714
0
                                      &p_sad16x16[11],
715
0
                                      &p_sad8x8[44],
716
0
                                      sub_sad);
717
    //---- 16x16 : 14
718
0
    block_index           = block_index + 16;
719
0
    search_position_index = search_position_index + 16;
720
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
721
0
                                      src_stride,
722
0
                                      ref_ptr + search_position_index,
723
0
                                      ref_luma_stride,
724
0
                                      &p_best_sad_8x8[56],
725
0
                                      &p_best_sad_16x16[14],
726
0
                                      &p_best_mv8x8[56],
727
0
                                      &p_best_mv16x16[14],
728
0
                                      curr_mv,
729
0
                                      &p_sad16x16[14],
730
0
                                      &p_sad8x8[56],
731
0
                                      sub_sad);
732
    //---- 16x16 : 15
733
0
    block_index           = block_index + 16;
734
0
    search_position_index = search_position_index + 16;
735
0
    svt_ext_sad_calculation_8x8_16x16(src_ptr + block_index,
736
0
                                      src_stride,
737
0
                                      ref_ptr + search_position_index,
738
0
                                      ref_luma_stride,
739
0
                                      &p_best_sad_8x8[60],
740
0
                                      &p_best_sad_16x16[15],
741
0
                                      &p_best_mv8x8[60],
742
0
                                      &p_best_mv16x16[15],
743
0
                                      curr_mv,
744
0
                                      &p_sad16x16[15],
745
0
                                      &p_sad8x8[60],
746
0
                                      sub_sad);
747
748
0
    svt_ext_sad_calculation_32x32_64x64(
749
0
        p_sad16x16, p_best_sad_32x32, p_best_sad_64x64, p_best_mv32x32, p_best_mv64x64, curr_mv, &p_sad32x32[0]);
750
0
}
751
752
/*******************************************
753
 * open_loop_me_fullpel_search_sblock
754
 *******************************************/
755
static void open_loop_me_fullpel_search_sblock(MeContext* me_ctx, uint32_t list_index, uint32_t ref_pic_index,
756
                                               int16_t x_search_area_origin, int16_t y_search_area_origin,
757
0
                                               uint32_t search_area_width, uint32_t search_area_height) {
758
0
    uint32_t x_search_index, y_search_index;
759
0
    uint32_t search_area_width_rest_8 = search_area_width & 7;
760
0
    uint32_t search_area_width_mult_8 = search_area_width - search_area_width_rest_8;
761
762
0
    for (y_search_index = 0; y_search_index < search_area_height; y_search_index++) {
763
0
        for (x_search_index = 0; x_search_index < search_area_width_mult_8; x_search_index += 8) {
764
            // this function will do:  x_search_index, +1, +2, ..., +7
765
0
            open_loop_me_get_eight_search_point_results_block(
766
0
                me_ctx,
767
0
                list_index,
768
0
                ref_pic_index,
769
0
                x_search_index + y_search_index * me_ctx->interpolated_full_stride[list_index][ref_pic_index],
770
0
                (int32_t)x_search_index + x_search_area_origin,
771
0
                (int32_t)y_search_index + y_search_area_origin);
772
0
        }
773
774
0
        for (x_search_index = search_area_width_mult_8; x_search_index < search_area_width; x_search_index++) {
775
0
            open_loop_me_get_search_point_results_block(
776
0
                me_ctx,
777
0
                list_index,
778
0
                ref_pic_index,
779
0
                x_search_index + y_search_index * me_ctx->interpolated_full_stride[list_index][ref_pic_index],
780
0
                (int32_t)x_search_index + x_search_area_origin,
781
0
                (int32_t)y_search_index + y_search_area_origin);
782
0
        }
783
0
    }
784
0
}
785
786
// Perform HME Level 0 for one 64x64 block on the given picture
787
static void hme_level_0(MeContext*           me_ctx, // ME context Ptr, used to get/update ME results
788
                        int16_t              org_x, // Block position in the horizontal direction- sixteenth resolution
789
                        int16_t              org_y, // Block position in the vertical direction- sixteenth resolution
790
                        uint32_t             block_width, // Block width - sixteenth resolution
791
                        uint32_t             block_height, // Block height - sixteenth resolution
792
                        int16_t              sa_width, // search area width
793
                        int16_t              sa_height, // search area height
794
                        EbPictureBufferDesc* sixteenth_ref_pic_ptr, // sixteenth-downsampled reference picture
795
                        uint32_t             sr_w, // current search region index in the horizontal direction
796
                        uint32_t             sr_h, // current search region index in the vertical direction
797
                        uint64_t*            best_sad, // output: Level0 SAD at (sr_w, sr_h)
798
                        int16_t*             hme_l0_sc_x, // output: Level0 xMV at (sr_w, sr_h)
799
                        int16_t*             hme_l0_sc_y // output: Level0 yMV at (sr_w, sr_h)
800
0
) {
801
    // round up the search region width to nearest multiple of 8 because the SAD calculation performance (for
802
    // intrinsic functions) is the same for search region width from 1 to 8
803
0
    sa_width           = (int16_t)((sa_width + 7) & ~0x07);
804
0
    int16_t pad_width  = (int16_t)(sixteenth_ref_pic_ptr->border) - 1;
805
0
    int16_t pad_height = (int16_t)(sixteenth_ref_pic_ptr->border) - 1;
806
807
0
    int16_t x_search_region_distance = sa_width * sr_w;
808
0
    int16_t y_search_region_distance = sa_height * sr_h;
809
0
    int16_t sa_origin_x              = -(int16_t)((sa_width * me_ctx->num_hme_sa_w) >> 1) + x_search_region_distance;
810
0
    int16_t sa_origin_y              = -(int16_t)((sa_height * me_ctx->num_hme_sa_h) >> 1) + y_search_region_distance;
811
    // Correct the left edge of the Search Area if it is not on the reference picture
812
0
    if (((org_x + sa_origin_x) < -pad_width)) {
813
0
        sa_origin_x = -pad_width - org_x;
814
0
        sa_width    = sa_width - (-pad_width - (org_x + sa_origin_x));
815
0
    }
816
817
    // Correct the right edge of the Search Area if its not on the reference picture
818
0
    if (((org_x + sa_origin_x) > (int16_t)sixteenth_ref_pic_ptr->width - 1)) {
819
0
        sa_origin_x = sa_origin_x - ((org_x + sa_origin_x) - ((int16_t)sixteenth_ref_pic_ptr->width - 1));
820
0
    }
821
822
0
    if (((org_x + sa_origin_x + sa_width) > (int16_t)sixteenth_ref_pic_ptr->width)) {
823
0
        sa_width = MAX(1, sa_width - ((org_x + sa_origin_x + sa_width) - (int16_t)sixteenth_ref_pic_ptr->width));
824
0
    }
825
    // Constrain x_HME_L1 to be a multiple of 8 (round down as cropping alrea performed)
826
0
    sa_width = (sa_width < 8) ? sa_width : sa_width & ~0x07;
827
    // Correct the top edge of the Search Area if it is not on the reference picture
828
0
    if (((org_y + sa_origin_y) < -pad_height)) {
829
0
        sa_origin_y = -pad_height - org_y;
830
0
        sa_height   = sa_height - (-pad_height - (org_y + sa_origin_y));
831
0
    }
832
833
    // Correct the bottom edge of the Search Area if its not on the reference picture
834
0
    if (((org_y + sa_origin_y) > (int16_t)sixteenth_ref_pic_ptr->height - 1)) {
835
0
        sa_origin_y = sa_origin_y - ((org_y + sa_origin_y) - ((int16_t)sixteenth_ref_pic_ptr->height - 1));
836
0
    }
837
838
0
    if ((org_y + sa_origin_y + sa_height > (int16_t)sixteenth_ref_pic_ptr->height)) {
839
0
        sa_height = MAX(1, sa_height - ((org_y + sa_origin_y + sa_height) - (int16_t)sixteenth_ref_pic_ptr->height));
840
0
    }
841
842
    // Move to the top left of the search region
843
0
    int16_t x_top_left_search_region = (org_x) + sa_origin_x;
844
0
    int16_t y_top_left_search_region = (org_y) + sa_origin_y;
845
0
    int32_t search_region_index = x_top_left_search_region + y_top_left_search_region * sixteenth_ref_pic_ptr->y_stride;
846
847
    // Put the first search location into level0 results
848
0
    svt_sad_loop_kernel(&me_ctx->sixteenth_b64_buffer[0],
849
0
                        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? me_ctx->sixteenth_b64_buffer_stride
850
0
                                                                       : me_ctx->sixteenth_b64_buffer_stride * 2,
851
0
                        &sixteenth_ref_pic_ptr->y_buffer[search_region_index],
852
0
                        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? sixteenth_ref_pic_ptr->y_stride
853
0
                                                                       : sixteenth_ref_pic_ptr->y_stride * 2,
854
0
                        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? block_height : block_height >> 1,
855
0
                        block_width,
856
                        /* results */
857
0
                        best_sad,
858
0
                        hme_l0_sc_x,
859
0
                        hme_l0_sc_y,
860
                        /* range */
861
0
                        sixteenth_ref_pic_ptr->y_stride,
862
0
                        0, // skip search line
863
0
                        sa_width,
864
0
                        sa_height);
865
866
0
    *best_sad = (me_ctx->hme_search_method == FULL_SAD_SEARCH)
867
0
        ? *best_sad
868
0
        : *best_sad * 2; // Multiply by 2 because considered only ever other line
869
0
    *hme_l0_sc_x += sa_origin_x;
870
0
    *hme_l0_sc_x *= 4; // Multiply by 4 because operating on 1/4 resolution
871
0
    *hme_l0_sc_y += sa_origin_y;
872
0
    *hme_l0_sc_y *= 4; // Multiply by 4 because operating on 1/4 resolution
873
874
0
    return;
875
0
}
876
877
// Perform HME Level 1 for one 64x64 block on the given picture
878
static void hme_level_1(MeContext*           me_ctx, // ME context Ptr, used to get/update ME results
879
                        int16_t              org_x, // Block position in the horizontal direction - quarter resolution
880
                        int16_t              org_y, // Block position in the vertical direction - quarter resolution
881
                        uint32_t             block_width, // Block width - quarter resolution
882
                        uint32_t             block_height, // Block height - quarter resolution
883
                        EbPictureBufferDesc* quarter_ref_pic_ptr, // quarter reference picture
884
                        int16_t              sa_width, // hme level 1 search area in width
885
                        int16_t              sa_height, // hme level 1 search area in height
886
                        int16_t              hme_l0_sc_x, // input parameter, best Level0 xMV at (sr_w, sr_h)
887
                        int16_t              hme_l0_sc_y, // input parameter, best Level0 yMV at (sr_w, sr_h)
888
                        uint64_t*            best_sad, // output parameter, Level1 SAD at (sr_w, sr_h)
889
                        int16_t*             hme_l1_sc_x, // output parameter, Level1 xMV at (sr_w, sr_h)
890
                        int16_t*             hme_l1_sc_y // output parameter, Level1 yMV at (sr_w, sr_h)
891
0
) {
892
    // round up the search region width to nearest multiple of 8 because the SAD calculation performance (for
893
    // intrinsic functions) is the same for search region width from 1 to 8
894
0
    sa_width = (int16_t)((sa_width + 7) & ~0x07);
895
896
0
    int16_t pad_width  = (int16_t)(quarter_ref_pic_ptr->border) - 1;
897
0
    int16_t pad_height = (int16_t)(quarter_ref_pic_ptr->border) - 1;
898
899
0
    int16_t sa_origin_x = -(sa_width >> 1) + hme_l0_sc_x;
900
0
    int16_t sa_origin_y = -(sa_height >> 1) + hme_l0_sc_y;
901
902
    // Correct the left edge of the Search Area if it is not on the reference picture
903
0
    if (((org_x + sa_origin_x) < -pad_width)) {
904
0
        sa_origin_x = -pad_width - org_x;
905
0
        sa_width    = sa_width - (-pad_width - (org_x + sa_origin_x));
906
0
    }
907
908
    // Correct the right edge of the Search Area if its not on the reference picture
909
0
    if (((org_x + sa_origin_x) > (int16_t)quarter_ref_pic_ptr->width - 1)) {
910
0
        sa_origin_x = sa_origin_x - ((org_x + sa_origin_x) - ((int16_t)quarter_ref_pic_ptr->width - 1));
911
0
    }
912
913
0
    if (((org_x + sa_origin_x + sa_width) > (int16_t)quarter_ref_pic_ptr->width)) {
914
0
        sa_width = MAX(1, sa_width - ((org_x + sa_origin_x + sa_width) - (int16_t)quarter_ref_pic_ptr->width));
915
0
    }
916
917
    // Constrain x_HME_L1 to be a multiple of 8 (round down as cropping alrea performed)
918
0
    sa_width = (sa_width < 8) ? sa_width : sa_width & ~0x07;
919
920
    // Correct the top edge of the Search Area if it is not on the reference picture
921
0
    if (((org_y + sa_origin_y) < -pad_height)) {
922
0
        sa_origin_y = -pad_height - org_y;
923
0
        sa_height   = sa_height - (-pad_height - (org_y + sa_origin_y));
924
0
    }
925
926
    // Correct the bottom edge of the Search Area if its not on the reference picture
927
0
    if (((org_y + sa_origin_y) > (int16_t)quarter_ref_pic_ptr->height - 1)) {
928
0
        sa_origin_y = sa_origin_y - ((org_y + sa_origin_y) - ((int16_t)quarter_ref_pic_ptr->height - 1));
929
0
    }
930
931
0
    if ((org_y + sa_origin_y + sa_height > (int16_t)quarter_ref_pic_ptr->height)) {
932
0
        sa_height = MAX(1, sa_height - ((org_y + sa_origin_y + sa_height) - (int16_t)quarter_ref_pic_ptr->height));
933
0
    }
934
935
    // Move to the top left of the search region
936
0
    int16_t x_top_left_search_region = (org_x) + sa_origin_x;
937
0
    int16_t y_top_left_search_region = (org_y) + sa_origin_y;
938
0
    int32_t search_region_index = x_top_left_search_region + y_top_left_search_region * quarter_ref_pic_ptr->y_stride;
939
940
    // Put the first search location into level1 results
941
0
    svt_sad_loop_kernel(&me_ctx->quarter_b64_buffer[0],
942
0
                        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? me_ctx->quarter_b64_buffer_stride
943
0
                                                                       : me_ctx->quarter_b64_buffer_stride * 2,
944
0
                        &quarter_ref_pic_ptr->y_buffer[search_region_index],
945
0
                        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? quarter_ref_pic_ptr->y_stride
946
0
                                                                       : quarter_ref_pic_ptr->y_stride * 2,
947
0
                        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? block_height : block_height >> 1,
948
0
                        block_width,
949
                        /* results */
950
0
                        best_sad,
951
0
                        hme_l1_sc_x,
952
0
                        hme_l1_sc_y,
953
                        /* range */
954
0
                        quarter_ref_pic_ptr->y_stride,
955
0
                        0, // skip search line
956
0
                        sa_width,
957
0
                        sa_height);
958
959
0
    *best_sad = (me_ctx->hme_search_method == FULL_SAD_SEARCH)
960
0
        ? *best_sad
961
0
        : *best_sad * 2; // Multiply by 2 because considered only ever other line
962
0
    *hme_l1_sc_x += sa_origin_x;
963
0
    *hme_l1_sc_x *= 2; // Multiply by 2 because operating on 1/2 resolution
964
0
    *hme_l1_sc_y += sa_origin_y;
965
0
    *hme_l1_sc_y *= 2; // Multiply by 2 because operating on 1/2 resolution
966
967
0
    return;
968
0
}
969
970
// Perform HME Level 2 for one 64x64 block on the given picture
971
void hme_level_2(MeContext*           me_ctx, // ME context Ptr, used to get/update ME results
972
                 int16_t              org_x, // Block position in the horizontal direction
973
                 int16_t              org_y, // Block position in the vertical direction
974
                 uint32_t             block_width, // Block pwidth - full resolution
975
                 uint32_t             block_height, // Block height - full resolution
976
                 EbPictureBufferDesc* ref_pic_ptr, // reference picture
977
                 int16_t              sa_width, // hme level 1 search area in width
978
                 int16_t              sa_height, // hme level 1 search area in height
979
                 int16_t              hme_l1_sc_x, // best Level1 xMV at (sr_w, sr_h)
980
                 int16_t              hme_l1_sc_y, // best Level1 yMV at (sr_w, sr_h)
981
                 uint64_t*            best_sad, // Level2 SAD at (sr_w, sr_h)
982
                 int16_t*             hme_l2_sc_x, // Level2 xMV at (sr_w, sr_h)
983
                 int16_t*             hme_l2_sc_y // Level2 yMV at (sr_w, sr_h)
984
0
) {
985
    // round up the search region width to nearest multiple of 8 because the SAD calculation performance (for
986
    // intrinsic functions) is the same for search region width from 1 to 8
987
0
    sa_width = (int16_t)((sa_width + 7) & ~0x07);
988
989
0
    int16_t pad_width  = (int16_t)BLOCK_SIZE_64 - 1;
990
0
    int16_t pad_height = (int16_t)BLOCK_SIZE_64 - 1;
991
992
0
    int16_t sa_origin_x = -(sa_width >> 1) + hme_l1_sc_x;
993
0
    int16_t sa_origin_y = -(sa_height >> 1) + hme_l1_sc_y;
994
995
    // Correct the left edge of the Search Area if it is not on the reference picture
996
0
    if (((org_x + sa_origin_x) < -pad_width)) {
997
0
        sa_origin_x = -pad_width - org_x;
998
0
        sa_width    = sa_width - (-pad_width - (org_x + sa_origin_x));
999
0
    }
1000
1001
    // Correct the right edge of the Search Area if its not on the reference picture
1002
0
    if (((org_x + sa_origin_x) > (int16_t)ref_pic_ptr->width - 1)) {
1003
0
        sa_origin_x = sa_origin_x - ((org_x + sa_origin_x) - ((int16_t)ref_pic_ptr->width - 1));
1004
0
    }
1005
1006
0
    if (((org_x + sa_origin_x + sa_width) > (int16_t)ref_pic_ptr->width)) {
1007
0
        sa_width = MAX(1, sa_width - ((org_x + sa_origin_x + sa_width) - (int16_t)ref_pic_ptr->width));
1008
0
    }
1009
1010
    // Constrain x_HME_L1 to be a multiple of 8 (round down as cropping already performed)
1011
0
    sa_width = (sa_width < 8) ? sa_width : sa_width & ~0x07;
1012
1013
    // Correct the top edge of the Search Area if it is not on the reference picture
1014
0
    if (((org_y + sa_origin_y) < -pad_height)) {
1015
0
        sa_origin_y = -pad_height - org_y;
1016
0
        sa_height   = sa_height - (-pad_height - (org_y + sa_origin_y));
1017
0
    }
1018
1019
    // Correct the bottom edge of the Search Area if its not on the reference picture
1020
0
    if (((org_y + sa_origin_y) > (int16_t)ref_pic_ptr->height - 1)) {
1021
0
        sa_origin_y = sa_origin_y - ((org_y + sa_origin_y) - ((int16_t)ref_pic_ptr->height - 1));
1022
0
    }
1023
1024
0
    if ((org_y + sa_origin_y + sa_height > (int16_t)ref_pic_ptr->height)) {
1025
0
        sa_height = MAX(1, sa_height - ((org_y + sa_origin_y + sa_height) - (int16_t)ref_pic_ptr->height));
1026
0
    }
1027
1028
    // Move to the top left of the search region
1029
0
    int16_t x_top_left_search_region = (org_x) + sa_origin_x;
1030
0
    int16_t y_top_left_search_region = (org_y) + sa_origin_y;
1031
0
    int32_t search_region_index      = x_top_left_search_region + y_top_left_search_region * ref_pic_ptr->y_stride;
1032
1033
    // Put the first search location into level2 results
1034
0
    svt_sad_loop_kernel(
1035
0
        me_ctx->b64_src_ptr,
1036
0
        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? me_ctx->b64_src_stride : me_ctx->b64_src_stride * 2,
1037
0
        &ref_pic_ptr->y_buffer[search_region_index],
1038
0
        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? ref_pic_ptr->y_stride : ref_pic_ptr->y_stride * 2,
1039
0
        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? block_height : block_height >> 1,
1040
0
        block_width,
1041
        /* results */
1042
0
        best_sad,
1043
0
        hme_l2_sc_x,
1044
0
        hme_l2_sc_y,
1045
        /* range */
1046
0
        ref_pic_ptr->y_stride,
1047
0
        0, // skip search line
1048
0
        sa_width,
1049
0
        sa_height);
1050
1051
0
    *best_sad = (me_ctx->hme_search_method == FULL_SAD_SEARCH)
1052
0
        ? *best_sad
1053
0
        : *best_sad * 2; // Multiply by 2 because considered only ever other line
1054
0
    *hme_l2_sc_x += sa_origin_x;
1055
0
    *hme_l2_sc_y += sa_origin_y;
1056
1057
0
    return;
1058
0
}
1059
1060
uint32_t check_00_center(EbPictureBufferDesc* ref_pic_ptr, MeContext* me_ctx, uint32_t sb_origin_x,
1061
                         uint32_t sb_origin_y, uint32_t sb_width, uint32_t sb_height, int16_t* x_search_center,
1062
                         int16_t* y_search_center, uint32_t zz_sad)
1063
1064
0
{
1065
0
    const int16_t org_x         = (int16_t)sb_origin_x;
1066
0
    const int16_t org_y         = (int16_t)sb_origin_y;
1067
0
    const int     subsample_sad = 1;
1068
0
    const int16_t pad_width     = (int16_t)BLOCK_SIZE_64 - 1;
1069
0
    const int16_t pad_height    = (int16_t)BLOCK_SIZE_64 - 1;
1070
1071
0
    int32_t  search_region_index = org_x + (org_y)*ref_pic_ptr->y_stride;
1072
0
    uint64_t zero_mv_sad;
1073
0
    if (me_ctx->me_early_exit_th) {
1074
0
        zero_mv_sad = zz_sad;
1075
0
    } else {
1076
0
        zero_mv_sad = svt_nxm_sad_kernel(me_ctx->b64_src_ptr,
1077
0
                                         me_ctx->b64_src_stride << subsample_sad,
1078
0
                                         &(ref_pic_ptr->y_buffer[search_region_index]),
1079
0
                                         ref_pic_ptr->y_stride << subsample_sad,
1080
0
                                         sb_height >> subsample_sad,
1081
0
                                         sb_width);
1082
0
    }
1083
1084
0
    zero_mv_sad = zero_mv_sad << subsample_sad;
1085
1086
    // FIX
1087
    // Correct the left edge of the Search Area if it is not on the reference
1088
    // Picture
1089
0
    *x_search_center = ((org_x + *x_search_center) < -pad_width) ? -pad_width - org_x : *x_search_center;
1090
    // Correct the right edge of the Search Area if its not on the reference
1091
    // Picture
1092
0
    *x_search_center = ((org_x + *x_search_center) > (int16_t)ref_pic_ptr->width - 1)
1093
0
        ? *x_search_center - ((org_x + *x_search_center) - ((int16_t)ref_pic_ptr->width - 1))
1094
0
        : *x_search_center;
1095
    // Correct the top edge of the Search Area if it is not on the reference
1096
    // Picture
1097
0
    *y_search_center = ((org_y + *y_search_center) < -pad_height) ? -pad_height - org_y : *y_search_center;
1098
    // Correct the bottom edge of the Search Area if its not on the reference
1099
    // Picture
1100
0
    *y_search_center = ((org_y + *y_search_center) > (int16_t)ref_pic_ptr->height - 1)
1101
0
        ? *y_search_center - ((org_y + *y_search_center) - ((int16_t)ref_pic_ptr->height - 1))
1102
0
        : *y_search_center;
1103
    ///
1104
1105
0
    uint64_t zero_mv_cost = zero_mv_sad << COST_PRECISION;
1106
0
    search_region_index   = (int16_t)(org_x) + *x_search_center +
1107
0
        ((int16_t)(org_y) + *y_search_center) * ref_pic_ptr->y_stride;
1108
1109
0
    uint64_t hme_mv_sad = svt_nxm_sad_kernel(me_ctx->b64_src_ptr,
1110
0
                                             me_ctx->b64_src_stride << subsample_sad,
1111
0
                                             &(ref_pic_ptr->y_buffer[search_region_index]),
1112
0
                                             ref_pic_ptr->y_stride << subsample_sad,
1113
0
                                             sb_height >> subsample_sad,
1114
0
                                             sb_width);
1115
1116
0
    hme_mv_sad                  = hme_mv_sad << subsample_sad;
1117
0
    uint64_t hme_mv_cost        = hme_mv_sad << COST_PRECISION;
1118
0
    uint64_t search_center_cost = MIN(zero_mv_cost, hme_mv_cost);
1119
1120
0
    *x_search_center = (search_center_cost == zero_mv_cost) ? 0 : *x_search_center;
1121
0
    *y_search_center = (search_center_cost == zero_mv_cost) ? 0 : *y_search_center;
1122
0
    return hme_mv_sad;
1123
0
}
1124
1125
// get ME references based on level:
1126
// level: 0 => sixteenth, 1 => quarter, 2 => original
1127
1128
static EbPictureBufferDesc* get_me_reference(PictureParentControlSet* pcs, MeContext* me_ctx, uint8_t list_index,
1129
                                             uint8_t ref_pic_index, uint8_t level, uint16_t* dist, uint16_t input_width,
1130
0
                                             uint16_t input_height) {
1131
0
    EbPictureBufferDesc* ref_pic_ptr;
1132
0
    ref_pic_ptr = level == 0 ? me_ctx->me_ds_ref_array[list_index][ref_pic_index].sixteenth_picture_ptr
1133
0
        : level == 1         ? me_ctx->me_ds_ref_array[list_index][ref_pic_index].quarter_picture_ptr
1134
0
                             : me_ctx->me_ds_ref_array[list_index][ref_pic_index].picture_ptr;
1135
1136
0
    if ((input_width >> (2 - level)) != ref_pic_ptr->width || (input_height >> (2 - level)) != ref_pic_ptr->height) {
1137
0
        SVT_WARN("picture %3llu: HME level%d resolution mismatch! input (%dx%d) != (%dx%d) pa ref. \n",
1138
0
                 pcs->picture_number,
1139
0
                 level,
1140
0
                 input_width >> (2 - level),
1141
0
                 input_height >> (2 - level),
1142
0
                 ref_pic_ptr->width,
1143
0
                 ref_pic_ptr->height);
1144
0
    }
1145
1146
0
    *dist = (int16_t)ABS((int64_t)pcs->picture_number -
1147
0
                         (int64_t)me_ctx->me_ds_ref_array[list_index][ref_pic_index].picture_number);
1148
0
    return ref_pic_ptr;
1149
0
}
1150
1151
// factor to slowdown the ME search region growth to MAX
1152
0
uint16_t svt_aom_get_scaled_picture_distance(uint16_t dist) {
1153
0
    uint8_t round_up = ((dist % 8) == 0) ? 0 : 1;
1154
0
    return ((dist * 5) / 8) + round_up;
1155
0
}
1156
1157
static const double search_area_multipliers[3][5] = {
1158
    {1.0, 1.0, 3.0, 4.0, 5.0}, /* boost=1 */
1159
    {1.0, 1.0, 2.5, 3.5, 4.5}, /* boost=2 */
1160
    {1.0, 1.0, 2.0, 2.5, 3.5} /* boost=3 */
1161
};
1162
1163
0
static void apply_me_sa_boost(int16_t* width, int16_t* height, uint64_t hme_sad, int sc_class_me_boost) {
1164
0
    int index;
1165
0
    if (hme_sad > 4 * 64 * 64) {
1166
0
        index = 4;
1167
0
    } else if (hme_sad > 3 * 64 * 64) {
1168
0
        index = 3;
1169
0
    } else if (hme_sad > 2 * 64 * 64) {
1170
0
        index = 2;
1171
0
    } else {
1172
0
        index = 0;
1173
0
    }
1174
1175
0
    const double mult = search_area_multipliers[sc_class_me_boost - 1][index];
1176
1177
0
    *width  = (int16_t)(*width * mult);
1178
0
    *height = (int16_t)(*height * mult);
1179
0
}
1180
1181
/*******************************************
1182
 *   performs integer search motion estimation for
1183
 all avaiable references frames
1184
 *******************************************/
1185
static void integer_search_b64(PictureParentControlSet* pcs, MeContext* me_ctx, uint32_t b64_origin_x,
1186
0
                               uint32_t b64_origin_y, EbPictureBufferDesc* input_ptr) {
1187
0
    int16_t  picture_width  = pcs->aligned_width;
1188
0
    int16_t  picture_height = pcs->aligned_height;
1189
0
    uint32_t b64_width      = me_ctx->b64_width;
1190
0
    uint32_t b64_height     = me_ctx->b64_height;
1191
0
    int16_t  pad_width      = (int16_t)BLOCK_SIZE_64 - 1;
1192
0
    int16_t  pad_height     = (int16_t)BLOCK_SIZE_64 - 1;
1193
0
    int16_t  org_x          = (int16_t)b64_origin_x;
1194
0
    int16_t  org_y          = (int16_t)b64_origin_y;
1195
0
    int16_t  search_area_width;
1196
0
    int16_t  search_area_height;
1197
0
    int16_t  x_search_area_origin;
1198
0
    int16_t  y_search_area_origin;
1199
0
    int16_t  x_top_left_search_region;
1200
0
    int16_t  y_top_left_search_region;
1201
0
    int32_t  search_region_index;
1202
0
    uint32_t num_of_list_to_search;
1203
0
    uint32_t list_index;
1204
0
    uint8_t  ref_pic_index;
1205
    // Final ME Search Center
1206
0
    int16_t              x_search_center = 0;
1207
0
    int16_t              y_search_center = 0;
1208
0
    EbPictureBufferDesc* ref_pic_ptr;
1209
0
    num_of_list_to_search = me_ctx->num_of_list_to_search;
1210
1211
    // Uni-Prediction motion estimation loop
1212
    // List Loop
1213
0
    for (list_index = REF_LIST_0; list_index < num_of_list_to_search; ++list_index) {
1214
0
        uint8_t num_of_ref_pic_to_search = me_ctx->num_of_ref_pic_to_search[list_index];
1215
1216
        // Ref Picture Loop
1217
0
        for (ref_pic_index = 0; ref_pic_index < num_of_ref_pic_to_search; ++ref_pic_index) {
1218
0
            uint16_t dist = 0;
1219
0
            ref_pic_ptr   = get_me_reference(
1220
0
                pcs, me_ctx, list_index, ref_pic_index, 2, &dist, input_ptr->width, input_ptr->height);
1221
            // Get hme results
1222
0
            if (me_ctx->search_results[list_index][ref_pic_index].do_ref == 0) {
1223
0
                continue; //so will not get ME results for those references.
1224
0
            }
1225
0
            x_search_center    = me_ctx->search_results[list_index][ref_pic_index].hme_sc_x;
1226
0
            y_search_center    = me_ctx->search_results[list_index][ref_pic_index].hme_sc_y;
1227
0
            search_area_width  = me_ctx->me_sa.sa_min.width;
1228
0
            search_area_height = me_ctx->me_sa.sa_min.height;
1229
1230
            // factor to slowdown the ME search region growth to MAX
1231
0
            if (me_ctx->me_type != ME_MCTF) {
1232
0
                dist = svt_aom_get_scaled_picture_distance(dist);
1233
0
            }
1234
0
            search_area_width  = MIN((search_area_width * dist), me_ctx->me_sa.sa_max.width);
1235
0
            search_area_height = MIN((search_area_height * dist), me_ctx->me_sa.sa_max.height);
1236
0
            if (me_ctx->mv_based_sa_adj.enabled && (!me_ctx->mv_based_sa_adj.nearest_ref_only || ref_pic_index == 0)) {
1237
0
                if (ABS(x_search_center) > me_ctx->mv_based_sa_adj.mv_size_th) {
1238
0
                    search_area_width *= me_ctx->mv_based_sa_adj.sa_multiplier;
1239
0
                }
1240
0
                if (ABS(y_search_center) > me_ctx->mv_based_sa_adj.mv_size_th) {
1241
0
                    search_area_height *= me_ctx->mv_based_sa_adj.sa_multiplier;
1242
0
                }
1243
0
            }
1244
0
            if (me_ctx->sc_class_me_boost &&
1245
0
                (pcs->ahd_error == (uint32_t)~0 || // Use ahd_error only when it is derived
1246
0
                 pcs->ahd_error <
1247
0
                     ((((20 * pcs->enhanced_pic->width * pcs->enhanced_pic->height) / 128)) *
1248
0
                      (uint32_t)(INPUT_SIZE_COUNT -
1249
0
                                 pcs->input_resolution)))) { // Only if there are low temporal variations between frames
1250
0
                const uint64_t hme_sad = me_ctx->search_results[list_index][ref_pic_index].hme_sad;
1251
0
                apply_me_sa_boost(&search_area_width, &search_area_height, hme_sad, me_ctx->sc_class_me_boost);
1252
0
            }
1253
            // Constrain x_ME to be a multiple of 8 (round up)
1254
            // Update ME search reagion size based on hme-data
1255
0
            search_area_width = (MAX(1, (search_area_width / me_ctx->reduce_me_sr_divisor[list_index][ref_pic_index])) +
1256
0
                                 7) &
1257
0
                ~0x07;
1258
0
            search_area_height = MAX(3, (search_area_height / me_ctx->reduce_me_sr_divisor[list_index][ref_pic_index]));
1259
0
            int16_t  search_area_height_before_sr_reduction = search_area_height;
1260
0
            uint64_t best_hme_sad                           = (uint64_t)~0;
1261
0
            if (me_ctx->me_early_exit_th) {
1262
0
                if (me_ctx->zz_sad[list_index][ref_pic_index] < (me_ctx->me_early_exit_th / 6)) {
1263
0
                    search_area_width  = 1;
1264
0
                    search_area_height = 1;
1265
0
                }
1266
0
            } else {
1267
0
                uint8_t hme_is_accuarte = 1;
1268
0
                if ((x_search_center != 0 || y_search_center != 0) && (me_ctx->is_ref == true)) {
1269
0
                    best_hme_sad = check_00_center(ref_pic_ptr,
1270
0
                                                   me_ctx,
1271
0
                                                   b64_origin_x,
1272
0
                                                   b64_origin_y,
1273
0
                                                   b64_width,
1274
0
                                                   b64_height,
1275
0
                                                   &x_search_center,
1276
0
                                                   &y_search_center,
1277
0
                                                   me_ctx->zz_sad[list_index][ref_pic_index]);
1278
1279
0
                    if (x_search_center == 0 && y_search_center == 0) {
1280
0
                        hme_is_accuarte = 0;
1281
0
                    }
1282
0
                }
1283
0
                if (me_ctx->me_sr_adjustment_ctrls.enable_me_sr_adjustment == 2) {
1284
0
                    if ((hme_is_accuarte && (best_hme_sad < (24 * 24))) ||
1285
0
                        (me_ctx->is_ref && me_ctx->search_results[list_index][ref_pic_index].hme_sad < (24 * 24))) {
1286
0
                        search_area_height = search_area_height / 2;
1287
0
                    }
1288
0
                    if (list_index || ref_pic_index) {
1289
0
                        if (me_ctx->p_sb_best_sad[0][0][0] < 5000) {
1290
0
                            if (search_area_height == search_area_height_before_sr_reduction) {
1291
0
                                search_area_height = search_area_height >> 1;
1292
0
                                search_area_width  = search_area_width >> 1;
1293
0
                            }
1294
0
                        }
1295
0
                    }
1296
0
                }
1297
0
            }
1298
0
            svt_initialize_buffer_32bits(me_ctx->p_sb_best_sad[list_index][ref_pic_index], 21, 1, MAX_SAD_VALUE);
1299
0
            me_ctx->p_best_sad_64x64 = &(me_ctx->p_sb_best_sad[list_index][ref_pic_index][ME_TIER_ZERO_PU_64x64]);
1300
0
            me_ctx->p_best_sad_32x32 = &(me_ctx->p_sb_best_sad[list_index][ref_pic_index][ME_TIER_ZERO_PU_32x32_0]);
1301
0
            me_ctx->p_best_sad_16x16 = &(me_ctx->p_sb_best_sad[list_index][ref_pic_index][ME_TIER_ZERO_PU_16x16_0]);
1302
0
            me_ctx->p_best_sad_8x8   = &(me_ctx->p_sb_best_sad[list_index][ref_pic_index][ME_TIER_ZERO_PU_8x8_0]);
1303
1304
0
            me_ctx->p_best_mv64x64 = &(me_ctx->p_sb_best_mv[list_index][ref_pic_index][ME_TIER_ZERO_PU_64x64]);
1305
0
            me_ctx->p_best_mv32x32 = &(me_ctx->p_sb_best_mv[list_index][ref_pic_index][ME_TIER_ZERO_PU_32x32_0]);
1306
0
            me_ctx->p_best_mv16x16 = &(me_ctx->p_sb_best_mv[list_index][ref_pic_index][ME_TIER_ZERO_PU_16x16_0]);
1307
0
            me_ctx->p_best_mv8x8   = &(me_ctx->p_sb_best_mv[list_index][ref_pic_index][ME_TIER_ZERO_PU_8x8_0]);
1308
1309
            /* If search area is large enough, check the ME 8x8 SAD variance, and if low, reduce search area
1310
            * (as the 64x64 MVs are likely good for all the 8x8 blocks that make it up).  If the search area
1311
            * is already low, the overhead of searching one additional point will be high (and fruitless, since
1312
            * the minimum search size that will be set by the 8x8 SAD variance algorithm is 8x3.
1313
            */
1314
0
            if (me_ctx->me_8x8_var_ctrls.enabled && (search_area_width * search_area_height > 24)) {
1315
0
                x_search_area_origin     = x_search_center;
1316
0
                y_search_area_origin     = y_search_center;
1317
0
                x_top_left_search_region = (int16_t)(b64_origin_x) - (ME_FILTER_TAP >> 1) + x_search_area_origin;
1318
0
                y_top_left_search_region = (int16_t)(b64_origin_y) - (ME_FILTER_TAP >> 1) + y_search_area_origin;
1319
0
                search_region_index = (x_top_left_search_region) + (y_top_left_search_region)*ref_pic_ptr->y_stride;
1320
0
                me_ctx->integer_buffer_ptr[list_index][ref_pic_index] = &(ref_pic_ptr->y_buffer[search_region_index]);
1321
0
                me_ctx->interpolated_full_stride[list_index][ref_pic_index] = ref_pic_ptr->y_stride;
1322
1323
0
                open_loop_me_fullpel_search_sblock(
1324
0
                    me_ctx, list_index, ref_pic_index, x_search_center, y_search_center, 1, 1);
1325
1326
                // Since only one point was searched, the 64x64 SAD will be the same as the sum of the 8x8 SADs
1327
0
                const uint32_t mean_dist_8x8     = me_ctx->p_best_sad_64x64[0] / 64;
1328
0
                uint32_t       sum_ofsq_dist_8x8 = 0;
1329
0
                for (unsigned i = 0; i < 64; i++) {
1330
0
                    const int32_t diff = ((int32_t)me_ctx->p_best_sad_8x8[i] - (int32_t)mean_dist_8x8);
1331
0
                    sum_ofsq_dist_8x8 += diff * diff;
1332
0
                }
1333
1334
0
                uint32_t me_8x8_cost_var = (uint32_t)(sum_ofsq_dist_8x8 / 64);
1335
1336
0
                if (me_8x8_cost_var > me_ctx->me_8x8_var_ctrls.me_sr_mult2_th) {
1337
0
                    search_area_width  = (MAX(1, search_area_width * 3 / 2) + 7) & ~0x7;
1338
0
                    search_area_height = MAX(1, search_area_height * 3 / 2);
1339
0
                }
1340
1341
0
                if (me_8x8_cost_var < me_ctx->me_8x8_var_ctrls.me_sr_div4_th) {
1342
0
                    search_area_width  = (MAX(1, search_area_width >> 2) + 7) & ~0x7;
1343
0
                    search_area_height = MAX(1, search_area_height >> 2);
1344
0
                    search_area_height = MAX(3, search_area_height);
1345
0
                } else if (me_8x8_cost_var < me_ctx->me_8x8_var_ctrls.me_sr_div2_th) {
1346
0
                    search_area_width  = (MIN(search_area_width, search_area_width >> 1) + 7) & ~0x7;
1347
0
                    search_area_height = MIN(search_area_height, search_area_height >> 1);
1348
0
                    search_area_height = MAX(3, search_area_height);
1349
0
                }
1350
0
            }
1351
0
            x_search_area_origin = x_search_center - (search_area_width >> 1);
1352
0
            y_search_area_origin = y_search_center - (search_area_height >> 1);
1353
1354
            // Correct the left edge of the Search Area if it is not on the
1355
            // reference Picture
1356
0
            x_search_area_origin = ((org_x + x_search_area_origin) < -pad_width) ? -pad_width - org_x
1357
0
                                                                                 : x_search_area_origin;
1358
0
            search_area_width    = ((org_x + x_search_area_origin) < -pad_width)
1359
0
                   ? search_area_width - (-pad_width - (org_x + x_search_area_origin))
1360
0
                   : search_area_width;
1361
            // Correct the right edge of the Search Area if its not on the
1362
            // reference Picture
1363
0
            x_search_area_origin = ((org_x + x_search_area_origin) > picture_width - 1)
1364
0
                ? x_search_area_origin - ((org_x + x_search_area_origin) - (picture_width - 1))
1365
0
                : x_search_area_origin;
1366
1367
0
            search_area_width = ((org_x + x_search_area_origin + search_area_width) > picture_width)
1368
0
                ? MAX(1, search_area_width - ((org_x + x_search_area_origin + search_area_width) - picture_width))
1369
0
                : search_area_width;
1370
1371
            // Constrain x_ME to be a multiple of 8 (round down as cropping
1372
            // already performed)
1373
0
            search_area_width = (search_area_width < 8) ? search_area_width : search_area_width & ~0x07;
1374
1375
            // Correct the top edge of the Search Area if it is not on the
1376
            // reference Picture
1377
0
            y_search_area_origin = ((org_y + y_search_area_origin) < -pad_height) ? -pad_height - org_y
1378
0
                                                                                  : y_search_area_origin;
1379
0
            search_area_height   = ((org_y + y_search_area_origin) < -pad_height)
1380
0
                  ? search_area_height - (-pad_height - (org_y + y_search_area_origin))
1381
0
                  : search_area_height;
1382
            // Correct the bottom edge of the Search Area if its not on the
1383
            // reference Picture
1384
0
            y_search_area_origin = ((org_y + y_search_area_origin) > picture_height - 1)
1385
0
                ? y_search_area_origin - ((org_y + y_search_area_origin) - (picture_height - 1))
1386
0
                : y_search_area_origin;
1387
0
            search_area_height   = (org_y + y_search_area_origin + search_area_height > picture_height)
1388
0
                  ? MAX(1, search_area_height - ((org_y + y_search_area_origin + search_area_height) - picture_height))
1389
0
                  : search_area_height;
1390
1391
0
            x_top_left_search_region = (int16_t)(b64_origin_x) - (ME_FILTER_TAP >> 1) + x_search_area_origin;
1392
0
            y_top_left_search_region = (int16_t)(b64_origin_y) - (ME_FILTER_TAP >> 1) + y_search_area_origin;
1393
0
            search_region_index      = (x_top_left_search_region) + (y_top_left_search_region)*ref_pic_ptr->y_stride;
1394
0
            me_ctx->integer_buffer_ptr[list_index][ref_pic_index]       = &(ref_pic_ptr->y_buffer[search_region_index]);
1395
0
            me_ctx->interpolated_full_stride[list_index][ref_pic_index] = ref_pic_ptr->y_stride;
1396
1397
            // Move to the top left of the search region
1398
0
            x_top_left_search_region = (int16_t)(b64_origin_x) + x_search_area_origin;
1399
0
            y_top_left_search_region = (int16_t)(b64_origin_y) + y_search_area_origin;
1400
0
            open_loop_me_fullpel_search_sblock(me_ctx,
1401
0
                                               list_index,
1402
0
                                               ref_pic_index,
1403
0
                                               x_search_area_origin,
1404
0
                                               y_search_area_origin,
1405
0
                                               search_area_width,
1406
0
                                               search_area_height);
1407
0
        }
1408
0
    }
1409
0
}
1410
1411
/*
1412
  using previous stage ME results (Integer Search) for each reference
1413
  frame. keep only the references that are close to the best reference.
1414
*/
1415
0
static void me_prune_ref(MeContext* me_ctx) {
1416
0
    uint8_t num_of_list_to_search = me_ctx->num_of_list_to_search;
1417
0
    for (uint8_t list_index = REF_LIST_0; list_index < num_of_list_to_search; ++list_index) {
1418
0
        uint8_t num_of_ref_pic_to_search = me_ctx->num_of_ref_pic_to_search[list_index];
1419
        // Ref Picture Loop
1420
0
        for (uint8_t ref_pic_index = 0; ref_pic_index < num_of_ref_pic_to_search; ++ref_pic_index) {
1421
0
            me_ctx->search_results[list_index][ref_pic_index].hme_sad = 0;
1422
            // Get hme results
1423
0
            if (me_ctx->search_results[list_index][ref_pic_index].do_ref == 0) {
1424
0
                me_ctx->search_results[list_index][ref_pic_index].hme_sad = MAX_SAD_VALUE * 64;
1425
0
                continue;
1426
0
            }
1427
0
            me_ctx->p_best_sad_8x8 = &(me_ctx->p_sb_best_sad[list_index][ref_pic_index][ME_TIER_ZERO_PU_8x8_0]);
1428
            // 8x8   [64 partitions]
1429
0
            for (uint32_t pu_index = 0; pu_index < 64; ++pu_index) {
1430
0
                uint32_t idx = tab8x8[pu_index];
1431
0
                me_ctx->search_results[list_index][ref_pic_index].hme_sad += me_ctx->p_best_sad_8x8[idx];
1432
0
            }
1433
0
        }
1434
0
    }
1435
1436
0
    uint16_t prune_ref_th = me_ctx->me_hme_prune_ctrls.prune_ref_if_me_sad_dev_bigger_than_th;
1437
0
    if (me_ctx->me_hme_prune_ctrls.enable_me_hme_ref_pruning && prune_ref_th != (uint16_t)~0) {
1438
0
        uint64_t best = (uint64_t)~0;
1439
0
        for (int i = 0; i < MAX_NUM_OF_REF_PIC_LIST; ++i) {
1440
0
            for (int j = 0; j < REF_LIST_MAX_DEPTH; ++j) {
1441
0
                if (me_ctx->search_results[i][j].hme_sad < best) {
1442
0
                    best = me_ctx->search_results[i][j].hme_sad;
1443
0
                }
1444
0
            }
1445
0
        }
1446
0
        for (uint32_t li = 0; li < MAX_NUM_OF_REF_PIC_LIST; li++) {
1447
0
            for (uint32_t ri = 1; ri < REF_LIST_MAX_DEPTH; ri++) {
1448
                // Prune references based on ME sad
1449
0
                if ((me_ctx->search_results[li][ri].hme_sad - best) * 100 > (prune_ref_th * best)) {
1450
0
                    me_ctx->search_results[li][ri].do_ref = 0;
1451
0
                }
1452
0
            }
1453
0
        }
1454
0
    }
1455
0
}
1456
1457
/* perform  motion search over a given search area*/
1458
static void prehme_core(MeContext* me_ctx, int16_t org_x, int16_t org_y, uint32_t sb_width, uint32_t sb_height,
1459
0
                        EbPictureBufferDesc* sixteenth_ref_pic_ptr, SearchInfo* prehme_data) {
1460
0
    int16_t x_top_left_search_region;
1461
0
    int16_t y_top_left_search_region;
1462
0
    int32_t search_region_index;
1463
1464
0
    int16_t pad_width  = (int16_t)(sixteenth_ref_pic_ptr->border) - 1;
1465
0
    int16_t pad_height = (int16_t)(sixteenth_ref_pic_ptr->border) - 1;
1466
1467
0
    int16_t search_area_width  = prehme_data->sa.width;
1468
0
    int16_t search_area_height = prehme_data->sa.height;
1469
1470
0
    int16_t x_search_area_origin = -(int16_t)(search_area_width >> 1);
1471
0
    int16_t y_search_area_origin = -(int16_t)(search_area_height >> 1);
1472
1473
    // Correct the left edge of the Search Area if it is not on the reference Picture
1474
0
    x_search_area_origin = ((org_x + x_search_area_origin) < -pad_width) ? -pad_width - org_x : x_search_area_origin;
1475
1476
0
    search_area_width = ((org_x + x_search_area_origin) < -pad_width)
1477
0
        ? search_area_width - (-pad_width - (org_x + x_search_area_origin))
1478
0
        : search_area_width;
1479
1480
    // Correct the right edge of the Search Area if its not on the reference Picture
1481
0
    x_search_area_origin = ((org_x + x_search_area_origin) > (int16_t)sixteenth_ref_pic_ptr->width - 1)
1482
0
        ? x_search_area_origin - ((org_x + x_search_area_origin) - ((int16_t)sixteenth_ref_pic_ptr->width - 1))
1483
0
        : x_search_area_origin;
1484
1485
0
    search_area_width = ((org_x + x_search_area_origin + search_area_width) > (int16_t)sixteenth_ref_pic_ptr->width)
1486
0
        ? MAX(1,
1487
0
              search_area_width -
1488
0
                  ((org_x + x_search_area_origin + search_area_width) - (int16_t)sixteenth_ref_pic_ptr->width))
1489
0
        : search_area_width;
1490
1491
    // Correct the top edge of the Search Area if it is not on the reference Picture
1492
0
    y_search_area_origin = ((org_y + y_search_area_origin) < -pad_height) ? -pad_height - org_y : y_search_area_origin;
1493
1494
0
    search_area_height = ((org_y + y_search_area_origin) < -pad_height)
1495
0
        ? search_area_height - (-pad_height - (org_y + y_search_area_origin))
1496
0
        : search_area_height;
1497
1498
    // Correct the bottom edge of the Search Area if its not on the reference Picture
1499
0
    y_search_area_origin = ((org_y + y_search_area_origin) > (int16_t)sixteenth_ref_pic_ptr->height - 1)
1500
0
        ? y_search_area_origin - ((org_y + y_search_area_origin) - ((int16_t)sixteenth_ref_pic_ptr->height - 1))
1501
0
        : y_search_area_origin;
1502
1503
0
    search_area_height = (org_y + y_search_area_origin + search_area_height > (int16_t)sixteenth_ref_pic_ptr->height)
1504
0
        ? MAX(1,
1505
0
              search_area_height -
1506
0
                  ((org_y + y_search_area_origin + search_area_height) - (int16_t)sixteenth_ref_pic_ptr->height))
1507
0
        : search_area_height;
1508
1509
0
    x_top_left_search_region = (org_x) + x_search_area_origin;
1510
0
    y_top_left_search_region = (org_y) + y_search_area_origin;
1511
0
    search_region_index      = x_top_left_search_region + y_top_left_search_region * sixteenth_ref_pic_ptr->y_stride;
1512
1513
0
    svt_sad_loop_kernel(&me_ctx->sixteenth_b64_buffer[0],
1514
0
                        me_ctx->hme_search_method == FULL_SAD_SEARCH ? me_ctx->sixteenth_b64_buffer_stride
1515
0
                                                                     : me_ctx->sixteenth_b64_buffer_stride * 2,
1516
0
                        &sixteenth_ref_pic_ptr->y_buffer[search_region_index],
1517
0
                        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? sixteenth_ref_pic_ptr->y_stride
1518
0
                                                                       : sixteenth_ref_pic_ptr->y_stride * 2,
1519
0
                        (me_ctx->hme_search_method == FULL_SAD_SEARCH) ? sb_height : sb_height >> 1,
1520
0
                        sb_width,
1521
                        /* results */
1522
0
                        &prehme_data->sad,
1523
0
                        &prehme_data->best_mv.x,
1524
0
                        &prehme_data->best_mv.y,
1525
0
                        sixteenth_ref_pic_ptr->y_stride,
1526
0
                        me_ctx->prehme_ctrl.skip_search_line,
1527
0
                        search_area_width,
1528
0
                        search_area_height);
1529
1530
0
    prehme_data->sad = (me_ctx->hme_search_method == FULL_SAD_SEARCH)
1531
0
        ? prehme_data->sad
1532
0
        : prehme_data->sad * 2; // Multiply by 2 because considered only ever other line
1533
0
    prehme_data->best_mv.x += x_search_area_origin;
1534
0
    prehme_data->best_mv.x *= 4; // Multiply by 4 because operating on 1/4 resolution
1535
0
    prehme_data->best_mv.y += y_search_area_origin;
1536
0
    prehme_data->best_mv.y *= 4; // Multiply by 4 because operating on 1/4 resolution
1537
0
    prehme_data->valid = 1;
1538
0
    return;
1539
0
}
1540
1541
static uint32_t get_zz_sad(EbPictureBufferDesc* ref_pic_ptr, MeContext* me_ctx, uint32_t sb_origin_x,
1542
                           uint32_t sb_origin_y, uint32_t sb_width, uint32_t sb_height)
1543
1544
0
{
1545
0
    uint32_t zero_mv_sad;
1546
0
    int16_t  org_x         = (int16_t)sb_origin_x;
1547
0
    int16_t  org_y         = (int16_t)sb_origin_y;
1548
0
    uint32_t subsample_sad = 1;
1549
1550
0
    int32_t search_region_index = org_x + (org_y)*ref_pic_ptr->y_stride;
1551
1552
0
    zero_mv_sad = svt_nxm_sad_kernel(me_ctx->b64_src_ptr,
1553
0
                                     me_ctx->b64_src_stride << subsample_sad,
1554
0
                                     &(ref_pic_ptr->y_buffer[search_region_index]),
1555
0
                                     ref_pic_ptr->y_stride << subsample_sad,
1556
0
                                     sb_height >> subsample_sad,
1557
0
                                     sb_width);
1558
1559
0
    zero_mv_sad = zero_mv_sad << subsample_sad;
1560
1561
0
    return zero_mv_sad;
1562
0
}
1563
1564
// Determine if pre-HME for the current picture and search region should be skipped.
1565
// Return 1 if can early exit (i.e. skip pre-hme for current frame and search region)
1566
// Return 0 if can't skip
1567
0
static bool check_prehme_early_exit(MeContext* me_ctx, uint8_t list_i, uint8_t ref_i, uint8_t sr_i) {
1568
0
    SearchInfo* prehme_data = &me_ctx->prehme_data[list_i][ref_i][sr_i];
1569
1570
0
    if (me_ctx->me_early_exit_th) {
1571
0
        if (me_ctx->zz_sad[list_i][ref_i] < me_ctx->me_early_exit_th) {
1572
0
            prehme_data->best_mv.as_int = 0;
1573
0
            prehme_data->sad            = 0;
1574
0
            prehme_data->valid          = 1;
1575
0
            return 1;
1576
0
        }
1577
0
    }
1578
1579
0
    if (me_ctx->prehme_ctrl.l1_early_exit) {
1580
0
        if (list_i == 1 && me_ctx->prehme_data[0][ref_i][sr_i].valid &&
1581
0
            ((me_ctx->prehme_data[0][ref_i][sr_i].sad < (32 * 32)) ||
1582
0
             ((ABS(me_ctx->prehme_data[0][ref_i][sr_i].best_mv.x) < 16) &&
1583
0
              (ABS(me_ctx->prehme_data[0][ref_i][sr_i].best_mv.y) < 16)))) {
1584
0
            prehme_data->best_mv.x = -me_ctx->prehme_data[0][ref_i][sr_i].best_mv.x;
1585
0
            prehme_data->best_mv.y = -me_ctx->prehme_data[0][ref_i][sr_i].best_mv.y;
1586
0
            prehme_data->sad       = me_ctx->prehme_data[0][ref_i][sr_i].sad;
1587
0
            prehme_data->valid     = 1;
1588
0
            return 1;
1589
0
        }
1590
0
    }
1591
0
    return 0;
1592
0
}
1593
1594
/* Perform Pre-HME for one Block 64x64*/
1595
static void prehme_b64(PictureParentControlSet* pcs, uint32_t org_x, uint32_t org_y, MeContext* me_ctx,
1596
0
                       EbPictureBufferDesc* input_ptr) {
1597
0
    const uint32_t block_width  = me_ctx->b64_width;
1598
0
    const uint32_t block_height = me_ctx->b64_height;
1599
0
    uint32_t       best_sad     = MAX_U32;
1600
    // List Loop
1601
0
    for (int list_i = REF_LIST_0; list_i < me_ctx->num_of_list_to_search; ++list_i) {
1602
        // Ref Picture Loop
1603
0
        const uint8_t num_of_ref_pic_to_search = me_ctx->num_of_ref_pic_to_search[list_i];
1604
0
        for (uint8_t ref_i = 0; ref_i < num_of_ref_pic_to_search; ++ref_i) {
1605
0
            uint16_t             dist              = 0;
1606
0
            EbPictureBufferDesc* sixteenth_ref_pic = get_me_reference(
1607
0
                pcs, me_ctx, list_i, ref_i, 0, &dist, input_ptr->width, input_ptr->height);
1608
1609
0
            if (me_ctx->temporal_layer_index > 0 || list_i == 0) {
1610
0
                uint32_t hme_sr_factor = svt_aom_get_scaled_picture_distance(dist);
1611
1612
0
                for (uint8_t sr_i = 0; sr_i < SEARCH_REGION_COUNT; sr_i++) {
1613
0
                    if (check_prehme_early_exit(me_ctx, list_i, ref_i, sr_i)) {
1614
0
                        continue;
1615
0
                    }
1616
1617
0
                    SearchInfo* prehme_data = &me_ctx->prehme_data[list_i][ref_i][sr_i];
1618
0
                    if (!me_ctx->search_results[list_i][ref_i].do_ref) {
1619
0
                        prehme_data->best_mv.as_int = 0;
1620
0
                        prehme_data->sad            = MAX_U32;
1621
0
                        continue;
1622
0
                    }
1623
0
                    prehme_data->sa.width  = MIN((me_ctx->prehme_ctrl.prehme_sa_cfg[sr_i].sa_min.width * hme_sr_factor),
1624
0
                                                me_ctx->prehme_ctrl.prehme_sa_cfg[sr_i].sa_max.width);
1625
0
                    prehme_data->sa.height = MIN(
1626
0
                        (me_ctx->prehme_ctrl.prehme_sa_cfg[sr_i].sa_min.height * hme_sr_factor),
1627
0
                        me_ctx->prehme_ctrl.prehme_sa_cfg[sr_i].sa_max.height);
1628
1629
0
                    prehme_core(me_ctx,
1630
0
                                ((int16_t)org_x) >> 2,
1631
0
                                ((int16_t)org_y) >> 2,
1632
0
                                block_width >> 2,
1633
0
                                block_height >> 2,
1634
0
                                sixteenth_ref_pic,
1635
0
                                prehme_data);
1636
0
                    me_ctx->performed_phme[list_i][ref_i][sr_i] = 1;
1637
0
                }
1638
0
                uint32_t min_sad = (uint32_t)MIN(me_ctx->prehme_data[list_i][ref_i][0].sad,
1639
0
                                                 me_ctx->prehme_data[list_i][ref_i][1].sad);
1640
0
                best_sad         = MIN(best_sad, min_sad);
1641
0
            } else {
1642
                // PW: Does this account for base pictures
1643
0
                for (uint8_t sr_i = 0; sr_i < SEARCH_REGION_COUNT; sr_i++) {
1644
0
                    me_ctx->prehme_data[1][ref_i][sr_i].best_mv.x = -me_ctx->prehme_data[0][ref_i][sr_i].best_mv.x;
1645
0
                    me_ctx->prehme_data[1][ref_i][sr_i].best_mv.y = -me_ctx->prehme_data[0][ref_i][sr_i].best_mv.y;
1646
0
                    me_ctx->prehme_data[1][ref_i][sr_i].sad       = me_ctx->prehme_data[0][ref_i][sr_i].sad;
1647
0
                }
1648
0
            }
1649
0
        } // End ref pic loop
1650
0
    } // End list loop
1651
0
    if (!frame_is_boosted(pcs) && best_sad < me_ctx->me_hme_prune_ctrls.phme_sad_th) {
1652
0
        for (int list_i = REF_LIST_0; list_i < me_ctx->num_of_list_to_search; ++list_i) {
1653
0
            for (uint8_t ref_i = 0; ref_i < me_ctx->num_of_ref_pic_to_search[list_i]; ++ref_i) {
1654
0
                if (!me_ctx->search_results[list_i][ref_i].do_ref) {
1655
0
                    continue;
1656
0
                }
1657
0
                if (ref_i == 0) {
1658
0
                    continue;
1659
0
                }
1660
1661
0
                const uint32_t prhme_th   = me_ctx->me_hme_prune_ctrls.phme_sad_pct;
1662
0
                uint32_t       prehme_sad = (uint32_t)MIN(me_ctx->prehme_data[list_i][ref_i][0].sad,
1663
0
                                                    me_ctx->prehme_data[list_i][ref_i][1].sad);
1664
0
                if ((prehme_sad - best_sad) * 100 > (prhme_th * best_sad)) {
1665
0
                    me_ctx->search_results[list_i][ref_i].do_ref = 0;
1666
0
                }
1667
0
            }
1668
0
        }
1669
0
    }
1670
0
}
1671
1672
// Set the HME L0 search area.  Perform scaling based on list index and ref index.
1673
// HME L0 search area should be the same for each search region
1674
static void get_hme_l0_search_area(MeContext* me_ctx, uint8_t list_index, uint8_t ref_pic_index, uint16_t dist,
1675
0
                                   int16_t* sa_width, int16_t* sa_height) {
1676
    // Reduce HME search area for higher ref indices
1677
0
    if (me_ctx->me_sr_adjustment_ctrls.enable_me_sr_adjustment &&
1678
0
        me_ctx->me_sr_adjustment_ctrls.distance_based_hme_resizing) {
1679
0
        uint8_t is_hor   = 1;
1680
0
        uint8_t is_ver   = 1;
1681
0
        uint8_t is_still = 0;
1682
1683
0
        if (me_ctx->reduce_hme_l0_sr_th_min && me_ctx->reduce_hme_l0_sr_th_max) {
1684
0
            if (list_index || ref_pic_index) {
1685
0
                int16_t l0_mvx = me_ctx->x_hme_level0_search_center[0][0][0 /*quadrant-x*/][0 /*quadrant-y*/];
1686
0
                int16_t l0_mvy = me_ctx->y_hme_level0_search_center[0][0][0 /*quadrant-x*/][0 /*quadrant-y*/];
1687
1688
                // Determine whether the computed motion from list0/ref_index0 is in vertical or horizintal direction
1689
0
                is_ver   = ((ABS(l0_mvx) < me_ctx->reduce_hme_l0_sr_th_min) &&
1690
0
                          (ABS(l0_mvy) > me_ctx->reduce_hme_l0_sr_th_max));
1691
0
                is_hor   = ((ABS(l0_mvx) > me_ctx->reduce_hme_l0_sr_th_max) &&
1692
0
                          (ABS(l0_mvy) < me_ctx->reduce_hme_l0_sr_th_min));
1693
0
                is_still = ((ABS(l0_mvx) < (me_ctx->reduce_hme_l0_sr_th_min * 3)) &&
1694
0
                            (ABS(l0_mvy) < (me_ctx->reduce_hme_l0_sr_th_min * 3)));
1695
0
            }
1696
0
        }
1697
1698
0
        uint8_t x_offset = 1;
1699
0
        uint8_t y_offset = 1;
1700
0
        if (!is_ver) {
1701
0
            y_offset = 2;
1702
0
        }
1703
0
        if (!is_hor) {
1704
0
            x_offset = 2;
1705
0
        }
1706
1707
0
        if (me_ctx->me_sr_adjustment_ctrls.enable_me_sr_adjustment == 2) {
1708
0
            if (is_still) {
1709
0
                x_offset = 4;
1710
0
                y_offset = 4;
1711
0
            }
1712
0
        }
1713
1714
0
        me_ctx->hme_l0_sa.sa_min.width  = me_ctx->hme_l0_sa.sa_min.width / (x_offset + ref_pic_index);
1715
0
        me_ctx->hme_l0_sa.sa_min.height = me_ctx->hme_l0_sa.sa_min.height / (y_offset + ref_pic_index);
1716
0
        me_ctx->hme_l0_sa.sa_max.width  = me_ctx->hme_l0_sa.sa_max.width / (x_offset + ref_pic_index);
1717
0
        me_ctx->hme_l0_sa.sa_max.height = me_ctx->hme_l0_sa.sa_max.height / (y_offset + ref_pic_index);
1718
0
    }
1719
1720
0
    int32_t hme_sr_factor = svt_aom_get_scaled_picture_distance(dist);
1721
1722
    // Derive the search area width and height, rounding the width up to the nearest sixteenth
1723
0
    int16_t search_area_width  = me_ctx->hme_l0_sa.sa_min.width / me_ctx->num_hme_sa_w;
1724
0
    search_area_width          = (int16_t)MIN((((search_area_width * hme_sr_factor) + 15) & ~0x0F),
1725
0
                                     (((me_ctx->hme_l0_sa.sa_max.width / me_ctx->num_hme_sa_w) + 15) & ~0x0F));
1726
0
    int16_t search_area_height = me_ctx->hme_l0_sa.sa_min.height / me_ctx->num_hme_sa_h;
1727
0
    search_area_height         = (int16_t)MIN((search_area_height * hme_sr_factor),
1728
0
                                      me_ctx->hme_l0_sa.sa_max.height / me_ctx->num_hme_sa_h);
1729
1730
0
    *sa_width  = search_area_width;
1731
0
    *sa_height = search_area_height;
1732
0
}
1733
1734
//this functions returns the worst quadrant in terms of sad.
1735
//it is implemented w/o for loops to get away from a VS2022 compiler issue.
1736
//it then assumes a fixed quadrant sizes of 2 each direction.
1737
static void get_worst_quadrant(MeContext* me_ctx, uint32_t list_index, uint32_t ref_pic_index, uint8_t* best_w,
1738
0
                               uint8_t* best_h) {
1739
0
    if (me_ctx->num_hme_sa_w != 2 || me_ctx->num_hme_sa_h != 2) {
1740
0
        svt_aom_assert_err(0, "update other quadrant sizes");
1741
0
        return;
1742
0
    }
1743
0
    uint64_t max_sad = 0;
1744
1745
0
    if (me_ctx->hme_level0_sad[list_index][ref_pic_index][0][0] > max_sad) {
1746
0
        max_sad = me_ctx->hme_level0_sad[list_index][ref_pic_index][0][0];
1747
0
        *best_w = 0;
1748
0
        *best_h = 0;
1749
0
    }
1750
0
    if (me_ctx->hme_level0_sad[list_index][ref_pic_index][1][0] > max_sad) {
1751
0
        max_sad = me_ctx->hme_level0_sad[list_index][ref_pic_index][1][0];
1752
0
        *best_w = 1;
1753
0
        *best_h = 0;
1754
0
    }
1755
0
    if (me_ctx->hme_level0_sad[list_index][ref_pic_index][0][1] > max_sad) {
1756
0
        max_sad = me_ctx->hme_level0_sad[list_index][ref_pic_index][0][1];
1757
0
        *best_w = 0;
1758
0
        *best_h = 1;
1759
0
    }
1760
0
    if (me_ctx->hme_level0_sad[list_index][ref_pic_index][1][1] > max_sad) {
1761
0
        *best_w = 1;
1762
0
        *best_h = 1;
1763
0
    }
1764
0
}
1765
1766
/*******************************************
1767
 * performs hierarchical ME level 0 for one 64x64 block (uni-prediction only)
1768
 *******************************************/
1769
static void hme_level0_b64(PictureParentControlSet* pcs, uint32_t org_x, uint32_t org_y, MeContext* me_ctx,
1770
0
                           EbPictureBufferDesc* input_ptr) {
1771
0
    const uint32_t block_width  = me_ctx->b64_width;
1772
0
    const uint32_t block_height = me_ctx->b64_height;
1773
1774
    // store base HME sizes, to be used if using ref-index based HME resizing
1775
0
    SearchAreaMinMax base_hme_sa;
1776
0
    base_hme_sa.sa_min = (SearchArea){me_ctx->hme_l0_sa.sa_min.width, me_ctx->hme_l0_sa.sa_min.height};
1777
0
    base_hme_sa.sa_max = (SearchArea){me_ctx->hme_l0_sa.sa_max.width, me_ctx->hme_l0_sa.sa_max.height};
1778
1779
    // List Loop
1780
0
    const uint8_t num_of_list_to_search = me_ctx->num_of_list_to_search;
1781
0
    for (uint8_t list_index = REF_LIST_0; list_index < num_of_list_to_search; ++list_index) {
1782
        // Ref Picture Loop
1783
0
        const uint8_t num_of_ref_pic_to_search = me_ctx->num_of_ref_pic_to_search[list_index];
1784
0
        for (uint8_t ref_pic_index = 0; ref_pic_index < num_of_ref_pic_to_search; ++ref_pic_index) {
1785
            // If me_early_exit_th is enabled, skip HME L0 for the current block if the zero-zero SAD is low
1786
0
            if (me_ctx->me_early_exit_th) {
1787
0
                if (me_ctx->zz_sad[list_index][ref_pic_index] < (me_ctx->me_early_exit_th >> 2)) {
1788
0
                    for (uint32_t sr_idx_y = 0; sr_idx_y < me_ctx->num_hme_sa_h; sr_idx_y++) {
1789
0
                        for (uint32_t sr_idx_x = 0; sr_idx_x < me_ctx->num_hme_sa_w; sr_idx_x++) {
1790
0
                            me_ctx->x_hme_level0_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] = 0;
1791
0
                            me_ctx->y_hme_level0_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] = 0;
1792
0
                            me_ctx->hme_level0_sad[list_index][ref_pic_index][sr_idx_x][sr_idx_y]             = 0;
1793
0
                        }
1794
0
                    }
1795
0
                    continue;
1796
0
                }
1797
0
            }
1798
0
            if (me_ctx->prev_me_stage_based_exit_th) {
1799
0
                uint8_t sr_i = me_ctx->prehme_data[list_index][ref_pic_index][0].sad <=
1800
0
                        me_ctx->prehme_data[list_index][ref_pic_index][1].sad
1801
0
                    ? 0
1802
0
                    : 1;
1803
0
                if (me_ctx->performed_phme[list_index][ref_pic_index][sr_i]) {
1804
0
                    if (me_ctx->prehme_data[list_index][ref_pic_index][sr_i].sad <
1805
0
                        (me_ctx->prev_me_stage_based_exit_th >> 4)) {
1806
0
                        for (uint32_t sr_idx_y = 0; sr_idx_y < me_ctx->num_hme_sa_h; sr_idx_y++) {
1807
0
                            for (uint32_t sr_idx_x = 0; sr_idx_x < me_ctx->num_hme_sa_w; sr_idx_x++) {
1808
0
                                me_ctx->x_hme_level0_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] =
1809
0
                                    me_ctx->prehme_data[list_index][ref_pic_index][sr_i].best_mv.x;
1810
0
                                me_ctx->y_hme_level0_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] =
1811
0
                                    me_ctx->prehme_data[list_index][ref_pic_index][sr_i].best_mv.y;
1812
0
                                me_ctx->hme_level0_sad[list_index][ref_pic_index][sr_idx_x][sr_idx_y] =
1813
0
                                    me_ctx->prehme_data[list_index][ref_pic_index][sr_i].sad;
1814
0
                            }
1815
0
                        }
1816
0
                        continue;
1817
0
                    }
1818
0
                }
1819
0
            }
1820
1821
0
            if (!me_ctx->search_results[list_index][ref_pic_index].do_ref) {
1822
0
                for (uint32_t sr_idx_y = 0; sr_idx_y < me_ctx->num_hme_sa_h; sr_idx_y++) {
1823
0
                    for (uint32_t sr_idx_x = 0; sr_idx_x < me_ctx->num_hme_sa_w; sr_idx_x++) {
1824
0
                        me_ctx->x_hme_level0_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] = 0;
1825
0
                        me_ctx->y_hme_level0_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] = 0;
1826
0
                        me_ctx->hme_level0_sad[list_index][ref_pic_index][sr_idx_x][sr_idx_y]             = MAX_U32;
1827
0
                    }
1828
0
                }
1829
0
                continue;
1830
0
            }
1831
            // Get the sixteenth downsampled reference picture
1832
0
            uint16_t             dist              = 0;
1833
0
            EbPictureBufferDesc* sixteenth_ref_pic = get_me_reference(
1834
0
                pcs, me_ctx, list_index, ref_pic_index, 0, &dist, input_ptr->width, input_ptr->height);
1835
1836
0
            if (me_ctx->temporal_layer_index > 0 || list_index == 0) {
1837
                // Get the HME L0 search dimensions for the current frame
1838
0
                int16_t sa_width = 0, sa_height = 0;
1839
0
                get_hme_l0_search_area(me_ctx, list_index, ref_pic_index, dist, &sa_width, &sa_height);
1840
0
                for (uint8_t sr_h = 0; sr_h < me_ctx->num_hme_sa_h; sr_h++) {
1841
0
                    for (uint8_t sr_w = 0; sr_w < me_ctx->num_hme_sa_w; sr_w++) {
1842
0
                        hme_level_0(me_ctx,
1843
0
                                    ((int16_t)org_x) >> 2,
1844
0
                                    ((int16_t)org_y) >> 2,
1845
0
                                    block_width >> 2,
1846
0
                                    block_height >> 2,
1847
0
                                    sa_width,
1848
0
                                    sa_height,
1849
0
                                    sixteenth_ref_pic,
1850
0
                                    sr_w,
1851
0
                                    sr_h,
1852
0
                                    &(me_ctx->hme_level0_sad[list_index][ref_pic_index][sr_w][sr_h]),
1853
0
                                    &(me_ctx->x_hme_level0_search_center[list_index][ref_pic_index][sr_w][sr_h]),
1854
0
                                    &(me_ctx->y_hme_level0_search_center[list_index][ref_pic_index][sr_w][sr_h]));
1855
0
                    }
1856
0
                }
1857
1858
                // reset base HME area
1859
0
                if (me_ctx->me_sr_adjustment_ctrls.enable_me_sr_adjustment &&
1860
0
                    me_ctx->me_sr_adjustment_ctrls.distance_based_hme_resizing) {
1861
0
                    me_ctx->hme_l0_sa.sa_min = base_hme_sa.sa_min;
1862
0
                    me_ctx->hme_l0_sa.sa_max = base_hme_sa.sa_max;
1863
0
                }
1864
1865
0
                if (me_ctx->prehme_ctrl.enable) {
1866
                    //get the worst quadrant
1867
0
                    uint8_t sr_h_max = 0, sr_w_max = 0;
1868
0
                    get_worst_quadrant(me_ctx, list_index, ref_pic_index, &sr_w_max, &sr_h_max);
1869
1870
0
                    uint8_t sr_i = me_ctx->prehme_data[list_index][ref_pic_index][0].sad <=
1871
0
                            me_ctx->prehme_data[list_index][ref_pic_index][1].sad
1872
0
                        ? 0
1873
0
                        : 1;
1874
                    //replace worst with pre-hme
1875
0
                    if (me_ctx->prehme_data[list_index][ref_pic_index][sr_i].sad <
1876
0
                        me_ctx->hme_level0_sad[list_index][ref_pic_index][sr_w_max][sr_h_max]) {
1877
0
                        me_ctx->hme_level0_sad[list_index][ref_pic_index][sr_w_max][sr_h_max] =
1878
0
                            me_ctx->prehme_data[list_index][ref_pic_index][sr_i].sad;
1879
1880
0
                        me_ctx->x_hme_level0_search_center[list_index][ref_pic_index][sr_w_max][sr_h_max] =
1881
0
                            me_ctx->prehme_data[list_index][ref_pic_index][sr_i].best_mv.x;
1882
1883
0
                        me_ctx->y_hme_level0_search_center[list_index][ref_pic_index][sr_w_max][sr_h_max] =
1884
0
                            me_ctx->prehme_data[list_index][ref_pic_index][sr_i].best_mv.y;
1885
0
                    }
1886
0
                }
1887
0
            }
1888
0
        } // End ref pic loop
1889
0
    } // End list loop
1890
0
}
1891
1892
/*******************************************
1893
 * performs hierarchical ME level 1 for one 64x64 block (uni-prediction only)
1894
 *******************************************/
1895
static void hme_level1_b64(PictureParentControlSet* pcs, uint32_t org_x, uint32_t org_y, MeContext* me_ctx,
1896
0
                           EbPictureBufferDesc* input_ptr) {
1897
0
    const uint32_t block_width  = me_ctx->b64_width;
1898
0
    const uint32_t block_height = me_ctx->b64_height;
1899
1900
    // List Loop
1901
0
    const uint8_t num_of_list_to_search = me_ctx->num_of_list_to_search;
1902
0
    for (uint32_t list_index = REF_LIST_0; list_index < num_of_list_to_search; ++list_index) {
1903
        // Ref Picture Loop
1904
0
        const uint8_t num_of_ref_pic_to_search = me_ctx->num_of_ref_pic_to_search[list_index];
1905
0
        for (uint8_t ref_pic_index = 0; ref_pic_index < num_of_ref_pic_to_search; ++ref_pic_index) {
1906
0
            uint16_t             dist            = 0;
1907
0
            EbPictureBufferDesc* quarter_ref_pic = get_me_reference(
1908
0
                pcs, me_ctx, list_index, ref_pic_index, 1, &dist, input_ptr->width, input_ptr->height);
1909
1910
0
            if (me_ctx->temporal_layer_index > 0 || list_index == 0) {
1911
                // If me_early_exit_th is enabled, skip HME L0 for the current block if the zero-zero SAD is low
1912
0
                if (me_ctx->me_early_exit_th) {
1913
0
                    if (me_ctx->zz_sad[list_index][ref_pic_index] < (me_ctx->me_early_exit_th >> 2)) {
1914
0
                        for (uint32_t sr_idx_y = 0; sr_idx_y < me_ctx->num_hme_sa_h; sr_idx_y++) {
1915
0
                            for (uint32_t sr_idx_x = 0; sr_idx_x < me_ctx->num_hme_sa_w; sr_idx_x++) {
1916
0
                                me_ctx->x_hme_level1_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] = 0;
1917
0
                                me_ctx->y_hme_level1_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] = 0;
1918
0
                                me_ctx->hme_level1_sad[list_index][ref_pic_index][sr_idx_x][sr_idx_y]             = 0;
1919
0
                            }
1920
0
                        }
1921
0
                        continue;
1922
0
                    }
1923
0
                }
1924
0
                if (!me_ctx->search_results[list_index][ref_pic_index].do_ref) {
1925
0
                    for (uint32_t sr_idx_y = 0; sr_idx_y < me_ctx->num_hme_sa_h; sr_idx_y++) {
1926
0
                        for (uint32_t sr_idx_x = 0; sr_idx_x < me_ctx->num_hme_sa_w; sr_idx_x++) {
1927
0
                            me_ctx->x_hme_level1_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] = 0;
1928
0
                            me_ctx->y_hme_level1_search_center[list_index][ref_pic_index][sr_idx_x][sr_idx_y] = 0;
1929
0
                            me_ctx->hme_level1_sad[list_index][ref_pic_index][sr_idx_x][sr_idx_y]             = MAX_U32;
1930
0
                        }
1931
0
                    }
1932
0
                    continue;
1933
0
                }
1934
0
                for (uint8_t sr_h = 0; sr_h < me_ctx->num_hme_sa_h; sr_h++) {
1935
0
                    for (uint8_t sr_w = 0; sr_w < me_ctx->num_hme_sa_w; sr_w++) {
1936
0
                        if (me_ctx->prev_me_stage_based_exit_th) {
1937
0
                            if (me_ctx->hme_level0_sad[list_index][ref_pic_index][sr_w][sr_h] <
1938
0
                                (me_ctx->prev_me_stage_based_exit_th >> 5)) {
1939
0
                                me_ctx->x_hme_level1_search_center[list_index][ref_pic_index][sr_w][sr_h] =
1940
0
                                    me_ctx->x_hme_level0_search_center[list_index][ref_pic_index][sr_w][sr_h];
1941
0
                                me_ctx->y_hme_level1_search_center[list_index][ref_pic_index][sr_w][sr_h] =
1942
0
                                    me_ctx->y_hme_level0_search_center[list_index][ref_pic_index][sr_w][sr_h];
1943
0
                                me_ctx->hme_level1_sad[list_index][ref_pic_index][sr_w][sr_h] =
1944
0
                                    me_ctx->hme_level0_sad[list_index][ref_pic_index][sr_w][sr_h];
1945
0
                                continue;
1946
0
                            }
1947
0
                        }
1948
1949
0
                        hme_level_1(me_ctx,
1950
0
                                    ((int16_t)org_x) >> 1,
1951
0
                                    ((int16_t)org_y) >> 1,
1952
0
                                    block_width >> 1,
1953
0
                                    block_height >> 1,
1954
0
                                    quarter_ref_pic,
1955
0
                                    (int16_t)me_ctx->hme_l1_sa.width,
1956
0
                                    (int16_t)me_ctx->hme_l1_sa.height,
1957
0
                                    me_ctx->x_hme_level0_search_center[list_index][ref_pic_index][sr_w][sr_h] >> 1,
1958
0
                                    me_ctx->y_hme_level0_search_center[list_index][ref_pic_index][sr_w][sr_h] >> 1,
1959
0
                                    &(me_ctx->hme_level1_sad[list_index][ref_pic_index][sr_w][sr_h]),
1960
0
                                    &(me_ctx->x_hme_level1_search_center[list_index][ref_pic_index][sr_w][sr_h]),
1961
0
                                    &(me_ctx->y_hme_level1_search_center[list_index][ref_pic_index][sr_w][sr_h]));
1962
0
                    }
1963
0
                }
1964
0
            }
1965
0
        } // End ref pic loop
1966
0
    } // End list loop
1967
0
}
1968
1969
/*******************************************
1970
 * performs hierarchical ME level 2 for one 64x64 block (uni-prediction only)
1971
 *******************************************/
1972
static void hme_level2_b64(PictureParentControlSet* pcs, uint32_t org_x, uint32_t org_y, MeContext* me_ctx,
1973
0
                           EbPictureBufferDesc* input_ptr) {
1974
0
    const uint32_t block_width  = me_ctx->b64_width;
1975
0
    const uint32_t block_height = me_ctx->b64_height;
1976
    // List Loop
1977
0
    const uint8_t num_of_list_to_search = me_ctx->num_of_list_to_search;
1978
0
    for (int list_index = REF_LIST_0; list_index < num_of_list_to_search; ++list_index) {
1979
        // Ref Picture Loop
1980
0
        const uint8_t num_of_ref_pic_to_search = me_ctx->num_of_ref_pic_to_search[list_index];
1981
0
        for (uint8_t ref_pic_index = 0; ref_pic_index < num_of_ref_pic_to_search; ++ref_pic_index) {
1982
0
            uint16_t             dist    = 0;
1983
0
            EbPictureBufferDesc* ref_pic = get_me_reference(
1984
0
                pcs, me_ctx, list_index, ref_pic_index, 2, &dist, input_ptr->width, input_ptr->height);
1985
1986
0
            if (me_ctx->temporal_layer_index > 0 || list_index == 0) {
1987
0
                for (uint8_t sr_h = 0; sr_h < me_ctx->num_hme_sa_h; sr_h++) {
1988
0
                    for (uint8_t sr_w = 0; sr_w < me_ctx->num_hme_sa_w; sr_w++) {
1989
0
                        if (me_ctx->prev_me_stage_based_exit_th) {
1990
0
                            if (me_ctx->hme_level1_sad[list_index][ref_pic_index][sr_w][sr_h] <
1991
0
                                (me_ctx->prev_me_stage_based_exit_th >> 2)) {
1992
0
                                me_ctx->x_hme_level2_search_center[list_index][ref_pic_index][sr_w][sr_h] =
1993
0
                                    me_ctx->x_hme_level1_search_center[list_index][ref_pic_index][sr_w][sr_h];
1994
0
                                me_ctx->y_hme_level2_search_center[list_index][ref_pic_index][sr_w][sr_h] =
1995
0
                                    me_ctx->y_hme_level1_search_center[list_index][ref_pic_index][sr_w][sr_h];
1996
0
                                me_ctx->hme_level2_sad[list_index][ref_pic_index][sr_w][sr_h] =
1997
0
                                    me_ctx->hme_level1_sad[list_index][ref_pic_index][sr_w][sr_h];
1998
0
                                continue;
1999
0
                            }
2000
0
                        }
2001
2002
0
                        hme_level_2(me_ctx,
2003
0
                                    (int16_t)org_x,
2004
0
                                    (int16_t)org_y,
2005
0
                                    block_width,
2006
0
                                    block_height,
2007
0
                                    ref_pic,
2008
0
                                    (int16_t)me_ctx->hme_l2_sa.width,
2009
0
                                    (int16_t)me_ctx->hme_l2_sa.height,
2010
0
                                    me_ctx->x_hme_level1_search_center[list_index][ref_pic_index][sr_w][sr_h],
2011
0
                                    me_ctx->y_hme_level1_search_center[list_index][ref_pic_index][sr_w][sr_h],
2012
0
                                    &(me_ctx->hme_level2_sad[list_index][ref_pic_index][sr_w][sr_h]),
2013
0
                                    &(me_ctx->x_hme_level2_search_center[list_index][ref_pic_index][sr_w][sr_h]),
2014
0
                                    &(me_ctx->y_hme_level2_search_center[list_index][ref_pic_index][sr_w][sr_h]));
2015
0
                    }
2016
0
                }
2017
0
            }
2018
0
        } // End ref pic loop
2019
0
    } // End list loop
2020
0
}
2021
2022
/*******************************************
2023
 *   Set the final search centre
2024
 *******************************************/
2025
2026
0
void set_final_search_centre_sb(PictureParentControlSet* pcs, MeContext* me_ctx) {
2027
0
    UNUSED(pcs);
2028
    // Hierarchical ME Search Center
2029
0
    int16_t xHmeSearchCenter = 0;
2030
0
    int16_t yHmeSearchCenter = 0;
2031
2032
    // Final ME Search Center
2033
0
    int16_t x_search_center = 0;
2034
0
    int16_t y_search_center = 0;
2035
2036
    // Search Center SADs
2037
0
    uint64_t hmeMvSad = 0;
2038
0
    uint32_t num_of_list_to_search;
2039
0
    uint32_t list_index;
2040
0
    uint8_t  ref_pic_index;
2041
    // Configure HME level 0, level 1 and level 2 from static config parameters
2042
0
    bool enable_hme_level0_flag = me_ctx->enable_hme_level0_flag;
2043
0
    bool enable_hme_level1_flag = me_ctx->enable_hme_level1_flag;
2044
0
    bool enable_hme_level2_flag = me_ctx->enable_hme_level2_flag;
2045
2046
0
    uint64_t best_cost    = (uint64_t)~0;
2047
0
    me_ctx->best_list_idx = 0;
2048
0
    me_ctx->best_ref_idx  = 0;
2049
0
    num_of_list_to_search = me_ctx->num_of_list_to_search;
2050
2051
    // Uni-Prediction motion estimation loop
2052
    // List Loop
2053
0
    for (list_index = REF_LIST_0; list_index < num_of_list_to_search; ++list_index) {
2054
0
        uint8_t num_of_ref_pic_to_search = me_ctx->num_of_ref_pic_to_search[list_index];
2055
        // Ref Picture Loop
2056
0
        for (ref_pic_index = 0; ref_pic_index < num_of_ref_pic_to_search; ++ref_pic_index) {
2057
0
            if (me_ctx->temporal_layer_index > 0 || list_index == 0) {
2058
0
                if (me_ctx->enable_hme_flag) {
2059
                    // Hierarchical ME - Search Center
2060
0
                    if (enable_hme_level0_flag && !enable_hme_level1_flag && !enable_hme_level2_flag) {
2061
0
                        xHmeSearchCenter = me_ctx->x_hme_level0_search_center[list_index][ref_pic_index][0][0];
2062
0
                        yHmeSearchCenter = me_ctx->y_hme_level0_search_center[list_index][ref_pic_index][0][0];
2063
0
                        hmeMvSad         = me_ctx->hme_level0_sad[list_index][ref_pic_index][0][0];
2064
2065
0
                        uint32_t search_region_number_in_width  = 1;
2066
0
                        uint32_t search_region_number_in_height = 0;
2067
0
                        while (search_region_number_in_height < me_ctx->num_hme_sa_h) {
2068
0
                            while (search_region_number_in_width < me_ctx->num_hme_sa_w) {
2069
0
                                xHmeSearchCenter =
2070
0
                                    (me_ctx->hme_level0_sad[list_index][ref_pic_index][search_region_number_in_width]
2071
0
                                                           [search_region_number_in_height] < hmeMvSad)
2072
0
                                    ? me_ctx->x_hme_level0_search_center[list_index][ref_pic_index]
2073
0
                                                                        [search_region_number_in_width]
2074
0
                                                                        [search_region_number_in_height]
2075
0
                                    : xHmeSearchCenter;
2076
0
                                yHmeSearchCenter =
2077
0
                                    (me_ctx->hme_level0_sad[list_index][ref_pic_index][search_region_number_in_width]
2078
0
                                                           [search_region_number_in_height] < hmeMvSad)
2079
0
                                    ? me_ctx->y_hme_level0_search_center[list_index][ref_pic_index]
2080
0
                                                                        [search_region_number_in_width]
2081
0
                                                                        [search_region_number_in_height]
2082
0
                                    : yHmeSearchCenter;
2083
0
                                hmeMvSad =
2084
0
                                    (me_ctx->hme_level0_sad[list_index][ref_pic_index][search_region_number_in_width]
2085
0
                                                           [search_region_number_in_height] < hmeMvSad)
2086
0
                                    ? me_ctx->hme_level0_sad[list_index][ref_pic_index][search_region_number_in_width]
2087
0
                                                            [search_region_number_in_height]
2088
0
                                    : hmeMvSad;
2089
0
                                search_region_number_in_width++;
2090
0
                            }
2091
0
                            search_region_number_in_width = 0;
2092
0
                            search_region_number_in_height++;
2093
0
                        }
2094
0
                    }
2095
2096
0
                    if (enable_hme_level1_flag && !enable_hme_level2_flag) {
2097
0
                        xHmeSearchCenter = me_ctx->x_hme_level1_search_center[list_index][ref_pic_index][0][0];
2098
0
                        yHmeSearchCenter = me_ctx->y_hme_level1_search_center[list_index][ref_pic_index][0][0];
2099
0
                        hmeMvSad         = me_ctx->hme_level1_sad[list_index][ref_pic_index][0][0];
2100
2101
0
                        uint32_t search_region_number_in_width  = 1;
2102
0
                        uint32_t search_region_number_in_height = 0;
2103
0
                        while (search_region_number_in_height < me_ctx->num_hme_sa_h) {
2104
0
                            while (search_region_number_in_width < me_ctx->num_hme_sa_w) {
2105
0
                                xHmeSearchCenter =
2106
0
                                    (me_ctx->hme_level1_sad[list_index][ref_pic_index][search_region_number_in_width]
2107
0
                                                           [search_region_number_in_height] < hmeMvSad)
2108
0
                                    ? me_ctx->x_hme_level1_search_center[list_index][ref_pic_index]
2109
0
                                                                        [search_region_number_in_width]
2110
0
                                                                        [search_region_number_in_height]
2111
0
                                    : xHmeSearchCenter;
2112
0
                                yHmeSearchCenter =
2113
0
                                    (me_ctx->hme_level1_sad[list_index][ref_pic_index][search_region_number_in_width]
2114
0
                                                           [search_region_number_in_height] < hmeMvSad)
2115
0
                                    ? me_ctx->y_hme_level1_search_center[list_index][ref_pic_index]
2116
0
                                                                        [search_region_number_in_width]
2117
0
                                                                        [search_region_number_in_height]
2118
0
                                    : yHmeSearchCenter;
2119
0
                                hmeMvSad =
2120
0
                                    (me_ctx->hme_level1_sad[list_index][ref_pic_index][search_region_number_in_width]
2121
0
                                                           [search_region_number_in_height] < hmeMvSad)
2122
0
                                    ? me_ctx->hme_level1_sad[list_index][ref_pic_index][search_region_number_in_width]
2123
0
                                                            [search_region_number_in_height]
2124
0
                                    : hmeMvSad;
2125
0
                                search_region_number_in_width++;
2126
0
                            }
2127
0
                            search_region_number_in_width = 0;
2128
0
                            search_region_number_in_height++;
2129
0
                        }
2130
0
                    }
2131
2132
0
                    if (enable_hme_level2_flag) {
2133
0
                        xHmeSearchCenter = me_ctx->x_hme_level2_search_center[list_index][ref_pic_index][0][0];
2134
0
                        yHmeSearchCenter = me_ctx->y_hme_level2_search_center[list_index][ref_pic_index][0][0];
2135
0
                        hmeMvSad         = me_ctx->hme_level2_sad[list_index][ref_pic_index][0][0];
2136
2137
0
                        uint32_t search_region_number_in_width  = 1;
2138
0
                        uint32_t search_region_number_in_height = 0;
2139
0
                        while (search_region_number_in_height < me_ctx->num_hme_sa_h) {
2140
0
                            while (search_region_number_in_width < me_ctx->num_hme_sa_w) {
2141
0
                                xHmeSearchCenter =
2142
0
                                    (me_ctx->hme_level2_sad[list_index][ref_pic_index][search_region_number_in_width]
2143
0
                                                           [search_region_number_in_height] < hmeMvSad)
2144
0
                                    ? me_ctx->x_hme_level2_search_center[list_index][ref_pic_index]
2145
0
                                                                        [search_region_number_in_width]
2146
0
                                                                        [search_region_number_in_height]
2147
0
                                    : xHmeSearchCenter;
2148
0
                                yHmeSearchCenter =
2149
0
                                    (me_ctx->hme_level2_sad[list_index][ref_pic_index][search_region_number_in_width]
2150
0
                                                           [search_region_number_in_height] < hmeMvSad)
2151
0
                                    ? me_ctx->y_hme_level2_search_center[list_index][ref_pic_index]
2152
0
                                                                        [search_region_number_in_width]
2153
0
                                                                        [search_region_number_in_height]
2154
0
                                    : yHmeSearchCenter;
2155
0
                                hmeMvSad =
2156
0
                                    (me_ctx->hme_level2_sad[list_index][ref_pic_index][search_region_number_in_width]
2157
0
                                                           [search_region_number_in_height] < hmeMvSad)
2158
0
                                    ? me_ctx->hme_level2_sad[list_index][ref_pic_index][search_region_number_in_width]
2159
0
                                                            [search_region_number_in_height]
2160
0
                                    : hmeMvSad;
2161
0
                                search_region_number_in_width++;
2162
0
                            }
2163
0
                            search_region_number_in_width = 0;
2164
0
                            search_region_number_in_height++;
2165
0
                        }
2166
0
                    }
2167
2168
0
                    x_search_center = xHmeSearchCenter;
2169
0
                    y_search_center = yHmeSearchCenter;
2170
0
                }
2171
0
            } else {
2172
0
                x_search_center = 0;
2173
0
                y_search_center = 0;
2174
0
            }
2175
2176
            //sc valid for all cases. 0,0 if hme not done.
2177
0
            me_ctx->search_results[list_index][ref_pic_index].hme_sc_x = x_search_center;
2178
0
            me_ctx->search_results[list_index][ref_pic_index].hme_sc_y = y_search_center;
2179
2180
0
            me_ctx->search_results[list_index][ref_pic_index].hme_sad =
2181
0
                hmeMvSad; //this is not valid in all cases. only when HME is done, and when HMELevel2 is done
2182
            //also for base layer some references are redundant!!
2183
0
            if (hmeMvSad < best_cost) {
2184
0
                best_cost             = hmeMvSad;
2185
0
                me_ctx->best_list_idx = list_index;
2186
0
                me_ctx->best_ref_idx  = ref_pic_index;
2187
0
            }
2188
0
        }
2189
0
    }
2190
0
}
2191
2192
// Initialize zz SAD array
2193
0
static void init_zz_sad(PictureParentControlSet* pcs, MeContext* me_ctx, uint32_t org_x, uint32_t org_y) {
2194
0
    const uint32_t block_width  = me_ctx->b64_width;
2195
0
    const uint32_t block_height = me_ctx->b64_height;
2196
0
    uint32_t       best_zz_sad  = MAX_U32;
2197
    // List Loop
2198
0
    for (int list_i = REF_LIST_0; list_i < me_ctx->num_of_list_to_search; ++list_i) {
2199
        // Ref Picture Loop
2200
0
        for (uint8_t ref_i = 0; ref_i < me_ctx->num_of_ref_pic_to_search[list_i]; ++ref_i) {
2201
0
            if (me_ctx->temporal_layer_index > 0 || list_i == 0) {
2202
0
                EbPictureBufferDesc* ref_pic = me_ctx->me_ds_ref_array[list_i][ref_i].picture_ptr;
2203
0
                uint32_t             zz_sad  = get_zz_sad(ref_pic, me_ctx, org_x, org_y, block_width, block_height);
2204
                //normalize for incomplete b64
2205
0
                zz_sad                        = (zz_sad * 64 * 64) / (block_width * block_height);
2206
0
                me_ctx->zz_sad[list_i][ref_i] = zz_sad;
2207
0
                best_zz_sad                   = MIN(best_zz_sad, zz_sad);
2208
0
            }
2209
0
        }
2210
0
    }
2211
0
    const uint32_t zz_th = me_ctx->me_hme_prune_ctrls.zz_sad_th;
2212
0
    if (!frame_is_boosted(pcs) && best_zz_sad < zz_th) {
2213
0
        for (int list_i = REF_LIST_0; list_i < me_ctx->num_of_list_to_search; ++list_i) {
2214
0
            for (uint8_t ref_i = 0; ref_i < me_ctx->num_of_ref_pic_to_search[list_i]; ++ref_i) {
2215
0
                if (ref_i == 0) {
2216
0
                    continue;
2217
0
                }
2218
2219
0
                const uint32_t zz_sad_pct = me_ctx->me_hme_prune_ctrls.zz_sad_pct;
2220
0
                if ((me_ctx->zz_sad[list_i][ref_i] - best_zz_sad) * 100 > (zz_sad_pct * best_zz_sad)) {
2221
0
                    me_ctx->search_results[list_i][ref_i].do_ref = 0;
2222
0
                }
2223
0
            }
2224
0
        }
2225
0
    }
2226
2227
0
    const uint32_t safe_limit_zz_th = me_ctx->me_safe_limit_zz_th;
2228
0
    if (safe_limit_zz_th) {
2229
0
        bool me_safe_limit_refs = false;
2230
0
        if (pcs->hierarchical_levels > 0 && me_ctx->num_of_list_to_search == 2 && frame_is_leaf(pcs) &&
2231
0
            pcs->similar_brightness_refs && me_ctx->zz_sad[0][0] < safe_limit_zz_th &&
2232
0
            me_ctx->zz_sad[1][0] < safe_limit_zz_th) {
2233
0
            me_safe_limit_refs = true;
2234
0
        }
2235
2236
0
        for (int list_i = REF_LIST_0; list_i < me_ctx->num_of_list_to_search; ++list_i) {
2237
0
            for (uint8_t ref_i = 0; ref_i < me_ctx->num_of_ref_pic_to_search[list_i]; ++ref_i) {
2238
0
                if (me_safe_limit_refs && ref_i > 0) {
2239
0
                    me_ctx->search_results[list_i][ref_i].do_ref = 0;
2240
0
                }
2241
0
            }
2242
0
        }
2243
0
    }
2244
0
}
2245
2246
/*******************************************
2247
 * performs hierarchical ME for a 64x64 block for every ref frame
2248
 *******************************************/
2249
static void hme_b64(PictureParentControlSet* pcs, uint32_t org_x, uint32_t org_y, MeContext* me_ctx,
2250
0
                    EbPictureBufferDesc* input_ptr) {
2251
    // If needed, initialize the zz sad array
2252
0
    if (me_ctx->me_early_exit_th || me_ctx->me_safe_limit_zz_th) {
2253
0
        init_zz_sad(pcs, me_ctx, org_x, org_y);
2254
0
    }
2255
2256
0
    if (me_ctx->prehme_ctrl.enable) {
2257
        // perform pre-HME
2258
0
        prehme_b64(pcs, org_x, org_y, me_ctx, input_ptr);
2259
0
    }
2260
2261
0
    if (me_ctx->enable_hme_flag) {
2262
        // perform hierarchical ME level 0
2263
0
        if (me_ctx->enable_hme_level0_flag) {
2264
0
            hme_level0_b64(pcs, org_x, org_y, me_ctx, input_ptr);
2265
0
        }
2266
2267
        // perform hierarchical ME level 1
2268
0
        if (me_ctx->enable_hme_level1_flag) {
2269
0
            hme_level1_b64(pcs, org_x, org_y, me_ctx, input_ptr);
2270
0
        }
2271
2272
        // perform hierarchical ME level 2
2273
0
        if (me_ctx->enable_hme_level2_flag) {
2274
0
            hme_level2_b64(pcs, org_x, org_y, me_ctx, input_ptr);
2275
0
        }
2276
0
    }
2277
2278
    // Set final MV centre
2279
0
    set_final_search_centre_sb(pcs, me_ctx);
2280
2281
0
    if (me_ctx->me_type == ME_MCTF) {
2282
0
        if (ABS(me_ctx->search_results[0][0].hme_sc_x) > ABS(me_ctx->search_results[0][0].hme_sc_y)) {
2283
0
            me_ctx->tf_tot_horz_blks++;
2284
0
        } else {
2285
0
            me_ctx->tf_tot_vert_blks++;
2286
0
        }
2287
0
    }
2288
0
}
2289
2290
0
static void hme_prune_ref_and_adjust_sr(MeContext* me_ctx) {
2291
0
    uint16_t prune_ref_th = me_ctx->me_hme_prune_ctrls.prune_ref_if_hme_sad_dev_bigger_than_th;
2292
0
    if (me_ctx->me_hme_prune_ctrls.enable_me_hme_ref_pruning && (prune_ref_th != (uint16_t)~0)) {
2293
0
        uint64_t best = (uint64_t)~0;
2294
0
        for (int i = 0; i < MAX_NUM_OF_REF_PIC_LIST; ++i) {
2295
0
            for (int j = 0; j < REF_LIST_MAX_DEPTH; ++j) {
2296
0
                if (me_ctx->search_results[i][j].hme_sad < best) {
2297
0
                    best = me_ctx->search_results[i][j].hme_sad;
2298
0
                }
2299
0
            }
2300
0
        }
2301
        // Prune references based on HME sad
2302
0
        for (uint32_t li = 0; li < MAX_NUM_OF_REF_PIC_LIST; li++) {
2303
0
            for (uint32_t ri = 1; ri < REF_LIST_MAX_DEPTH; ri++) {
2304
0
                if ((me_ctx->search_results[li][ri].hme_sad - best) * 100 > (prune_ref_th * best)) {
2305
0
                    me_ctx->search_results[li][ri].do_ref = 0;
2306
0
                }
2307
0
            }
2308
0
        }
2309
0
    }
2310
0
    if (me_ctx->me_sr_adjustment_ctrls.enable_me_sr_adjustment) {
2311
0
        uint16_t mv_length_th              = me_ctx->me_sr_adjustment_ctrls.reduce_me_sr_based_on_mv_length_th;
2312
0
        uint16_t stationary_hme_sad_abs_th = me_ctx->me_sr_adjustment_ctrls.stationary_hme_sad_abs_th;
2313
0
        uint16_t reduce_me_sr_based_on_hme_sad_abs_th =
2314
0
            me_ctx->me_sr_adjustment_ctrls.reduce_me_sr_based_on_hme_sad_abs_th;
2315
        // Reduce the ME search region if the hme sad is low
2316
0
        for (uint32_t li = 0; li < MAX_NUM_OF_REF_PIC_LIST; li++) {
2317
0
            for (uint32_t ri = 0; ri < REF_LIST_MAX_DEPTH; ri++) {
2318
0
                if (ABS(me_ctx->search_results[li][ri].hme_sc_x) <= mv_length_th &&
2319
0
                    ABS(me_ctx->search_results[li][ri].hme_sc_y) <= mv_length_th &&
2320
0
                    me_ctx->search_results[li][ri].hme_sad < stationary_hme_sad_abs_th) {
2321
0
                    me_ctx->reduce_me_sr_divisor[li][ri] = me_ctx->me_sr_adjustment_ctrls.stationary_me_sr_divisor;
2322
0
                } else if (me_ctx->search_results[li][ri].hme_sad < reduce_me_sr_based_on_hme_sad_abs_th) {
2323
0
                    me_ctx->reduce_me_sr_divisor[li][ri] = me_ctx->me_sr_adjustment_ctrls.me_sr_divisor_for_low_hme_sad;
2324
0
                }
2325
0
            }
2326
0
        }
2327
0
    }
2328
0
}
2329
2330
static const uint8_t z_to_raster[85] = {
2331
    0,  1,  2,  3,  4,  5,  6,  9,  10, 7,  8,  11, 12, 13, 14, 17, 18, 15, 16, 19, 20, 21, 22, 29, 30, 23, 24, 31, 32,
2332
    37, 38, 45, 46, 39, 40, 47, 48, 25, 26, 33, 34, 27, 28, 35, 36, 41, 42, 49, 50, 43, 44, 51, 52, 53, 54, 61, 62, 55,
2333
    56, 63, 64, 69, 70, 77, 78, 71, 72, 79, 80, 57, 58, 65, 66, 59, 60, 67, 68, 73, 74, 81, 82, 75, 76, 83, 84};
2334
2335
static void construct_me_candidate_array_mrp_off(PictureParentControlSet* pcs, MeContext* me_ctx,
2336
0
                                                 uint32_t num_of_list_to_search, uint32_t sb_index) {
2337
    // This function should only be called if there is one ref frame in each list
2338
0
    assert(me_ctx->num_of_ref_pic_to_search[0] == 1);
2339
0
    assert(me_ctx->num_of_ref_pic_to_search[1] == 1);
2340
0
    const uint8_t ref_pic_idx = 0;
2341
2342
    // Set whether the reference from each list is allowed
2343
0
    uint8_t blk_do_ref_org[MAX_NUM_OF_REF_PIC_LIST];
2344
0
    blk_do_ref_org[REF_LIST_0] = me_ctx->search_results[REF_LIST_0][0].do_ref;
2345
0
    blk_do_ref_org[REF_LIST_1] = (num_of_list_to_search == 1) ? 0 : me_ctx->search_results[REF_LIST_1][0].do_ref;
2346
2347
0
    if (num_of_list_to_search < 2 || !me_ctx->search_results[REF_LIST_1][0].do_ref) {
2348
0
        num_of_list_to_search = 1;
2349
0
    }
2350
0
    const uint32_t me_prune_th = (blk_do_ref_org[0] && blk_do_ref_org[1]) ? me_ctx->prune_me_candidates_th : 0;
2351
2352
    // Set the count to 1 for all PUs using memset, which is faster than setting at the end of each loop.  The count will only need
2353
    // to be updated if both reference frames are allowed.
2354
0
    uint8_t number_of_pus = pcs->enable_me_16x16
2355
0
        ? pcs->enable_me_8x8 ? pcs->max_number_of_pus_per_sb : MAX_SB64_PU_COUNT_NO_8X8
2356
0
        : MAX_SB64_PU_COUNT_WO_16X16;
2357
0
    memset(pcs->pa_me_data->me_results[sb_index]->total_me_candidate_index, 1, number_of_pus);
2358
2359
0
    for (uint8_t n_idx = 0; n_idx < pcs->max_number_of_pus_per_sb; ++n_idx) {
2360
0
        const uint8_t pu_index       = z_to_raster[n_idx];
2361
0
        uint8_t       me_cand_offset = 0;
2362
2363
0
        uint8_t      use_me_pu          = pcs->enable_me_16x16 ? pcs->enable_me_8x8 || n_idx < MAX_SB64_PU_COUNT_NO_8X8
2364
0
                                                               : n_idx < MAX_SB64_PU_COUNT_WO_16X16;
2365
0
        MeCandidate* me_candidate_array = NULL;
2366
0
        if (use_me_pu) {
2367
0
            me_candidate_array =
2368
0
                &pcs->pa_me_data->me_results[sb_index]->me_candidate_array[pu_index * pcs->pa_me_data->max_cand];
2369
0
        }
2370
0
        uint8_t        blk_do_ref[MAX_NUM_OF_REF_PIC_LIST] = {blk_do_ref_org[REF_LIST_0], blk_do_ref_org[REF_LIST_1]};
2371
0
        const uint32_t best_me_dist                        = blk_do_ref_org[REF_LIST_0] && blk_do_ref_org[REF_LIST_1]
2372
0
                                   ? MIN(me_ctx->p_sb_best_sad[REF_LIST_0][ref_pic_idx][n_idx],
2373
0
                  me_ctx->p_sb_best_sad[REF_LIST_1][ref_pic_idx][n_idx])
2374
0
                                   : blk_do_ref_org[REF_LIST_0] ? me_ctx->p_sb_best_sad[REF_LIST_0][ref_pic_idx][n_idx]
2375
0
                                                                : me_ctx->p_sb_best_sad[REF_LIST_1][ref_pic_idx][n_idx];
2376
2377
0
        me_ctx->me_distortion[pu_index] = best_me_dist;
2378
0
        int8_t min_dist_list            = -1;
2379
        // If both refs have a candidate, use only the best one for unipred
2380
0
        if (me_ctx->use_best_unipred_cand_only && blk_do_ref[REF_LIST_0] && blk_do_ref[REF_LIST_1]) {
2381
0
            min_dist_list = me_ctx->p_sb_best_sad[REF_LIST_0][ref_pic_idx][n_idx] <
2382
0
                    me_ctx->p_sb_best_sad[REF_LIST_1][ref_pic_idx][n_idx]
2383
0
                ? 0
2384
0
                : 1;
2385
0
        }
2386
        // Unipred candidates
2387
0
        for (int list_index = REF_LIST_0;
2388
0
             (uint32_t)list_index < num_of_list_to_search && (use_me_pu || me_cand_offset == 0);
2389
0
             ++list_index) {
2390
            //ME was skipped, so do not add this Unipred candidate
2391
0
            if (blk_do_ref[list_index] == 0) {
2392
0
                continue;
2393
0
            }
2394
2395
0
            if (me_prune_th > 0) {
2396
0
                uint32_t current_to_best_dist_distance = (me_ctx->p_sb_best_sad[list_index][ref_pic_idx][n_idx] -
2397
0
                                                          best_me_dist) *
2398
0
                    100;
2399
0
                if (current_to_best_dist_distance > (best_me_dist * me_prune_th)) {
2400
0
                    blk_do_ref[list_index] = 0;
2401
0
                    continue;
2402
0
                }
2403
0
            }
2404
0
            if (min_dist_list != -1 && min_dist_list != list_index) {
2405
                // Need to save the MV in case bipred is injected
2406
0
                if (use_me_pu) {
2407
0
                    pcs->pa_me_data->me_results[sb_index]
2408
0
                        ->me_mv_array[pu_index * pcs->pa_me_data->max_refs +
2409
0
                                      (list_index ? pcs->pa_me_data->max_l0 : 0) + ref_pic_idx]
2410
0
                        .as_int = me_ctx->p_sb_best_mv[list_index][ref_pic_idx][n_idx];
2411
0
                }
2412
0
                continue;
2413
0
            }
2414
0
            if (use_me_pu) {
2415
0
                me_candidate_array[me_cand_offset].direction  = list_index;
2416
0
                me_candidate_array[me_cand_offset].ref_idx_l0 = ref_pic_idx;
2417
0
                me_candidate_array[me_cand_offset].ref_idx_l1 = ref_pic_idx;
2418
0
                me_candidate_array[me_cand_offset].ref0_list  = list_index == 0 ? list_index : 24;
2419
0
                me_candidate_array[me_cand_offset].ref1_list  = list_index == 1 ? list_index : 24;
2420
2421
0
                pcs->pa_me_data->me_results[sb_index]
2422
0
                    ->me_mv_array[pu_index * pcs->pa_me_data->max_refs + (list_index ? pcs->pa_me_data->max_l0 : 0) +
2423
0
                                  ref_pic_idx]
2424
0
                    .as_int = me_ctx->p_sb_best_mv[list_index][ref_pic_idx][n_idx];
2425
0
            }
2426
2427
0
            me_cand_offset++;
2428
0
        }
2429
2430
        // Can have up to one bipred cand (LAST ,BWD)
2431
0
        if (blk_do_ref[REF_LIST_0] && blk_do_ref[REF_LIST_1] && use_me_pu) {
2432
            // If get here, will have 3 candidates, since both unipred directions are valid
2433
0
            assert(num_of_list_to_search == 2);
2434
0
            me_candidate_array[me_cand_offset].direction  = BI_PRED;
2435
0
            me_candidate_array[me_cand_offset].ref_idx_l0 = ref_pic_idx;
2436
0
            me_candidate_array[me_cand_offset].ref_idx_l1 = ref_pic_idx;
2437
0
            me_candidate_array[me_cand_offset].ref0_list  = REFERENCE_PIC_LIST_0;
2438
0
            me_candidate_array[me_cand_offset].ref1_list  = REFERENCE_PIC_LIST_1;
2439
2440
            // store total me candidate count
2441
0
            pcs->pa_me_data->me_results[sb_index]->total_me_candidate_index[pu_index] = me_cand_offset + 1;
2442
0
        }
2443
0
    }
2444
0
}
2445
2446
static void construct_me_candidate_array_single_ref(PictureParentControlSet* pcs, MeContext* ctx,
2447
0
                                                    uint32_t num_of_list_to_search, uint32_t sb_index) {
2448
    // This function should only be called if there is one ref frame in list 0
2449
0
    assert(ctx->num_of_ref_pic_to_search[0] == 1);
2450
0
    assert(ctx->num_of_ref_pic_to_search[1] == 0);
2451
0
    const uint8_t ref_pic_idx = 0;
2452
2453
    // Set whether the reference from each list is allowed
2454
0
    uint8_t blk_do_ref = ctx->search_results[REF_LIST_0][0].do_ref;
2455
2456
0
    if (num_of_list_to_search < 2 || !ctx->search_results[REF_LIST_1][0].do_ref) {
2457
0
        num_of_list_to_search = 1;
2458
0
    }
2459
2460
    // Set the count to 1 for all PUs using memset, which is faster than setting at the end of each loop.  The count will only need
2461
    // to be updated if both reference frames are allowed.
2462
0
    uint8_t number_of_pus = pcs->enable_me_16x16
2463
0
        ? pcs->enable_me_8x8 ? pcs->max_number_of_pus_per_sb : MAX_SB64_PU_COUNT_NO_8X8
2464
0
        : MAX_SB64_PU_COUNT_WO_16X16;
2465
0
    memset(pcs->pa_me_data->me_results[sb_index]->total_me_candidate_index, 1, number_of_pus);
2466
2467
0
    for (uint8_t n_idx = 0; n_idx < pcs->max_number_of_pus_per_sb; ++n_idx) {
2468
0
        const uint8_t pu_index = z_to_raster[n_idx];
2469
2470
0
        uint8_t      use_me_pu          = pcs->enable_me_16x16 ? pcs->enable_me_8x8 || n_idx < MAX_SB64_PU_COUNT_NO_8X8
2471
0
                                                               : n_idx < MAX_SB64_PU_COUNT_WO_16X16;
2472
0
        MeCandidate* me_candidate_array = NULL;
2473
0
        if (use_me_pu) {
2474
0
            me_candidate_array =
2475
0
                &pcs->pa_me_data->me_results[sb_index]->me_candidate_array[pu_index * pcs->pa_me_data->max_cand];
2476
0
        }
2477
0
        ctx->me_distortion[pu_index] = ctx->p_sb_best_sad[REF_LIST_0][ref_pic_idx][n_idx];
2478
0
        ;
2479
2480
        //ME was skipped, so do not add this Unipred candidate
2481
0
        if (blk_do_ref == 0) {
2482
0
            continue;
2483
0
        }
2484
2485
0
        if (use_me_pu) {
2486
0
            me_candidate_array[0].direction  = REF_LIST_0;
2487
0
            me_candidate_array[0].ref_idx_l0 = ref_pic_idx;
2488
0
            me_candidate_array[0].ref_idx_l1 = ref_pic_idx;
2489
0
            me_candidate_array[0].ref0_list  = 0;
2490
0
            me_candidate_array[0].ref1_list  = 0;
2491
2492
0
            pcs->pa_me_data->me_results[sb_index]
2493
0
                ->me_mv_array[pu_index * pcs->pa_me_data->max_refs + ref_pic_idx]
2494
0
                .as_int = ctx->p_sb_best_mv[0][ref_pic_idx][n_idx];
2495
0
        }
2496
0
    }
2497
0
}
2498
2499
static void construct_me_candidate_array(PictureParentControlSet* pcs, MeContext* me_ctx,
2500
0
                                         uint32_t num_of_list_to_search, uint32_t sb_index) {
2501
0
    for (uint32_t n_idx = 0; n_idx < pcs->max_number_of_pus_per_sb; ++n_idx) {
2502
0
        uint8_t pu_index       = (n_idx > 4) ? z_to_raster[n_idx] : n_idx;
2503
0
        uint8_t me_cand_offset = 0;
2504
2505
0
        uint8_t      use_me_pu          = pcs->enable_me_16x16 ? pcs->enable_me_8x8 || n_idx < MAX_SB64_PU_COUNT_NO_8X8
2506
0
                                                               : n_idx < MAX_SB64_PU_COUNT_WO_16X16;
2507
0
        MeCandidate* me_candidate_array = NULL;
2508
0
        if (use_me_pu) {
2509
0
            me_candidate_array =
2510
0
                &pcs->pa_me_data->me_results[sb_index]->me_candidate_array[pu_index * pcs->pa_me_data->max_cand];
2511
0
        }
2512
0
        uint8_t        blk_do_ref[MAX_NUM_OF_REF_PIC_LIST][MAX_REF_IDX];
2513
0
        uint32_t       current_to_best_dist_distance;
2514
0
        const uint32_t me_prune_th  = me_ctx->prune_me_candidates_th; //to change to 32bit
2515
0
        uint32_t       best_me_dist = (uint32_t)~0;
2516
2517
        // Determine the best ME distortion
2518
0
        for (uint32_t list_index = REF_LIST_0; list_index < num_of_list_to_search; list_index++) {
2519
0
            const uint8_t num_of_ref_pic_to_search = me_ctx->num_of_ref_pic_to_search[list_index];
2520
0
            for (uint32_t ref_pic = 0; ref_pic < num_of_ref_pic_to_search; ref_pic++) {
2521
0
                blk_do_ref[list_index][ref_pic] = me_ctx->search_results[list_index][ref_pic].do_ref;
2522
0
                if (blk_do_ref[list_index][ref_pic] == 0) {
2523
0
                    continue;
2524
0
                }
2525
2526
0
                best_me_dist = me_ctx->p_sb_best_sad[list_index][ref_pic][n_idx] < best_me_dist
2527
0
                    ? me_ctx->p_sb_best_sad[list_index][ref_pic][n_idx]
2528
0
                    : best_me_dist;
2529
0
            }
2530
0
        }
2531
2532
0
        me_ctx->me_distortion[pu_index] = best_me_dist;
2533
        // Unipred candidates
2534
0
        for (uint32_t list_index = REF_LIST_0; list_index < num_of_list_to_search && (use_me_pu || me_cand_offset == 0);
2535
0
             ++list_index) {
2536
0
            const uint8_t num_of_ref_pic_to_search = me_ctx->num_of_ref_pic_to_search[list_index];
2537
2538
0
            for (uint32_t ref_pic_index = 0;
2539
0
                 (ref_pic_index < num_of_ref_pic_to_search) && (use_me_pu || (me_cand_offset == 0));
2540
0
                 ++ref_pic_index) {
2541
                //ME was skipped, so do not add this Unipred candidate
2542
0
                if (blk_do_ref[list_index][ref_pic_index] == 0) {
2543
0
                    continue;
2544
0
                }
2545
2546
0
                if (me_prune_th > 0) {
2547
0
                    current_to_best_dist_distance = (me_ctx->p_sb_best_sad[list_index][ref_pic_index][n_idx] -
2548
0
                                                     best_me_dist) *
2549
0
                        100;
2550
0
                    if (current_to_best_dist_distance > (best_me_dist * me_prune_th)) {
2551
0
                        blk_do_ref[list_index][ref_pic_index] = 0;
2552
0
                        continue;
2553
0
                    }
2554
0
                }
2555
0
                if (use_me_pu) {
2556
0
                    me_candidate_array[me_cand_offset].direction  = list_index;
2557
0
                    me_candidate_array[me_cand_offset].ref_idx_l0 = ref_pic_index;
2558
0
                    me_candidate_array[me_cand_offset].ref_idx_l1 = ref_pic_index;
2559
0
                    me_candidate_array[me_cand_offset].ref0_list  = list_index == 0 ? list_index : 24;
2560
0
                    me_candidate_array[me_cand_offset].ref1_list  = list_index == 1 ? list_index : 24;
2561
2562
0
                    pcs->pa_me_data->me_results[sb_index]
2563
0
                        ->me_mv_array[pu_index * pcs->pa_me_data->max_refs +
2564
0
                                      (list_index ? pcs->pa_me_data->max_l0 : 0) + ref_pic_index]
2565
0
                        .as_int = me_ctx->p_sb_best_mv[list_index][ref_pic_index][n_idx];
2566
0
                }
2567
0
                me_cand_offset++;
2568
0
            }
2569
0
        }
2570
0
        if (num_of_list_to_search == 2 && use_me_pu) {
2571
            // 1st set of BIPRED cand
2572
            // (LAST ,BWD), (LAST,ALT ), (LAST,ALT2 )
2573
            // (LAST2,BWD), (LAST2,ALT), (LAST2,ALT2)
2574
            // (LAST3,BWD), (LAST3,ALT), (LAST3,ALT2)
2575
            // (GOLD ,BWD), (GOLD,ALT ), (GOLD,ALT2 )
2576
0
            for (uint32_t first_list_ref_pict_idx = 0;
2577
0
                 first_list_ref_pict_idx < me_ctx->num_of_ref_pic_to_search[REF_LIST_0];
2578
0
                 first_list_ref_pict_idx++) {
2579
0
                for (uint32_t second_list_ref_pict_idx = 0;
2580
0
                     second_list_ref_pict_idx < me_ctx->num_of_ref_pic_to_search[REF_LIST_1];
2581
0
                     second_list_ref_pict_idx++) {
2582
0
                    if (pcs->scs->mrp_ctrls.only_l_bwd &&
2583
0
                        (first_list_ref_pict_idx > 0 || second_list_ref_pict_idx > 0)) {
2584
0
                        continue;
2585
0
                    }
2586
0
                    if (blk_do_ref[REF_LIST_0][first_list_ref_pict_idx] &&
2587
0
                        blk_do_ref[REF_LIST_1][second_list_ref_pict_idx]) {
2588
0
                        me_candidate_array[me_cand_offset].direction  = BI_PRED;
2589
0
                        me_candidate_array[me_cand_offset].ref_idx_l0 = first_list_ref_pict_idx;
2590
0
                        me_candidate_array[me_cand_offset].ref_idx_l1 = second_list_ref_pict_idx;
2591
0
                        me_candidate_array[me_cand_offset].ref0_list  = REFERENCE_PIC_LIST_0;
2592
0
                        me_candidate_array[me_cand_offset].ref1_list  = REFERENCE_PIC_LIST_1;
2593
0
                        me_cand_offset++;
2594
0
                    }
2595
0
                }
2596
0
            }
2597
0
            if (!pcs->scs->mrp_ctrls.only_l_bwd) {
2598
                // 2nd set of BIPRED cand: (LAST,LAST2) (LAST,LAST3) (LAST,GOLD)
2599
0
                for (uint32_t first_list_ref_pict_idx = 1;
2600
0
                     first_list_ref_pict_idx < me_ctx->num_of_ref_pic_to_search[REF_LIST_0];
2601
0
                     first_list_ref_pict_idx++) {
2602
0
                    if (blk_do_ref[REF_LIST_0][0] && blk_do_ref[REF_LIST_0][first_list_ref_pict_idx]) {
2603
0
                        me_candidate_array[me_cand_offset].direction  = BI_PRED;
2604
0
                        me_candidate_array[me_cand_offset].ref_idx_l0 = 0;
2605
0
                        me_candidate_array[me_cand_offset].ref_idx_l1 = first_list_ref_pict_idx;
2606
0
                        me_candidate_array[me_cand_offset].ref0_list  = REFERENCE_PIC_LIST_0;
2607
0
                        me_candidate_array[me_cand_offset].ref1_list  = REFERENCE_PIC_LIST_0;
2608
0
                        me_cand_offset++;
2609
0
                    }
2610
0
                }
2611
0
            }
2612
2613
            // 3rd set of BIPRED cand: (BWD, ALT)
2614
0
            if (!pcs->scs->mrp_ctrls.only_l_bwd) {
2615
0
                if (me_ctx->num_of_ref_pic_to_search[REF_LIST_1] == 3 && blk_do_ref[REF_LIST_1][0] &&
2616
0
                    blk_do_ref[REF_LIST_1][2]) {
2617
0
                    {
2618
0
                        me_candidate_array[me_cand_offset].direction  = BI_PRED;
2619
0
                        me_candidate_array[me_cand_offset].ref_idx_l0 = 0;
2620
0
                        me_candidate_array[me_cand_offset].ref_idx_l1 = 2;
2621
0
                        me_candidate_array[me_cand_offset].ref0_list  = REFERENCE_PIC_LIST_1;
2622
0
                        me_candidate_array[me_cand_offset].ref1_list  = REFERENCE_PIC_LIST_1;
2623
0
                        me_cand_offset++;
2624
0
                    }
2625
0
                }
2626
0
            }
2627
0
        }
2628
2629
        // store total me candidate count
2630
0
        if (use_me_pu) {
2631
0
            pcs->pa_me_data->me_results[sb_index]->total_me_candidate_index[pu_index] = me_cand_offset;
2632
0
        }
2633
0
    }
2634
0
}
2635
2636
// Active and stationary detection for global motion
2637
static void perform_gm_detection(
2638
    PictureParentControlSet* pcs, // input parameter, Picture Control Set Ptr
2639
    uint32_t                 sb_index, // input parameter, SB Index
2640
    MeContext*               me_ctx // input parameter, ME Context Ptr, used to store decimated/interpolated SB/SR
2641
0
) {
2642
0
    SequenceControlSet* scs = pcs->scs;
2643
0
    uint64_t            per_sig_cnt[MAX_NUM_OF_REF_PIC_LIST][REF_LIST_MAX_DEPTH][NUM_MV_COMPONENTS][NUM_MV_HIST];
2644
0
    uint64_t            tot_cnt = 0;
2645
0
    svt_memset(per_sig_cnt, 0, sizeof(per_sig_cnt));
2646
2647
0
    if (scs->input_resolution <= INPUT_SIZE_480p_RANGE) {
2648
0
        for (unsigned i = 0; i < 64; i++) {
2649
0
            uint8_t n_idx = 21 + i;
2650
0
            if (!pcs->enable_me_8x8) {
2651
0
                if (n_idx >= MAX_SB64_PU_COUNT_NO_8X8) {
2652
0
                    n_idx = me_idx_85_8x8_to_16x16_conversion[n_idx - MAX_SB64_PU_COUNT_NO_8X8];
2653
0
                }
2654
0
                if (!pcs->enable_me_16x16) {
2655
0
                    if (n_idx >= MAX_SB64_PU_COUNT_WO_16X16) {
2656
0
                        n_idx = me_idx_16x16_to_parent_32x32_conversion[n_idx - MAX_SB64_PU_COUNT_WO_16X16];
2657
0
                    }
2658
0
                }
2659
0
            }
2660
0
            MeCandidate* me_candidate = &(
2661
0
                pcs->pa_me_data->me_results[sb_index]->me_candidate_array[n_idx * pcs->pa_me_data->max_cand]);
2662
2663
0
            uint32_t list_index    = (me_candidate->direction == 0 || me_candidate->direction == 2)
2664
0
                   ? me_candidate->ref0_list
2665
0
                   : me_candidate->ref1_list;
2666
0
            uint32_t ref_pic_index = (me_candidate->direction == 0 || me_candidate->direction == 2)
2667
0
                ? me_candidate->ref_idx_l0
2668
0
                : me_candidate->ref_idx_l1;
2669
2670
            // Active block detection
2671
0
            const int active_th = 4;
2672
0
            int       mx        = _MVXT(me_ctx->p_sb_best_mv[list_index][ref_pic_index][n_idx]) * 4;
2673
0
            if (mx < -active_th) {
2674
0
                per_sig_cnt[list_index][ref_pic_index][0][0]++;
2675
0
            } else if (mx > active_th) {
2676
0
                per_sig_cnt[list_index][ref_pic_index][0][1]++;
2677
0
            }
2678
0
            int my = _MVYT(me_ctx->p_sb_best_mv[list_index][ref_pic_index][n_idx]) * 4;
2679
0
            if (my < -active_th) {
2680
0
                per_sig_cnt[list_index][ref_pic_index][1][0]++;
2681
0
            } else if (my > active_th) {
2682
0
                per_sig_cnt[list_index][ref_pic_index][1][1]++;
2683
0
            }
2684
2685
0
            tot_cnt++;
2686
0
        }
2687
0
    } else {
2688
0
        for (unsigned i = 0; i < 16; i++) {
2689
0
            uint8_t n_idx = 5 + i;
2690
0
            if (!pcs->enable_me_16x16) {
2691
0
                if (n_idx >= MAX_SB64_PU_COUNT_WO_16X16) {
2692
0
                    n_idx = me_idx_16x16_to_parent_32x32_conversion[n_idx - MAX_SB64_PU_COUNT_WO_16X16];
2693
0
                }
2694
0
            }
2695
0
            MeCandidate* me_candidate = &(
2696
0
                pcs->pa_me_data->me_results[sb_index]->me_candidate_array[n_idx * pcs->pa_me_data->max_cand]);
2697
2698
0
            uint32_t list_index    = (me_candidate->direction == 0 || me_candidate->direction == 2)
2699
0
                   ? me_candidate->ref0_list
2700
0
                   : me_candidate->ref1_list;
2701
0
            uint32_t ref_pic_index = (me_candidate->direction == 0 || me_candidate->direction == 2)
2702
0
                ? me_candidate->ref_idx_l0
2703
0
                : me_candidate->ref_idx_l1;
2704
2705
            // Active block detection
2706
0
            const int active_th = 32;
2707
0
            int       mx        = _MVXT(me_ctx->p_sb_best_mv[list_index][ref_pic_index][n_idx]) * 4;
2708
0
            if (mx < -active_th) {
2709
0
                per_sig_cnt[list_index][ref_pic_index][0][0]++;
2710
0
            } else if (mx > active_th) {
2711
0
                per_sig_cnt[list_index][ref_pic_index][0][1]++;
2712
0
            }
2713
0
            int my = _MVYT(me_ctx->p_sb_best_mv[list_index][ref_pic_index][n_idx]) * 4;
2714
0
            if (my < -active_th) {
2715
0
                per_sig_cnt[list_index][ref_pic_index][1][0]++;
2716
0
            } else if (my > active_th) {
2717
0
                per_sig_cnt[list_index][ref_pic_index][1][1]++;
2718
0
            }
2719
2720
0
            tot_cnt++;
2721
0
        }
2722
0
    }
2723
2724
0
    for (int l = 0; l < MAX_NUM_OF_REF_PIC_LIST; l++) {
2725
0
        for (int r = 0; r < REF_LIST_MAX_DEPTH; r++) {
2726
0
            for (int c = 0; c < NUM_MV_COMPONENTS; c++) {
2727
0
                for (int s = 0; s < NUM_MV_HIST; s++) {
2728
0
                    if (per_sig_cnt[l][r][c][s] > (tot_cnt / 2)) {
2729
0
                        pcs->rc_me_allow_gm[sb_index] = 1;
2730
0
                        break;
2731
0
                    }
2732
0
                }
2733
0
            }
2734
0
        }
2735
0
    }
2736
0
}
2737
2738
// Compute the distortion per block size based on the ME results
2739
static void compute_distortion(
2740
    PictureParentControlSet* pcs, // input parameter, Picture Control Set Ptr
2741
    uint32_t                 b64_index, // input parameter, B64 Index
2742
    MeContext*               me_ctx // input parameter, ME Context Ptr, used to store decimated/interpolated SB/SR
2743
0
) {
2744
0
    SequenceControlSet* scs = pcs->scs;
2745
    // Determine sb_64x64_me_class
2746
0
    B64Geom* b64_geom   = &pcs->b64_geom[b64_index];
2747
0
    uint32_t b64_size   = 64 * 64;
2748
0
    uint32_t dist_64x64 = 0, dist_32x32 = 0, dist_16x16 = 0, dist_8x8 = 0;
2749
2750
    // 64x64
2751
0
    { dist_64x64 = me_ctx->me_distortion[0]; }
2752
2753
    // 32x32
2754
0
    for (unsigned i = 0; i < 4; i++) {
2755
0
        dist_32x32 += me_ctx->me_distortion[1 + i];
2756
0
    }
2757
2758
    // 16x16
2759
0
    for (unsigned i = 0; i < 16; i++) {
2760
0
        dist_16x16 += me_ctx->me_distortion[5 + i];
2761
0
    }
2762
2763
    // 8x8
2764
0
    for (unsigned i = 0; i < 64; i++) {
2765
0
        dist_8x8 += me_ctx->me_distortion[21 + i];
2766
0
    }
2767
2768
0
    uint64_t mean_dist_8x8     = dist_8x8 / 64;
2769
0
    uint64_t sum_ofsq_dist_8x8 = 0;
2770
0
    for (unsigned i = 0; i < 64; i++) {
2771
0
        const int64_t diff = ((int64_t)me_ctx->me_distortion[21 + i] - (int64_t)mean_dist_8x8);
2772
0
        sum_ofsq_dist_8x8 += diff * diff;
2773
0
    }
2774
2775
0
    pcs->me_8x8_cost_variance[b64_index] = (uint32_t)(sum_ofsq_dist_8x8 / 64);
2776
    // Compute the sum of the distortion of all 16 16x16 (720 and above) and
2777
    // 64 8x8 (for lower resolutions) blocks in the SB
2778
0
    pcs->rc_me_distortion[b64_index] = (scs->input_resolution <= INPUT_SIZE_480p_RANGE) ? dist_8x8 : dist_16x16;
2779
0
    const uint32_t pix_num           = b64_geom->width * b64_geom->height;
2780
    // Normalize
2781
0
    pcs->me_64x64_distortion[b64_index] = (dist_64x64 * b64_size) / (pix_num);
2782
0
    pcs->me_32x32_distortion[b64_index] = (dist_32x32 * b64_size) / (pix_num);
2783
0
    pcs->me_16x16_distortion[b64_index] = (dist_16x16 * b64_size) / (pix_num);
2784
0
    pcs->me_8x8_distortion[b64_index]   = (dist_8x8 * b64_size) / (pix_num);
2785
0
}
2786
2787
// Initialize data used in ME/HME
2788
0
static INLINE void init_me_hme_data(MeContext* me_ctx) {
2789
    // Initialize HME search centres to 0
2790
0
    if (me_ctx->enable_hme_flag) {
2791
0
        svt_memset(me_ctx->x_hme_level0_search_center, 0, sizeof(me_ctx->x_hme_level0_search_center));
2792
0
        svt_memset(me_ctx->y_hme_level0_search_center, 0, sizeof(me_ctx->y_hme_level0_search_center));
2793
2794
0
        svt_memset(me_ctx->x_hme_level1_search_center, 0, sizeof(me_ctx->x_hme_level1_search_center));
2795
0
        svt_memset(me_ctx->y_hme_level1_search_center, 0, sizeof(me_ctx->y_hme_level1_search_center));
2796
2797
0
        svt_memset(me_ctx->x_hme_level2_search_center, 0, sizeof(me_ctx->x_hme_level2_search_center));
2798
0
        svt_memset(me_ctx->y_hme_level2_search_center, 0, sizeof(me_ctx->y_hme_level2_search_center));
2799
0
    }
2800
2801
    // R2R FIX: no winner integer MV is set in special case like initial p_sb_best_mv for overlay case,
2802
    // then it sends dirty p_sb_best_mv to MD, initializing it is necessary
2803
0
    svt_memset(me_ctx->p_sb_best_mv, 0, sizeof(me_ctx->p_sb_best_mv));
2804
2805
    //init hme results buffer
2806
0
    for (uint32_t li = 0; li < MAX_NUM_OF_REF_PIC_LIST; li++) {
2807
0
        for (uint32_t ri = 0; ri < REF_LIST_MAX_DEPTH; ri++) {
2808
0
            if (me_ctx->me_type != ME_MCTF) {
2809
0
                me_ctx->search_results[li][ri].list_i = li;
2810
0
            }
2811
0
            me_ctx->search_results[li][ri].ref_i   = ri;
2812
0
            me_ctx->search_results[li][ri].do_ref  = 1;
2813
0
            me_ctx->search_results[li][ri].hme_sad = MAX_U32;
2814
0
            me_ctx->reduce_me_sr_divisor[li][ri]   = 1;
2815
0
            me_ctx->zz_sad[li][ri]                 = (uint32_t)~0;
2816
0
            me_ctx->prehme_data[li][ri][0].valid   = 0;
2817
0
            me_ctx->prehme_data[li][ri][1].valid   = 0;
2818
0
        }
2819
0
    }
2820
0
    svt_memset(me_ctx->performed_phme, 0, sizeof(me_ctx->performed_phme));
2821
0
}
2822
2823
/*******************************************
2824
* motion_estimation
2825
*   performs ME on 64x64 blocks
2826
*******************************************/
2827
2828
// Early-exit path for static 64x64 blocks. If the list0/ref0 (0,0) SAD is
2829
// below me_ctx->me_static_b64_th, populate the minimal set of outputs that
2830
// downstream consumers (construct_me_candidate_array*, compute_distortion)
2831
// need and return true so the caller can skip init/HME/integer ME.
2832
0
static bool me_static_b64_bypass(MeContext* me_ctx, uint32_t b64_origin_x, uint32_t b64_origin_y) {
2833
0
    if (!me_ctx->me_static_b64_th) {
2834
0
        return false;
2835
0
    }
2836
2837
    // The bypass decision uses the list0/ref0 zero-motion SAD: if the block is static against the
2838
    // primary reference, skip the full ME pipeline (HME + integer search).
2839
0
    const uint32_t l0r0_raw = get_zz_sad(me_ctx->me_ds_ref_array[0][0].picture_ptr,
2840
0
                                         me_ctx,
2841
0
                                         b64_origin_x,
2842
0
                                         b64_origin_y,
2843
0
                                         me_ctx->b64_width,
2844
0
                                         me_ctx->b64_height);
2845
0
    if ((uint64_t)l0r0_raw * 64 * 64 >= (uint64_t)me_ctx->me_static_b64_th * me_ctx->b64_width * me_ctx->b64_height) {
2846
0
        return false;
2847
0
    }
2848
2849
    // Static block against list0/ref0. Fill the zero-MV ME result for list0/ref0 only, and disable
2850
    // every farther reference (do_ref = 0) so mode decision skips it entirely. This matches the
2851
    // optimization's intent -- the bypass exits ME for ALL references on a static block, not just
2852
    // ref0 -- while removing the non-determinism. The previous code filled only list0/ref0 and left
2853
    // the other ref slots holding a stale per-ref best-SAD from a previously processed b64;
2854
    // construct_me_candidate_array() consumed that for best-distortion / candidate pruning, and which
2855
    // b64s a thread picks up depends on ME segment scheduling, so the bitstream became thread-count /
2856
    // run dependent. With do_ref = 0 those slots are never read. do_ref is re-initialized to 1 for
2857
    // every reference by init_me_hme_data() at the top of each b64, so disabling it here is per-b64
2858
    // safe. The single-reference path is unchanged (no farther refs to disable).
2859
0
    const uint32_t zz_sad = (uint32_t)((uint64_t)l0r0_raw * 64 * 64 / (me_ctx->b64_width * me_ctx->b64_height));
2860
0
    me_ctx->zz_sad[0][0]                = zz_sad;
2861
0
    me_ctx->search_results[0][0].do_ref = 1;
2862
    // 64x64
2863
0
    me_ctx->p_sb_best_sad[0][0][RASTER_SCAN_CU_INDEX_64x64] = zz_sad;
2864
    // 32x32
2865
0
    const uint32_t sad32 = zz_sad >> 2;
2866
0
    for (int i = RASTER_SCAN_CU_INDEX_32x32_0; i <= RASTER_SCAN_CU_INDEX_32x32_3; i++) {
2867
0
        me_ctx->p_sb_best_sad[0][0][i] = sad32;
2868
0
    }
2869
    // 16x16
2870
0
    const uint32_t sad16 = zz_sad >> 4;
2871
0
    for (int i = RASTER_SCAN_CU_INDEX_16x16_0; i <= RASTER_SCAN_CU_INDEX_16x16_15; i++) {
2872
0
        me_ctx->p_sb_best_sad[0][0][i] = sad16;
2873
0
    }
2874
    // 8x8
2875
0
    const uint32_t sad8 = zz_sad >> 6;
2876
0
    for (int i = RASTER_SCAN_CU_INDEX_8x8_0; i < SQUARE_PU_COUNT; i++) {
2877
0
        me_ctx->p_sb_best_sad[0][0][i] = sad8;
2878
0
    }
2879
    // Disable every farther reference: do_ref = 0 => skipped in MD, stale SAD never read.
2880
0
    for (uint32_t list_index = REF_LIST_0; list_index < me_ctx->num_of_list_to_search; ++list_index) {
2881
0
        for (uint8_t ref_idx = 0; ref_idx < me_ctx->num_of_ref_pic_to_search[list_index]; ++ref_idx) {
2882
0
            if (list_index != 0 || ref_idx != 0)
2883
0
                me_ctx->search_results[list_index][ref_idx].do_ref = 0;
2884
0
        }
2885
0
    }
2886
0
    return true;
2887
0
}
2888
2889
EbErrorType svt_aom_motion_estimation_b64(
2890
    PictureParentControlSet* pcs, // input parameter, Picture Control Set Ptr
2891
    uint32_t                 b64_index, // input parameter, SB Index
2892
    uint32_t                 b64_origin_x, // input parameter, SB Origin X
2893
    uint32_t                 b64_origin_y, // input parameter, SB Origin X
2894
    MeContext*               me_ctx, // input parameter, ME Context Ptr, used to store decimated/interpolated SB/SR
2895
    EbPictureBufferDesc*     input_ptr) // input parameter, source Picture Ptr
2896
2897
0
{
2898
0
    EbErrorType return_error = EB_ErrorNone;
2899
2900
0
    uint32_t num_of_list_to_search = me_ctx->num_of_list_to_search;
2901
2902
    // input picture width and height might be disaligned after resizing
2903
    // we use aligned width and height to avoid disalignment of calculation
2904
    // of block size
2905
0
    uint16_t aligned_width  = (uint16_t)ALIGN_POWER_OF_TWO(input_ptr->width, 3);
2906
0
    uint16_t aligned_height = (uint16_t)ALIGN_POWER_OF_TWO(input_ptr->height, 3);
2907
0
    me_ctx->b64_width  = (aligned_width - b64_origin_x) < BLOCK_SIZE_64 ? aligned_width - b64_origin_x : BLOCK_SIZE_64;
2908
0
    me_ctx->b64_height = (aligned_height - b64_origin_y) < BLOCK_SIZE_64 ? aligned_height - b64_origin_y
2909
0
                                                                         : BLOCK_SIZE_64;
2910
2911
    //pruning of the references is not done for alt-ref / when HMeLevel2 not done
2912
0
    uint8_t prune_ref = me_ctx->enable_hme_flag && me_ctx->me_type != ME_MCTF;
2913
    // Initialize ME/HME buffers. This MUST run for every b64, including the static-b64 bypass
2914
    // below: init_me_hme_data zeroes the *entire* p_sb_best_mv across all lists/refs (the
2915
    // "R2R FIX" dirty-MV guard) and resets the per-ref search_results. The bypass only populates
2916
    // list0/ref0, so without this the other ref/list slots retain a stale MV from a previously
2917
    // processed b64, which can drive an out-of-bounds reference fetch in inter prediction
2918
    // (observed as a SIGSEGV in svt_av1_convolve_2d_copy_sr_neon on edge SBs at >=1080p RTC).
2919
0
    init_me_hme_data(me_ctx);
2920
0
    if (!me_static_b64_bypass(me_ctx, b64_origin_x, b64_origin_y)) {
2921
        // HME: Perform Hierarchical Motion Estimation for all reference frames for the current 64x64 block.
2922
0
        hme_b64(pcs, b64_origin_x, b64_origin_y, me_ctx, input_ptr);
2923
2924
0
        if (me_ctx->me_type == ME_MCTF && me_ctx->search_results[0][0].hme_sad < me_ctx->tf_me_exit_th) {
2925
0
            me_ctx->tf_use_pred_64x64_only_th = (uint8_t)~0;
2926
0
            return return_error;
2927
0
        }
2928
        // prune the reference frames based on the HME outputs.
2929
0
        if (prune_ref) {
2930
0
            hme_prune_ref_and_adjust_sr(me_ctx);
2931
0
        }
2932
        // Full pel: Perform the Integer Motion Estimation on the allowed reference frames.
2933
0
        integer_search_b64(pcs, me_ctx, b64_origin_x, b64_origin_y, input_ptr);
2934
2935
        // prune the reference frames
2936
0
        if (prune_ref && me_ctx->me_hme_prune_ctrls.enable_me_hme_ref_pruning) {
2937
0
            me_prune_ref(me_ctx);
2938
0
        }
2939
0
    }
2940
2941
0
    if (me_ctx->me_type != ME_MCTF) {
2942
0
        {
2943
0
            if (me_ctx->num_of_ref_pic_to_search[REF_LIST_0] == 1 &&
2944
0
                me_ctx->num_of_ref_pic_to_search[REF_LIST_1] == 0) {
2945
0
                construct_me_candidate_array_single_ref(pcs, me_ctx, num_of_list_to_search, b64_index);
2946
0
            } else if (me_ctx->num_of_ref_pic_to_search[REF_LIST_0] == 1 &&
2947
0
                       me_ctx->num_of_ref_pic_to_search[REF_LIST_1] == 1) {
2948
0
                construct_me_candidate_array_mrp_off(pcs, me_ctx, num_of_list_to_search, b64_index);
2949
0
            } else {
2950
0
                construct_me_candidate_array(pcs, me_ctx, num_of_list_to_search, b64_index);
2951
0
            }
2952
0
        }
2953
        // Save the distortion per block size
2954
0
        compute_distortion(pcs, b64_index, me_ctx);
2955
2956
        // Perform GM detection if GM is enabled
2957
0
        pcs->rc_me_allow_gm[b64_index] = 0;
2958
2959
0
        if (pcs->gm_ctrls.enabled) {
2960
0
            perform_gm_detection(pcs, b64_index, me_ctx);
2961
0
        }
2962
0
    }
2963
0
    return return_error;
2964
0
}