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