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