/src/libvpx/vpx_scale/generic/yv12config.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
3 | | * |
4 | | * Use of this source code is governed by a BSD-style license |
5 | | * that can be found in the LICENSE file in the root of the source |
6 | | * tree. An additional intellectual property rights grant can be found |
7 | | * in the file PATENTS. All contributing project authors may |
8 | | * be found in the AUTHORS file in the root of the source tree. |
9 | | */ |
10 | | |
11 | | #include <assert.h> |
12 | | #include <limits.h> |
13 | | |
14 | | #include "vpx_scale/yv12config.h" |
15 | | #include "vpx_mem/vpx_mem.h" |
16 | | #include "vpx_ports/mem.h" |
17 | | |
18 | | #if defined(VPX_MAX_ALLOCABLE_MEMORY) |
19 | | #include "vp9/common/vp9_onyxc_int.h" |
20 | | #endif // VPX_MAX_ALLOCABLE_MEMORY |
21 | | /**************************************************************************** |
22 | | * Exports |
23 | | ****************************************************************************/ |
24 | | |
25 | | /**************************************************************************** |
26 | | * |
27 | | ****************************************************************************/ |
28 | | #define yv12_align_addr(addr, align) \ |
29 | 885k | (void *)(((size_t)(addr) + ((align)-1)) & (size_t) - (align)) |
30 | | |
31 | 201k | int vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) { |
32 | 201k | if (ybf) { |
33 | | // If libvpx is using frame buffer callbacks then buffer_alloc_sz must |
34 | | // not be set. |
35 | 201k | if (ybf->buffer_alloc_sz > 0) { |
36 | 54.0k | vpx_free(ybf->buffer_alloc); |
37 | 54.0k | } |
38 | | |
39 | | /* buffer_alloc isn't accessed by most functions. Rather y_buffer, |
40 | | u_buffer and v_buffer point to buffer_alloc and are used. Clear out |
41 | | all of this so that a freed pointer isn't inadvertently used */ |
42 | 201k | memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG)); |
43 | 201k | } else { |
44 | 0 | return -1; |
45 | 0 | } |
46 | | |
47 | 201k | return 0; |
48 | 201k | } |
49 | | |
50 | | int vp8_yv12_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, |
51 | 54.0k | int height, int border) { |
52 | 54.0k | if (ybf) { |
53 | 54.0k | int aligned_width = (width + 15) & ~15; |
54 | 54.0k | int aligned_height = (height + 15) & ~15; |
55 | 54.0k | int y_stride = ((aligned_width + 2 * border) + 31) & ~31; |
56 | 54.0k | int yplane_size = (aligned_height + 2 * border) * y_stride; |
57 | 54.0k | int uv_width = aligned_width >> 1; |
58 | 54.0k | int uv_height = aligned_height >> 1; |
59 | | /** There is currently a bunch of code which assumes |
60 | | * uv_stride == y_stride/2, so enforce this here. */ |
61 | 54.0k | int uv_stride = y_stride >> 1; |
62 | 54.0k | int uvplane_size = (uv_height + border) * uv_stride; |
63 | 54.0k | const size_t frame_size = yplane_size + 2 * uvplane_size; |
64 | | |
65 | 54.0k | if (!ybf->buffer_alloc) { |
66 | 54.0k | ybf->buffer_alloc = (uint8_t *)vpx_memalign(32, frame_size); |
67 | 54.0k | if (!ybf->buffer_alloc) { |
68 | 0 | ybf->buffer_alloc_sz = 0; |
69 | 0 | return -1; |
70 | 0 | } |
71 | 54.0k | #if defined(__has_feature) |
72 | | #if __has_feature(memory_sanitizer) |
73 | | // This memset is needed for fixing the issue of using uninitialized |
74 | | // value in msan test. It will cause a perf loss, so only do this for |
75 | | // msan test. |
76 | | memset(ybf->buffer_alloc, 0, frame_size); |
77 | | #endif |
78 | 54.0k | #endif |
79 | 54.0k | ybf->buffer_alloc_sz = frame_size; |
80 | 54.0k | } |
81 | | |
82 | 54.0k | if (ybf->buffer_alloc_sz < frame_size) return -1; |
83 | | |
84 | | /* Only support allocating buffers that have a border that's a multiple |
85 | | * of 32. The border restriction is required to get 16-byte alignment of |
86 | | * the start of the chroma rows without introducing an arbitrary gap |
87 | | * between planes, which would break the semantics of things like |
88 | | * vpx_img_set_rect(). */ |
89 | 54.0k | if (border & 0x1f) return -3; |
90 | | |
91 | 54.0k | ybf->y_crop_width = width; |
92 | 54.0k | ybf->y_crop_height = height; |
93 | 54.0k | ybf->y_width = aligned_width; |
94 | 54.0k | ybf->y_height = aligned_height; |
95 | 54.0k | ybf->y_stride = y_stride; |
96 | | |
97 | 54.0k | ybf->uv_crop_width = (width + 1) / 2; |
98 | 54.0k | ybf->uv_crop_height = (height + 1) / 2; |
99 | 54.0k | ybf->uv_width = uv_width; |
100 | 54.0k | ybf->uv_height = uv_height; |
101 | 54.0k | ybf->uv_stride = uv_stride; |
102 | | |
103 | 54.0k | ybf->alpha_width = 0; |
104 | 54.0k | ybf->alpha_height = 0; |
105 | 54.0k | ybf->alpha_stride = 0; |
106 | | |
107 | 54.0k | ybf->border = border; |
108 | 54.0k | ybf->frame_size = frame_size; |
109 | | |
110 | 54.0k | ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border; |
111 | 54.0k | ybf->u_buffer = |
112 | 54.0k | ybf->buffer_alloc + yplane_size + (border / 2 * uv_stride) + border / 2; |
113 | 54.0k | ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + |
114 | 54.0k | (border / 2 * uv_stride) + border / 2; |
115 | 54.0k | ybf->alpha_buffer = NULL; |
116 | | |
117 | 54.0k | ybf->corrupted = 0; /* assume not currupted by errors */ |
118 | 54.0k | return 0; |
119 | 54.0k | } |
120 | 0 | return -2; |
121 | 54.0k | } |
122 | | |
123 | | int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, |
124 | 54.0k | int border) { |
125 | 54.0k | if (ybf) { |
126 | 54.0k | vp8_yv12_de_alloc_frame_buffer(ybf); |
127 | 54.0k | return vp8_yv12_realloc_frame_buffer(ybf, width, height, border); |
128 | 54.0k | } |
129 | 0 | return -2; |
130 | 54.0k | } |
131 | | |
132 | | #if CONFIG_VP9 |
133 | | // TODO(jkoleszar): Maybe replace this with struct vpx_image |
134 | | |
135 | 313k | int vpx_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) { |
136 | 313k | if (ybf) { |
137 | 313k | if (ybf->buffer_alloc_sz > 0) { |
138 | 93.1k | vpx_free(ybf->buffer_alloc); |
139 | 93.1k | } |
140 | | |
141 | | /* buffer_alloc isn't accessed by most functions. Rather y_buffer, |
142 | | u_buffer and v_buffer point to buffer_alloc and are used. Clear out |
143 | | all of this so that a freed pointer isn't inadvertently used */ |
144 | 313k | memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG)); |
145 | 313k | } else { |
146 | 0 | return -1; |
147 | 0 | } |
148 | | |
149 | 313k | return 0; |
150 | 313k | } |
151 | | |
152 | | int vpx_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, |
153 | | int ss_x, int ss_y, |
154 | | #if CONFIG_VP9_HIGHBITDEPTH |
155 | | int use_highbitdepth, |
156 | | #endif |
157 | | int border, int byte_alignment, |
158 | | vpx_codec_frame_buffer_t *fb, |
159 | 295k | vpx_get_frame_buffer_cb_fn_t cb, void *cb_priv) { |
160 | 295k | #if CONFIG_SIZE_LIMIT |
161 | 295k | if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) return -1; |
162 | 295k | #endif |
163 | | |
164 | | /* Only support allocating buffers that have a border that's a multiple |
165 | | * of 32. The border restriction is required to get 16-byte alignment of |
166 | | * the start of the chroma rows without introducing an arbitrary gap |
167 | | * between planes, which would break the semantics of things like |
168 | | * vpx_img_set_rect(). */ |
169 | 295k | if (border & 0x1f) return -3; |
170 | | |
171 | 295k | if (ybf) { |
172 | 295k | const int vp9_byte_align = (byte_alignment == 0) ? 1 : byte_alignment; |
173 | 295k | const int aligned_width = (width + 7) & ~7; |
174 | 295k | const int aligned_height = (height + 7) & ~7; |
175 | 295k | const int y_stride = ((aligned_width + 2 * border) + 31) & ~31; |
176 | 295k | const uint64_t yplane_size = |
177 | 295k | (aligned_height + 2 * border) * (uint64_t)y_stride + byte_alignment; |
178 | 295k | const int uv_width = aligned_width >> ss_x; |
179 | 295k | const int uv_height = aligned_height >> ss_y; |
180 | 295k | const int uv_stride = y_stride >> ss_x; |
181 | 295k | const int uv_border_w = border >> ss_x; |
182 | 295k | const int uv_border_h = border >> ss_y; |
183 | 295k | const uint64_t uvplane_size = |
184 | 295k | (uv_height + 2 * uv_border_h) * (uint64_t)uv_stride + byte_alignment; |
185 | | |
186 | 295k | #if CONFIG_VP9_HIGHBITDEPTH |
187 | 295k | const uint64_t frame_size = |
188 | 295k | (1 + use_highbitdepth) * (yplane_size + 2 * uvplane_size); |
189 | | #else |
190 | | const uint64_t frame_size = yplane_size + 2 * uvplane_size; |
191 | | #endif // CONFIG_VP9_HIGHBITDEPTH |
192 | | |
193 | 295k | uint8_t *buf = NULL; |
194 | | |
195 | 295k | #if defined(VPX_MAX_ALLOCABLE_MEMORY) |
196 | | // The decoder may allocate REF_FRAMES frame buffers in the frame buffer |
197 | | // pool. Bound the total amount of allocated memory as if these REF_FRAMES |
198 | | // frame buffers were allocated in a single allocation. |
199 | 295k | if (frame_size > VPX_MAX_ALLOCABLE_MEMORY / REF_FRAMES) return -1; |
200 | 295k | #endif // VPX_MAX_ALLOCABLE_MEMORY |
201 | | |
202 | | // frame_size is stored in buffer_alloc_sz, which is a size_t. If it won't |
203 | | // fit, fail early. |
204 | 295k | if (frame_size > SIZE_MAX) { |
205 | 0 | return -1; |
206 | 0 | } |
207 | | |
208 | 295k | if (cb != NULL) { |
209 | 0 | const int align_addr_extra_size = 31; |
210 | 0 | const uint64_t external_frame_size = frame_size + align_addr_extra_size; |
211 | |
|
212 | 0 | assert(fb != NULL); |
213 | |
|
214 | 0 | if (external_frame_size != (size_t)external_frame_size) return -1; |
215 | | |
216 | | // Allocation to hold larger frame, or first allocation. |
217 | 0 | if (cb(cb_priv, (size_t)external_frame_size, fb) < 0) return -1; |
218 | | |
219 | 0 | if (fb->data == NULL || fb->size < external_frame_size) return -1; |
220 | | |
221 | 0 | ybf->buffer_alloc = (uint8_t *)yv12_align_addr(fb->data, 32); |
222 | |
|
223 | 0 | #if defined(__has_feature) |
224 | | #if __has_feature(memory_sanitizer) |
225 | | // This memset is needed for fixing the issue of using uninitialized |
226 | | // value in msan test. It will cause a perf loss, so only do this for |
227 | | // msan test. |
228 | | memset(ybf->buffer_alloc, 0, (size_t)frame_size); |
229 | | #endif |
230 | 0 | #endif |
231 | 295k | } else if (frame_size > ybf->buffer_alloc_sz) { |
232 | | // Allocation to hold larger frame, or first allocation. |
233 | 93.1k | vpx_free(ybf->buffer_alloc); |
234 | 93.1k | ybf->buffer_alloc = NULL; |
235 | 93.1k | ybf->buffer_alloc_sz = 0; |
236 | | |
237 | 93.1k | ybf->buffer_alloc = (uint8_t *)vpx_memalign(32, (size_t)frame_size); |
238 | 93.1k | if (!ybf->buffer_alloc) return -1; |
239 | | |
240 | 93.1k | ybf->buffer_alloc_sz = (size_t)frame_size; |
241 | | |
242 | | // This memset is needed for fixing valgrind error from C loop filter |
243 | | // due to access uninitialized memory in frame border. It could be |
244 | | // removed if border is totally removed. |
245 | 93.1k | memset(ybf->buffer_alloc, 0, ybf->buffer_alloc_sz); |
246 | 93.1k | } |
247 | | |
248 | 295k | ybf->y_crop_width = width; |
249 | 295k | ybf->y_crop_height = height; |
250 | 295k | ybf->y_width = aligned_width; |
251 | 295k | ybf->y_height = aligned_height; |
252 | 295k | ybf->y_stride = y_stride; |
253 | | |
254 | 295k | ybf->uv_crop_width = (width + ss_x) >> ss_x; |
255 | 295k | ybf->uv_crop_height = (height + ss_y) >> ss_y; |
256 | 295k | ybf->uv_width = uv_width; |
257 | 295k | ybf->uv_height = uv_height; |
258 | 295k | ybf->uv_stride = uv_stride; |
259 | | |
260 | 295k | ybf->border = border; |
261 | 295k | ybf->frame_size = (size_t)frame_size; |
262 | 295k | ybf->subsampling_x = ss_x; |
263 | 295k | ybf->subsampling_y = ss_y; |
264 | | |
265 | 295k | buf = ybf->buffer_alloc; |
266 | 295k | #if CONFIG_VP9_HIGHBITDEPTH |
267 | 295k | if (use_highbitdepth) { |
268 | | // Store uint16 addresses when using 16bit framebuffers |
269 | 0 | buf = CONVERT_TO_BYTEPTR(ybf->buffer_alloc); |
270 | 0 | ybf->flags = YV12_FLAG_HIGHBITDEPTH; |
271 | 295k | } else { |
272 | 295k | ybf->flags = 0; |
273 | 295k | } |
274 | 295k | #endif // CONFIG_VP9_HIGHBITDEPTH |
275 | | |
276 | 295k | ybf->y_buffer = (uint8_t *)yv12_align_addr( |
277 | 295k | buf + (border * y_stride) + border, vp9_byte_align); |
278 | 295k | ybf->u_buffer = (uint8_t *)yv12_align_addr( |
279 | 295k | buf + yplane_size + (uv_border_h * uv_stride) + uv_border_w, |
280 | 295k | vp9_byte_align); |
281 | 295k | ybf->v_buffer = |
282 | 295k | (uint8_t *)yv12_align_addr(buf + yplane_size + uvplane_size + |
283 | 295k | (uv_border_h * uv_stride) + uv_border_w, |
284 | 295k | vp9_byte_align); |
285 | | |
286 | 295k | ybf->corrupted = 0; /* assume not corrupted by errors */ |
287 | 295k | return 0; |
288 | 295k | } |
289 | 0 | return -2; |
290 | 295k | } |
291 | | |
292 | | int vpx_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height, |
293 | | int ss_x, int ss_y, |
294 | | #if CONFIG_VP9_HIGHBITDEPTH |
295 | | int use_highbitdepth, |
296 | | #endif |
297 | 74.6k | int border, int byte_alignment) { |
298 | 74.6k | if (ybf) { |
299 | 74.6k | vpx_free_frame_buffer(ybf); |
300 | 74.6k | return vpx_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, |
301 | 74.6k | #if CONFIG_VP9_HIGHBITDEPTH |
302 | 74.6k | use_highbitdepth, |
303 | 74.6k | #endif |
304 | 74.6k | border, byte_alignment, NULL, NULL, NULL); |
305 | 74.6k | } |
306 | 0 | return -2; |
307 | 74.6k | } |
308 | | #endif |