Coverage Report

Created: 2026-10-17 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/avm/av2/common/ccso.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, Alliance for Open Media. All rights reserved
3
 *
4
 * This source code is subject to the terms of the BSD 3-Clause Clear License
5
 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6
 * License was not distributed with this source code in the LICENSE file, you
7
 * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.  If the
8
 * Alliance for Open Media Patent License 1.0 was not distributed with this
9
 * source code in the PATENTS file, you can obtain it at
10
 * aomedia.org/license/patent-license/.
11
 */
12
13
#include <assert.h>
14
#include <math.h>
15
#include <string.h>
16
17
#include "config/avm_scale_rtcd.h"
18
19
#include "avm/avm_integer.h"
20
#include "av2/common/ccso.h"
21
#include "av2/common/reconinter.h"
22
#include "av2/common/av2_common_int.h"
23
24
// Derivation of CCSO unit size, ccso unit shall not across tile boundaries
25
int get_ccso_unit_size_log2_adaptive_tile(const AV2_COMMON *cm,
26
                                          int sb_size_log2,
27
2.77M
                                          int unit_size_log2) {
28
2.77M
  if (cm->seq_params.ccso_unit_matches_sb_size)
29
2.74M
    return sb_size_log2;
30
27.8k
  else if (cm->tiles.cols == 1 && cm->tiles.rows == 1)
31
6.41k
    return unit_size_log2;
32
21.3k
  int unit_size = unit_size_log2;
33
21.8k
  if (sb_size_log2 < unit_size_log2) {
34
21.8k
    int e2 = 0, e4 = 0;
35
177k
    for (int i = 0; i < cm->tiles.cols - 1; ++i) {
36
155k
      const int size =
37
155k
          cm->tiles.col_start_sb[i + 1] - cm->tiles.col_start_sb[i];
38
155k
      e2 += size & 1;
39
155k
      e4 += size & 3;
40
155k
    }
41
71.0k
    for (int i = 0; i < cm->tiles.rows - 1; ++i) {
42
49.1k
      const int size =
43
49.1k
          cm->tiles.row_start_sb[i + 1] - cm->tiles.row_start_sb[i];
44
49.1k
      e2 += size & 1;
45
49.1k
      e4 += size & 3;
46
49.1k
    }
47
21.8k
    if (e4 == 0)
48
742
      unit_size = AVMMIN(sb_size_log2 + 2, unit_size_log2);
49
21.1k
    else if (e2 == 0)
50
4.65k
      unit_size = AVMMIN(sb_size_log2 + 1, unit_size_log2);
51
16.4k
    else
52
16.4k
      unit_size = AVMMIN(sb_size_log2, unit_size_log2);
53
18.4E
  } else {
54
18.4E
    unit_size = sb_size_log2;
55
18.4E
  }
56
21.3k
  return unit_size;
57
2.77M
}
58
59
/* Pad the border of a frame */
60
void extend_ccso_border(const YV12_BUFFER_CONFIG *frame, uint16_t *buf,
61
142
                        const int d) {
62
142
  int s = frame->y_width + (CCSO_PADDING_SIZE << 1);
63
142
  int h = frame->y_height;
64
142
  int w = frame->y_width;
65
142
  uint16_t *p = &buf[d * s + d];
66
142k
  for (int y = 0; y < h; y++) {
67
851k
    for (int x = 0; x < d; x++) {
68
709k
      *(p - d + x) = p[0];
69
709k
      p[w + x] = p[w - 1];
70
709k
    }
71
141k
    p += s;
72
141k
  }
73
142
  p -= (s + d);
74
852
  for (int y = 0; y < d; y++) {
75
710
    memcpy(p + (y + 1) * s, p, sizeof(uint16_t) * (w + (d << 1)));
76
710
  }
77
142
  p -= ((h - 1) * s);
78
852
  for (int y = 0; y < d; y++) {
79
710
    memcpy(p - (y + 1) * s, p, sizeof(uint16_t) * (w + (d << 1)));
80
710
  }
81
142
}
82
83
void extend_ccso_tile_border(const int tile_height, const int tile_width,
84
                             const int tile_stride, uint16_t *buf,
85
165
                             const int d) {
86
165
  uint16_t *p = &buf[d * tile_stride + d];
87
96.6k
  for (int y = 0; y < tile_height; y++) {
88
578k
    for (int x = 0; x < d; x++) {
89
482k
      *(p - d + x) = p[0];
90
482k
      p[tile_width + x] = p[tile_width - 1];
91
482k
    }
92
96.4k
    p += tile_stride;
93
96.4k
  }
94
165
  p -= (tile_stride + d);
95
990
  for (int y = 0; y < d; y++) {
96
825
    memcpy(p + (y + 1) * tile_stride, p,
97
825
           sizeof(uint16_t) * (tile_width + (d << 1)));
98
825
  }
99
165
  p -= ((tile_height - 1) * tile_stride);
100
990
  for (int y = 0; y < d; y++) {
101
825
    memcpy(p - (y + 1) * tile_stride, p,
102
825
           sizeof(uint16_t) * (tile_width + (d << 1)));
103
825
  }
104
165
}
105
106
/* Derive the quantized index, later it can be used for retriving offset values
107
 * from the look-up table */
108
void cal_filter_support(int *rec_luma_idx, const uint16_t *rec_y,
109
                        const int quant_step_size, const int inv_quant_step,
110
686k
                        const int *rec_idx, const int edge_clf) {
111
686k
  if (edge_clf == 0) {
112
1.77M
    for (int i = 0; i < 2; i++) {
113
1.18M
      int d = rec_y[rec_idx[i]] - rec_y[0];
114
1.18M
      if (d > quant_step_size)
115
124k
        rec_luma_idx[i] = 2;
116
1.05M
      else if (d < inv_quant_step)
117
124k
        rec_luma_idx[i] = 0;
118
934k
      else
119
934k
        rec_luma_idx[i] = 1;
120
1.18M
    }
121
591k
  } else {  // if (edge_clf == 1)
122
284k
    for (int i = 0; i < 2; i++) {
123
189k
      int d = rec_y[rec_idx[i]] - rec_y[0];
124
189k
      if (d < inv_quant_step)
125
17.9k
        rec_luma_idx[i] = 0;
126
171k
      else
127
171k
        rec_luma_idx[i] = 1;
128
189k
    }
129
94.9k
  }
130
686k
}
131
132
/* Derive sample locations for CCSO */
133
void derive_ccso_sample_pos(int *rec_idx, const int ccso_stride,
134
367
                            const uint8_t ext_filter_support) {
135
  // Input sample locations for CCSO
136
  // 4 2 0 3 5
137
  // 6 1 x 1 6
138
  // 5 3 0 2 4
139
367
  assert(ext_filter_support < 7);
140
367
  if (ext_filter_support == 0) {
141
191
    rec_idx[0] = -1 * ccso_stride;
142
191
    rec_idx[1] = 1 * ccso_stride;
143
191
  } else if (ext_filter_support == 1) {
144
35
    rec_idx[0] = -1;
145
35
    rec_idx[1] = 1;
146
141
  } else if (ext_filter_support == 4) {
147
18
    rec_idx[0] = -ccso_stride - 2;
148
18
    rec_idx[1] = ccso_stride + 2;
149
123
  } else if (ext_filter_support == 5) {
150
7
    rec_idx[0] = ccso_stride - 2;
151
7
    rec_idx[1] = -ccso_stride + 2;
152
116
  } else if (ext_filter_support == 2) {
153
20
    rec_idx[0] = -1 * ccso_stride - 1;
154
20
    rec_idx[1] = 1 * ccso_stride + 1;
155
96
  } else if (ext_filter_support == 3) {
156
2
    rec_idx[0] = -1 * ccso_stride + 1;
157
2
    rec_idx[1] = 1 * ccso_stride - 1;
158
94
  } else {  // ext_filter_support == 6
159
94
    rec_idx[0] = 2;
160
94
    rec_idx[1] = -2;
161
94
  }
162
367
}
163
164
/* Derive rect area of a tile for CCSO process */
165
INLINE static AV2PixelRect av2_get_tile_rect_ccso(const TileInfo *tile_info,
166
                                                  const AV2_COMMON *cm,
167
266
                                                  MACROBLOCKD *xd, int is_uv) {
168
266
  AV2PixelRect r;
169
170
  // Calculate position in the Y plane
171
266
  r.left = tile_info->mi_col_start * MI_SIZE;
172
266
  r.right = tile_info->mi_col_end * MI_SIZE;
173
266
  r.top = tile_info->mi_row_start * MI_SIZE;
174
266
  r.bottom = tile_info->mi_row_end * MI_SIZE;
175
176
266
  const int frame_w = xd->plane[0].dst.width;
177
266
  const int frame_h = xd->plane[0].dst.height;
178
179
  // Make sure we don't fall off the bottom-right of the frame.
180
266
  r.right = AVMMIN(r.right, frame_w);
181
266
  r.bottom = AVMMIN(r.bottom, frame_h);
182
183
  // Convert to coordinates in the appropriate plane
184
266
  const int ss_x = is_uv && cm->seq_params.subsampling_x;
185
266
  const int ss_y = is_uv && cm->seq_params.subsampling_y;
186
187
266
  r.left = ROUND_POWER_OF_TWO(r.left, ss_x);
188
266
  r.right = ROUND_POWER_OF_TWO(r.right, ss_x);
189
266
  r.top = ROUND_POWER_OF_TWO(r.top, ss_y);
190
266
  r.bottom = ROUND_POWER_OF_TWO(r.bottom, ss_y);
191
192
266
  return r;
193
266
}
194
195
// Cross-component Sample Offset band offset only case.
196
void ccso_filter_block_hbd_wo_buf_bo_only_c(
197
    const uint16_t *src_y, uint16_t *dst_yuv, const int x, const int y,
198
    const int pic_width, const int pic_height, const int8_t *offset_buf,
199
    const int src_y_stride, const int dst_stride, const int y_uv_hscale,
200
    const int y_uv_vscale, const int max_val, const int blk_size_x,
201
0
    const int blk_size_y, const bool isSingleBand, const uint8_t shift_bits) {
202
0
  const int y_end = AVMMIN(pic_height - y, blk_size_y);
203
0
  const int x_end = AVMMIN(pic_width - x, blk_size_x);
204
0
  for (int y_start = 0; y_start < y_end; y_start++) {
205
0
    const int y_pos = y_start;
206
0
    for (int x_start = 0; x_start < x_end; x_start++) {
207
0
      const int x_pos = x + x_start;
208
0
      const int band_num = isSingleBand
209
0
                               ? 0
210
0
                               : src_y[(y_pos << y_uv_vscale) * src_y_stride +
211
0
                                       (x_pos << y_uv_hscale)] >>
212
0
                                     shift_bits;
213
0
      const int lut_idx_ext = (band_num << 4);
214
0
      const int offset_val = offset_buf[lut_idx_ext];
215
0
      dst_yuv[y_pos * dst_stride + x_pos] =
216
0
          clamp(offset_val + dst_yuv[y_pos * dst_stride + x_pos], 0, max_val);
217
0
    }
218
0
  }
219
0
}
220
221
void ccso_filter_block_hbd_wo_buf_c(
222
    const uint16_t *src_y, uint16_t *dst_yuv, const int x, const int y,
223
    const int pic_width, const int pic_height, int *src_cls,
224
    const int8_t *offset_buf, const int src_y_stride, const int dst_stride,
225
    const int y_uv_hscale, const int y_uv_vscale, const int thr,
226
    const int neg_thr, const int *src_loc, const int max_val,
227
    const int blk_size_x, const int blk_size_y, const bool isSingleBand,
228
103
    const uint8_t shift_bits, const int edge_clf, const uint8_t ccso_bo_only) {
229
103
  const int y_end = AVMMIN(pic_height - y, blk_size_y);
230
103
  const int x_end = AVMMIN(pic_width - x, blk_size_x);
231
5.37k
  for (int y_start = 0; y_start < y_end; y_start++) {
232
5.27k
    const int y_pos = y_start;
233
266k
    for (int x_start = 0; x_start < x_end; x_start++) {
234
261k
      const int x_pos = x + x_start;
235
261k
      if (!ccso_bo_only) {
236
0
        cal_filter_support(src_cls,
237
0
                           &src_y[(y_pos << y_uv_vscale) * src_y_stride +
238
0
                                  (x_pos << y_uv_hscale)],
239
0
                           thr, neg_thr, src_loc, edge_clf);
240
261k
      } else {
241
261k
        src_cls[0] = 0;
242
261k
        src_cls[1] = 0;
243
261k
      }
244
261k
      const int band_num = isSingleBand
245
261k
                               ? 0
246
261k
                               : src_y[(y_pos << y_uv_vscale) * src_y_stride +
247
4.08k
                                       (x_pos << y_uv_hscale)] >>
248
4.08k
                                     shift_bits;
249
261k
      const int lut_idx_ext = (band_num << 4) + (src_cls[0] << 2) + src_cls[1];
250
261k
      const int offset_val = offset_buf[lut_idx_ext];
251
261k
      dst_yuv[y_pos * dst_stride + x_pos] =
252
261k
          clamp(offset_val + dst_yuv[y_pos * dst_stride + x_pos], 0, max_val);
253
261k
    }
254
5.27k
  }
255
103
}
256
257
// If there is at-least 1 segment is lossless in a frame, we have
258
// to do 4x4 processing, because minimum lossless block can be 4x4
259
// size. Although, regardless the value of
260
// cm->features.has_lossless_segment, we can always do 4x4
261
// processing, however, for software optimization purpose we have
262
// used  full block processing for whole lossy frame.
263
void ccso_filter_block_hbd_wo_buf_4x4_c(
264
    AV2_COMMON *cm, const uint16_t *src_y, uint16_t *dst_yuv,
265
    int tile_col_start, int tile_row_start, const int x, const int y,
266
    const int pic_width, const int pic_height, int *src_cls,
267
    const int8_t *offset_buf, const int src_y_stride, const int dst_stride,
268
    const int y_uv_hscale, const int y_uv_vscale, const int thr,
269
    const int neg_thr, const int *src_loc, const int max_val,
270
    const int blk_size_x, const int blk_size_y, const bool isSingleBand,
271
    const uint8_t shift_bits, const int edge_clf, const uint8_t ccso_bo_only,
272
1.01k
    int plane) {
273
1.01k
  const CommonModeInfoParams *const mi_params = &cm->mi_params;
274
1.01k
  const int y_end = AVMMIN(pic_height - y, blk_size_y);
275
1.01k
  const int x_end = AVMMIN(pic_width - x, blk_size_x);
276
1.01k
  int min_b_size_x = (1 << MI_SIZE_LOG2) >> y_uv_hscale;
277
1.01k
  int min_b_size_y = (1 << MI_SIZE_LOG2) >> y_uv_vscale;
278
279
9.17k
  for (int y_start = 0; y_start < y_end; y_start += min_b_size_y) {
280
8.16k
    const int y_pos = y_start;
281
73.9k
    for (int x_start = 0; x_start < x_end; x_start += min_b_size_x) {
282
65.7k
      const int x_pos = x + x_start;
283
65.7k
      const int this_mi_row =
284
65.7k
          ((tile_row_start + y_pos + y) << y_uv_vscale) >> MI_SIZE_LOG2;
285
65.7k
      const int this_mi_col =
286
65.7k
          ((tile_col_start + x_pos) << y_uv_hscale) >> MI_SIZE_LOG2;
287
288
65.7k
      MB_MODE_INFO **this_mbmi_ptr = mi_params->mi_grid_base +
289
65.7k
                                     this_mi_row * mi_params->mi_stride +
290
65.7k
                                     this_mi_col;
291
65.7k
      MB_MODE_INFO **this_mbmi =
292
65.7k
          get_mi_location_from_collocated_mi(cm, this_mbmi_ptr, plane);
293
294
65.7k
      const int is_lossless =
295
65.7k
          cm->features.lossless_segment[this_mbmi[0]->segment_id];
296
65.7k
      if (!is_lossless) {
297
60.9k
        int j_max = AVMMIN(x_pos + min_b_size_x, x + x_start + x_end);
298
60.9k
        int i_max = AVMMIN(y_pos + min_b_size_y, y_end);
299
302k
        for (int i_pos_4x4 = y_pos; i_pos_4x4 < i_max; i_pos_4x4++) {
300
1.20M
          for (int j_pos_4x4 = x_pos; j_pos_4x4 < j_max; j_pos_4x4++) {
301
962k
            if (!ccso_bo_only) {
302
675k
              cal_filter_support(
303
675k
                  src_cls,
304
675k
                  &src_y[(i_pos_4x4 << y_uv_vscale) * src_y_stride +
305
675k
                         (j_pos_4x4 << y_uv_hscale)],
306
675k
                  thr, neg_thr, src_loc, edge_clf);
307
675k
            } else {
308
287k
              src_cls[0] = 0;
309
287k
              src_cls[1] = 0;
310
287k
            }
311
962k
            const int band_num =
312
962k
                isSingleBand ? 0
313
962k
                             : src_y[(i_pos_4x4 << y_uv_vscale) * src_y_stride +
314
287k
                                     (j_pos_4x4 << y_uv_hscale)] >>
315
287k
                                   shift_bits;
316
962k
            const int lut_idx_ext =
317
962k
                (band_num << 4) + (src_cls[0] << 2) + src_cls[1];
318
962k
            const int offset_val = offset_buf[lut_idx_ext];
319
962k
            dst_yuv[i_pos_4x4 * dst_stride + j_pos_4x4] =
320
962k
                clamp(offset_val + dst_yuv[i_pos_4x4 * dst_stride + j_pos_4x4],
321
962k
                      0, max_val);
322
962k
          }
323
241k
        }
324
60.9k
      }
325
65.7k
    }
326
8.16k
  }
327
1.01k
}
328
329
// Apply CCSO for each process block row
330
void av2_apply_ccso_filter_for_row(AV2_COMMON *cm, MACROBLOCKD *xd,
331
                                   const uint16_t *src_y, uint16_t *dst_yuv,
332
                                   int *src_loc, int *src_cls, int blk_row,
333
                                   int thr, int blk_size, int blk_size_proc,
334
                                   int blk_log2_x, int blk_log2_y,
335
                                   int unit_log2_x, int unit_log2_y,
336
2.27k
                                   int plane) {
337
2.27k
  const CommonModeInfoParams *const mi_params = &cm->mi_params;
338
2.27k
  const int src_y_stride = xd->plane[0].dst.width + (CCSO_PADDING_SIZE << 1);
339
2.27k
  const uint8_t max_band_log2 = cm->ccso_info.max_band_log2[plane];
340
2.27k
  const int dst_stride = xd->plane[plane].dst.stride;
341
2.27k
  const int pic_height = xd->plane[plane].dst.height;
342
2.27k
  const int pic_width = xd->plane[plane].dst.width;
343
2.27k
  const int neg_thr = thr * -1;
344
2.27k
  const bool is_single_band = !max_band_log2;
345
2.27k
  const uint8_t shift_bits = cm->seq_params.bit_depth - max_band_log2;
346
2.27k
  const int max_val = (1 << cm->seq_params.bit_depth) - 1;
347
2.27k
  const int edge_clf = cm->ccso_info.edge_clf[plane];
348
2.27k
  const int y_uv_hscale = xd->plane[plane].subsampling_x;
349
2.27k
  const int y_uv_vscale = xd->plane[plane].subsampling_y;
350
351
4.60k
  for (int blk_col = 0; blk_col < pic_width; blk_col += blk_size_proc) {
352
2.32k
    const int ccso_blk_idx =
353
2.32k
        (blk_size >> MI_SIZE_LOG2) * (blk_row >> blk_log2_y) *
354
2.32k
            mi_params->mi_stride +
355
2.32k
        (blk_size >> MI_SIZE_LOG2) * (blk_col >> blk_log2_x);
356
2.32k
    const bool use_ccso =
357
2.32k
        (plane == 0)   ? mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_y
358
2.32k
        : (plane == 1) ? mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_u
359
339
                       : mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_v;
360
2.32k
    if (!use_ccso) continue;
361
362
    // FPU level skip
363
1.20k
    const int x_mbmi = (blk_col >> unit_log2_x) << unit_log2_x;
364
1.20k
    const int y_mbmi = (blk_row >> unit_log2_y) << unit_log2_y;
365
1.20k
    const int mbmi_idx =
366
1.20k
        get_mi_grid_idx(mi_params, y_mbmi >> (MI_SIZE_LOG2 - y_uv_vscale),
367
1.20k
                        x_mbmi >> (MI_SIZE_LOG2 - y_uv_hscale));
368
1.20k
    const int use_ccso_local =
369
1.20k
        mi_params->mi_grid_base[mbmi_idx]->local_ccso_blk_flag;
370
1.20k
    if (!use_ccso_local) continue;
371
372
1.20k
    if (cm->bru.enabled &&
373
0
        mi_params->mi_grid_base[mbmi_idx]->sb_active_mode != BRU_ACTIVE_SB) {
374
0
      avm_internal_error(
375
0
          &cm->error, AVM_CODEC_ERROR,
376
0
          "Invalid BRU activity in CCSO: only active SB can be filtered");
377
0
      return;
378
0
    }
379
1.20k
    if (cm->bridge_frame_info.is_bridge_frame) {
380
0
      avm_internal_error(
381
0
          &cm->error, AVM_CODEC_ERROR,
382
0
          "Invalid Bridge frame activity in CCSO: can not be filtered");
383
0
      return;
384
0
    }
385
386
1.20k
    if (cm->features.has_lossless_segment) {
387
1.01k
      ccso_filter_block_hbd_wo_buf_4x4_c(
388
1.01k
          cm, src_y, dst_yuv, 0, 0, blk_col, blk_row, pic_width, pic_height,
389
1.01k
          src_cls, cm->ccso_info.filter_offset[plane], src_y_stride, dst_stride,
390
1.01k
          y_uv_hscale, y_uv_vscale, thr, neg_thr, src_loc, max_val,
391
1.01k
          blk_size_proc, blk_size_proc, is_single_band, shift_bits, edge_clf,
392
1.01k
          cm->ccso_info.ccso_bo_only[plane], plane);
393
1.01k
    } else {
394
184
      if (cm->ccso_info.ccso_bo_only[plane]) {
395
115
        ccso_filter_block_hbd_wo_buf_bo_only(
396
115
            src_y, dst_yuv, blk_col, blk_row, pic_width, pic_height,
397
115
            cm->ccso_info.filter_offset[plane], src_y_stride, dst_stride,
398
115
            y_uv_hscale, y_uv_vscale, max_val, blk_size_proc, blk_size_proc,
399
115
            is_single_band, shift_bits);
400
115
      } else {
401
69
        ccso_filter_block_hbd_wo_buf(
402
69
            src_y, dst_yuv, blk_col, blk_row, pic_width, pic_height, src_cls,
403
69
            cm->ccso_info.filter_offset[plane], src_y_stride, dst_stride,
404
69
            y_uv_hscale, y_uv_vscale, thr, neg_thr, src_loc, max_val,
405
69
            blk_size_proc, blk_size_proc, is_single_band, shift_bits, edge_clf,
406
69
            0);
407
69
      }
408
184
    }
409
1.20k
  }
410
2.27k
}
411
412
/* Apply CCSO on luma or chroma component when single or multiple bands are
413
 * applied */
414
void apply_ccso_filter(AV2_COMMON *cm, MACROBLOCKD *xd, int plane,
415
                       const uint16_t *src_y, uint16_t *dst_yuv, int dst_stride,
416
                       int proc_unit_log2, uint16_t thr, uint8_t filter_sup,
417
202
                       uint8_t max_band_log2, int edge_clf) {
418
202
  const int ccso_ext_stride = xd->plane[0].dst.width + (CCSO_PADDING_SIZE << 1);
419
202
  const int pic_height = xd->plane[plane].dst.height;
420
202
  int src_cls[2];
421
202
  int src_loc[2];
422
202
  const int y_uv_hscale = xd->plane[plane].subsampling_x;
423
202
  const int y_uv_vscale = xd->plane[plane].subsampling_y;
424
202
  derive_ccso_sample_pos(src_loc, ccso_ext_stride, filter_sup);
425
202
  const int ccso_blk_size = get_ccso_unit_size_log2_adaptive_tile(
426
202
      cm, cm->mib_size_log2 + MI_SIZE_LOG2, CCSO_BLK_SIZE);
427
202
  const int blk_log2 = ccso_blk_size;
428
202
  const int blk_size = 1 << blk_log2;
429
202
  const int blk_log2_x = blk_log2 - y_uv_hscale;
430
202
  const int blk_log2_y = blk_log2 - y_uv_vscale;
431
202
  src_y += CCSO_PADDING_SIZE * ccso_ext_stride + CCSO_PADDING_SIZE;
432
202
  const int unit_log2_x = AVMMIN(proc_unit_log2, blk_log2_x);
433
202
  const int unit_log2_y = AVMMIN(proc_unit_log2, blk_log2_y);
434
202
  const CommonModeInfoParams *const mi_params = &cm->mi_params;
435
202
  const uint8_t shift_bits = cm->seq_params.bit_depth - max_band_log2;
436
202
  const bool is_single_band = !max_band_log2;
437
202
  const int max_val = (1 << cm->seq_params.bit_depth) - 1;
438
202
  const int neg_thr = thr * -1;
439
202
  const int unit_size_x = 1 << unit_log2_x;
440
202
  const int unit_size_y = 1 << unit_log2_y;
441
202
  const int blk_size_x = 1 << blk_log2_x;
442
202
  const int blk_size_y = 1 << blk_log2_y;
443
202
  if (cm->seq_params.disable_loopfilters_across_tiles) {
444
165
    int tile_rows = cm->tiles.rows;
445
165
    int tile_cols = cm->tiles.cols;
446
165
    TileInfo tile_info_y;
447
165
    AV2PixelRect tile_rect_y;
448
330
    for (int tile_row = 0; tile_row < tile_rows; ++tile_row) {
449
165
      int tile_height = 0;
450
330
      for (int tile_col = 0; tile_col < tile_cols; ++tile_col) {
451
165
        av2_tile_init(&tile_info_y, cm, tile_row, tile_col);
452
165
        tile_rect_y = av2_get_tile_rect_ccso(&tile_info_y, cm, xd, 0);
453
454
165
        int tile_row_start = tile_rect_y.top;
455
165
        int tile_col_start = tile_rect_y.left;
456
165
        int tile_row_end = tile_rect_y.bottom;
457
165
        int tile_col_end = tile_rect_y.right;
458
165
        int tile_width = tile_col_end - tile_col_start;
459
165
        tile_height = tile_row_end - tile_row_start;
460
165
        const int ccso_ext_tile_stride = tile_width + (CCSO_PADDING_SIZE << 1);
461
165
        derive_ccso_sample_pos(src_loc, ccso_ext_tile_stride, filter_sup);
462
463
165
        uint16_t *ext_rec_tile_y = NULL;
464
        // const uint16_t *rec_y = cm->cur_frame->buf.y_buffer;
465
165
        ext_rec_tile_y = avm_malloc(sizeof(*ext_rec_tile_y) *
466
165
                                    (tile_height + (CCSO_PADDING_SIZE << 1)) *
467
165
                                    (tile_width + (CCSO_PADDING_SIZE << 1)));
468
96.6k
        for (int r = 0; r < tile_height; ++r) {
469
35.5M
          for (int c = 0; c < tile_width; ++c) {
470
35.4M
            ext_rec_tile_y[(r + CCSO_PADDING_SIZE) * ccso_ext_tile_stride + c +
471
35.4M
                           CCSO_PADDING_SIZE] =
472
35.4M
                src_y[(r + tile_row_start) * ccso_ext_stride +
473
35.4M
                      (c + tile_col_start)];
474
35.4M
          }
475
96.4k
        }
476
165
        extend_ccso_tile_border(tile_height, tile_width, ccso_ext_tile_stride,
477
165
                                ext_rec_tile_y, CCSO_PADDING_SIZE);
478
479
165
        uint16_t *src_tile_y = ext_rec_tile_y;
480
165
        src_tile_y +=
481
165
            CCSO_PADDING_SIZE * ccso_ext_tile_stride + CCSO_PADDING_SIZE;
482
165
        if (plane != 0) {
483
101
          TileInfo tile_info_uv;
484
101
          AV2PixelRect tile_rect_uv;
485
101
          av2_tile_init(&tile_info_uv, cm, tile_row, tile_col);
486
101
          tile_rect_uv = av2_get_tile_rect_ccso(&tile_info_uv, cm, xd, 1);
487
101
          tile_row_start = tile_rect_uv.top;
488
101
          tile_col_start = tile_rect_uv.left;
489
101
          tile_row_end = tile_rect_uv.bottom;
490
101
          tile_col_end = tile_rect_uv.right;
491
101
          tile_width = tile_col_end - tile_col_start;
492
101
          tile_height = tile_row_end - tile_row_start;
493
101
        }
494
165
        uint16_t *dst_tile_yuv = dst_yuv + tile_col_start;
495
1.18k
        for (int frame_pxl_y = tile_row_start; frame_pxl_y < tile_row_end;
496
1.01k
             frame_pxl_y += blk_size_y) {
497
3.88k
          for (int frame_pxl_x = tile_col_start; frame_pxl_x < tile_col_end;
498
2.86k
               frame_pxl_x += blk_size_x) {
499
            // int x = frame_pxl_x;
500
            // int y = frame_pxl_y;
501
2.86k
            int tile_pxl_x = frame_pxl_x - tile_col_start;
502
2.86k
            int tile_pxl_y = frame_pxl_y - tile_row_start;
503
504
2.86k
            const int ccso_blk_idx =
505
2.86k
                (blk_size >> MI_SIZE_LOG2) * (frame_pxl_y >> blk_log2_y) *
506
2.86k
                    mi_params->mi_stride +
507
2.86k
                (blk_size >> MI_SIZE_LOG2) * (frame_pxl_x >> blk_log2_x);
508
2.86k
            const bool use_ccso =
509
2.86k
                (plane == 0) ? mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_y
510
2.86k
                : (plane == 1)
511
1.70k
                    ? mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_u
512
1.70k
                    : mi_params->mi_grid_base[ccso_blk_idx]->ccso_blk_v;
513
2.86k
            if (!use_ccso) continue;
514
1.25k
            const uint16_t *src_unit_y = src_tile_y;
515
1.25k
            uint16_t *dst_unit_yuv = dst_tile_yuv;
516
1.25k
            const int y_end = AVMMIN(tile_row_end - frame_pxl_y, blk_size_y);
517
1.25k
            const int x_end = AVMMIN(tile_col_end - frame_pxl_x, blk_size_x);
518
2.52k
            for (int unit_y = 0; unit_y < y_end; unit_y += unit_size_y) {
519
2.53k
              for (int unit_x = 0; unit_x < x_end; unit_x += unit_size_x) {
520
                // FPU level skip
521
1.26k
                const int mbmi_idx = get_mi_grid_idx(
522
1.26k
                    mi_params,
523
1.26k
                    (frame_pxl_y + unit_y) >> (MI_SIZE_LOG2 - y_uv_vscale),
524
1.26k
                    (frame_pxl_x + unit_x) >> (MI_SIZE_LOG2 - y_uv_hscale));
525
1.26k
                const int use_ccso_local =
526
1.26k
                    mi_params->mi_grid_base[mbmi_idx]->local_ccso_blk_flag;
527
1.26k
                if (!use_ccso_local) {
528
0
                  continue;
529
0
                }
530
1.26k
                if (cm->bru.enabled &&
531
0
                    mi_params->mi_grid_base[mbmi_idx]->sb_active_mode !=
532
0
                        BRU_ACTIVE_SB) {
533
0
                  avm_internal_error(&cm->error, AVM_CODEC_ERROR,
534
0
                                     "Invalid BRU activity in CCSO: only "
535
0
                                     "active SB can be filtered");
536
0
                  return;
537
0
                }
538
1.26k
                if (cm->features.has_lossless_segment) {
539
0
                  ccso_filter_block_hbd_wo_buf_4x4_c(
540
0
                      cm, src_unit_y, dst_unit_yuv, tile_col_start,
541
0
                      tile_row_start, tile_pxl_x + unit_x, tile_pxl_y + unit_y,
542
0
                      tile_width, tile_height, src_cls,
543
0
                      cm->ccso_info.filter_offset[plane], ccso_ext_tile_stride,
544
0
                      dst_stride, y_uv_hscale, y_uv_vscale, thr, neg_thr,
545
0
                      src_loc, max_val, unit_size_x, unit_size_y,
546
0
                      is_single_band, shift_bits, edge_clf,
547
0
                      cm->ccso_info.ccso_bo_only[plane], plane);
548
1.26k
                } else {
549
1.26k
                  if (cm->ccso_info.ccso_bo_only[plane]) {
550
103
                    ccso_filter_block_hbd_wo_buf_c(
551
103
                        src_unit_y, dst_unit_yuv, tile_pxl_x + unit_x,
552
103
                        tile_pxl_y + unit_y, tile_width, tile_height, src_cls,
553
103
                        cm->ccso_info.filter_offset[plane],
554
103
                        ccso_ext_tile_stride, dst_stride, y_uv_hscale,
555
103
                        y_uv_vscale, thr, neg_thr, src_loc, max_val,
556
103
                        unit_size_x, unit_size_y, is_single_band, shift_bits,
557
103
                        edge_clf, cm->ccso_info.ccso_bo_only[plane]);
558
1.16k
                  } else {
559
1.16k
                    ccso_filter_block_hbd_wo_buf(
560
1.16k
                        src_unit_y, dst_unit_yuv, tile_pxl_x + unit_x,
561
1.16k
                        tile_pxl_y + unit_y, tile_width, tile_height, src_cls,
562
1.16k
                        cm->ccso_info.filter_offset[plane],
563
1.16k
                        ccso_ext_tile_stride, dst_stride, y_uv_hscale,
564
1.16k
                        y_uv_vscale, thr, neg_thr, src_loc, max_val,
565
1.16k
                        unit_size_x, unit_size_y, is_single_band, shift_bits,
566
1.16k
                        edge_clf, 0);
567
1.16k
                  }
568
1.26k
                }
569
1.26k
              }
570
1.26k
              dst_unit_yuv += (dst_stride << unit_log2_y);
571
1.26k
              src_unit_y +=
572
1.26k
                  (ccso_ext_tile_stride << (unit_log2_y + y_uv_vscale));
573
1.26k
            }
574
1.25k
          }
575
1.01k
          dst_tile_yuv += (dst_stride << blk_log2_y);
576
1.01k
          src_tile_y += (ccso_ext_tile_stride << (blk_log2_y + y_uv_vscale));
577
1.01k
        }
578
165
        avm_free(ext_rec_tile_y);
579
165
      }
580
165
      dst_yuv += (dst_stride * tile_height);
581
      // src_y += (ccso_ext_stride * (cm->tiles.height << (MI_SIZE_LOG2)));
582
165
    }
583
165
    return;
584
165
  }
585
37
  const int blk_log2_proc = CCSO_PROC_BLK_LOG2;
586
37
  const int blk_size_proc = 1 << blk_log2_proc;
587
2.30k
  for (int blk_row = 0; blk_row < pic_height; blk_row += blk_size_proc) {
588
2.27k
    av2_apply_ccso_filter_for_row(
589
2.27k
        cm, xd, src_y, dst_yuv, src_loc, src_cls, blk_row, thr, blk_size,
590
2.27k
        blk_size_proc, blk_log2_x, blk_log2_y, unit_log2_x, unit_log2_y, plane);
591
2.27k
    dst_yuv += dst_stride << blk_log2_proc;
592
2.27k
    src_y += ccso_ext_stride << (blk_log2_proc + y_uv_vscale);
593
2.27k
  }
594
37
}
595
596
/* Apply CCSO for one frame */
597
void ccso_frame(YV12_BUFFER_CONFIG *frame, AV2_COMMON *cm, MACROBLOCKD *xd,
598
142
                uint16_t *ext_rec_y) {
599
142
  const int num_planes = av2_num_planes(cm);
600
142
  av2_setup_dst_planes(xd->plane, frame, 0, 0, 0, num_planes, NULL);
601
602
566
  for (int plane = 0; plane < num_planes; plane++) {
603
424
    const int dst_stride = xd->plane[plane].dst.stride;
604
424
    const uint16_t quant_step_size = quant_sz[cm->ccso_info.scale_idx[plane]]
605
424
                                             [cm->ccso_info.quant_idx[plane]];
606
424
    if (cm->ccso_info.ccso_enable[plane]) {
607
202
      apply_ccso_filter(
608
202
          cm, xd, plane, ext_rec_y, &(xd->plane[plane].dst.buf)[0], dst_stride,
609
202
          cm->mib_size_log2 -
610
202
              AVMMAX(xd->plane[plane].subsampling_x,
611
202
                     xd->plane[plane].subsampling_y) +
612
202
              MI_SIZE_LOG2,
613
202
          quant_step_size, cm->ccso_info.ext_filter_support[plane],
614
202
          cm->ccso_info.max_band_log2[plane], cm->ccso_info.edge_clf[plane]);
615
202
    }
616
424
  }
617
142
}
618
619
// This function is to copy ccso filter parameters between frames when
620
// ccso_reuse is true.
621
void av2_copy_ccso_filters(CcsoInfo *to, CcsoInfo *from, int plane,
622
7.44k
                           bool frame_level, bool block_level, int sb_count) {
623
7.44k
  if (frame_level) {
624
7.44k
    memcpy(to->filter_offset[plane], from->filter_offset[plane],
625
7.44k
           sizeof(to->filter_offset[plane]));
626
7.44k
    to->quant_idx[plane] = from->quant_idx[plane];
627
7.44k
    to->ext_filter_support[plane] = from->ext_filter_support[plane];
628
7.44k
    to->edge_clf[plane] = from->edge_clf[plane];
629
7.44k
    to->ccso_bo_only[plane] = from->ccso_bo_only[plane];
630
7.44k
    to->max_band_log2[plane] = from->max_band_log2[plane];
631
7.44k
    to->scale_idx[plane] = from->scale_idx[plane];
632
7.44k
  }
633
634
7.44k
  if (block_level) {
635
0
    if (to->sb_filter_control[plane]) {
636
0
      memcpy(to->sb_filter_control[plane], from->sb_filter_control[plane],
637
0
             sizeof(*from->sb_filter_control[plane]) * sb_count);
638
0
    }
639
0
  }
640
641
7.44k
  to->ccso_enable[plane] = from->ccso_enable[plane];
642
7.44k
}