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