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