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_config.h" 14#include "vpx_scale/yv12config.h" 15#include "vpx_mem/vpx_mem.h" 16#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH 17#include "vp9/common/vp9_common.h" 18#endif 19 20/**************************************************************************** 21* Exports 22****************************************************************************/ 23 24/**************************************************************************** 25 * 26 ****************************************************************************/ 27#define yv12_align_addr(addr, align) \ 28 (void*)(((size_t)(addr) + ((align) - 1)) & (size_t)-(align)) 29 30int 31vp8_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 vpx_memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG)); 43 } else { 44 return -1; 45 } 46 47 return 0; 48} 49 50int vp8_yv12_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, 51 int width, 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 int 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 ybf->buffer_alloc_sz = frame_size; 68 } 69 70 if (!ybf->buffer_alloc || ybf->buffer_alloc_sz < frame_size) 71 return -1; 72 73 /* Only support allocating buffers that have a border that's a multiple 74 * of 32. The border restriction is required to get 16-byte alignment of 75 * the start of the chroma rows without introducing an arbitrary gap 76 * between planes, which would break the semantics of things like 77 * vpx_img_set_rect(). */ 78 if (border & 0x1f) 79 return -3; 80 81 ybf->y_crop_width = width; 82 ybf->y_crop_height = height; 83 ybf->y_width = aligned_width; 84 ybf->y_height = aligned_height; 85 ybf->y_stride = y_stride; 86 87 ybf->uv_crop_width = (width + 1) / 2; 88 ybf->uv_crop_height = (height + 1) / 2; 89 ybf->uv_width = uv_width; 90 ybf->uv_height = uv_height; 91 ybf->uv_stride = uv_stride; 92 93 ybf->alpha_width = 0; 94 ybf->alpha_height = 0; 95 ybf->alpha_stride = 0; 96 97 ybf->border = border; 98 ybf->frame_size = frame_size; 99 100 ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border; 101 ybf->u_buffer = ybf->buffer_alloc + yplane_size + (border / 2 * uv_stride) + border / 2; 102 ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + (border / 2 * uv_stride) + border / 2; 103 ybf->alpha_buffer = NULL; 104 105 ybf->corrupted = 0; /* assume not currupted by errors */ 106 return 0; 107 } 108 return -2; 109} 110 111int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, 112 int width, int height, int border) { 113 if (ybf) { 114 vp8_yv12_de_alloc_frame_buffer(ybf); 115 return vp8_yv12_realloc_frame_buffer(ybf, width, height, border); 116 } 117 return -2; 118} 119 120#if CONFIG_VP9 121// TODO(jkoleszar): Maybe replace this with struct vpx_image 122 123int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) { 124 if (ybf) { 125 if (ybf->buffer_alloc_sz > 0) { 126 vpx_free(ybf->buffer_alloc); 127 } 128 129 /* buffer_alloc isn't accessed by most functions. Rather y_buffer, 130 u_buffer and v_buffer point to buffer_alloc and are used. Clear out 131 all of this so that a freed pointer isn't inadvertently used */ 132 vpx_memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG)); 133 } else { 134 return -1; 135 } 136 137 return 0; 138} 139 140int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, 141 int width, int height, 142 int ss_x, int ss_y, 143#if CONFIG_VP9_HIGHBITDEPTH 144 int use_highbitdepth, 145#endif 146 int border, 147 vpx_codec_frame_buffer_t *fb, 148 vpx_get_frame_buffer_cb_fn_t cb, 149 void *cb_priv) { 150 if (ybf) { 151 const int aligned_width = (width + 7) & ~7; 152 const int aligned_height = (height + 7) & ~7; 153 const int y_stride = ((aligned_width + 2 * border) + 31) & ~31; 154 const uint64_t yplane_size = (aligned_height + 2 * border) * 155 (uint64_t)y_stride; 156 const int uv_width = aligned_width >> ss_x; 157 const int uv_height = aligned_height >> ss_y; 158 const int uv_stride = y_stride >> ss_x; 159 const int uv_border_w = border >> ss_x; 160 const int uv_border_h = border >> ss_y; 161 const uint64_t uvplane_size = (uv_height + 2 * uv_border_h) * 162 (uint64_t)uv_stride; 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; 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 if (cb != NULL) { 187 const int align_addr_extra_size = 31; 188 const uint64_t external_frame_size = frame_size + align_addr_extra_size; 189 190 assert(fb != NULL); 191 192 if (external_frame_size != (size_t)external_frame_size) 193 return -1; 194 195 // Allocation to hold larger frame, or first allocation. 196 if (cb(cb_priv, (size_t)external_frame_size, fb) < 0) 197 return -1; 198 199 if (fb->data == NULL || fb->size < external_frame_size) 200 return -1; 201 202 ybf->buffer_alloc = (uint8_t *)yv12_align_addr(fb->data, 32); 203 } else if (frame_size > (size_t)ybf->buffer_alloc_sz) { 204 // Allocation to hold larger frame, or first allocation. 205 vpx_free(ybf->buffer_alloc); 206 ybf->buffer_alloc = NULL; 207 208 if (frame_size != (size_t)frame_size) 209 return -1; 210 211 ybf->buffer_alloc = (uint8_t *)vpx_memalign(32, (size_t)frame_size); 212 if (!ybf->buffer_alloc) 213 return -1; 214 215 ybf->buffer_alloc_sz = (int)frame_size; 216 217 // This memset is needed for fixing valgrind error from C loop filter 218 // due to access uninitialized memory in frame border. It could be 219 // removed if border is totally removed. 220 vpx_memset(ybf->buffer_alloc, 0, ybf->buffer_alloc_sz); 221 } 222 223 /* Only support allocating buffers that have a border that's a multiple 224 * of 32. The border restriction is required to get 16-byte alignment of 225 * the start of the chroma rows without introducing an arbitrary gap 226 * between planes, which would break the semantics of things like 227 * vpx_img_set_rect(). */ 228 if (border & 0x1f) 229 return -3; 230 231 ybf->y_crop_width = width; 232 ybf->y_crop_height = height; 233 ybf->y_width = aligned_width; 234 ybf->y_height = aligned_height; 235 ybf->y_stride = y_stride; 236 237 ybf->uv_crop_width = (width + ss_x) >> ss_x; 238 ybf->uv_crop_height = (height + ss_y) >> ss_y; 239 ybf->uv_width = uv_width; 240 ybf->uv_height = uv_height; 241 ybf->uv_stride = uv_stride; 242 243 ybf->border = border; 244 ybf->frame_size = (int)frame_size; 245 246#if CONFIG_VP9_HIGHBITDEPTH 247 if (use_highbitdepth) { 248 // Store uint16 addresses when using 16bit framebuffers 249 uint8_t *p = CONVERT_TO_BYTEPTR(ybf->buffer_alloc); 250 ybf->y_buffer = p + (border * y_stride) + border; 251 ybf->u_buffer = p + yplane_size + 252 (uv_border_h * uv_stride) + uv_border_w; 253 ybf->v_buffer = p + yplane_size + uvplane_size + 254 (uv_border_h * uv_stride) + uv_border_w; 255 ybf->flags = YV12_FLAG_HIGHBITDEPTH; 256 } else { 257 ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border; 258 ybf->u_buffer = ybf->buffer_alloc + yplane_size + 259 (uv_border_h * uv_stride) + uv_border_w; 260 ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + 261 (uv_border_h * uv_stride) + uv_border_w; 262 ybf->flags = 0; 263 } 264#else 265 ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border; 266 ybf->u_buffer = ybf->buffer_alloc + yplane_size + 267 (uv_border_h * uv_stride) + uv_border_w; 268 ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + 269 (uv_border_h * uv_stride) + uv_border_w; 270#endif // CONFIG_VP9_HIGHBITDEPTH 271 272#if CONFIG_ALPHA 273 ybf->alpha_width = alpha_width; 274 ybf->alpha_height = alpha_height; 275 ybf->alpha_stride = alpha_stride; 276 ybf->alpha_buffer = ybf->buffer_alloc + yplane_size + 2 * uvplane_size + 277 (alpha_border_h * alpha_stride) + alpha_border_w; 278#endif 279 ybf->corrupted = 0; /* assume not corrupted by errors */ 280 return 0; 281 } 282 return -2; 283} 284 285int vp9_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 if (ybf) { 293 vp9_free_frame_buffer(ybf); 294 return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, 295#if CONFIG_VP9_HIGHBITDEPTH 296 use_highbitdepth, 297#endif 298 border, NULL, NULL, NULL); 299 } 300 return -2; 301} 302#endif 303