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