yv12extend.c (17974B)
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 #include "config/aom_scale_rtcd.h" 16 17 #include "aom/aom_integer.h" 18 #include "aom_mem/aom_mem.h" 19 #include "aom_ports/mem.h" 20 #include "aom_scale/yv12config.h" 21 22 static void extend_plane(uint8_t *const src, int src_stride, int width, 23 int height, int extend_top, int extend_left, 24 int extend_bottom, int extend_right, int v_start, 25 int v_end) { 26 assert(src != NULL); 27 int i; 28 const int linesize = extend_left + extend_right + width; 29 assert(linesize <= src_stride); 30 31 /* copy the left and right most columns out */ 32 uint8_t *src_ptr1 = src + v_start * src_stride; 33 uint8_t *src_ptr2 = src + v_start * src_stride + width - 1; 34 uint8_t *dst_ptr1 = src + v_start * src_stride - extend_left; 35 uint8_t *dst_ptr2 = src_ptr2 + 1; 36 37 for (i = v_start; i < v_end; ++i) { 38 memset(dst_ptr1, src_ptr1[0], extend_left); 39 memset(dst_ptr2, src_ptr2[0], extend_right); 40 src_ptr1 += src_stride; 41 src_ptr2 += src_stride; 42 dst_ptr1 += src_stride; 43 dst_ptr2 += src_stride; 44 } 45 46 /* Now copy the top and bottom lines into each line of the respective 47 * borders 48 */ 49 src_ptr1 = src - extend_left; 50 dst_ptr1 = src_ptr1 + src_stride * -extend_top; 51 52 for (i = 0; i < extend_top; ++i) { 53 memcpy(dst_ptr1, src_ptr1, linesize); 54 dst_ptr1 += src_stride; 55 } 56 57 src_ptr2 = src_ptr1 + src_stride * (height - 1); 58 dst_ptr2 = src_ptr2; 59 60 for (i = 0; i < extend_bottom; ++i) { 61 dst_ptr2 += src_stride; 62 memcpy(dst_ptr2, src_ptr2, linesize); 63 } 64 } 65 66 #if CONFIG_AV1_HIGHBITDEPTH 67 static void extend_plane_high(uint8_t *const src8, int src_stride, int width, 68 int height, int extend_top, int extend_left, 69 int extend_bottom, int extend_right, int v_start, 70 int v_end) { 71 int i; 72 const int linesize = extend_left + extend_right + width; 73 assert(linesize <= src_stride); 74 uint16_t *src = CONVERT_TO_SHORTPTR(src8); 75 76 /* copy the left and right most columns out */ 77 uint16_t *src_ptr1 = src + v_start * src_stride; 78 uint16_t *src_ptr2 = src + v_start * src_stride + width - 1; 79 uint16_t *dst_ptr1 = src + v_start * src_stride - extend_left; 80 uint16_t *dst_ptr2 = src_ptr2 + 1; 81 82 for (i = v_start; i < v_end; ++i) { 83 aom_memset16(dst_ptr1, src_ptr1[0], extend_left); 84 aom_memset16(dst_ptr2, src_ptr2[0], extend_right); 85 src_ptr1 += src_stride; 86 src_ptr2 += src_stride; 87 dst_ptr1 += src_stride; 88 dst_ptr2 += src_stride; 89 } 90 91 /* Now copy the top and bottom lines into each line of the respective 92 * borders 93 */ 94 src_ptr1 = src - extend_left; 95 dst_ptr1 = src_ptr1 + src_stride * -extend_top; 96 97 for (i = 0; i < extend_top; ++i) { 98 memcpy(dst_ptr1, src_ptr1, linesize * sizeof(uint16_t)); 99 dst_ptr1 += src_stride; 100 } 101 102 src_ptr2 = src_ptr1 + src_stride * (height - 1); 103 dst_ptr2 = src_ptr2; 104 105 for (i = 0; i < extend_bottom; ++i) { 106 dst_ptr2 += src_stride; 107 memcpy(dst_ptr2, src_ptr2, linesize * sizeof(uint16_t)); 108 } 109 } 110 #endif // CONFIG_AV1_HIGHBITDEPTH 111 112 void aom_extend_frame_borders_plane_row_c(const YV12_BUFFER_CONFIG *ybf, 113 int plane, int v_start, int v_end) { 114 const int ext_size = ybf->border; 115 const int ss_x = ybf->subsampling_x; 116 const int ss_y = ybf->subsampling_y; 117 118 assert(ybf->y_height - ybf->y_crop_height < 16); 119 assert(ybf->y_width - ybf->y_crop_width < 16); 120 assert(ybf->y_height - ybf->y_crop_height >= 0); 121 assert(ybf->y_width - ybf->y_crop_width >= 0); 122 123 const int is_uv = plane > 0; 124 const int top = ext_size >> (is_uv ? ss_y : 0); 125 const int left = ext_size >> (is_uv ? ss_x : 0); 126 const int bottom = top + ybf->heights[is_uv] - ybf->crop_heights[is_uv]; 127 const int right = left + ybf->widths[is_uv] - ybf->crop_widths[is_uv]; 128 const int extend_top_border = (v_start == 0); 129 const int extend_bottom_border = (v_end == ybf->crop_heights[is_uv]); 130 131 #if CONFIG_AV1_HIGHBITDEPTH 132 if (ybf->flags & YV12_FLAG_HIGHBITDEPTH) { 133 extend_plane_high(ybf->buffers[plane], ybf->strides[is_uv], 134 ybf->crop_widths[is_uv], ybf->crop_heights[is_uv], 135 extend_top_border ? top : 0, left, 136 extend_bottom_border ? bottom : 0, right, v_start, v_end); 137 return; 138 } 139 #endif 140 141 extend_plane(ybf->buffers[plane], ybf->strides[is_uv], 142 ybf->crop_widths[is_uv], ybf->crop_heights[is_uv], 143 extend_top_border ? top : 0, left, 144 extend_bottom_border ? bottom : 0, right, v_start, v_end); 145 } 146 147 void aom_yv12_extend_frame_borders_c(YV12_BUFFER_CONFIG *ybf, 148 const int num_planes) { 149 assert(ybf->border % 2 == 0); 150 assert(ybf->y_height - ybf->y_crop_height < 16); 151 assert(ybf->y_width - ybf->y_crop_width < 16); 152 assert(ybf->y_height - ybf->y_crop_height >= 0); 153 assert(ybf->y_width - ybf->y_crop_width >= 0); 154 155 #if CONFIG_AV1_HIGHBITDEPTH 156 if (ybf->flags & YV12_FLAG_HIGHBITDEPTH) { 157 for (int plane = 0; plane < num_planes; ++plane) { 158 const int is_uv = plane > 0; 159 const int plane_border = ybf->border >> is_uv; 160 extend_plane_high( 161 ybf->buffers[plane], ybf->strides[is_uv], ybf->crop_widths[is_uv], 162 ybf->crop_heights[is_uv], plane_border, plane_border, 163 plane_border + ybf->heights[is_uv] - ybf->crop_heights[is_uv], 164 plane_border + ybf->widths[is_uv] - ybf->crop_widths[is_uv], 0, 165 ybf->crop_heights[is_uv]); 166 } 167 return; 168 } 169 #endif 170 171 for (int plane = 0; plane < num_planes; ++plane) { 172 const int is_uv = plane > 0; 173 const int plane_border = ybf->border >> is_uv; 174 extend_plane(ybf->buffers[plane], ybf->strides[is_uv], 175 ybf->crop_widths[is_uv], ybf->crop_heights[is_uv], 176 plane_border, plane_border, 177 plane_border + ybf->heights[is_uv] - ybf->crop_heights[is_uv], 178 plane_border + ybf->widths[is_uv] - ybf->crop_widths[is_uv], 0, 179 ybf->crop_heights[is_uv]); 180 } 181 } 182 183 static void extend_frame(YV12_BUFFER_CONFIG *const ybf, int ext_size, 184 const int num_planes) { 185 const int ss_x = ybf->subsampling_x; 186 const int ss_y = ybf->subsampling_y; 187 188 assert(ybf->y_height - ybf->y_crop_height < 16); 189 assert(ybf->y_width - ybf->y_crop_width < 16); 190 assert(ybf->y_height - ybf->y_crop_height >= 0); 191 assert(ybf->y_width - ybf->y_crop_width >= 0); 192 193 #if CONFIG_AV1_HIGHBITDEPTH 194 if (ybf->flags & YV12_FLAG_HIGHBITDEPTH) { 195 for (int plane = 0; plane < num_planes; ++plane) { 196 const int is_uv = plane > 0; 197 const int top = ext_size >> (is_uv ? ss_y : 0); 198 const int left = ext_size >> (is_uv ? ss_x : 0); 199 const int bottom = top + ybf->heights[is_uv] - ybf->crop_heights[is_uv]; 200 const int right = left + ybf->widths[is_uv] - ybf->crop_widths[is_uv]; 201 extend_plane_high(ybf->buffers[plane], ybf->strides[is_uv], 202 ybf->crop_widths[is_uv], ybf->crop_heights[is_uv], top, 203 left, bottom, right, 0, ybf->crop_heights[is_uv]); 204 } 205 return; 206 } 207 #endif 208 209 for (int plane = 0; plane < num_planes; ++plane) { 210 const int is_uv = plane > 0; 211 const int top = ext_size >> (is_uv ? ss_y : 0); 212 const int left = ext_size >> (is_uv ? ss_x : 0); 213 const int bottom = top + ybf->heights[is_uv] - ybf->crop_heights[is_uv]; 214 const int right = left + ybf->widths[is_uv] - ybf->crop_widths[is_uv]; 215 extend_plane(ybf->buffers[plane], ybf->strides[is_uv], 216 ybf->crop_widths[is_uv], ybf->crop_heights[is_uv], top, left, 217 bottom, right, 0, ybf->crop_heights[is_uv]); 218 } 219 } 220 221 void aom_extend_frame_borders_c(YV12_BUFFER_CONFIG *ybf, const int num_planes) { 222 extend_frame(ybf, ybf->border, num_planes); 223 } 224 225 #if CONFIG_AV1_HIGHBITDEPTH 226 static void memcpy_short_addr(uint8_t *dst8, const uint8_t *src8, int num) { 227 uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); 228 uint16_t *src = CONVERT_TO_SHORTPTR(src8); 229 memcpy(dst, src, num * sizeof(uint16_t)); 230 } 231 #endif 232 233 // Copies the source image into the destination image and updates the 234 // destination's UMV borders. 235 // Note: The frames are assumed to be identical in size. 236 void aom_yv12_copy_frame_c(const YV12_BUFFER_CONFIG *src_bc, 237 YV12_BUFFER_CONFIG *dst_bc, const int num_planes) { 238 assert(src_bc->y_width == dst_bc->y_width); 239 assert(src_bc->y_height == dst_bc->y_height); 240 241 #if CONFIG_AV1_HIGHBITDEPTH 242 assert((src_bc->flags & YV12_FLAG_HIGHBITDEPTH) == 243 (dst_bc->flags & YV12_FLAG_HIGHBITDEPTH)); 244 245 if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) { 246 for (int plane = 0; plane < num_planes; ++plane) { 247 const uint8_t *plane_src = src_bc->buffers[plane]; 248 uint8_t *plane_dst = dst_bc->buffers[plane]; 249 const int is_uv = plane > 0; 250 251 for (int row = 0; row < src_bc->heights[is_uv]; ++row) { 252 memcpy_short_addr(plane_dst, plane_src, src_bc->widths[is_uv]); 253 plane_src += src_bc->strides[is_uv]; 254 plane_dst += dst_bc->strides[is_uv]; 255 } 256 } 257 aom_yv12_extend_frame_borders_c(dst_bc, num_planes); 258 return; 259 } 260 #endif 261 for (int plane = 0; plane < num_planes; ++plane) { 262 const uint8_t *plane_src = src_bc->buffers[plane]; 263 uint8_t *plane_dst = dst_bc->buffers[plane]; 264 const int is_uv = plane > 0; 265 266 for (int row = 0; row < src_bc->heights[is_uv]; ++row) { 267 memcpy(plane_dst, plane_src, src_bc->widths[is_uv]); 268 plane_src += src_bc->strides[is_uv]; 269 plane_dst += dst_bc->strides[is_uv]; 270 } 271 } 272 aom_yv12_extend_frame_borders_c(dst_bc, num_planes); 273 } 274 275 void aom_yv12_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc, 276 YV12_BUFFER_CONFIG *dst_ybc, int use_crop) { 277 int row; 278 int width = use_crop ? src_ybc->y_crop_width : src_ybc->y_width; 279 int height = use_crop ? src_ybc->y_crop_height : src_ybc->y_height; 280 const uint8_t *src = src_ybc->y_buffer; 281 uint8_t *dst = dst_ybc->y_buffer; 282 283 #if CONFIG_AV1_HIGHBITDEPTH 284 if (src_ybc->flags & YV12_FLAG_HIGHBITDEPTH) { 285 const uint16_t *src16 = CONVERT_TO_SHORTPTR(src); 286 uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst); 287 for (row = 0; row < height; ++row) { 288 memcpy(dst16, src16, width * sizeof(uint16_t)); 289 src16 += src_ybc->y_stride; 290 dst16 += dst_ybc->y_stride; 291 } 292 return; 293 } 294 #endif 295 296 for (row = 0; row < height; ++row) { 297 memcpy(dst, src, width); 298 src += src_ybc->y_stride; 299 dst += dst_ybc->y_stride; 300 } 301 } 302 303 void aom_yv12_copy_u_c(const YV12_BUFFER_CONFIG *src_bc, 304 YV12_BUFFER_CONFIG *dst_bc, int use_crop) { 305 int row; 306 int width = use_crop ? src_bc->uv_crop_width : src_bc->uv_width; 307 int height = use_crop ? src_bc->uv_crop_height : src_bc->uv_height; 308 const uint8_t *src = src_bc->u_buffer; 309 uint8_t *dst = dst_bc->u_buffer; 310 #if CONFIG_AV1_HIGHBITDEPTH 311 if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) { 312 const uint16_t *src16 = CONVERT_TO_SHORTPTR(src); 313 uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst); 314 for (row = 0; row < height; ++row) { 315 memcpy(dst16, src16, width * sizeof(uint16_t)); 316 src16 += src_bc->uv_stride; 317 dst16 += dst_bc->uv_stride; 318 } 319 return; 320 } 321 #endif 322 for (row = 0; row < height; ++row) { 323 memcpy(dst, src, width); 324 src += src_bc->uv_stride; 325 dst += dst_bc->uv_stride; 326 } 327 } 328 329 void aom_yv12_copy_v_c(const YV12_BUFFER_CONFIG *src_bc, 330 YV12_BUFFER_CONFIG *dst_bc, int use_crop) { 331 int row; 332 int width = use_crop ? src_bc->uv_crop_width : src_bc->uv_width; 333 int height = use_crop ? src_bc->uv_crop_height : src_bc->uv_height; 334 const uint8_t *src = src_bc->v_buffer; 335 uint8_t *dst = dst_bc->v_buffer; 336 #if CONFIG_AV1_HIGHBITDEPTH 337 if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) { 338 const uint16_t *src16 = CONVERT_TO_SHORTPTR(src); 339 uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst); 340 for (row = 0; row < height; ++row) { 341 memcpy(dst16, src16, width * sizeof(uint16_t)); 342 src16 += src_bc->uv_stride; 343 dst16 += dst_bc->uv_stride; 344 } 345 return; 346 } 347 #endif 348 for (row = 0; row < height; ++row) { 349 memcpy(dst, src, width); 350 src += src_bc->uv_stride; 351 dst += dst_bc->uv_stride; 352 } 353 } 354 355 void aom_yv12_partial_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc, int hstart1, 356 int hend1, int vstart1, int vend1, 357 YV12_BUFFER_CONFIG *dst_ybc, int hstart2, 358 int vstart2) { 359 int row; 360 const uint8_t *src = src_ybc->y_buffer; 361 uint8_t *dst = dst_ybc->y_buffer; 362 #if CONFIG_AV1_HIGHBITDEPTH 363 if (src_ybc->flags & YV12_FLAG_HIGHBITDEPTH) { 364 const uint16_t *src16 = 365 CONVERT_TO_SHORTPTR(src + vstart1 * src_ybc->y_stride + hstart1); 366 uint16_t *dst16 = 367 CONVERT_TO_SHORTPTR(dst + vstart2 * dst_ybc->y_stride + hstart2); 368 369 for (row = vstart1; row < vend1; ++row) { 370 memcpy(dst16, src16, (hend1 - hstart1) * sizeof(uint16_t)); 371 src16 += src_ybc->y_stride; 372 dst16 += dst_ybc->y_stride; 373 } 374 return; 375 } 376 #endif 377 src = (src + vstart1 * src_ybc->y_stride + hstart1); 378 dst = (dst + vstart2 * dst_ybc->y_stride + hstart2); 379 380 for (row = vstart1; row < vend1; ++row) { 381 memcpy(dst, src, (hend1 - hstart1)); 382 src += src_ybc->y_stride; 383 dst += dst_ybc->y_stride; 384 } 385 } 386 387 void aom_yv12_partial_coloc_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc, 388 YV12_BUFFER_CONFIG *dst_ybc, int hstart, 389 int hend, int vstart, int vend) { 390 aom_yv12_partial_copy_y_c(src_ybc, hstart, hend, vstart, vend, dst_ybc, 391 hstart, vstart); 392 } 393 394 void aom_yv12_partial_copy_u_c(const YV12_BUFFER_CONFIG *src_bc, int hstart1, 395 int hend1, int vstart1, int vend1, 396 YV12_BUFFER_CONFIG *dst_bc, int hstart2, 397 int vstart2) { 398 int row; 399 const uint8_t *src = src_bc->u_buffer; 400 uint8_t *dst = dst_bc->u_buffer; 401 #if CONFIG_AV1_HIGHBITDEPTH 402 if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) { 403 const uint16_t *src16 = 404 CONVERT_TO_SHORTPTR(src + vstart1 * src_bc->uv_stride + hstart1); 405 uint16_t *dst16 = 406 CONVERT_TO_SHORTPTR(dst + vstart2 * dst_bc->uv_stride + hstart2); 407 for (row = vstart1; row < vend1; ++row) { 408 memcpy(dst16, src16, (hend1 - hstart1) * sizeof(uint16_t)); 409 src16 += src_bc->uv_stride; 410 dst16 += dst_bc->uv_stride; 411 } 412 return; 413 } 414 #endif 415 src = (src + vstart1 * src_bc->uv_stride + hstart1); 416 dst = (dst + vstart2 * dst_bc->uv_stride + hstart2); 417 418 for (row = vstart1; row < vend1; ++row) { 419 memcpy(dst, src, (hend1 - hstart1)); 420 src += src_bc->uv_stride; 421 dst += dst_bc->uv_stride; 422 } 423 } 424 425 void aom_yv12_partial_coloc_copy_u_c(const YV12_BUFFER_CONFIG *src_bc, 426 YV12_BUFFER_CONFIG *dst_bc, int hstart, 427 int hend, int vstart, int vend) { 428 aom_yv12_partial_copy_u_c(src_bc, hstart, hend, vstart, vend, dst_bc, hstart, 429 vstart); 430 } 431 432 void aom_yv12_partial_copy_v_c(const YV12_BUFFER_CONFIG *src_bc, int hstart1, 433 int hend1, int vstart1, int vend1, 434 YV12_BUFFER_CONFIG *dst_bc, int hstart2, 435 int vstart2) { 436 int row; 437 const uint8_t *src = src_bc->v_buffer; 438 uint8_t *dst = dst_bc->v_buffer; 439 #if CONFIG_AV1_HIGHBITDEPTH 440 if (src_bc->flags & YV12_FLAG_HIGHBITDEPTH) { 441 const uint16_t *src16 = 442 CONVERT_TO_SHORTPTR(src + vstart1 * src_bc->uv_stride + hstart1); 443 uint16_t *dst16 = 444 CONVERT_TO_SHORTPTR(dst + vstart2 * dst_bc->uv_stride + hstart2); 445 for (row = vstart1; row < vend1; ++row) { 446 memcpy(dst16, src16, (hend1 - hstart1) * sizeof(uint16_t)); 447 src16 += src_bc->uv_stride; 448 dst16 += dst_bc->uv_stride; 449 } 450 return; 451 } 452 #endif 453 src = (src + vstart1 * src_bc->uv_stride + hstart1); 454 dst = (dst + vstart2 * dst_bc->uv_stride + hstart2); 455 456 for (row = vstart1; row < vend1; ++row) { 457 memcpy(dst, src, (hend1 - hstart1)); 458 src += src_bc->uv_stride; 459 dst += dst_bc->uv_stride; 460 } 461 } 462 463 void aom_yv12_partial_coloc_copy_v_c(const YV12_BUFFER_CONFIG *src_bc, 464 YV12_BUFFER_CONFIG *dst_bc, int hstart, 465 int hend, int vstart, int vend) { 466 aom_yv12_partial_copy_v_c(src_bc, hstart, hend, vstart, vend, dst_bc, hstart, 467 vstart); 468 } 469 470 int aom_yv12_realloc_with_new_border_c(YV12_BUFFER_CONFIG *ybf, int new_border, 471 int byte_alignment, bool alloc_pyramid, 472 int num_planes) { 473 if (ybf) { 474 if (new_border == ybf->border) return 0; 475 YV12_BUFFER_CONFIG new_buf; 476 memset(&new_buf, 0, sizeof(new_buf)); 477 const int error = aom_alloc_frame_buffer( 478 &new_buf, ybf->y_crop_width, ybf->y_crop_height, ybf->subsampling_x, 479 ybf->subsampling_y, ybf->flags & YV12_FLAG_HIGHBITDEPTH, new_border, 480 byte_alignment, alloc_pyramid, 0); 481 if (error) return error; 482 // Copy image buffer 483 aom_yv12_copy_frame(ybf, &new_buf, num_planes); 484 485 // Extend up to new border 486 aom_extend_frame_borders(&new_buf, num_planes); 487 488 // Now free the old buffer and replace with the new 489 aom_free_frame_buffer(ybf); 490 *ybf = new_buf; 491 return 0; 492 } 493 return -2; 494 }