Coverage Report

Created: 2026-11-12 08:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/av1/encoder/context_tree.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3
 *
4
 * This source code is subject to the terms of the BSD 2 Clause License and
5
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
 * was not distributed with this source code in the LICENSE file, you can
7
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8
 * Media Patent License 1.0 was not distributed with this source code in the
9
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10
 */
11
12
#include "av1/encoder/context_tree.h"
13
#include "av1/encoder/encoder.h"
14
#include "av1/encoder/rd.h"
15
#include <assert.h>
16
17
void av1_copy_tree_context(PICK_MODE_CONTEXT *dst_ctx,
18
0
                           PICK_MODE_CONTEXT *src_ctx) {
19
0
  dst_ctx->mic = src_ctx->mic;
20
0
  dst_ctx->mbmi_ext_best = src_ctx->mbmi_ext_best;
21
22
0
  dst_ctx->num_4x4_blk = src_ctx->num_4x4_blk;
23
0
  dst_ctx->skippable = src_ctx->skippable;
24
#if CONFIG_INTERNAL_STATS
25
  dst_ctx->best_mode_index = src_ctx->best_mode_index;
26
#endif  // CONFIG_INTERNAL_STATS
27
28
0
  av1_copy_array(dst_ctx->tx_type_map, src_ctx->tx_type_map,
29
0
                 src_ctx->num_4x4_blk);
30
31
0
  dst_ctx->rd_stats = src_ctx->rd_stats;
32
0
  dst_ctx->rd_mode_is_ready = src_ctx->rd_mode_is_ready;
33
0
}
34
35
void av1_setup_shared_coeff_buffer(const SequenceHeader *const seq_params,
36
                                   PC_TREE_SHARED_BUFFERS *shared_bufs,
37
0
                                   struct aom_internal_error_info *error) {
38
0
  const int num_planes = seq_params->monochrome ? 1 : MAX_MB_PLANE;
39
0
  const int max_sb_square_y = 1 << num_pels_log2_lookup[seq_params->sb_size];
40
0
  const int max_sb_square_uv = max_sb_square_y >> (seq_params->subsampling_x +
41
0
                                                   seq_params->subsampling_y);
42
0
  for (int i = 0; i < num_planes; i++) {
43
0
    const int max_num_pix =
44
0
        (i == AOM_PLANE_Y) ? max_sb_square_y : max_sb_square_uv;
45
0
    AOM_CHECK_MEM_ERROR(error, shared_bufs->coeff_buf[i],
46
0
                        aom_memalign(32, max_num_pix * sizeof(tran_low_t)));
47
0
    AOM_CHECK_MEM_ERROR(error, shared_bufs->qcoeff_buf[i],
48
0
                        aom_memalign(32, max_num_pix * sizeof(tran_low_t)));
49
0
    AOM_CHECK_MEM_ERROR(error, shared_bufs->dqcoeff_buf[i],
50
0
                        aom_memalign(32, max_num_pix * sizeof(tran_low_t)));
51
0
  }
52
0
}
53
54
0
void av1_free_shared_coeff_buffer(PC_TREE_SHARED_BUFFERS *shared_bufs) {
55
0
  for (int i = 0; i < 3; i++) {
56
0
    aom_free(shared_bufs->coeff_buf[i]);
57
0
    aom_free(shared_bufs->qcoeff_buf[i]);
58
0
    aom_free(shared_bufs->dqcoeff_buf[i]);
59
0
    shared_bufs->coeff_buf[i] = NULL;
60
0
    shared_bufs->qcoeff_buf[i] = NULL;
61
0
    shared_bufs->dqcoeff_buf[i] = NULL;
62
0
  }
63
0
}
64
65
PICK_MODE_CONTEXT *av1_alloc_pmc(const struct AV1_COMP *const cpi,
66
                                 BLOCK_SIZE bsize,
67
0
                                 PC_TREE_SHARED_BUFFERS *shared_bufs) {
68
0
  const AV1_COMMON *const cm = &cpi->common;
69
0
  const int num_planes = av1_num_planes(cm);
70
0
  const int num_pix = block_size_wide[bsize] * block_size_high[bsize];
71
0
  const int num_blk = num_pix / 16;
72
73
  // Allocate PICK_MODE_CONTEXT and all sub-arrays (eobs, txb_entropy_ctx,
74
  // color_index_map, tx_type_map) in a single 32-byte aligned memory block to
75
  // avoid multiple aom_memalign/aom_free calls per partition context.
76
0
  const size_t ctx_sz = (sizeof(PICK_MODE_CONTEXT) + 31) & ~(size_t)31;
77
0
  const size_t eob_sz = (num_blk * sizeof(uint16_t) + 31) & ~(size_t)31;
78
0
  const size_t txb_ctx_sz =
79
0
      (num_blk * sizeof(ENTROPY_CONTEXT) + 31) & ~(size_t)31;
80
0
  const bool use_palette = (num_pix <= MAX_PALETTE_SQUARE) &&
81
0
                           cm->features.allow_screen_content_tools;
82
0
  const size_t pal_sz =
83
0
      use_palette ? ((num_pix * sizeof(uint8_t) + 31) & ~(size_t)31) : 0;
84
0
  const size_t tx_type_sz = num_blk * sizeof(uint8_t);
85
86
0
  const size_t total_sz = ctx_sz + (size_t)num_planes * (eob_sz + txb_ctx_sz) +
87
0
                          2 * pal_sz + tx_type_sz;
88
0
  uint8_t *raw = (uint8_t *)aom_memalign(32, total_sz);
89
0
  if (!raw) return NULL;
90
91
0
  PICK_MODE_CONTEXT *ctx = (PICK_MODE_CONTEXT *)raw;
92
0
  memset(ctx, 0, sizeof(*ctx));
93
0
  ctx->rd_mode_is_ready = 0;
94
0
  ctx->num_4x4_blk = num_blk;
95
96
0
  uint8_t *ptr = raw + ctx_sz;
97
0
  for (int i = 0; i < num_planes; ++i) {
98
0
    ctx->coeff[i] = shared_bufs->coeff_buf[i];
99
0
    ctx->qcoeff[i] = shared_bufs->qcoeff_buf[i];
100
0
    ctx->dqcoeff[i] = shared_bufs->dqcoeff_buf[i];
101
0
    ctx->eobs[i] = (uint16_t *)ptr;
102
0
    ptr += eob_sz;
103
0
    ctx->txb_entropy_ctx[i] = ptr;
104
0
    ptr += txb_ctx_sz;
105
0
  }
106
107
0
  if (use_palette) {
108
0
    ctx->color_index_map[0] = ptr;
109
0
    ptr += pal_sz;
110
0
    ctx->color_index_map[1] = ptr;
111
0
    ptr += pal_sz;
112
0
  } else {
113
0
    ctx->color_index_map[0] = NULL;
114
0
    ctx->color_index_map[1] = NULL;
115
0
  }
116
117
0
  ctx->tx_type_map = ptr;
118
0
  memset(ctx->tx_type_map, 0, tx_type_sz);
119
120
0
  av1_invalid_rd_stats(&ctx->rd_stats);
121
122
0
  return ctx;
123
0
}
124
125
0
void av1_reset_pmc(PICK_MODE_CONTEXT *ctx) {
126
0
  av1_zero_array(ctx->tx_type_map, ctx->num_4x4_blk);
127
0
  av1_invalid_rd_stats(&ctx->rd_stats);
128
0
}
129
130
0
void av1_free_pmc(PICK_MODE_CONTEXT *ctx, int num_planes) {
131
0
  (void)num_planes;
132
0
  if (ctx == NULL) return;
133
0
  aom_free(ctx);
134
0
}
135
136
0
PC_TREE *av1_alloc_pc_tree_node(BLOCK_SIZE bsize) {
137
0
  PC_TREE *pc_tree = aom_calloc(1, sizeof(*pc_tree));
138
0
  if (pc_tree == NULL) return NULL;
139
140
0
  pc_tree->partitioning = PARTITION_NONE;
141
0
  pc_tree->block_size = bsize;
142
143
0
  return pc_tree;
144
0
}
145
146
#define FREE_PMC_NODE(CTX)         \
147
0
  do {                             \
148
0
    av1_free_pmc(CTX, num_planes); \
149
0
    CTX = NULL;                    \
150
0
  } while (0)
151
152
void av1_free_pc_tree_recursive(PC_TREE *pc_tree, int num_planes, int keep_best,
153
                                int keep_none,
154
0
                                PARTITION_SEARCH_TYPE partition_search_type) {
155
0
  if (pc_tree == NULL) return;
156
157
  // Avoid freeing of extended partitions as they are not supported when
158
  // partition_search_type is VAR_BASED_PARTITION.
159
0
  if (partition_search_type == VAR_BASED_PARTITION && !keep_best &&
160
0
      !keep_none) {
161
0
    FREE_PMC_NODE(pc_tree->none);
162
163
0
    for (int i = 0; i < 2; ++i) {
164
0
      FREE_PMC_NODE(pc_tree->horizontal[i]);
165
0
      FREE_PMC_NODE(pc_tree->vertical[i]);
166
0
    }
167
168
0
#if !defined(NDEBUG) && !CONFIG_REALTIME_ONLY
169
0
    for (int i = 0; i < 3; ++i) {
170
0
      assert(pc_tree->horizontala[i] == NULL);
171
0
      assert(pc_tree->horizontalb[i] == NULL);
172
0
      assert(pc_tree->verticala[i] == NULL);
173
0
      assert(pc_tree->verticalb[i] == NULL);
174
0
    }
175
0
    for (int i = 0; i < 4; ++i) {
176
0
      assert(pc_tree->horizontal4[i] == NULL);
177
0
      assert(pc_tree->vertical4[i] == NULL);
178
0
    }
179
0
#endif
180
181
0
    for (int i = 0; i < 4; ++i) {
182
0
      if (pc_tree->split[i] != NULL) {
183
0
        av1_free_pc_tree_recursive(pc_tree->split[i], num_planes, 0, 0,
184
0
                                   partition_search_type);
185
0
        pc_tree->split[i] = NULL;
186
0
      }
187
0
    }
188
0
    aom_free(pc_tree);
189
0
    return;
190
0
  }
191
192
0
  const PARTITION_TYPE partition = pc_tree->partitioning;
193
194
0
  if (!keep_none && (!keep_best || (partition != PARTITION_NONE)))
195
0
    FREE_PMC_NODE(pc_tree->none);
196
197
0
  for (int i = 0; i < 2; ++i) {
198
0
    if (!keep_best || (partition != PARTITION_HORZ))
199
0
      FREE_PMC_NODE(pc_tree->horizontal[i]);
200
0
    if (!keep_best || (partition != PARTITION_VERT))
201
0
      FREE_PMC_NODE(pc_tree->vertical[i]);
202
0
  }
203
0
#if !CONFIG_REALTIME_ONLY
204
0
  for (int i = 0; i < 3; ++i) {
205
0
    if (!keep_best || (partition != PARTITION_HORZ_A))
206
0
      FREE_PMC_NODE(pc_tree->horizontala[i]);
207
0
    if (!keep_best || (partition != PARTITION_HORZ_B))
208
0
      FREE_PMC_NODE(pc_tree->horizontalb[i]);
209
0
    if (!keep_best || (partition != PARTITION_VERT_A))
210
0
      FREE_PMC_NODE(pc_tree->verticala[i]);
211
0
    if (!keep_best || (partition != PARTITION_VERT_B))
212
0
      FREE_PMC_NODE(pc_tree->verticalb[i]);
213
0
  }
214
0
  for (int i = 0; i < 4; ++i) {
215
0
    if (!keep_best || (partition != PARTITION_HORZ_4))
216
0
      FREE_PMC_NODE(pc_tree->horizontal4[i]);
217
0
    if (!keep_best || (partition != PARTITION_VERT_4))
218
0
      FREE_PMC_NODE(pc_tree->vertical4[i]);
219
0
  }
220
0
#endif
221
0
  if (!keep_best || (partition != PARTITION_SPLIT)) {
222
0
    for (int i = 0; i < 4; ++i) {
223
0
      if (pc_tree->split[i] != NULL) {
224
0
        av1_free_pc_tree_recursive(pc_tree->split[i], num_planes, 0, 0,
225
0
                                   partition_search_type);
226
0
        pc_tree->split[i] = NULL;
227
0
      }
228
0
    }
229
0
  }
230
231
0
  if (!keep_best && !keep_none) aom_free(pc_tree);
232
0
}
233
234
0
int av1_setup_sms_tree(AV1_COMP *const cpi, ThreadData *td) {
235
  // The structure 'sms_tree' is used to store the simple motion search data for
236
  // partition pruning in inter frames. Hence, the memory allocations and
237
  // initializations related to it are avoided for allintra encoding mode.
238
0
  if (cpi->oxcf.kf_cfg.key_freq_max == 0) return 0;
239
240
0
  AV1_COMMON *const cm = &cpi->common;
241
0
  const int stat_generation_stage = is_stat_generation_stage(cpi);
242
0
  const int is_sb_size_128 = cm->seq_params->sb_size == BLOCK_128X128;
243
0
  const int tree_nodes =
244
0
      av1_get_pc_tree_nodes(is_sb_size_128, stat_generation_stage);
245
0
  int sms_tree_index = 0;
246
0
  SIMPLE_MOTION_DATA_TREE *this_sms;
247
0
  int square_index = 1;
248
0
  int nodes;
249
250
0
  aom_free(td->sms_tree);
251
0
  td->sms_tree =
252
0
      (SIMPLE_MOTION_DATA_TREE *)aom_calloc(tree_nodes, sizeof(*td->sms_tree));
253
0
  if (!td->sms_tree) return -1;
254
0
  this_sms = &td->sms_tree[0];
255
256
0
  if (!stat_generation_stage) {
257
0
    const int leaf_factor = is_sb_size_128 ? 4 : 1;
258
0
    const int leaf_nodes = 256 * leaf_factor;
259
260
    // Sets up all the leaf nodes in the tree.
261
0
    for (sms_tree_index = 0; sms_tree_index < leaf_nodes; ++sms_tree_index) {
262
0
      SIMPLE_MOTION_DATA_TREE *const tree = &td->sms_tree[sms_tree_index];
263
0
      tree->block_size = square[0];
264
0
    }
265
266
    // Each node has 4 leaf nodes, fill each block_size level of the tree
267
    // from leafs to the root.
268
0
    for (nodes = leaf_nodes >> 2; nodes > 0; nodes >>= 2) {
269
0
      for (int i = 0; i < nodes; ++i) {
270
0
        SIMPLE_MOTION_DATA_TREE *const tree = &td->sms_tree[sms_tree_index];
271
0
        tree->block_size = square[square_index];
272
0
        for (int j = 0; j < 4; j++) tree->split[j] = this_sms++;
273
0
        ++sms_tree_index;
274
0
      }
275
0
      ++square_index;
276
0
    }
277
0
  } else {
278
    // Allocation for firstpass/LAP stage
279
    // TODO(Mufaddal): refactor square_index to use a common block_size macro
280
    // from firstpass.c
281
0
    SIMPLE_MOTION_DATA_TREE *const tree = &td->sms_tree[sms_tree_index];
282
0
    square_index = 2;
283
0
    tree->block_size = square[square_index];
284
0
  }
285
286
  // Set up the root node for the largest superblock size
287
0
  td->sms_root = &td->sms_tree[tree_nodes - 1];
288
0
  return 0;
289
0
}
290
291
0
void av1_free_sms_tree(ThreadData *td) {
292
0
  aom_free(td->sms_tree);
293
  td->sms_tree = NULL;
294
0
}