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