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