1/* 2 * Copyright 2013 The LibYuv 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 "libyuv/scale.h" 12 13#include <assert.h> 14#include <string.h> 15 16#include "libyuv/cpu_id.h" 17#include "libyuv/planar_functions.h" // For CopyARGB 18#include "libyuv/row.h" 19#include "libyuv/scale_row.h" 20 21#ifdef __cplusplus 22namespace libyuv { 23extern "C" { 24#endif 25 26static __inline int Abs(int v) { 27 return v >= 0 ? v : -v; 28} 29 30// CPU agnostic row functions 31void ScaleRowDown2_C(const uint8* src_ptr, ptrdiff_t src_stride, 32 uint8* dst, int dst_width) { 33 int x; 34 for (x = 0; x < dst_width - 1; x += 2) { 35 dst[0] = src_ptr[1]; 36 dst[1] = src_ptr[3]; 37 dst += 2; 38 src_ptr += 4; 39 } 40 if (dst_width & 1) { 41 dst[0] = src_ptr[1]; 42 } 43} 44 45void ScaleRowDown2_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 46 uint16* dst, int dst_width) { 47 int x; 48 for (x = 0; x < dst_width - 1; x += 2) { 49 dst[0] = src_ptr[1]; 50 dst[1] = src_ptr[3]; 51 dst += 2; 52 src_ptr += 4; 53 } 54 if (dst_width & 1) { 55 dst[0] = src_ptr[1]; 56 } 57} 58 59void ScaleRowDown2Linear_C(const uint8* src_ptr, ptrdiff_t src_stride, 60 uint8* dst, int dst_width) { 61 const uint8* s = src_ptr; 62 int x; 63 for (x = 0; x < dst_width - 1; x += 2) { 64 dst[0] = (s[0] + s[1] + 1) >> 1; 65 dst[1] = (s[2] + s[3] + 1) >> 1; 66 dst += 2; 67 s += 4; 68 } 69 if (dst_width & 1) { 70 dst[0] = (s[0] + s[1] + 1) >> 1; 71 } 72} 73 74void ScaleRowDown2Linear_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 75 uint16* dst, int dst_width) { 76 const uint16* s = src_ptr; 77 int x; 78 for (x = 0; x < dst_width - 1; x += 2) { 79 dst[0] = (s[0] + s[1] + 1) >> 1; 80 dst[1] = (s[2] + s[3] + 1) >> 1; 81 dst += 2; 82 s += 4; 83 } 84 if (dst_width & 1) { 85 dst[0] = (s[0] + s[1] + 1) >> 1; 86 } 87} 88 89void ScaleRowDown2Box_C(const uint8* src_ptr, ptrdiff_t src_stride, 90 uint8* dst, int dst_width) { 91 const uint8* s = src_ptr; 92 const uint8* t = src_ptr + src_stride; 93 int x; 94 for (x = 0; x < dst_width - 1; x += 2) { 95 dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2; 96 dst[1] = (s[2] + s[3] + t[2] + t[3] + 2) >> 2; 97 dst += 2; 98 s += 4; 99 t += 4; 100 } 101 if (dst_width & 1) { 102 dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2; 103 } 104} 105 106void ScaleRowDown2Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 107 uint16* dst, int dst_width) { 108 const uint16* s = src_ptr; 109 const uint16* t = src_ptr + src_stride; 110 int x; 111 for (x = 0; x < dst_width - 1; x += 2) { 112 dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2; 113 dst[1] = (s[2] + s[3] + t[2] + t[3] + 2) >> 2; 114 dst += 2; 115 s += 4; 116 t += 4; 117 } 118 if (dst_width & 1) { 119 dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2; 120 } 121} 122 123void ScaleRowDown4_C(const uint8* src_ptr, ptrdiff_t src_stride, 124 uint8* dst, int dst_width) { 125 int x; 126 for (x = 0; x < dst_width - 1; x += 2) { 127 dst[0] = src_ptr[2]; 128 dst[1] = src_ptr[6]; 129 dst += 2; 130 src_ptr += 8; 131 } 132 if (dst_width & 1) { 133 dst[0] = src_ptr[2]; 134 } 135} 136 137void ScaleRowDown4_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 138 uint16* dst, int dst_width) { 139 int x; 140 for (x = 0; x < dst_width - 1; x += 2) { 141 dst[0] = src_ptr[2]; 142 dst[1] = src_ptr[6]; 143 dst += 2; 144 src_ptr += 8; 145 } 146 if (dst_width & 1) { 147 dst[0] = src_ptr[2]; 148 } 149} 150 151void ScaleRowDown4Box_C(const uint8* src_ptr, ptrdiff_t src_stride, 152 uint8* dst, int dst_width) { 153 intptr_t stride = src_stride; 154 int x; 155 for (x = 0; x < dst_width - 1; x += 2) { 156 dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] + 157 src_ptr[stride + 0] + src_ptr[stride + 1] + 158 src_ptr[stride + 2] + src_ptr[stride + 3] + 159 src_ptr[stride * 2 + 0] + src_ptr[stride * 2 + 1] + 160 src_ptr[stride * 2 + 2] + src_ptr[stride * 2 + 3] + 161 src_ptr[stride * 3 + 0] + src_ptr[stride * 3 + 1] + 162 src_ptr[stride * 3 + 2] + src_ptr[stride * 3 + 3] + 163 8) >> 4; 164 dst[1] = (src_ptr[4] + src_ptr[5] + src_ptr[6] + src_ptr[7] + 165 src_ptr[stride + 4] + src_ptr[stride + 5] + 166 src_ptr[stride + 6] + src_ptr[stride + 7] + 167 src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5] + 168 src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7] + 169 src_ptr[stride * 3 + 4] + src_ptr[stride * 3 + 5] + 170 src_ptr[stride * 3 + 6] + src_ptr[stride * 3 + 7] + 171 8) >> 4; 172 dst += 2; 173 src_ptr += 8; 174 } 175 if (dst_width & 1) { 176 dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] + 177 src_ptr[stride + 0] + src_ptr[stride + 1] + 178 src_ptr[stride + 2] + src_ptr[stride + 3] + 179 src_ptr[stride * 2 + 0] + src_ptr[stride * 2 + 1] + 180 src_ptr[stride * 2 + 2] + src_ptr[stride * 2 + 3] + 181 src_ptr[stride * 3 + 0] + src_ptr[stride * 3 + 1] + 182 src_ptr[stride * 3 + 2] + src_ptr[stride * 3 + 3] + 183 8) >> 4; 184 } 185} 186 187void ScaleRowDown4Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 188 uint16* dst, int dst_width) { 189 intptr_t stride = src_stride; 190 int x; 191 for (x = 0; x < dst_width - 1; x += 2) { 192 dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] + 193 src_ptr[stride + 0] + src_ptr[stride + 1] + 194 src_ptr[stride + 2] + src_ptr[stride + 3] + 195 src_ptr[stride * 2 + 0] + src_ptr[stride * 2 + 1] + 196 src_ptr[stride * 2 + 2] + src_ptr[stride * 2 + 3] + 197 src_ptr[stride * 3 + 0] + src_ptr[stride * 3 + 1] + 198 src_ptr[stride * 3 + 2] + src_ptr[stride * 3 + 3] + 199 8) >> 4; 200 dst[1] = (src_ptr[4] + src_ptr[5] + src_ptr[6] + src_ptr[7] + 201 src_ptr[stride + 4] + src_ptr[stride + 5] + 202 src_ptr[stride + 6] + src_ptr[stride + 7] + 203 src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5] + 204 src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7] + 205 src_ptr[stride * 3 + 4] + src_ptr[stride * 3 + 5] + 206 src_ptr[stride * 3 + 6] + src_ptr[stride * 3 + 7] + 207 8) >> 4; 208 dst += 2; 209 src_ptr += 8; 210 } 211 if (dst_width & 1) { 212 dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] + 213 src_ptr[stride + 0] + src_ptr[stride + 1] + 214 src_ptr[stride + 2] + src_ptr[stride + 3] + 215 src_ptr[stride * 2 + 0] + src_ptr[stride * 2 + 1] + 216 src_ptr[stride * 2 + 2] + src_ptr[stride * 2 + 3] + 217 src_ptr[stride * 3 + 0] + src_ptr[stride * 3 + 1] + 218 src_ptr[stride * 3 + 2] + src_ptr[stride * 3 + 3] + 219 8) >> 4; 220 } 221} 222 223void ScaleRowDown34_C(const uint8* src_ptr, ptrdiff_t src_stride, 224 uint8* dst, int dst_width) { 225 int x; 226 assert((dst_width % 3 == 0) && (dst_width > 0)); 227 for (x = 0; x < dst_width; x += 3) { 228 dst[0] = src_ptr[0]; 229 dst[1] = src_ptr[1]; 230 dst[2] = src_ptr[3]; 231 dst += 3; 232 src_ptr += 4; 233 } 234} 235 236void ScaleRowDown34_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 237 uint16* dst, int dst_width) { 238 int x; 239 assert((dst_width % 3 == 0) && (dst_width > 0)); 240 for (x = 0; x < dst_width; x += 3) { 241 dst[0] = src_ptr[0]; 242 dst[1] = src_ptr[1]; 243 dst[2] = src_ptr[3]; 244 dst += 3; 245 src_ptr += 4; 246 } 247} 248 249// Filter rows 0 and 1 together, 3 : 1 250void ScaleRowDown34_0_Box_C(const uint8* src_ptr, ptrdiff_t src_stride, 251 uint8* d, int dst_width) { 252 const uint8* s = src_ptr; 253 const uint8* t = src_ptr + src_stride; 254 int x; 255 assert((dst_width % 3 == 0) && (dst_width > 0)); 256 for (x = 0; x < dst_width; x += 3) { 257 uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; 258 uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; 259 uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; 260 uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; 261 uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; 262 uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; 263 d[0] = (a0 * 3 + b0 + 2) >> 2; 264 d[1] = (a1 * 3 + b1 + 2) >> 2; 265 d[2] = (a2 * 3 + b2 + 2) >> 2; 266 d += 3; 267 s += 4; 268 t += 4; 269 } 270} 271 272void ScaleRowDown34_0_Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 273 uint16* d, int dst_width) { 274 const uint16* s = src_ptr; 275 const uint16* t = src_ptr + src_stride; 276 int x; 277 assert((dst_width % 3 == 0) && (dst_width > 0)); 278 for (x = 0; x < dst_width; x += 3) { 279 uint16 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; 280 uint16 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; 281 uint16 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; 282 uint16 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; 283 uint16 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; 284 uint16 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; 285 d[0] = (a0 * 3 + b0 + 2) >> 2; 286 d[1] = (a1 * 3 + b1 + 2) >> 2; 287 d[2] = (a2 * 3 + b2 + 2) >> 2; 288 d += 3; 289 s += 4; 290 t += 4; 291 } 292} 293 294// Filter rows 1 and 2 together, 1 : 1 295void ScaleRowDown34_1_Box_C(const uint8* src_ptr, ptrdiff_t src_stride, 296 uint8* d, int dst_width) { 297 const uint8* s = src_ptr; 298 const uint8* t = src_ptr + src_stride; 299 int x; 300 assert((dst_width % 3 == 0) && (dst_width > 0)); 301 for (x = 0; x < dst_width; x += 3) { 302 uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; 303 uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; 304 uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; 305 uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; 306 uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; 307 uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; 308 d[0] = (a0 + b0 + 1) >> 1; 309 d[1] = (a1 + b1 + 1) >> 1; 310 d[2] = (a2 + b2 + 1) >> 1; 311 d += 3; 312 s += 4; 313 t += 4; 314 } 315} 316 317void ScaleRowDown34_1_Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 318 uint16* d, int dst_width) { 319 const uint16* s = src_ptr; 320 const uint16* t = src_ptr + src_stride; 321 int x; 322 assert((dst_width % 3 == 0) && (dst_width > 0)); 323 for (x = 0; x < dst_width; x += 3) { 324 uint16 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2; 325 uint16 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1; 326 uint16 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2; 327 uint16 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2; 328 uint16 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1; 329 uint16 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2; 330 d[0] = (a0 + b0 + 1) >> 1; 331 d[1] = (a1 + b1 + 1) >> 1; 332 d[2] = (a2 + b2 + 1) >> 1; 333 d += 3; 334 s += 4; 335 t += 4; 336 } 337} 338 339// Scales a single row of pixels using point sampling. 340void ScaleCols_C(uint8* dst_ptr, const uint8* src_ptr, 341 int dst_width, int x, int dx) { 342 int j; 343 for (j = 0; j < dst_width - 1; j += 2) { 344 dst_ptr[0] = src_ptr[x >> 16]; 345 x += dx; 346 dst_ptr[1] = src_ptr[x >> 16]; 347 x += dx; 348 dst_ptr += 2; 349 } 350 if (dst_width & 1) { 351 dst_ptr[0] = src_ptr[x >> 16]; 352 } 353} 354 355void ScaleCols_16_C(uint16* dst_ptr, const uint16* src_ptr, 356 int dst_width, int x, int dx) { 357 int j; 358 for (j = 0; j < dst_width - 1; j += 2) { 359 dst_ptr[0] = src_ptr[x >> 16]; 360 x += dx; 361 dst_ptr[1] = src_ptr[x >> 16]; 362 x += dx; 363 dst_ptr += 2; 364 } 365 if (dst_width & 1) { 366 dst_ptr[0] = src_ptr[x >> 16]; 367 } 368} 369 370// Scales a single row of pixels up by 2x using point sampling. 371void ScaleColsUp2_C(uint8* dst_ptr, const uint8* src_ptr, 372 int dst_width, int x, int dx) { 373 int j; 374 for (j = 0; j < dst_width - 1; j += 2) { 375 dst_ptr[1] = dst_ptr[0] = src_ptr[0]; 376 src_ptr += 1; 377 dst_ptr += 2; 378 } 379 if (dst_width & 1) { 380 dst_ptr[0] = src_ptr[0]; 381 } 382} 383 384void ScaleColsUp2_16_C(uint16* dst_ptr, const uint16* src_ptr, 385 int dst_width, int x, int dx) { 386 int j; 387 for (j = 0; j < dst_width - 1; j += 2) { 388 dst_ptr[1] = dst_ptr[0] = src_ptr[0]; 389 src_ptr += 1; 390 dst_ptr += 2; 391 } 392 if (dst_width & 1) { 393 dst_ptr[0] = src_ptr[0]; 394 } 395} 396 397// (1-f)a + fb can be replaced with a + f(b-a) 398#define BLENDER(a, b, f) (uint8)((int)(a) + \ 399 ((int)(f) * ((int)(b) - (int)(a)) >> 16)) 400 401void ScaleFilterCols_C(uint8* dst_ptr, const uint8* src_ptr, 402 int dst_width, int x, int dx) { 403 int j; 404 for (j = 0; j < dst_width - 1; j += 2) { 405 int xi = x >> 16; 406 int a = src_ptr[xi]; 407 int b = src_ptr[xi + 1]; 408 dst_ptr[0] = BLENDER(a, b, x & 0xffff); 409 x += dx; 410 xi = x >> 16; 411 a = src_ptr[xi]; 412 b = src_ptr[xi + 1]; 413 dst_ptr[1] = BLENDER(a, b, x & 0xffff); 414 x += dx; 415 dst_ptr += 2; 416 } 417 if (dst_width & 1) { 418 int xi = x >> 16; 419 int a = src_ptr[xi]; 420 int b = src_ptr[xi + 1]; 421 dst_ptr[0] = BLENDER(a, b, x & 0xffff); 422 } 423} 424 425void ScaleFilterCols64_C(uint8* dst_ptr, const uint8* src_ptr, 426 int dst_width, int x32, int dx) { 427 int64 x = (int64)(x32); 428 int j; 429 for (j = 0; j < dst_width - 1; j += 2) { 430 int64 xi = x >> 16; 431 int a = src_ptr[xi]; 432 int b = src_ptr[xi + 1]; 433 dst_ptr[0] = BLENDER(a, b, x & 0xffff); 434 x += dx; 435 xi = x >> 16; 436 a = src_ptr[xi]; 437 b = src_ptr[xi + 1]; 438 dst_ptr[1] = BLENDER(a, b, x & 0xffff); 439 x += dx; 440 dst_ptr += 2; 441 } 442 if (dst_width & 1) { 443 int64 xi = x >> 16; 444 int a = src_ptr[xi]; 445 int b = src_ptr[xi + 1]; 446 dst_ptr[0] = BLENDER(a, b, x & 0xffff); 447 } 448} 449#undef BLENDER 450 451#define BLENDER(a, b, f) (uint16)((int)(a) + \ 452 ((int)(f) * ((int)(b) - (int)(a)) >> 16)) 453 454void ScaleFilterCols_16_C(uint16* dst_ptr, const uint16* src_ptr, 455 int dst_width, int x, int dx) { 456 int j; 457 for (j = 0; j < dst_width - 1; j += 2) { 458 int xi = x >> 16; 459 int a = src_ptr[xi]; 460 int b = src_ptr[xi + 1]; 461 dst_ptr[0] = BLENDER(a, b, x & 0xffff); 462 x += dx; 463 xi = x >> 16; 464 a = src_ptr[xi]; 465 b = src_ptr[xi + 1]; 466 dst_ptr[1] = BLENDER(a, b, x & 0xffff); 467 x += dx; 468 dst_ptr += 2; 469 } 470 if (dst_width & 1) { 471 int xi = x >> 16; 472 int a = src_ptr[xi]; 473 int b = src_ptr[xi + 1]; 474 dst_ptr[0] = BLENDER(a, b, x & 0xffff); 475 } 476} 477 478void ScaleFilterCols64_16_C(uint16* dst_ptr, const uint16* src_ptr, 479 int dst_width, int x32, int dx) { 480 int64 x = (int64)(x32); 481 int j; 482 for (j = 0; j < dst_width - 1; j += 2) { 483 int64 xi = x >> 16; 484 int a = src_ptr[xi]; 485 int b = src_ptr[xi + 1]; 486 dst_ptr[0] = BLENDER(a, b, x & 0xffff); 487 x += dx; 488 xi = x >> 16; 489 a = src_ptr[xi]; 490 b = src_ptr[xi + 1]; 491 dst_ptr[1] = BLENDER(a, b, x & 0xffff); 492 x += dx; 493 dst_ptr += 2; 494 } 495 if (dst_width & 1) { 496 int64 xi = x >> 16; 497 int a = src_ptr[xi]; 498 int b = src_ptr[xi + 1]; 499 dst_ptr[0] = BLENDER(a, b, x & 0xffff); 500 } 501} 502#undef BLENDER 503 504void ScaleRowDown38_C(const uint8* src_ptr, ptrdiff_t src_stride, 505 uint8* dst, int dst_width) { 506 int x; 507 assert(dst_width % 3 == 0); 508 for (x = 0; x < dst_width; x += 3) { 509 dst[0] = src_ptr[0]; 510 dst[1] = src_ptr[3]; 511 dst[2] = src_ptr[6]; 512 dst += 3; 513 src_ptr += 8; 514 } 515} 516 517void ScaleRowDown38_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 518 uint16* dst, int dst_width) { 519 int x; 520 assert(dst_width % 3 == 0); 521 for (x = 0; x < dst_width; x += 3) { 522 dst[0] = src_ptr[0]; 523 dst[1] = src_ptr[3]; 524 dst[2] = src_ptr[6]; 525 dst += 3; 526 src_ptr += 8; 527 } 528} 529 530// 8x3 -> 3x1 531void ScaleRowDown38_3_Box_C(const uint8* src_ptr, 532 ptrdiff_t src_stride, 533 uint8* dst_ptr, int dst_width) { 534 intptr_t stride = src_stride; 535 int i; 536 assert((dst_width % 3 == 0) && (dst_width > 0)); 537 for (i = 0; i < dst_width; i += 3) { 538 dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + 539 src_ptr[stride + 0] + src_ptr[stride + 1] + 540 src_ptr[stride + 2] + src_ptr[stride * 2 + 0] + 541 src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2]) * 542 (65536 / 9) >> 16; 543 dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] + 544 src_ptr[stride + 3] + src_ptr[stride + 4] + 545 src_ptr[stride + 5] + src_ptr[stride * 2 + 3] + 546 src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5]) * 547 (65536 / 9) >> 16; 548 dst_ptr[2] = (src_ptr[6] + src_ptr[7] + 549 src_ptr[stride + 6] + src_ptr[stride + 7] + 550 src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7]) * 551 (65536 / 6) >> 16; 552 src_ptr += 8; 553 dst_ptr += 3; 554 } 555} 556 557void ScaleRowDown38_3_Box_16_C(const uint16* src_ptr, 558 ptrdiff_t src_stride, 559 uint16* dst_ptr, int dst_width) { 560 intptr_t stride = src_stride; 561 int i; 562 assert((dst_width % 3 == 0) && (dst_width > 0)); 563 for (i = 0; i < dst_width; i += 3) { 564 dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + 565 src_ptr[stride + 0] + src_ptr[stride + 1] + 566 src_ptr[stride + 2] + src_ptr[stride * 2 + 0] + 567 src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2]) * 568 (65536 / 9) >> 16; 569 dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] + 570 src_ptr[stride + 3] + src_ptr[stride + 4] + 571 src_ptr[stride + 5] + src_ptr[stride * 2 + 3] + 572 src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5]) * 573 (65536 / 9) >> 16; 574 dst_ptr[2] = (src_ptr[6] + src_ptr[7] + 575 src_ptr[stride + 6] + src_ptr[stride + 7] + 576 src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7]) * 577 (65536 / 6) >> 16; 578 src_ptr += 8; 579 dst_ptr += 3; 580 } 581} 582 583// 8x2 -> 3x1 584void ScaleRowDown38_2_Box_C(const uint8* src_ptr, ptrdiff_t src_stride, 585 uint8* dst_ptr, int dst_width) { 586 intptr_t stride = src_stride; 587 int i; 588 assert((dst_width % 3 == 0) && (dst_width > 0)); 589 for (i = 0; i < dst_width; i += 3) { 590 dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + 591 src_ptr[stride + 0] + src_ptr[stride + 1] + 592 src_ptr[stride + 2]) * (65536 / 6) >> 16; 593 dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] + 594 src_ptr[stride + 3] + src_ptr[stride + 4] + 595 src_ptr[stride + 5]) * (65536 / 6) >> 16; 596 dst_ptr[2] = (src_ptr[6] + src_ptr[7] + 597 src_ptr[stride + 6] + src_ptr[stride + 7]) * 598 (65536 / 4) >> 16; 599 src_ptr += 8; 600 dst_ptr += 3; 601 } 602} 603 604void ScaleRowDown38_2_Box_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 605 uint16* dst_ptr, int dst_width) { 606 intptr_t stride = src_stride; 607 int i; 608 assert((dst_width % 3 == 0) && (dst_width > 0)); 609 for (i = 0; i < dst_width; i += 3) { 610 dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + 611 src_ptr[stride + 0] + src_ptr[stride + 1] + 612 src_ptr[stride + 2]) * (65536 / 6) >> 16; 613 dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] + 614 src_ptr[stride + 3] + src_ptr[stride + 4] + 615 src_ptr[stride + 5]) * (65536 / 6) >> 16; 616 dst_ptr[2] = (src_ptr[6] + src_ptr[7] + 617 src_ptr[stride + 6] + src_ptr[stride + 7]) * 618 (65536 / 4) >> 16; 619 src_ptr += 8; 620 dst_ptr += 3; 621 } 622} 623 624void ScaleAddRows_C(const uint8* src_ptr, ptrdiff_t src_stride, 625 uint16* dst_ptr, int src_width, int src_height) { 626 int x; 627 assert(src_width > 0); 628 assert(src_height > 0); 629 for (x = 0; x < src_width; ++x) { 630 const uint8* s = src_ptr + x; 631 unsigned int sum = 0u; 632 int y; 633 for (y = 0; y < src_height; ++y) { 634 sum += s[0]; 635 s += src_stride; 636 } 637 // TODO(fbarchard): Consider limitting height to 256 to avoid overflow. 638 dst_ptr[x] = sum < 65535u ? sum : 65535u; 639 } 640} 641 642void ScaleAddRows_16_C(const uint16* src_ptr, ptrdiff_t src_stride, 643 uint32* dst_ptr, int src_width, int src_height) { 644 int x; 645 assert(src_width > 0); 646 assert(src_height > 0); 647 for (x = 0; x < src_width; ++x) { 648 const uint16* s = src_ptr + x; 649 unsigned int sum = 0u; 650 int y; 651 for (y = 0; y < src_height; ++y) { 652 sum += s[0]; 653 s += src_stride; 654 } 655 // No risk of overflow here now 656 dst_ptr[x] = sum; 657 } 658} 659 660void ScaleARGBRowDown2_C(const uint8* src_argb, 661 ptrdiff_t src_stride, 662 uint8* dst_argb, int dst_width) { 663 const uint32* src = (const uint32*)(src_argb); 664 uint32* dst = (uint32*)(dst_argb); 665 666 int x; 667 for (x = 0; x < dst_width - 1; x += 2) { 668 dst[0] = src[1]; 669 dst[1] = src[3]; 670 src += 4; 671 dst += 2; 672 } 673 if (dst_width & 1) { 674 dst[0] = src[1]; 675 } 676} 677 678void ScaleARGBRowDown2Linear_C(const uint8* src_argb, 679 ptrdiff_t src_stride, 680 uint8* dst_argb, int dst_width) { 681 int x; 682 for (x = 0; x < dst_width; ++x) { 683 dst_argb[0] = (src_argb[0] + src_argb[4] + 1) >> 1; 684 dst_argb[1] = (src_argb[1] + src_argb[5] + 1) >> 1; 685 dst_argb[2] = (src_argb[2] + src_argb[6] + 1) >> 1; 686 dst_argb[3] = (src_argb[3] + src_argb[7] + 1) >> 1; 687 src_argb += 8; 688 dst_argb += 4; 689 } 690} 691 692void ScaleARGBRowDown2Box_C(const uint8* src_argb, ptrdiff_t src_stride, 693 uint8* dst_argb, int dst_width) { 694 int x; 695 for (x = 0; x < dst_width; ++x) { 696 dst_argb[0] = (src_argb[0] + src_argb[4] + 697 src_argb[src_stride] + src_argb[src_stride + 4] + 2) >> 2; 698 dst_argb[1] = (src_argb[1] + src_argb[5] + 699 src_argb[src_stride + 1] + src_argb[src_stride + 5] + 2) >> 2; 700 dst_argb[2] = (src_argb[2] + src_argb[6] + 701 src_argb[src_stride + 2] + src_argb[src_stride + 6] + 2) >> 2; 702 dst_argb[3] = (src_argb[3] + src_argb[7] + 703 src_argb[src_stride + 3] + src_argb[src_stride + 7] + 2) >> 2; 704 src_argb += 8; 705 dst_argb += 4; 706 } 707} 708 709void ScaleARGBRowDownEven_C(const uint8* src_argb, ptrdiff_t src_stride, 710 int src_stepx, 711 uint8* dst_argb, int dst_width) { 712 const uint32* src = (const uint32*)(src_argb); 713 uint32* dst = (uint32*)(dst_argb); 714 715 int x; 716 for (x = 0; x < dst_width - 1; x += 2) { 717 dst[0] = src[0]; 718 dst[1] = src[src_stepx]; 719 src += src_stepx * 2; 720 dst += 2; 721 } 722 if (dst_width & 1) { 723 dst[0] = src[0]; 724 } 725} 726 727void ScaleARGBRowDownEvenBox_C(const uint8* src_argb, 728 ptrdiff_t src_stride, 729 int src_stepx, 730 uint8* dst_argb, int dst_width) { 731 int x; 732 for (x = 0; x < dst_width; ++x) { 733 dst_argb[0] = (src_argb[0] + src_argb[4] + 734 src_argb[src_stride] + src_argb[src_stride + 4] + 2) >> 2; 735 dst_argb[1] = (src_argb[1] + src_argb[5] + 736 src_argb[src_stride + 1] + src_argb[src_stride + 5] + 2) >> 2; 737 dst_argb[2] = (src_argb[2] + src_argb[6] + 738 src_argb[src_stride + 2] + src_argb[src_stride + 6] + 2) >> 2; 739 dst_argb[3] = (src_argb[3] + src_argb[7] + 740 src_argb[src_stride + 3] + src_argb[src_stride + 7] + 2) >> 2; 741 src_argb += src_stepx * 4; 742 dst_argb += 4; 743 } 744} 745 746// Scales a single row of pixels using point sampling. 747void ScaleARGBCols_C(uint8* dst_argb, const uint8* src_argb, 748 int dst_width, int x, int dx) { 749 const uint32* src = (const uint32*)(src_argb); 750 uint32* dst = (uint32*)(dst_argb); 751 int j; 752 for (j = 0; j < dst_width - 1; j += 2) { 753 dst[0] = src[x >> 16]; 754 x += dx; 755 dst[1] = src[x >> 16]; 756 x += dx; 757 dst += 2; 758 } 759 if (dst_width & 1) { 760 dst[0] = src[x >> 16]; 761 } 762} 763 764void ScaleARGBCols64_C(uint8* dst_argb, const uint8* src_argb, 765 int dst_width, int x32, int dx) { 766 int64 x = (int64)(x32); 767 const uint32* src = (const uint32*)(src_argb); 768 uint32* dst = (uint32*)(dst_argb); 769 int j; 770 for (j = 0; j < dst_width - 1; j += 2) { 771 dst[0] = src[x >> 16]; 772 x += dx; 773 dst[1] = src[x >> 16]; 774 x += dx; 775 dst += 2; 776 } 777 if (dst_width & 1) { 778 dst[0] = src[x >> 16]; 779 } 780} 781 782// Scales a single row of pixels up by 2x using point sampling. 783void ScaleARGBColsUp2_C(uint8* dst_argb, const uint8* src_argb, 784 int dst_width, int x, int dx) { 785 const uint32* src = (const uint32*)(src_argb); 786 uint32* dst = (uint32*)(dst_argb); 787 int j; 788 for (j = 0; j < dst_width - 1; j += 2) { 789 dst[1] = dst[0] = src[0]; 790 src += 1; 791 dst += 2; 792 } 793 if (dst_width & 1) { 794 dst[0] = src[0]; 795 } 796} 797 798// Mimics SSSE3 blender 799#define BLENDER1(a, b, f) ((a) * (0x7f ^ f) + (b) * f) >> 7 800#define BLENDERC(a, b, f, s) (uint32)( \ 801 BLENDER1(((a) >> s) & 255, ((b) >> s) & 255, f) << s) 802#define BLENDER(a, b, f) \ 803 BLENDERC(a, b, f, 24) | BLENDERC(a, b, f, 16) | \ 804 BLENDERC(a, b, f, 8) | BLENDERC(a, b, f, 0) 805 806void ScaleARGBFilterCols_C(uint8* dst_argb, const uint8* src_argb, 807 int dst_width, int x, int dx) { 808 const uint32* src = (const uint32*)(src_argb); 809 uint32* dst = (uint32*)(dst_argb); 810 int j; 811 for (j = 0; j < dst_width - 1; j += 2) { 812 int xi = x >> 16; 813 int xf = (x >> 9) & 0x7f; 814 uint32 a = src[xi]; 815 uint32 b = src[xi + 1]; 816 dst[0] = BLENDER(a, b, xf); 817 x += dx; 818 xi = x >> 16; 819 xf = (x >> 9) & 0x7f; 820 a = src[xi]; 821 b = src[xi + 1]; 822 dst[1] = BLENDER(a, b, xf); 823 x += dx; 824 dst += 2; 825 } 826 if (dst_width & 1) { 827 int xi = x >> 16; 828 int xf = (x >> 9) & 0x7f; 829 uint32 a = src[xi]; 830 uint32 b = src[xi + 1]; 831 dst[0] = BLENDER(a, b, xf); 832 } 833} 834 835void ScaleARGBFilterCols64_C(uint8* dst_argb, const uint8* src_argb, 836 int dst_width, int x32, int dx) { 837 int64 x = (int64)(x32); 838 const uint32* src = (const uint32*)(src_argb); 839 uint32* dst = (uint32*)(dst_argb); 840 int j; 841 for (j = 0; j < dst_width - 1; j += 2) { 842 int64 xi = x >> 16; 843 int xf = (x >> 9) & 0x7f; 844 uint32 a = src[xi]; 845 uint32 b = src[xi + 1]; 846 dst[0] = BLENDER(a, b, xf); 847 x += dx; 848 xi = x >> 16; 849 xf = (x >> 9) & 0x7f; 850 a = src[xi]; 851 b = src[xi + 1]; 852 dst[1] = BLENDER(a, b, xf); 853 x += dx; 854 dst += 2; 855 } 856 if (dst_width & 1) { 857 int64 xi = x >> 16; 858 int xf = (x >> 9) & 0x7f; 859 uint32 a = src[xi]; 860 uint32 b = src[xi + 1]; 861 dst[0] = BLENDER(a, b, xf); 862 } 863} 864#undef BLENDER1 865#undef BLENDERC 866#undef BLENDER 867 868// Scale plane vertically with bilinear interpolation. 869void ScalePlaneVertical(int src_height, 870 int dst_width, int dst_height, 871 int src_stride, int dst_stride, 872 const uint8* src_argb, uint8* dst_argb, 873 int x, int y, int dy, 874 int bpp, enum FilterMode filtering) { 875 // TODO(fbarchard): Allow higher bpp. 876 int dst_width_bytes = dst_width * bpp; 877 void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb, 878 ptrdiff_t src_stride, int dst_width, int source_y_fraction) = 879 InterpolateRow_C; 880 const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0; 881 int j; 882 assert(bpp >= 1 && bpp <= 4); 883 assert(src_height != 0); 884 assert(dst_width > 0); 885 assert(dst_height > 0); 886 src_argb += (x >> 16) * bpp; 887#if defined(HAS_INTERPOLATEROW_SSE2) 888 if (TestCpuFlag(kCpuHasSSE2) && dst_width_bytes >= 16) { 889 InterpolateRow = InterpolateRow_Any_SSE2; 890 if (IS_ALIGNED(dst_width_bytes, 16)) { 891 InterpolateRow = InterpolateRow_Unaligned_SSE2; 892 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) && 893 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) { 894 InterpolateRow = InterpolateRow_SSE2; 895 } 896 } 897 } 898#endif 899#if defined(HAS_INTERPOLATEROW_SSSE3) 900 if (TestCpuFlag(kCpuHasSSSE3) && dst_width_bytes >= 16) { 901 InterpolateRow = InterpolateRow_Any_SSSE3; 902 if (IS_ALIGNED(dst_width_bytes, 16)) { 903 InterpolateRow = InterpolateRow_Unaligned_SSSE3; 904 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) && 905 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) { 906 InterpolateRow = InterpolateRow_SSSE3; 907 } 908 } 909 } 910#endif 911#if defined(HAS_INTERPOLATEROW_AVX2) 912 if (TestCpuFlag(kCpuHasAVX2) && dst_width_bytes >= 32) { 913 InterpolateRow = InterpolateRow_Any_AVX2; 914 if (IS_ALIGNED(dst_width_bytes, 32)) { 915 InterpolateRow = InterpolateRow_AVX2; 916 } 917 } 918#endif 919#if defined(HAS_INTERPOLATEROW_NEON) 920 if (TestCpuFlag(kCpuHasNEON) && dst_width_bytes >= 16) { 921 InterpolateRow = InterpolateRow_Any_NEON; 922 if (IS_ALIGNED(dst_width_bytes, 16)) { 923 InterpolateRow = InterpolateRow_NEON; 924 } 925 } 926#endif 927#if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2) 928 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_width_bytes >= 4 && 929 IS_ALIGNED(src_argb, 4) && IS_ALIGNED(src_stride, 4) && 930 IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride, 4)) { 931 InterpolateRow = InterpolateRow_Any_MIPS_DSPR2; 932 if (IS_ALIGNED(dst_width_bytes, 4)) { 933 InterpolateRow = InterpolateRow_MIPS_DSPR2; 934 } 935 } 936#endif 937 for (j = 0; j < dst_height; ++j) { 938 int yi; 939 int yf; 940 if (y > max_y) { 941 y = max_y; 942 } 943 yi = y >> 16; 944 yf = filtering ? ((y >> 8) & 255) : 0; 945 InterpolateRow(dst_argb, src_argb + yi * src_stride, 946 src_stride, dst_width_bytes, yf); 947 dst_argb += dst_stride; 948 y += dy; 949 } 950} 951void ScalePlaneVertical_16(int src_height, 952 int dst_width, int dst_height, 953 int src_stride, int dst_stride, 954 const uint16* src_argb, uint16* dst_argb, 955 int x, int y, int dy, 956 int wpp, enum FilterMode filtering) { 957 // TODO(fbarchard): Allow higher wpp. 958 int dst_width_words = dst_width * wpp; 959 void (*InterpolateRow)(uint16* dst_argb, const uint16* src_argb, 960 ptrdiff_t src_stride, int dst_width, int source_y_fraction) = 961 InterpolateRow_16_C; 962 const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0; 963 int j; 964 assert(wpp >= 1 && wpp <= 2); 965 assert(src_height != 0); 966 assert(dst_width > 0); 967 assert(dst_height > 0); 968 src_argb += (x >> 16) * wpp; 969#if defined(HAS_INTERPOLATEROW_16_SSE2) 970 if (TestCpuFlag(kCpuHasSSE2) && dst_width_bytes >= 16) { 971 InterpolateRow = InterpolateRow_Any_16_SSE2; 972 if (IS_ALIGNED(dst_width_bytes, 16)) { 973 InterpolateRow = InterpolateRow_Unaligned_16_SSE2; 974 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) && 975 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) { 976 InterpolateRow = InterpolateRow_16_SSE2; 977 } 978 } 979 } 980#endif 981#if defined(HAS_INTERPOLATEROW_16_SSSE3) 982 if (TestCpuFlag(kCpuHasSSSE3) && dst_width_bytes >= 16) { 983 InterpolateRow = InterpolateRow_Any_16_SSSE3; 984 if (IS_ALIGNED(dst_width_bytes, 16)) { 985 InterpolateRow = InterpolateRow_Unaligned_16_SSSE3; 986 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) && 987 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) { 988 InterpolateRow = InterpolateRow_16_SSSE3; 989 } 990 } 991 } 992#endif 993#if defined(HAS_INTERPOLATEROW_16_AVX2) 994 if (TestCpuFlag(kCpuHasAVX2) && dst_width_bytes >= 32) { 995 InterpolateRow = InterpolateRow_Any_16_AVX2; 996 if (IS_ALIGNED(dst_width_bytes, 32)) { 997 InterpolateRow = InterpolateRow_16_AVX2; 998 } 999 } 1000#endif 1001#if defined(HAS_INTERPOLATEROW_16_NEON) 1002 if (TestCpuFlag(kCpuHasNEON) && dst_width_bytes >= 16) { 1003 InterpolateRow = InterpolateRow_Any_16_NEON; 1004 if (IS_ALIGNED(dst_width_bytes, 16)) { 1005 InterpolateRow = InterpolateRow_16_NEON; 1006 } 1007 } 1008#endif 1009#if defined(HAS_INTERPOLATEROWS_16_MIPS_DSPR2) 1010 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_width_bytes >= 4 && 1011 IS_ALIGNED(src_argb, 4) && IS_ALIGNED(src_stride, 4) && 1012 IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride, 4)) { 1013 InterpolateRow = InterpolateRow_Any_16_MIPS_DSPR2; 1014 if (IS_ALIGNED(dst_width_bytes, 4)) { 1015 InterpolateRow = InterpolateRow_16_MIPS_DSPR2; 1016 } 1017 } 1018#endif 1019 for (j = 0; j < dst_height; ++j) { 1020 int yi; 1021 int yf; 1022 if (y > max_y) { 1023 y = max_y; 1024 } 1025 yi = y >> 16; 1026 yf = filtering ? ((y >> 8) & 255) : 0; 1027 InterpolateRow(dst_argb, src_argb + yi * src_stride, 1028 src_stride, dst_width_words, yf); 1029 dst_argb += dst_stride; 1030 y += dy; 1031 } 1032} 1033 1034// Simplify the filtering based on scale factors. 1035enum FilterMode ScaleFilterReduce(int src_width, int src_height, 1036 int dst_width, int dst_height, 1037 enum FilterMode filtering) { 1038 if (src_width < 0) { 1039 src_width = -src_width; 1040 } 1041 if (src_height < 0) { 1042 src_height = -src_height; 1043 } 1044 if (filtering == kFilterBox) { 1045 // If scaling both axis to 0.5 or larger, switch from Box to Bilinear. 1046 if (dst_width * 2 >= src_width && dst_height * 2 >= src_height) { 1047 filtering = kFilterBilinear; 1048 } 1049 // If scaling to larger, switch from Box to Bilinear. 1050 if (dst_width >= src_width || dst_height >= src_height) { 1051 filtering = kFilterBilinear; 1052 } 1053 } 1054 if (filtering == kFilterBilinear) { 1055 if (src_height == 1) { 1056 filtering = kFilterLinear; 1057 } 1058 // TODO(fbarchard): Detect any odd scale factor and reduce to Linear. 1059 if (dst_height == src_height || dst_height * 3 == src_height) { 1060 filtering = kFilterLinear; 1061 } 1062 // TODO(fbarchard): Remove 1 pixel wide filter restriction, which is to 1063 // avoid reading 2 pixels horizontally that causes memory exception. 1064 if (src_width == 1) { 1065 filtering = kFilterNone; 1066 } 1067 } 1068 if (filtering == kFilterLinear) { 1069 if (src_width == 1) { 1070 filtering = kFilterNone; 1071 } 1072 // TODO(fbarchard): Detect any odd scale factor and reduce to None. 1073 if (dst_width == src_width || dst_width * 3 == src_width) { 1074 filtering = kFilterNone; 1075 } 1076 } 1077 return filtering; 1078} 1079 1080// Divide num by div and return as 16.16 fixed point result. 1081int FixedDiv_C(int num, int div) { 1082 return (int)(((int64)(num) << 16) / div); 1083} 1084 1085// Divide num by div and return as 16.16 fixed point result. 1086int FixedDiv1_C(int num, int div) { 1087 return (int)((((int64)(num) << 16) - 0x00010001) / 1088 (div - 1)); 1089} 1090 1091#define CENTERSTART(dx, s) (dx < 0) ? -((-dx >> 1) + s) : ((dx >> 1) + s) 1092 1093// Compute slope values for stepping. 1094void ScaleSlope(int src_width, int src_height, 1095 int dst_width, int dst_height, 1096 enum FilterMode filtering, 1097 int* x, int* y, int* dx, int* dy) { 1098 assert(x != NULL); 1099 assert(y != NULL); 1100 assert(dx != NULL); 1101 assert(dy != NULL); 1102 assert(src_width != 0); 1103 assert(src_height != 0); 1104 assert(dst_width > 0); 1105 assert(dst_height > 0); 1106 // Check for 1 pixel and avoid FixedDiv overflow. 1107 if (dst_width == 1 && src_width >= 32768) { 1108 dst_width = src_width; 1109 } 1110 if (dst_height == 1 && src_height >= 32768) { 1111 dst_height = src_height; 1112 } 1113 if (filtering == kFilterBox) { 1114 // Scale step for point sampling duplicates all pixels equally. 1115 *dx = FixedDiv(Abs(src_width), dst_width); 1116 *dy = FixedDiv(src_height, dst_height); 1117 *x = 0; 1118 *y = 0; 1119 } else if (filtering == kFilterBilinear) { 1120 // Scale step for bilinear sampling renders last pixel once for upsample. 1121 if (dst_width <= Abs(src_width)) { 1122 *dx = FixedDiv(Abs(src_width), dst_width); 1123 *x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter. 1124 } else if (dst_width > 1) { 1125 *dx = FixedDiv1(Abs(src_width), dst_width); 1126 *x = 0; 1127 } 1128 if (dst_height <= src_height) { 1129 *dy = FixedDiv(src_height, dst_height); 1130 *y = CENTERSTART(*dy, -32768); // Subtract 0.5 (32768) to center filter. 1131 } else if (dst_height > 1) { 1132 *dy = FixedDiv1(src_height, dst_height); 1133 *y = 0; 1134 } 1135 } else if (filtering == kFilterLinear) { 1136 // Scale step for bilinear sampling renders last pixel once for upsample. 1137 if (dst_width <= Abs(src_width)) { 1138 *dx = FixedDiv(Abs(src_width), dst_width); 1139 *x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter. 1140 } else if (dst_width > 1) { 1141 *dx = FixedDiv1(Abs(src_width), dst_width); 1142 *x = 0; 1143 } 1144 *dy = FixedDiv(src_height, dst_height); 1145 *y = *dy >> 1; 1146 } else { 1147 // Scale step for point sampling duplicates all pixels equally. 1148 *dx = FixedDiv(Abs(src_width), dst_width); 1149 *dy = FixedDiv(src_height, dst_height); 1150 *x = CENTERSTART(*dx, 0); 1151 *y = CENTERSTART(*dy, 0); 1152 } 1153 // Negative src_width means horizontally mirror. 1154 if (src_width < 0) { 1155 *x += (dst_width - 1) * *dx; 1156 *dx = -*dx; 1157 // src_width = -src_width; // Caller must do this. 1158 } 1159} 1160#undef CENTERSTART 1161 1162#ifdef __cplusplus 1163} // extern "C" 1164} // namespace libyuv 1165#endif 1166