/src/aom/aom_scale/generic/yv12config.c
Line | Count | Source (jump to first uncovered line) |
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 <assert.h> |
13 | | |
14 | | #include "aom/internal/aom_image_internal.h" |
15 | | #include "aom_dsp/pyramid.h" |
16 | | #include "aom_dsp/flow_estimation/corner_detect.h" |
17 | | #include "aom_mem/aom_mem.h" |
18 | | #include "aom_ports/mem.h" |
19 | | #include "aom_scale/yv12config.h" |
20 | | #include "av1/common/enums.h" |
21 | | |
22 | | /**************************************************************************** |
23 | | * Exports |
24 | | ****************************************************************************/ |
25 | | |
26 | | /**************************************************************************** |
27 | | * |
28 | | ****************************************************************************/ |
29 | | |
30 | | // TODO(jkoleszar): Maybe replace this with struct aom_image |
31 | 268k | int aom_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) { |
32 | 268k | if (ybf) { |
33 | 268k | if (ybf->buffer_alloc_sz > 0) { |
34 | 8.89k | aom_free(ybf->buffer_alloc); |
35 | 8.89k | } |
36 | | #if CONFIG_AV1_ENCODER && !CONFIG_REALTIME_ONLY |
37 | | if (ybf->y_pyramid) { |
38 | | aom_free_pyramid(ybf->y_pyramid); |
39 | | } |
40 | | if (ybf->corners) { |
41 | | av1_free_corner_list(ybf->corners); |
42 | | } |
43 | | #endif // CONFIG_AV1_ENCODER && !CONFIG_REALTIME_ONLY |
44 | 268k | aom_remove_metadata_from_frame_buffer(ybf); |
45 | | /* buffer_alloc isn't accessed by most functions. Rather y_buffer, |
46 | | u_buffer and v_buffer point to buffer_alloc and are used. Clear out |
47 | | all of this so that a freed pointer isn't inadvertently used */ |
48 | 268k | memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG)); |
49 | 268k | return 0; |
50 | 268k | } |
51 | | |
52 | 0 | return AOM_CODEC_MEM_ERROR; |
53 | 268k | } |
54 | | |
55 | | static int realloc_frame_buffer_aligned( |
56 | | YV12_BUFFER_CONFIG *ybf, int width, int height, int ss_x, int ss_y, |
57 | | int use_highbitdepth, int border, int byte_alignment, |
58 | | aom_codec_frame_buffer_t *fb, aom_get_frame_buffer_cb_fn_t cb, |
59 | | void *cb_priv, const int y_stride, const uint64_t yplane_size, |
60 | | const uint64_t uvplane_size, const int aligned_width, |
61 | | const int aligned_height, const int uv_width, const int uv_height, |
62 | | const int uv_stride, const int uv_border_w, const int uv_border_h, |
63 | 499k | int num_pyramid_levels, int alloc_y_plane_only) { |
64 | 499k | if (ybf) { |
65 | 499k | const int aom_byte_align = (byte_alignment == 0) ? 1 : byte_alignment; |
66 | 499k | const uint64_t frame_size = |
67 | 499k | (1 + use_highbitdepth) * (yplane_size + 2 * uvplane_size); |
68 | | |
69 | 499k | uint8_t *buf = NULL; |
70 | | |
71 | 499k | #if CONFIG_REALTIME_ONLY || !CONFIG_AV1_ENCODER |
72 | | // We should only need an 8-bit version of the source frame if we are |
73 | | // encoding in non-realtime mode |
74 | 499k | (void)num_pyramid_levels; |
75 | 499k | assert(num_pyramid_levels == 0); |
76 | 0 | #endif // CONFIG_REALTIME_ONLY || !CONFIG_AV1_ENCODER |
77 | | |
78 | 0 | #if defined AOM_MAX_ALLOCABLE_MEMORY |
79 | | // The size of ybf->buffer_alloc. |
80 | 0 | uint64_t alloc_size = frame_size; |
81 | | #if CONFIG_AV1_ENCODER && !CONFIG_REALTIME_ONLY |
82 | | // The size of ybf->y_pyramid |
83 | | if (num_pyramid_levels > 0) { |
84 | | alloc_size += aom_get_pyramid_alloc_size( |
85 | | width, height, num_pyramid_levels, use_highbitdepth); |
86 | | alloc_size += av1_get_corner_list_size(); |
87 | | } |
88 | | #endif // CONFIG_AV1_ENCODER && !CONFIG_REALTIME_ONLY |
89 | | // The decoder may allocate REF_FRAMES frame buffers in the frame buffer |
90 | | // pool. Bound the total amount of allocated memory as if these REF_FRAMES |
91 | | // frame buffers were allocated in a single allocation. |
92 | 499k | if (alloc_size > AOM_MAX_ALLOCABLE_MEMORY / REF_FRAMES) |
93 | 280 | return AOM_CODEC_MEM_ERROR; |
94 | 499k | #endif |
95 | | |
96 | 499k | if (cb != NULL) { |
97 | 476k | const int align_addr_extra_size = 31; |
98 | 476k | const uint64_t external_frame_size = frame_size + align_addr_extra_size; |
99 | | |
100 | 476k | assert(fb != NULL); |
101 | | |
102 | 476k | if (external_frame_size != (size_t)external_frame_size) |
103 | 0 | return AOM_CODEC_MEM_ERROR; |
104 | | |
105 | | // Allocation to hold larger frame, or first allocation. |
106 | 476k | if (cb(cb_priv, (size_t)external_frame_size, fb) < 0) |
107 | 0 | return AOM_CODEC_MEM_ERROR; |
108 | | |
109 | 476k | if (fb->data == NULL || fb->size < external_frame_size) |
110 | 0 | return AOM_CODEC_MEM_ERROR; |
111 | | |
112 | 476k | ybf->buffer_alloc = (uint8_t *)aom_align_addr(fb->data, 32); |
113 | | |
114 | 476k | #if defined(__has_feature) |
115 | | #if __has_feature(memory_sanitizer) |
116 | | // This memset is needed for fixing the issue of using uninitialized |
117 | | // value in msan test. It will cause a perf loss, so only do this for |
118 | | // msan test. |
119 | | memset(ybf->buffer_alloc, 0, (size_t)frame_size); |
120 | | #endif |
121 | 476k | #endif |
122 | 476k | } else if (frame_size > ybf->buffer_alloc_sz) { |
123 | | // Allocation to hold larger frame, or first allocation. |
124 | 9.18k | aom_free(ybf->buffer_alloc); |
125 | 9.18k | ybf->buffer_alloc = NULL; |
126 | 9.18k | ybf->buffer_alloc_sz = 0; |
127 | | |
128 | 9.18k | if (frame_size != (size_t)frame_size) return AOM_CODEC_MEM_ERROR; |
129 | | |
130 | 9.18k | ybf->buffer_alloc = (uint8_t *)aom_memalign(32, (size_t)frame_size); |
131 | 9.18k | if (!ybf->buffer_alloc) return AOM_CODEC_MEM_ERROR; |
132 | | |
133 | 9.18k | ybf->buffer_alloc_sz = (size_t)frame_size; |
134 | | |
135 | | // This memset is needed for fixing valgrind error from C loop filter |
136 | | // due to access uninitialized memory in frame border. It could be |
137 | | // removed if border is totally removed. |
138 | 9.18k | memset(ybf->buffer_alloc, 0, ybf->buffer_alloc_sz); |
139 | 9.18k | } |
140 | | |
141 | 499k | ybf->y_crop_width = width; |
142 | 499k | ybf->y_crop_height = height; |
143 | 499k | ybf->y_width = aligned_width; |
144 | 499k | ybf->y_height = aligned_height; |
145 | 499k | ybf->y_stride = y_stride; |
146 | | |
147 | 499k | ybf->uv_crop_width = (width + ss_x) >> ss_x; |
148 | 499k | ybf->uv_crop_height = (height + ss_y) >> ss_y; |
149 | 499k | ybf->uv_width = uv_width; |
150 | 499k | ybf->uv_height = uv_height; |
151 | 499k | ybf->uv_stride = uv_stride; |
152 | | |
153 | 499k | ybf->border = border; |
154 | 499k | ybf->frame_size = (size_t)frame_size; |
155 | 499k | ybf->subsampling_x = ss_x; |
156 | 499k | ybf->subsampling_y = ss_y; |
157 | | |
158 | 499k | buf = ybf->buffer_alloc; |
159 | 499k | if (use_highbitdepth) { |
160 | | // Store uint16 addresses when using 16bit framebuffers |
161 | 143k | buf = CONVERT_TO_BYTEPTR(ybf->buffer_alloc); |
162 | 143k | ybf->flags = YV12_FLAG_HIGHBITDEPTH; |
163 | 356k | } else { |
164 | 356k | ybf->flags = 0; |
165 | 356k | } |
166 | | |
167 | 499k | ybf->y_buffer = (uint8_t *)aom_align_addr( |
168 | 499k | buf + (border * y_stride) + border, aom_byte_align); |
169 | 499k | if (!alloc_y_plane_only) { |
170 | 499k | ybf->u_buffer = (uint8_t *)aom_align_addr( |
171 | 499k | buf + yplane_size + (uv_border_h * uv_stride) + uv_border_w, |
172 | 499k | aom_byte_align); |
173 | 499k | ybf->v_buffer = |
174 | 499k | (uint8_t *)aom_align_addr(buf + yplane_size + uvplane_size + |
175 | 499k | (uv_border_h * uv_stride) + uv_border_w, |
176 | 499k | aom_byte_align); |
177 | 499k | } else { |
178 | 0 | ybf->u_buffer = NULL; |
179 | 0 | ybf->v_buffer = NULL; |
180 | 0 | } |
181 | | |
182 | 499k | ybf->use_external_reference_buffers = 0; |
183 | | |
184 | | #if CONFIG_AV1_ENCODER && !CONFIG_REALTIME_ONLY |
185 | | if (ybf->y_pyramid) { |
186 | | aom_free_pyramid(ybf->y_pyramid); |
187 | | ybf->y_pyramid = NULL; |
188 | | } |
189 | | if (ybf->corners) { |
190 | | av1_free_corner_list(ybf->corners); |
191 | | ybf->corners = NULL; |
192 | | } |
193 | | if (num_pyramid_levels > 0) { |
194 | | ybf->y_pyramid = aom_alloc_pyramid(width, height, num_pyramid_levels, |
195 | | use_highbitdepth); |
196 | | ybf->corners = av1_alloc_corner_list(); |
197 | | } |
198 | | #endif // CONFIG_AV1_ENCODER && !CONFIG_REALTIME_ONLY |
199 | | |
200 | 499k | ybf->corrupted = 0; /* assume not corrupted by errors */ |
201 | 499k | return 0; |
202 | 499k | } |
203 | 0 | return AOM_CODEC_MEM_ERROR; |
204 | 499k | } |
205 | | |
206 | | static int calc_stride_and_planesize( |
207 | | const int ss_x, const int ss_y, const int aligned_width, |
208 | | const int aligned_height, const int border, const int byte_alignment, |
209 | | int alloc_y_plane_only, int *y_stride, int *uv_stride, |
210 | 499k | uint64_t *yplane_size, uint64_t *uvplane_size, const int uv_height) { |
211 | | /* Only support allocating buffers that have a border that's a multiple |
212 | | * of 32. The border restriction is required to get 16-byte alignment of |
213 | | * the start of the chroma rows without introducing an arbitrary gap |
214 | | * between planes, which would break the semantics of things like |
215 | | * aom_img_set_rect(). */ |
216 | 499k | if (border & 0x1f) return AOM_CODEC_MEM_ERROR; |
217 | 499k | *y_stride = aom_calc_y_stride(aligned_width, border); |
218 | 499k | *yplane_size = |
219 | 499k | (aligned_height + 2 * border) * (uint64_t)(*y_stride) + byte_alignment; |
220 | | |
221 | 499k | if (!alloc_y_plane_only) { |
222 | 499k | *uv_stride = *y_stride >> ss_x; |
223 | 499k | *uvplane_size = |
224 | 499k | (uv_height + 2 * (border >> ss_y)) * (uint64_t)(*uv_stride) + |
225 | 499k | byte_alignment; |
226 | 499k | } else { |
227 | 0 | *uv_stride = 0; |
228 | 0 | *uvplane_size = 0; |
229 | 0 | } |
230 | 499k | return 0; |
231 | 499k | } |
232 | | |
233 | | int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, |
234 | | int ss_x, int ss_y, int use_highbitdepth, |
235 | | int border, int byte_alignment, |
236 | | aom_codec_frame_buffer_t *fb, |
237 | | aom_get_frame_buffer_cb_fn_t cb, void *cb_priv, |
238 | 500k | int num_pyramid_levels, int alloc_y_plane_only) { |
239 | 500k | #if CONFIG_SIZE_LIMIT |
240 | 500k | if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) |
241 | 132 | return AOM_CODEC_MEM_ERROR; |
242 | 499k | #endif |
243 | | |
244 | 499k | if (ybf) { |
245 | 499k | int y_stride = 0; |
246 | 499k | int uv_stride = 0; |
247 | 499k | uint64_t yplane_size = 0; |
248 | 499k | uint64_t uvplane_size = 0; |
249 | 499k | const int aligned_width = (width + 7) & ~7; |
250 | 499k | const int aligned_height = (height + 7) & ~7; |
251 | 499k | const int uv_width = aligned_width >> ss_x; |
252 | 499k | const int uv_height = aligned_height >> ss_y; |
253 | 499k | const int uv_border_w = border >> ss_x; |
254 | 499k | const int uv_border_h = border >> ss_y; |
255 | | |
256 | 499k | int error = calc_stride_and_planesize( |
257 | 499k | ss_x, ss_y, aligned_width, aligned_height, border, byte_alignment, |
258 | 499k | alloc_y_plane_only, &y_stride, &uv_stride, &yplane_size, &uvplane_size, |
259 | 499k | uv_height); |
260 | 499k | if (error) return error; |
261 | 499k | return realloc_frame_buffer_aligned( |
262 | 499k | ybf, width, height, ss_x, ss_y, use_highbitdepth, border, |
263 | 499k | byte_alignment, fb, cb, cb_priv, y_stride, yplane_size, uvplane_size, |
264 | 499k | aligned_width, aligned_height, uv_width, uv_height, uv_stride, |
265 | 499k | uv_border_w, uv_border_h, num_pyramid_levels, alloc_y_plane_only); |
266 | 499k | } |
267 | 0 | return AOM_CODEC_MEM_ERROR; |
268 | 499k | } |
269 | | |
270 | | int aom_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, |
271 | | int ss_x, int ss_y, int use_highbitdepth, int border, |
272 | | int byte_alignment, int num_pyramid_levels, |
273 | 6.26k | int alloc_y_plane_only) { |
274 | 6.26k | if (ybf) { |
275 | 6.26k | aom_free_frame_buffer(ybf); |
276 | 6.26k | return aom_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, |
277 | 6.26k | use_highbitdepth, border, byte_alignment, |
278 | 6.26k | NULL, NULL, NULL, num_pyramid_levels, |
279 | 6.26k | alloc_y_plane_only); |
280 | 6.26k | } |
281 | 0 | return AOM_CODEC_MEM_ERROR; |
282 | 6.26k | } |
283 | | |
284 | 268k | void aom_remove_metadata_from_frame_buffer(YV12_BUFFER_CONFIG *ybf) { |
285 | 268k | if (ybf && ybf->metadata) { |
286 | 0 | aom_img_metadata_array_free(ybf->metadata); |
287 | 0 | ybf->metadata = NULL; |
288 | 0 | } |
289 | 268k | } |
290 | | |
291 | | int aom_copy_metadata_to_frame_buffer(YV12_BUFFER_CONFIG *ybf, |
292 | 0 | const aom_metadata_array_t *arr) { |
293 | 0 | if (!ybf || !arr || !arr->metadata_array) return -1; |
294 | 0 | if (ybf->metadata == arr) return 0; |
295 | 0 | aom_remove_metadata_from_frame_buffer(ybf); |
296 | 0 | ybf->metadata = aom_img_metadata_array_alloc(arr->sz); |
297 | 0 | if (!ybf->metadata) return -1; |
298 | 0 | for (size_t i = 0; i < ybf->metadata->sz; i++) { |
299 | 0 | ybf->metadata->metadata_array[i] = aom_img_metadata_alloc( |
300 | 0 | arr->metadata_array[i]->type, arr->metadata_array[i]->payload, |
301 | 0 | arr->metadata_array[i]->sz, arr->metadata_array[i]->insert_flag); |
302 | 0 | if (ybf->metadata->metadata_array[i] == NULL) { |
303 | 0 | aom_img_metadata_array_free(ybf->metadata); |
304 | 0 | ybf->metadata = NULL; |
305 | 0 | return -1; |
306 | 0 | } |
307 | 0 | } |
308 | 0 | ybf->metadata->sz = arr->sz; |
309 | 0 | return 0; |
310 | 0 | } |