/src/mozilla-central/third_party/aom/av1/common/alloccommon.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2016, Alliance for Open Media. All rights reserved |
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 www.aomedia.org/license/software. 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 www.aomedia.org/license/patent. |
11 | | */ |
12 | | |
13 | | #include "config/aom_config.h" |
14 | | |
15 | | #include "aom_mem/aom_mem.h" |
16 | | |
17 | | #include "av1/common/alloccommon.h" |
18 | | #include "av1/common/blockd.h" |
19 | | #include "av1/common/entropymode.h" |
20 | | #include "av1/common/entropymv.h" |
21 | | #include "av1/common/onyxc_int.h" |
22 | | |
23 | 0 | int av1_get_MBs(int width, int height) { |
24 | 0 | const int aligned_width = ALIGN_POWER_OF_TWO(width, 3); |
25 | 0 | const int aligned_height = ALIGN_POWER_OF_TWO(height, 3); |
26 | 0 | const int mi_cols = aligned_width >> MI_SIZE_LOG2; |
27 | 0 | const int mi_rows = aligned_height >> MI_SIZE_LOG2; |
28 | 0 |
|
29 | 0 | const int mb_cols = (mi_cols + 2) >> 2; |
30 | 0 | const int mb_rows = (mi_rows + 2) >> 2; |
31 | 0 | return mb_rows * mb_cols; |
32 | 0 | } |
33 | | |
34 | | #if LOOP_FILTER_BITMASK |
35 | | static int alloc_loop_filter_mask(AV1_COMMON *cm) { |
36 | | aom_free(cm->lf.lfm); |
37 | | cm->lf.lfm = NULL; |
38 | | |
39 | | // Each lfm holds bit masks for all the 4x4 blocks in a max |
40 | | // 64x64 (128x128 for ext_partitions) region. The stride |
41 | | // and rows are rounded up / truncated to a multiple of 16 |
42 | | // (32 for ext_partition). |
43 | | cm->lf.lfm_stride = (cm->mi_cols + (MI_SIZE_64X64 - 1)) >> MIN_MIB_SIZE_LOG2; |
44 | | cm->lf.lfm_num = ((cm->mi_rows + (MI_SIZE_64X64 - 1)) >> MIN_MIB_SIZE_LOG2) * |
45 | | cm->lf.lfm_stride; |
46 | | cm->lf.lfm = |
47 | | (LoopFilterMask *)aom_calloc(cm->lf.lfm_num, sizeof(*cm->lf.lfm)); |
48 | | if (!cm->lf.lfm) return 1; |
49 | | |
50 | | unsigned int i; |
51 | | for (i = 0; i < cm->lf.lfm_num; ++i) av1_zero(cm->lf.lfm[i]); |
52 | | |
53 | | return 0; |
54 | | } |
55 | | |
56 | | static void free_loop_filter_mask(AV1_COMMON *cm) { |
57 | | if (cm->lf.lfm == NULL) return; |
58 | | |
59 | | aom_free(cm->lf.lfm); |
60 | | cm->lf.lfm = NULL; |
61 | | cm->lf.lfm_num = 0; |
62 | | cm->lf.lfm_stride = 0; |
63 | | } |
64 | | #endif |
65 | | |
66 | 0 | void av1_set_mb_mi(AV1_COMMON *cm, int width, int height) { |
67 | 0 | // Ensure that the decoded width and height are both multiples of |
68 | 0 | // 8 luma pixels (note: this may only be a multiple of 4 chroma pixels if |
69 | 0 | // subsampling is used). |
70 | 0 | // This simplifies the implementation of various experiments, |
71 | 0 | // eg. cdef, which operates on units of 8x8 luma pixels. |
72 | 0 | const int aligned_width = ALIGN_POWER_OF_TWO(width, 3); |
73 | 0 | const int aligned_height = ALIGN_POWER_OF_TWO(height, 3); |
74 | 0 |
|
75 | 0 | cm->mi_cols = aligned_width >> MI_SIZE_LOG2; |
76 | 0 | cm->mi_rows = aligned_height >> MI_SIZE_LOG2; |
77 | 0 | cm->mi_stride = calc_mi_size(cm->mi_cols); |
78 | 0 |
|
79 | 0 | cm->mb_cols = (cm->mi_cols + 2) >> 2; |
80 | 0 | cm->mb_rows = (cm->mi_rows + 2) >> 2; |
81 | 0 | cm->MBs = cm->mb_rows * cm->mb_cols; |
82 | 0 |
|
83 | | #if LOOP_FILTER_BITMASK |
84 | | alloc_loop_filter_mask(cm); |
85 | | #endif |
86 | | } |
87 | | |
88 | 0 | void av1_free_ref_frame_buffers(BufferPool *pool) { |
89 | 0 | int i; |
90 | 0 |
|
91 | 0 | for (i = 0; i < FRAME_BUFFERS; ++i) { |
92 | 0 | if (pool->frame_bufs[i].ref_count > 0 && |
93 | 0 | pool->frame_bufs[i].raw_frame_buffer.data != NULL) { |
94 | 0 | pool->release_fb_cb(pool->cb_priv, &pool->frame_bufs[i].raw_frame_buffer); |
95 | 0 | pool->frame_bufs[i].ref_count = 0; |
96 | 0 | } |
97 | 0 | aom_free(pool->frame_bufs[i].mvs); |
98 | 0 | pool->frame_bufs[i].mvs = NULL; |
99 | 0 | aom_free(pool->frame_bufs[i].seg_map); |
100 | 0 | pool->frame_bufs[i].seg_map = NULL; |
101 | 0 | aom_free_frame_buffer(&pool->frame_bufs[i].buf); |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | | // Assumes cm->rst_info[p].restoration_unit_size is already initialized |
106 | 0 | void av1_alloc_restoration_buffers(AV1_COMMON *cm) { |
107 | 0 | const int num_planes = av1_num_planes(cm); |
108 | 0 | for (int p = 0; p < num_planes; ++p) |
109 | 0 | av1_alloc_restoration_struct(cm, &cm->rst_info[p], p > 0); |
110 | 0 |
|
111 | 0 | if (cm->rst_tmpbuf == NULL) { |
112 | 0 | CHECK_MEM_ERROR(cm, cm->rst_tmpbuf, |
113 | 0 | (int32_t *)aom_memalign(16, RESTORATION_TMPBUF_SIZE)); |
114 | 0 | } |
115 | 0 |
|
116 | 0 | if (cm->rlbs == NULL) { |
117 | 0 | CHECK_MEM_ERROR(cm, cm->rlbs, aom_malloc(sizeof(RestorationLineBuffers))); |
118 | 0 | } |
119 | 0 |
|
120 | 0 | // For striped loop restoration, we divide each row of tiles into "stripes", |
121 | 0 | // of height 64 luma pixels but with an offset by RESTORATION_UNIT_OFFSET |
122 | 0 | // luma pixels to match the output from CDEF. We will need to store 2 * |
123 | 0 | // RESTORATION_CTX_VERT lines of data for each stripe, and also need to be |
124 | 0 | // able to quickly answer the question "Where is the <n>'th stripe for tile |
125 | 0 | // row <m>?" To make that efficient, we generate the rst_last_stripe array. |
126 | 0 | int num_stripes = 0; |
127 | 0 | for (int i = 0; i < cm->tile_rows; ++i) { |
128 | 0 | TileInfo tile_info; |
129 | 0 | av1_tile_set_row(&tile_info, cm, i); |
130 | 0 | const int mi_h = tile_info.mi_row_end - tile_info.mi_row_start; |
131 | 0 | const int ext_h = RESTORATION_UNIT_OFFSET + (mi_h << MI_SIZE_LOG2); |
132 | 0 | const int tile_stripes = (ext_h + 63) / 64; |
133 | 0 | num_stripes += tile_stripes; |
134 | 0 | cm->rst_end_stripe[i] = num_stripes; |
135 | 0 | } |
136 | 0 |
|
137 | 0 | // Now we need to allocate enough space to store the line buffers for the |
138 | 0 | // stripes |
139 | 0 | const int frame_w = cm->superres_upscaled_width; |
140 | 0 | const int use_highbd = cm->seq_params.use_highbitdepth ? 1 : 0; |
141 | 0 |
|
142 | 0 | for (int p = 0; p < num_planes; ++p) { |
143 | 0 | const int is_uv = p > 0; |
144 | 0 | const int ss_x = is_uv && cm->seq_params.subsampling_x; |
145 | 0 | const int plane_w = ((frame_w + ss_x) >> ss_x) + 2 * RESTORATION_EXTRA_HORZ; |
146 | 0 | const int stride = ALIGN_POWER_OF_TWO(plane_w, 5); |
147 | 0 | const int buf_size = num_stripes * stride * RESTORATION_CTX_VERT |
148 | 0 | << use_highbd; |
149 | 0 | RestorationStripeBoundaries *boundaries = &cm->rst_info[p].boundaries; |
150 | 0 |
|
151 | 0 | if (buf_size != boundaries->stripe_boundary_size || |
152 | 0 | boundaries->stripe_boundary_above == NULL || |
153 | 0 | boundaries->stripe_boundary_below == NULL) { |
154 | 0 | aom_free(boundaries->stripe_boundary_above); |
155 | 0 | aom_free(boundaries->stripe_boundary_below); |
156 | 0 |
|
157 | 0 | CHECK_MEM_ERROR(cm, boundaries->stripe_boundary_above, |
158 | 0 | (uint8_t *)aom_memalign(32, buf_size)); |
159 | 0 | CHECK_MEM_ERROR(cm, boundaries->stripe_boundary_below, |
160 | 0 | (uint8_t *)aom_memalign(32, buf_size)); |
161 | 0 |
|
162 | 0 | boundaries->stripe_boundary_size = buf_size; |
163 | 0 | } |
164 | 0 | boundaries->stripe_boundary_stride = stride; |
165 | 0 | } |
166 | 0 | } |
167 | | |
168 | 0 | void av1_free_restoration_buffers(AV1_COMMON *cm) { |
169 | 0 | int p; |
170 | 0 | for (p = 0; p < MAX_MB_PLANE; ++p) |
171 | 0 | av1_free_restoration_struct(&cm->rst_info[p]); |
172 | 0 | aom_free(cm->rst_tmpbuf); |
173 | 0 | cm->rst_tmpbuf = NULL; |
174 | 0 | aom_free(cm->rlbs); |
175 | 0 | cm->rlbs = NULL; |
176 | 0 | for (p = 0; p < MAX_MB_PLANE; ++p) { |
177 | 0 | RestorationStripeBoundaries *boundaries = &cm->rst_info[p].boundaries; |
178 | 0 | aom_free(boundaries->stripe_boundary_above); |
179 | 0 | aom_free(boundaries->stripe_boundary_below); |
180 | 0 | boundaries->stripe_boundary_above = NULL; |
181 | 0 | boundaries->stripe_boundary_below = NULL; |
182 | 0 | } |
183 | 0 |
|
184 | 0 | aom_free_frame_buffer(&cm->rst_frame); |
185 | 0 | } |
186 | | |
187 | | void av1_free_above_context_buffers(AV1_COMMON *cm, |
188 | 0 | int num_free_above_contexts) { |
189 | 0 | int i; |
190 | 0 | const int num_planes = cm->num_allocated_above_context_planes; |
191 | 0 |
|
192 | 0 | for (int tile_row = 0; tile_row < num_free_above_contexts; tile_row++) { |
193 | 0 | for (i = 0; i < num_planes; i++) { |
194 | 0 | aom_free(cm->above_context[i][tile_row]); |
195 | 0 | cm->above_context[i][tile_row] = NULL; |
196 | 0 | } |
197 | 0 | aom_free(cm->above_seg_context[tile_row]); |
198 | 0 | cm->above_seg_context[tile_row] = NULL; |
199 | 0 |
|
200 | 0 | aom_free(cm->above_txfm_context[tile_row]); |
201 | 0 | cm->above_txfm_context[tile_row] = NULL; |
202 | 0 | } |
203 | 0 | for (i = 0; i < num_planes; i++) { |
204 | 0 | aom_free(cm->above_context[i]); |
205 | 0 | cm->above_context[i] = NULL; |
206 | 0 | } |
207 | 0 | aom_free(cm->above_seg_context); |
208 | 0 | cm->above_seg_context = NULL; |
209 | 0 |
|
210 | 0 | aom_free(cm->above_txfm_context); |
211 | 0 | cm->above_txfm_context = NULL; |
212 | 0 |
|
213 | 0 | cm->num_allocated_above_contexts = 0; |
214 | 0 | cm->num_allocated_above_context_mi_col = 0; |
215 | 0 | cm->num_allocated_above_context_planes = 0; |
216 | 0 | } |
217 | | |
218 | 0 | void av1_free_context_buffers(AV1_COMMON *cm) { |
219 | 0 | cm->free_mi(cm); |
220 | 0 |
|
221 | 0 | av1_free_above_context_buffers(cm, cm->num_allocated_above_contexts); |
222 | 0 |
|
223 | | #if LOOP_FILTER_BITMASK |
224 | | free_loop_filter_mask(cm); |
225 | | #endif |
226 | | } |
227 | | |
228 | | int av1_alloc_above_context_buffers(AV1_COMMON *cm, |
229 | 0 | int num_alloc_above_contexts) { |
230 | 0 | const int num_planes = av1_num_planes(cm); |
231 | 0 | int plane_idx; |
232 | 0 | const int aligned_mi_cols = |
233 | 0 | ALIGN_POWER_OF_TWO(cm->mi_cols, MAX_MIB_SIZE_LOG2); |
234 | 0 |
|
235 | 0 | // Allocate above context buffers |
236 | 0 | cm->num_allocated_above_contexts = num_alloc_above_contexts; |
237 | 0 | cm->num_allocated_above_context_mi_col = aligned_mi_cols; |
238 | 0 | cm->num_allocated_above_context_planes = num_planes; |
239 | 0 | for (plane_idx = 0; plane_idx < num_planes; plane_idx++) { |
240 | 0 | cm->above_context[plane_idx] = (ENTROPY_CONTEXT **)aom_calloc( |
241 | 0 | num_alloc_above_contexts, sizeof(cm->above_context[0])); |
242 | 0 | if (!cm->above_context[plane_idx]) return 1; |
243 | 0 | } |
244 | 0 |
|
245 | 0 | cm->above_seg_context = (PARTITION_CONTEXT **)aom_calloc( |
246 | 0 | num_alloc_above_contexts, sizeof(cm->above_seg_context)); |
247 | 0 | if (!cm->above_seg_context) return 1; |
248 | 0 | |
249 | 0 | cm->above_txfm_context = (TXFM_CONTEXT **)aom_calloc( |
250 | 0 | num_alloc_above_contexts, sizeof(cm->above_txfm_context)); |
251 | 0 | if (!cm->above_txfm_context) return 1; |
252 | 0 | |
253 | 0 | for (int tile_row = 0; tile_row < num_alloc_above_contexts; tile_row++) { |
254 | 0 | for (plane_idx = 0; plane_idx < num_planes; plane_idx++) { |
255 | 0 | cm->above_context[plane_idx][tile_row] = (ENTROPY_CONTEXT *)aom_calloc( |
256 | 0 | aligned_mi_cols, sizeof(*cm->above_context[0][tile_row])); |
257 | 0 | if (!cm->above_context[plane_idx][tile_row]) return 1; |
258 | 0 | } |
259 | 0 |
|
260 | 0 | cm->above_seg_context[tile_row] = (PARTITION_CONTEXT *)aom_calloc( |
261 | 0 | aligned_mi_cols, sizeof(*cm->above_seg_context[tile_row])); |
262 | 0 | if (!cm->above_seg_context[tile_row]) return 1; |
263 | 0 | |
264 | 0 | cm->above_txfm_context[tile_row] = (TXFM_CONTEXT *)aom_calloc( |
265 | 0 | aligned_mi_cols, sizeof(*cm->above_txfm_context[tile_row])); |
266 | 0 | if (!cm->above_txfm_context[tile_row]) return 1; |
267 | 0 | } |
268 | 0 |
|
269 | 0 | return 0; |
270 | 0 | } |
271 | | |
272 | 0 | int av1_alloc_context_buffers(AV1_COMMON *cm, int width, int height) { |
273 | 0 | int new_mi_size; |
274 | 0 |
|
275 | 0 | av1_set_mb_mi(cm, width, height); |
276 | 0 | new_mi_size = cm->mi_stride * calc_mi_size(cm->mi_rows); |
277 | 0 | if (cm->mi_alloc_size < new_mi_size) { |
278 | 0 | cm->free_mi(cm); |
279 | 0 | if (cm->alloc_mi(cm, new_mi_size)) goto fail; |
280 | 0 | } |
281 | 0 | |
282 | 0 | return 0; |
283 | 0 | |
284 | 0 | fail: |
285 | 0 | // clear the mi_* values to force a realloc on resync |
286 | 0 | av1_set_mb_mi(cm, 0, 0); |
287 | 0 | av1_free_context_buffers(cm); |
288 | 0 | return 1; |
289 | 0 | } |
290 | | |
291 | 0 | void av1_remove_common(AV1_COMMON *cm) { |
292 | 0 | av1_free_context_buffers(cm); |
293 | 0 |
|
294 | 0 | aom_free(cm->fc); |
295 | 0 | cm->fc = NULL; |
296 | 0 | aom_free(cm->frame_contexts); |
297 | 0 | cm->frame_contexts = NULL; |
298 | 0 | } |
299 | | |
300 | 0 | void av1_init_context_buffers(AV1_COMMON *cm) { cm->setup_mi(cm); } |