michael@0: /* michael@0: * Copyright (c) 2010 The WebM project authors. All Rights Reserved. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license michael@0: * that can be found in the LICENSE file in the root of the source michael@0: * tree. An additional intellectual property rights grant can be found michael@0: * in the file PATENTS. All contributing project authors may michael@0: * be found in the AUTHORS file in the root of the source tree. michael@0: */ michael@0: michael@0: #include "./vpx_config.h" michael@0: #include "vpx_scale/yv12config.h" michael@0: #include "vpx_mem/vpx_mem.h" michael@0: michael@0: /**************************************************************************** michael@0: * Exports michael@0: ****************************************************************************/ michael@0: michael@0: /**************************************************************************** michael@0: * michael@0: ****************************************************************************/ michael@0: int michael@0: vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf) { michael@0: if (ybf) { michael@0: vpx_free(ybf->buffer_alloc); michael@0: michael@0: /* buffer_alloc isn't accessed by most functions. Rather y_buffer, michael@0: u_buffer and v_buffer point to buffer_alloc and are used. Clear out michael@0: all of this so that a freed pointer isn't inadvertently used */ michael@0: vpx_memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG)); michael@0: } else { michael@0: return -1; michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: int vp8_yv12_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, michael@0: int width, int height, int border) { michael@0: if (ybf) { michael@0: int aligned_width = (width + 15) & ~15; michael@0: int aligned_height = (height + 15) & ~15; michael@0: int y_stride = ((aligned_width + 2 * border) + 31) & ~31; michael@0: int yplane_size = (aligned_height + 2 * border) * y_stride; michael@0: int uv_width = aligned_width >> 1; michael@0: int uv_height = aligned_height >> 1; michael@0: /** There is currently a bunch of code which assumes michael@0: * uv_stride == y_stride/2, so enforce this here. */ michael@0: int uv_stride = y_stride >> 1; michael@0: int uvplane_size = (uv_height + border) * uv_stride; michael@0: const int frame_size = yplane_size + 2 * uvplane_size; michael@0: michael@0: if (!ybf->buffer_alloc) { michael@0: ybf->buffer_alloc = vpx_memalign(32, frame_size); michael@0: ybf->buffer_alloc_sz = frame_size; michael@0: } michael@0: michael@0: if (!ybf->buffer_alloc || ybf->buffer_alloc_sz < frame_size) michael@0: return -1; michael@0: michael@0: /* Only support allocating buffers that have a border that's a multiple michael@0: * of 32. The border restriction is required to get 16-byte alignment of michael@0: * the start of the chroma rows without introducing an arbitrary gap michael@0: * between planes, which would break the semantics of things like michael@0: * vpx_img_set_rect(). */ michael@0: if (border & 0x1f) michael@0: return -3; michael@0: michael@0: ybf->y_crop_width = width; michael@0: ybf->y_crop_height = height; michael@0: ybf->y_width = aligned_width; michael@0: ybf->y_height = aligned_height; michael@0: ybf->y_stride = y_stride; michael@0: michael@0: ybf->uv_width = uv_width; michael@0: ybf->uv_height = uv_height; michael@0: ybf->uv_stride = uv_stride; michael@0: michael@0: ybf->alpha_width = 0; michael@0: ybf->alpha_height = 0; michael@0: ybf->alpha_stride = 0; michael@0: michael@0: ybf->border = border; michael@0: ybf->frame_size = frame_size; michael@0: michael@0: ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border; michael@0: ybf->u_buffer = ybf->buffer_alloc + yplane_size + (border / 2 * uv_stride) + border / 2; michael@0: ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + (border / 2 * uv_stride) + border / 2; michael@0: ybf->alpha_buffer = NULL; michael@0: michael@0: ybf->corrupted = 0; /* assume not currupted by errors */ michael@0: return 0; michael@0: } michael@0: return -2; michael@0: } michael@0: michael@0: int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, michael@0: int width, int height, int border) { michael@0: if (ybf) { michael@0: vp8_yv12_de_alloc_frame_buffer(ybf); michael@0: return vp8_yv12_realloc_frame_buffer(ybf, width, height, border); michael@0: } michael@0: return -2; michael@0: } michael@0: michael@0: #if CONFIG_VP9 michael@0: // TODO(jkoleszar): Maybe replace this with struct vpx_image michael@0: michael@0: int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) { michael@0: if (ybf) { michael@0: vpx_free(ybf->buffer_alloc); michael@0: michael@0: /* buffer_alloc isn't accessed by most functions. Rather y_buffer, michael@0: u_buffer and v_buffer point to buffer_alloc and are used. Clear out michael@0: all of this so that a freed pointer isn't inadvertently used */ michael@0: vpx_memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG)); michael@0: } else { michael@0: return -1; michael@0: } michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, michael@0: int width, int height, michael@0: int ss_x, int ss_y, int border) { michael@0: if (ybf) { michael@0: const int aligned_width = (width + 7) & ~7; michael@0: const int aligned_height = (height + 7) & ~7; michael@0: const int y_stride = ((aligned_width + 2 * border) + 31) & ~31; michael@0: const int yplane_size = (aligned_height + 2 * border) * y_stride; michael@0: const int uv_width = aligned_width >> ss_x; michael@0: const int uv_height = aligned_height >> ss_y; michael@0: const int uv_stride = y_stride >> ss_x; michael@0: const int uv_border_w = border >> ss_x; michael@0: const int uv_border_h = border >> ss_y; michael@0: const int uvplane_size = (uv_height + 2 * uv_border_h) * uv_stride; michael@0: #if CONFIG_ALPHA michael@0: const int alpha_width = aligned_width; michael@0: const int alpha_height = aligned_height; michael@0: const int alpha_stride = y_stride; michael@0: const int alpha_border_w = border; michael@0: const int alpha_border_h = border; michael@0: const int alpha_plane_size = (alpha_height + 2 * alpha_border_h) * michael@0: alpha_stride; michael@0: const int frame_size = yplane_size + 2 * uvplane_size + michael@0: alpha_plane_size; michael@0: #else michael@0: const int frame_size = yplane_size + 2 * uvplane_size; michael@0: #endif michael@0: if (frame_size > ybf->buffer_alloc_sz) { michael@0: // Allocation to hold larger frame, or first allocation. michael@0: if (ybf->buffer_alloc) michael@0: vpx_free(ybf->buffer_alloc); michael@0: ybf->buffer_alloc = vpx_memalign(32, frame_size); michael@0: ybf->buffer_alloc_sz = frame_size; michael@0: } michael@0: michael@0: if (!ybf->buffer_alloc || ybf->buffer_alloc_sz < frame_size) michael@0: return -1; michael@0: michael@0: /* Only support allocating buffers that have a border that's a multiple michael@0: * of 32. The border restriction is required to get 16-byte alignment of michael@0: * the start of the chroma rows without introducing an arbitrary gap michael@0: * between planes, which would break the semantics of things like michael@0: * vpx_img_set_rect(). */ michael@0: if (border & 0x1f) michael@0: return -3; michael@0: michael@0: ybf->y_crop_width = width; michael@0: ybf->y_crop_height = height; michael@0: ybf->y_width = aligned_width; michael@0: ybf->y_height = aligned_height; michael@0: ybf->y_stride = y_stride; michael@0: michael@0: ybf->uv_crop_width = (width + ss_x) >> ss_x; michael@0: ybf->uv_crop_height = (height + ss_y) >> ss_y; michael@0: ybf->uv_width = uv_width; michael@0: ybf->uv_height = uv_height; michael@0: ybf->uv_stride = uv_stride; michael@0: michael@0: ybf->border = border; michael@0: ybf->frame_size = frame_size; michael@0: michael@0: ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border; michael@0: ybf->u_buffer = ybf->buffer_alloc + yplane_size + michael@0: (uv_border_h * uv_stride) + uv_border_w; michael@0: ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + michael@0: (uv_border_h * uv_stride) + uv_border_w; michael@0: michael@0: #if CONFIG_ALPHA michael@0: ybf->alpha_width = alpha_width; michael@0: ybf->alpha_height = alpha_height; michael@0: ybf->alpha_stride = alpha_stride; michael@0: ybf->alpha_buffer = ybf->buffer_alloc + yplane_size + 2 * uvplane_size + michael@0: (alpha_border_h * alpha_stride) + alpha_border_w; michael@0: #endif michael@0: ybf->corrupted = 0; /* assume not corrupted by errors */ michael@0: return 0; michael@0: } michael@0: return -2; michael@0: } michael@0: michael@0: int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, michael@0: int width, int height, michael@0: int ss_x, int ss_y, int border) { michael@0: if (ybf) { michael@0: vp9_free_frame_buffer(ybf); michael@0: return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, border); michael@0: } michael@0: return -2; michael@0: } michael@0: #endif