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