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