media/libyuv/source/scale.cc

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Copyright 2011 The LibYuv Project Authors. All rights reserved.
michael@0 3 *
michael@0 4 * Use of this source code is governed by a BSD-style license
michael@0 5 * that can be found in the LICENSE file in the root of the source
michael@0 6 * tree. An additional intellectual property rights grant can be found
michael@0 7 * in the file PATENTS. All contributing project authors may
michael@0 8 * be found in the AUTHORS file in the root of the source tree.
michael@0 9 */
michael@0 10
michael@0 11 #include "libyuv/scale.h"
michael@0 12
michael@0 13 #include <assert.h>
michael@0 14 #include <string.h>
michael@0 15
michael@0 16 #include "libyuv/cpu_id.h"
michael@0 17 #include "libyuv/planar_functions.h" // For CopyPlane
michael@0 18 #include "libyuv/row.h"
michael@0 19 #include "libyuv/scale_row.h"
michael@0 20
michael@0 21 #ifdef __cplusplus
michael@0 22 namespace libyuv {
michael@0 23 extern "C" {
michael@0 24 #endif
michael@0 25
michael@0 26 // Remove this macro if OVERREAD is safe.
michael@0 27 #define AVOID_OVERREAD 1
michael@0 28
michael@0 29 static __inline int Abs(int v) {
michael@0 30 return v >= 0 ? v : -v;
michael@0 31 }
michael@0 32
michael@0 33 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
michael@0 34
michael@0 35 // Scale plane, 1/2
michael@0 36 // This is an optimized version for scaling down a plane to 1/2 of
michael@0 37 // its original size.
michael@0 38
michael@0 39 static void ScalePlaneDown2(int src_width, int src_height,
michael@0 40 int dst_width, int dst_height,
michael@0 41 int src_stride, int dst_stride,
michael@0 42 const uint8* src_ptr, uint8* dst_ptr,
michael@0 43 enum FilterMode filtering) {
michael@0 44 void (*ScaleRowDown2)(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 45 uint8* dst_ptr, int dst_width) =
michael@0 46 filtering == kFilterNone ? ScaleRowDown2_C :
michael@0 47 (filtering == kFilterLinear ? ScaleRowDown2Linear_C :
michael@0 48 ScaleRowDown2Box_C);
michael@0 49 int row_stride = src_stride << 1;
michael@0 50 if (!filtering) {
michael@0 51 src_ptr += src_stride; // Point to odd rows.
michael@0 52 src_stride = 0;
michael@0 53 }
michael@0 54
michael@0 55 #if defined(HAS_SCALEROWDOWN2_NEON)
michael@0 56 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 16)) {
michael@0 57 ScaleRowDown2 = filtering ? ScaleRowDown2Box_NEON : ScaleRowDown2_NEON;
michael@0 58 }
michael@0 59 #elif defined(HAS_SCALEROWDOWN2_SSE2)
michael@0 60 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 16)) {
michael@0 61 ScaleRowDown2 = filtering == kFilterNone ? ScaleRowDown2_Unaligned_SSE2 :
michael@0 62 (filtering == kFilterLinear ? ScaleRowDown2Linear_Unaligned_SSE2 :
michael@0 63 ScaleRowDown2Box_Unaligned_SSE2);
michael@0 64 if (IS_ALIGNED(src_ptr, 16) &&
michael@0 65 IS_ALIGNED(src_stride, 16) && IS_ALIGNED(row_stride, 16) &&
michael@0 66 IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
michael@0 67 ScaleRowDown2 = filtering == kFilterNone ? ScaleRowDown2_SSE2 :
michael@0 68 (filtering == kFilterLinear ? ScaleRowDown2Linear_SSE2 :
michael@0 69 ScaleRowDown2Box_SSE2);
michael@0 70 }
michael@0 71 }
michael@0 72 #elif defined(HAS_SCALEROWDOWN2_MIPS_DSPR2)
michael@0 73 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(src_ptr, 4) &&
michael@0 74 IS_ALIGNED(src_stride, 4) && IS_ALIGNED(row_stride, 4) &&
michael@0 75 IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
michael@0 76 ScaleRowDown2 = filtering ?
michael@0 77 ScaleRowDown2Box_MIPS_DSPR2 : ScaleRowDown2_MIPS_DSPR2;
michael@0 78 }
michael@0 79 #endif
michael@0 80
michael@0 81 if (filtering == kFilterLinear) {
michael@0 82 src_stride = 0;
michael@0 83 }
michael@0 84 // TODO(fbarchard): Loop through source height to allow odd height.
michael@0 85 int y;
michael@0 86 for (y = 0; y < dst_height; ++y) {
michael@0 87 ScaleRowDown2(src_ptr, src_stride, dst_ptr, dst_width);
michael@0 88 src_ptr += row_stride;
michael@0 89 dst_ptr += dst_stride;
michael@0 90 }
michael@0 91 }
michael@0 92
michael@0 93 // Scale plane, 1/4
michael@0 94 // This is an optimized version for scaling down a plane to 1/4 of
michael@0 95 // its original size.
michael@0 96
michael@0 97 static void ScalePlaneDown4(int src_width, int src_height,
michael@0 98 int dst_width, int dst_height,
michael@0 99 int src_stride, int dst_stride,
michael@0 100 const uint8* src_ptr, uint8* dst_ptr,
michael@0 101 enum FilterMode filtering) {
michael@0 102 void (*ScaleRowDown4)(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 103 uint8* dst_ptr, int dst_width) =
michael@0 104 filtering ? ScaleRowDown4Box_C : ScaleRowDown4_C;
michael@0 105 int row_stride = src_stride << 2;
michael@0 106 if (!filtering) {
michael@0 107 src_ptr += src_stride * 2; // Point to row 2.
michael@0 108 src_stride = 0;
michael@0 109 }
michael@0 110 #if defined(HAS_SCALEROWDOWN4_NEON)
michael@0 111 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 8)) {
michael@0 112 ScaleRowDown4 = filtering ? ScaleRowDown4Box_NEON : ScaleRowDown4_NEON;
michael@0 113 }
michael@0 114 #elif defined(HAS_SCALEROWDOWN4_SSE2)
michael@0 115 if (TestCpuFlag(kCpuHasSSE2) &&
michael@0 116 IS_ALIGNED(dst_width, 8) && IS_ALIGNED(row_stride, 16) &&
michael@0 117 IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
michael@0 118 ScaleRowDown4 = filtering ? ScaleRowDown4Box_SSE2 : ScaleRowDown4_SSE2;
michael@0 119 }
michael@0 120 #elif defined(HAS_SCALEROWDOWN4_MIPS_DSPR2)
michael@0 121 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(row_stride, 4) &&
michael@0 122 IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
michael@0 123 IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
michael@0 124 ScaleRowDown4 = filtering ?
michael@0 125 ScaleRowDown4Box_MIPS_DSPR2 : ScaleRowDown4_MIPS_DSPR2;
michael@0 126 }
michael@0 127 #endif
michael@0 128
michael@0 129 if (filtering == kFilterLinear) {
michael@0 130 src_stride = 0;
michael@0 131 }
michael@0 132 int y;
michael@0 133 for (y = 0; y < dst_height; ++y) {
michael@0 134 ScaleRowDown4(src_ptr, src_stride, dst_ptr, dst_width);
michael@0 135 src_ptr += row_stride;
michael@0 136 dst_ptr += dst_stride;
michael@0 137 }
michael@0 138 }
michael@0 139
michael@0 140 // Scale plane down, 3/4
michael@0 141
michael@0 142 static void ScalePlaneDown34(int src_width, int src_height,
michael@0 143 int dst_width, int dst_height,
michael@0 144 int src_stride, int dst_stride,
michael@0 145 const uint8* src_ptr, uint8* dst_ptr,
michael@0 146 enum FilterMode filtering) {
michael@0 147 assert(dst_width % 3 == 0);
michael@0 148 void (*ScaleRowDown34_0)(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 149 uint8* dst_ptr, int dst_width);
michael@0 150 void (*ScaleRowDown34_1)(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 151 uint8* dst_ptr, int dst_width);
michael@0 152 if (!filtering) {
michael@0 153 ScaleRowDown34_0 = ScaleRowDown34_C;
michael@0 154 ScaleRowDown34_1 = ScaleRowDown34_C;
michael@0 155 } else {
michael@0 156 ScaleRowDown34_0 = ScaleRowDown34_0_Box_C;
michael@0 157 ScaleRowDown34_1 = ScaleRowDown34_1_Box_C;
michael@0 158 }
michael@0 159 #if defined(HAS_SCALEROWDOWN34_NEON)
michael@0 160 if (TestCpuFlag(kCpuHasNEON) && (dst_width % 24 == 0)) {
michael@0 161 if (!filtering) {
michael@0 162 ScaleRowDown34_0 = ScaleRowDown34_NEON;
michael@0 163 ScaleRowDown34_1 = ScaleRowDown34_NEON;
michael@0 164 } else {
michael@0 165 ScaleRowDown34_0 = ScaleRowDown34_0_Box_NEON;
michael@0 166 ScaleRowDown34_1 = ScaleRowDown34_1_Box_NEON;
michael@0 167 }
michael@0 168 }
michael@0 169 #endif
michael@0 170 #if defined(HAS_SCALEROWDOWN34_SSSE3)
michael@0 171 if (TestCpuFlag(kCpuHasSSSE3) && (dst_width % 24 == 0) &&
michael@0 172 IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
michael@0 173 if (!filtering) {
michael@0 174 ScaleRowDown34_0 = ScaleRowDown34_SSSE3;
michael@0 175 ScaleRowDown34_1 = ScaleRowDown34_SSSE3;
michael@0 176 } else {
michael@0 177 ScaleRowDown34_0 = ScaleRowDown34_0_Box_SSSE3;
michael@0 178 ScaleRowDown34_1 = ScaleRowDown34_1_Box_SSSE3;
michael@0 179 }
michael@0 180 }
michael@0 181 #endif
michael@0 182 #if defined(HAS_SCALEROWDOWN34_MIPS_DSPR2)
michael@0 183 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && (dst_width % 24 == 0) &&
michael@0 184 IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
michael@0 185 IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
michael@0 186 if (!filtering) {
michael@0 187 ScaleRowDown34_0 = ScaleRowDown34_MIPS_DSPR2;
michael@0 188 ScaleRowDown34_1 = ScaleRowDown34_MIPS_DSPR2;
michael@0 189 } else {
michael@0 190 ScaleRowDown34_0 = ScaleRowDown34_0_Box_MIPS_DSPR2;
michael@0 191 ScaleRowDown34_1 = ScaleRowDown34_1_Box_MIPS_DSPR2;
michael@0 192 }
michael@0 193 }
michael@0 194 #endif
michael@0 195
michael@0 196 const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride;
michael@0 197 int y;
michael@0 198 for (y = 0; y < dst_height - 2; y += 3) {
michael@0 199 ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width);
michael@0 200 src_ptr += src_stride;
michael@0 201 dst_ptr += dst_stride;
michael@0 202 ScaleRowDown34_1(src_ptr, filter_stride, dst_ptr, dst_width);
michael@0 203 src_ptr += src_stride;
michael@0 204 dst_ptr += dst_stride;
michael@0 205 ScaleRowDown34_0(src_ptr + src_stride, -filter_stride,
michael@0 206 dst_ptr, dst_width);
michael@0 207 src_ptr += src_stride * 2;
michael@0 208 dst_ptr += dst_stride;
michael@0 209 }
michael@0 210
michael@0 211 // Remainder 1 or 2 rows with last row vertically unfiltered
michael@0 212 if ((dst_height % 3) == 2) {
michael@0 213 ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width);
michael@0 214 src_ptr += src_stride;
michael@0 215 dst_ptr += dst_stride;
michael@0 216 ScaleRowDown34_1(src_ptr, 0, dst_ptr, dst_width);
michael@0 217 } else if ((dst_height % 3) == 1) {
michael@0 218 ScaleRowDown34_0(src_ptr, 0, dst_ptr, dst_width);
michael@0 219 }
michael@0 220 }
michael@0 221
michael@0 222
michael@0 223 // Scale plane, 3/8
michael@0 224 // This is an optimized version for scaling down a plane to 3/8
michael@0 225 // of its original size.
michael@0 226 //
michael@0 227 // Uses box filter arranges like this
michael@0 228 // aaabbbcc -> abc
michael@0 229 // aaabbbcc def
michael@0 230 // aaabbbcc ghi
michael@0 231 // dddeeeff
michael@0 232 // dddeeeff
michael@0 233 // dddeeeff
michael@0 234 // ggghhhii
michael@0 235 // ggghhhii
michael@0 236 // Boxes are 3x3, 2x3, 3x2 and 2x2
michael@0 237
michael@0 238 static void ScalePlaneDown38(int src_width, int src_height,
michael@0 239 int dst_width, int dst_height,
michael@0 240 int src_stride, int dst_stride,
michael@0 241 const uint8* src_ptr, uint8* dst_ptr,
michael@0 242 enum FilterMode filtering) {
michael@0 243 assert(dst_width % 3 == 0);
michael@0 244 void (*ScaleRowDown38_3)(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 245 uint8* dst_ptr, int dst_width);
michael@0 246 void (*ScaleRowDown38_2)(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 247 uint8* dst_ptr, int dst_width);
michael@0 248 if (!filtering) {
michael@0 249 ScaleRowDown38_3 = ScaleRowDown38_C;
michael@0 250 ScaleRowDown38_2 = ScaleRowDown38_C;
michael@0 251 } else {
michael@0 252 ScaleRowDown38_3 = ScaleRowDown38_3_Box_C;
michael@0 253 ScaleRowDown38_2 = ScaleRowDown38_2_Box_C;
michael@0 254 }
michael@0 255 #if defined(HAS_SCALEROWDOWN38_NEON)
michael@0 256 if (TestCpuFlag(kCpuHasNEON) && (dst_width % 12 == 0)) {
michael@0 257 if (!filtering) {
michael@0 258 ScaleRowDown38_3 = ScaleRowDown38_NEON;
michael@0 259 ScaleRowDown38_2 = ScaleRowDown38_NEON;
michael@0 260 } else {
michael@0 261 ScaleRowDown38_3 = ScaleRowDown38_3_Box_NEON;
michael@0 262 ScaleRowDown38_2 = ScaleRowDown38_2_Box_NEON;
michael@0 263 }
michael@0 264 }
michael@0 265 #elif defined(HAS_SCALEROWDOWN38_SSSE3)
michael@0 266 if (TestCpuFlag(kCpuHasSSSE3) && (dst_width % 24 == 0) &&
michael@0 267 IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
michael@0 268 if (!filtering) {
michael@0 269 ScaleRowDown38_3 = ScaleRowDown38_SSSE3;
michael@0 270 ScaleRowDown38_2 = ScaleRowDown38_SSSE3;
michael@0 271 } else {
michael@0 272 ScaleRowDown38_3 = ScaleRowDown38_3_Box_SSSE3;
michael@0 273 ScaleRowDown38_2 = ScaleRowDown38_2_Box_SSSE3;
michael@0 274 }
michael@0 275 }
michael@0 276 #elif defined(HAS_SCALEROWDOWN38_MIPS_DSPR2)
michael@0 277 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && (dst_width % 12 == 0) &&
michael@0 278 IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
michael@0 279 IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
michael@0 280 if (!filtering) {
michael@0 281 ScaleRowDown38_3 = ScaleRowDown38_MIPS_DSPR2;
michael@0 282 ScaleRowDown38_2 = ScaleRowDown38_MIPS_DSPR2;
michael@0 283 } else {
michael@0 284 ScaleRowDown38_3 = ScaleRowDown38_3_Box_MIPS_DSPR2;
michael@0 285 ScaleRowDown38_2 = ScaleRowDown38_2_Box_MIPS_DSPR2;
michael@0 286 }
michael@0 287 }
michael@0 288 #endif
michael@0 289
michael@0 290 const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride;
michael@0 291 int y;
michael@0 292 for (y = 0; y < dst_height - 2; y += 3) {
michael@0 293 ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
michael@0 294 src_ptr += src_stride * 3;
michael@0 295 dst_ptr += dst_stride;
michael@0 296 ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
michael@0 297 src_ptr += src_stride * 3;
michael@0 298 dst_ptr += dst_stride;
michael@0 299 ScaleRowDown38_2(src_ptr, filter_stride, dst_ptr, dst_width);
michael@0 300 src_ptr += src_stride * 2;
michael@0 301 dst_ptr += dst_stride;
michael@0 302 }
michael@0 303
michael@0 304 // Remainder 1 or 2 rows with last row vertically unfiltered
michael@0 305 if ((dst_height % 3) == 2) {
michael@0 306 ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
michael@0 307 src_ptr += src_stride * 3;
michael@0 308 dst_ptr += dst_stride;
michael@0 309 ScaleRowDown38_3(src_ptr, 0, dst_ptr, dst_width);
michael@0 310 } else if ((dst_height % 3) == 1) {
michael@0 311 ScaleRowDown38_3(src_ptr, 0, dst_ptr, dst_width);
michael@0 312 }
michael@0 313 }
michael@0 314
michael@0 315 static __inline uint32 SumBox(int iboxwidth, int iboxheight,
michael@0 316 ptrdiff_t src_stride, const uint8* src_ptr) {
michael@0 317 assert(iboxwidth > 0);
michael@0 318 assert(iboxheight > 0);
michael@0 319 uint32 sum = 0u;
michael@0 320 int y;
michael@0 321 for (y = 0; y < iboxheight; ++y) {
michael@0 322 int x;
michael@0 323 for (x = 0; x < iboxwidth; ++x) {
michael@0 324 sum += src_ptr[x];
michael@0 325 }
michael@0 326 src_ptr += src_stride;
michael@0 327 }
michael@0 328 return sum;
michael@0 329 }
michael@0 330
michael@0 331 static void ScalePlaneBoxRow_C(int dst_width, int boxheight,
michael@0 332 int x, int dx, ptrdiff_t src_stride,
michael@0 333 const uint8* src_ptr, uint8* dst_ptr) {
michael@0 334 int i;
michael@0 335 for (i = 0; i < dst_width; ++i) {
michael@0 336 int ix = x >> 16;
michael@0 337 x += dx;
michael@0 338 int boxwidth = (x >> 16) - ix;
michael@0 339 *dst_ptr++ = SumBox(boxwidth, boxheight, src_stride, src_ptr + ix) /
michael@0 340 (boxwidth * boxheight);
michael@0 341 }
michael@0 342 }
michael@0 343
michael@0 344 static __inline uint32 SumPixels(int iboxwidth, const uint16* src_ptr) {
michael@0 345 assert(iboxwidth > 0);
michael@0 346 uint32 sum = 0u;
michael@0 347 int x;
michael@0 348 for (x = 0; x < iboxwidth; ++x) {
michael@0 349 sum += src_ptr[x];
michael@0 350 }
michael@0 351 return sum;
michael@0 352 }
michael@0 353
michael@0 354 static void ScaleAddCols2_C(int dst_width, int boxheight, int x, int dx,
michael@0 355 const uint16* src_ptr, uint8* dst_ptr) {
michael@0 356 int scaletbl[2];
michael@0 357 int minboxwidth = (dx >> 16);
michael@0 358 scaletbl[0] = 65536 / (minboxwidth * boxheight);
michael@0 359 scaletbl[1] = 65536 / ((minboxwidth + 1) * boxheight);
michael@0 360 int* scaleptr = scaletbl - minboxwidth;
michael@0 361 int i;
michael@0 362 for (i = 0; i < dst_width; ++i) {
michael@0 363 int ix = x >> 16;
michael@0 364 x += dx;
michael@0 365 int boxwidth = (x >> 16) - ix;
michael@0 366 *dst_ptr++ = SumPixels(boxwidth, src_ptr + ix) * scaleptr[boxwidth] >> 16;
michael@0 367 }
michael@0 368 }
michael@0 369
michael@0 370 static void ScaleAddCols1_C(int dst_width, int boxheight, int x, int dx,
michael@0 371 const uint16* src_ptr, uint8* dst_ptr) {
michael@0 372 int boxwidth = (dx >> 16);
michael@0 373 int scaleval = 65536 / (boxwidth * boxheight);
michael@0 374 int i;
michael@0 375 for (i = 0; i < dst_width; ++i) {
michael@0 376 *dst_ptr++ = SumPixels(boxwidth, src_ptr + x) * scaleval >> 16;
michael@0 377 x += boxwidth;
michael@0 378 }
michael@0 379 }
michael@0 380
michael@0 381 // Scale plane down to any dimensions, with interpolation.
michael@0 382 // (boxfilter).
michael@0 383 //
michael@0 384 // Same method as SimpleScale, which is fixed point, outputting
michael@0 385 // one pixel of destination using fixed point (16.16) to step
michael@0 386 // through source, sampling a box of pixel with simple
michael@0 387 // averaging.
michael@0 388 static void ScalePlaneBox(int src_width, int src_height,
michael@0 389 int dst_width, int dst_height,
michael@0 390 int src_stride, int dst_stride,
michael@0 391 const uint8* src_ptr, uint8* dst_ptr) {
michael@0 392 // Initial source x/y coordinate and step values as 16.16 fixed point.
michael@0 393 int x = 0;
michael@0 394 int y = 0;
michael@0 395 int dx = 0;
michael@0 396 int dy = 0;
michael@0 397 ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterBox,
michael@0 398 &x, &y, &dx, &dy);
michael@0 399 src_width = Abs(src_width);
michael@0 400 const int max_y = (src_height << 16);
michael@0 401 // TODO(fbarchard): Remove this and make AddRows handle boxheight 1.
michael@0 402 if (!IS_ALIGNED(src_width, 16) || dst_height * 2 > src_height) {
michael@0 403 uint8* dst = dst_ptr;
michael@0 404 int j;
michael@0 405 for (j = 0; j < dst_height; ++j) {
michael@0 406 int iy = y >> 16;
michael@0 407 const uint8* src = src_ptr + iy * src_stride;
michael@0 408 y += dy;
michael@0 409 if (y > max_y) {
michael@0 410 y = max_y;
michael@0 411 }
michael@0 412 int boxheight = (y >> 16) - iy;
michael@0 413 ScalePlaneBoxRow_C(dst_width, boxheight,
michael@0 414 x, dx, src_stride,
michael@0 415 src, dst);
michael@0 416 dst += dst_stride;
michael@0 417 }
michael@0 418 return;
michael@0 419 }
michael@0 420 // Allocate a row buffer of uint16.
michael@0 421 align_buffer_64(row16, src_width * 2);
michael@0 422
michael@0 423 void (*ScaleAddCols)(int dst_width, int boxheight, int x, int dx,
michael@0 424 const uint16* src_ptr, uint8* dst_ptr) =
michael@0 425 (dx & 0xffff) ? ScaleAddCols2_C: ScaleAddCols1_C;
michael@0 426 void (*ScaleAddRows)(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 427 uint16* dst_ptr, int src_width, int src_height) = ScaleAddRows_C;
michael@0 428 #if defined(HAS_SCALEADDROWS_SSE2)
michael@0 429 if (TestCpuFlag(kCpuHasSSE2) &&
michael@0 430 #ifdef AVOID_OVERREAD
michael@0 431 IS_ALIGNED(src_width, 16) &&
michael@0 432 #endif
michael@0 433 IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
michael@0 434 ScaleAddRows = ScaleAddRows_SSE2;
michael@0 435 }
michael@0 436 #endif
michael@0 437
michael@0 438 int j;
michael@0 439 for (j = 0; j < dst_height; ++j) {
michael@0 440 int iy = y >> 16;
michael@0 441 const uint8* src = src_ptr + iy * src_stride;
michael@0 442 y += dy;
michael@0 443 if (y > (src_height << 16)) {
michael@0 444 y = (src_height << 16);
michael@0 445 }
michael@0 446 int boxheight = (y >> 16) - iy;
michael@0 447 ScaleAddRows(src, src_stride, (uint16*)(row16),
michael@0 448 src_width, boxheight);
michael@0 449 ScaleAddCols(dst_width, boxheight, x, dx, (uint16*)(row16),
michael@0 450 dst_ptr);
michael@0 451 dst_ptr += dst_stride;
michael@0 452 }
michael@0 453 free_aligned_buffer_64(row16);
michael@0 454 }
michael@0 455
michael@0 456 // Scale plane down with bilinear interpolation.
michael@0 457 void ScalePlaneBilinearDown(int src_width, int src_height,
michael@0 458 int dst_width, int dst_height,
michael@0 459 int src_stride, int dst_stride,
michael@0 460 const uint8* src_ptr, uint8* dst_ptr,
michael@0 461 enum FilterMode filtering) {
michael@0 462 // Initial source x/y coordinate and step values as 16.16 fixed point.
michael@0 463 int x = 0;
michael@0 464 int y = 0;
michael@0 465 int dx = 0;
michael@0 466 int dy = 0;
michael@0 467 ScaleSlope(src_width, src_height, dst_width, dst_height, filtering,
michael@0 468 &x, &y, &dx, &dy);
michael@0 469 src_width = Abs(src_width);
michael@0 470
michael@0 471 void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
michael@0 472 ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
michael@0 473 InterpolateRow_C;
michael@0 474 #if defined(HAS_INTERPOLATEROW_SSE2)
michael@0 475 if (TestCpuFlag(kCpuHasSSE2) && src_width >= 16) {
michael@0 476 InterpolateRow = InterpolateRow_Any_SSE2;
michael@0 477 if (IS_ALIGNED(src_width, 16)) {
michael@0 478 InterpolateRow = InterpolateRow_Unaligned_SSE2;
michael@0 479 if (IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
michael@0 480 InterpolateRow = InterpolateRow_SSE2;
michael@0 481 }
michael@0 482 }
michael@0 483 }
michael@0 484 #endif
michael@0 485 #if defined(HAS_INTERPOLATEROW_SSSE3)
michael@0 486 if (TestCpuFlag(kCpuHasSSSE3) && src_width >= 16) {
michael@0 487 InterpolateRow = InterpolateRow_Any_SSSE3;
michael@0 488 if (IS_ALIGNED(src_width, 16)) {
michael@0 489 InterpolateRow = InterpolateRow_Unaligned_SSSE3;
michael@0 490 if (IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
michael@0 491 InterpolateRow = InterpolateRow_SSSE3;
michael@0 492 }
michael@0 493 }
michael@0 494 }
michael@0 495 #endif
michael@0 496 #if defined(HAS_INTERPOLATEROW_AVX2)
michael@0 497 if (TestCpuFlag(kCpuHasAVX2) && src_width >= 32) {
michael@0 498 InterpolateRow = InterpolateRow_Any_AVX2;
michael@0 499 if (IS_ALIGNED(src_width, 32)) {
michael@0 500 InterpolateRow = InterpolateRow_AVX2;
michael@0 501 }
michael@0 502 }
michael@0 503 #endif
michael@0 504 #if defined(HAS_INTERPOLATEROW_NEON)
michael@0 505 if (TestCpuFlag(kCpuHasNEON) && src_width >= 16) {
michael@0 506 InterpolateRow = InterpolateRow_Any_NEON;
michael@0 507 if (IS_ALIGNED(src_width, 16)) {
michael@0 508 InterpolateRow = InterpolateRow_NEON;
michael@0 509 }
michael@0 510 }
michael@0 511 #endif
michael@0 512 #if defined(HAS_INTERPOLATEROW_MIPS_DSPR2)
michael@0 513 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && src_width >= 4) {
michael@0 514 InterpolateRow = InterpolateRow_Any_MIPS_DSPR2;
michael@0 515 if (IS_ALIGNED(src_width, 4)) {
michael@0 516 InterpolateRow = InterpolateRow_MIPS_DSPR2;
michael@0 517 }
michael@0 518 }
michael@0 519 #endif
michael@0 520
michael@0 521 void (*ScaleFilterCols)(uint8* dst_ptr, const uint8* src_ptr,
michael@0 522 int dst_width, int x, int dx) =
michael@0 523 (src_width >= 32768) ? ScaleFilterCols64_C : ScaleFilterCols_C;
michael@0 524
michael@0 525 #if defined(HAS_SCALEFILTERCOLS_SSSE3)
michael@0 526 if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
michael@0 527 ScaleFilterCols = ScaleFilterCols_SSSE3;
michael@0 528 }
michael@0 529 #endif
michael@0 530
michael@0 531 // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
michael@0 532 // Allocate a row buffer.
michael@0 533 align_buffer_64(row, src_width);
michael@0 534
michael@0 535 const int max_y = (src_height - 1) << 16;
michael@0 536 int j;
michael@0 537 for (j = 0; j < dst_height; ++j) {
michael@0 538 if (y > max_y) {
michael@0 539 y = max_y;
michael@0 540 }
michael@0 541 int yi = y >> 16;
michael@0 542 const uint8* src = src_ptr + yi * src_stride;
michael@0 543 if (filtering == kFilterLinear) {
michael@0 544 ScaleFilterCols(dst_ptr, src, dst_width, x, dx);
michael@0 545 } else {
michael@0 546 int yf = (y >> 8) & 255;
michael@0 547 InterpolateRow(row, src, src_stride, src_width, yf);
michael@0 548 ScaleFilterCols(dst_ptr, row, dst_width, x, dx);
michael@0 549 }
michael@0 550 dst_ptr += dst_stride;
michael@0 551 y += dy;
michael@0 552 }
michael@0 553 free_aligned_buffer_64(row);
michael@0 554 }
michael@0 555
michael@0 556 // Scale up down with bilinear interpolation.
michael@0 557 void ScalePlaneBilinearUp(int src_width, int src_height,
michael@0 558 int dst_width, int dst_height,
michael@0 559 int src_stride, int dst_stride,
michael@0 560 const uint8* src_ptr, uint8* dst_ptr,
michael@0 561 enum FilterMode filtering) {
michael@0 562 // Initial source x/y coordinate and step values as 16.16 fixed point.
michael@0 563 int x = 0;
michael@0 564 int y = 0;
michael@0 565 int dx = 0;
michael@0 566 int dy = 0;
michael@0 567 ScaleSlope(src_width, src_height, dst_width, dst_height, filtering,
michael@0 568 &x, &y, &dx, &dy);
michael@0 569 src_width = Abs(src_width);
michael@0 570
michael@0 571 void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
michael@0 572 ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
michael@0 573 InterpolateRow_C;
michael@0 574 #if defined(HAS_INTERPOLATEROW_SSE2)
michael@0 575 if (TestCpuFlag(kCpuHasSSE2) && dst_width >= 16) {
michael@0 576 InterpolateRow = InterpolateRow_Any_SSE2;
michael@0 577 if (IS_ALIGNED(dst_width, 16)) {
michael@0 578 InterpolateRow = InterpolateRow_Unaligned_SSE2;
michael@0 579 if (IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
michael@0 580 InterpolateRow = InterpolateRow_SSE2;
michael@0 581 }
michael@0 582 }
michael@0 583 }
michael@0 584 #endif
michael@0 585 #if defined(HAS_INTERPOLATEROW_SSSE3)
michael@0 586 if (TestCpuFlag(kCpuHasSSSE3) && dst_width >= 16) {
michael@0 587 InterpolateRow = InterpolateRow_Any_SSSE3;
michael@0 588 if (IS_ALIGNED(dst_width, 16)) {
michael@0 589 InterpolateRow = InterpolateRow_Unaligned_SSSE3;
michael@0 590 if (IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
michael@0 591 InterpolateRow = InterpolateRow_SSSE3;
michael@0 592 }
michael@0 593 }
michael@0 594 }
michael@0 595 #endif
michael@0 596 #if defined(HAS_INTERPOLATEROW_AVX2)
michael@0 597 if (TestCpuFlag(kCpuHasAVX2) && dst_width >= 32) {
michael@0 598 InterpolateRow = InterpolateRow_Any_AVX2;
michael@0 599 if (IS_ALIGNED(dst_width, 32)) {
michael@0 600 InterpolateRow = InterpolateRow_AVX2;
michael@0 601 }
michael@0 602 }
michael@0 603 #endif
michael@0 604 #if defined(HAS_INTERPOLATEROW_NEON)
michael@0 605 if (TestCpuFlag(kCpuHasNEON) && dst_width >= 16) {
michael@0 606 InterpolateRow = InterpolateRow_Any_NEON;
michael@0 607 if (IS_ALIGNED(dst_width, 16)) {
michael@0 608 InterpolateRow = InterpolateRow_NEON;
michael@0 609 }
michael@0 610 }
michael@0 611 #endif
michael@0 612 #if defined(HAS_INTERPOLATEROW_MIPS_DSPR2)
michael@0 613 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_width >= 4) {
michael@0 614 InterpolateRow = InterpolateRow_Any_MIPS_DSPR2;
michael@0 615 if (IS_ALIGNED(dst_width, 4)) {
michael@0 616 InterpolateRow = InterpolateRow_MIPS_DSPR2;
michael@0 617 }
michael@0 618 }
michael@0 619 #endif
michael@0 620
michael@0 621 void (*ScaleFilterCols)(uint8* dst_ptr, const uint8* src_ptr,
michael@0 622 int dst_width, int x, int dx) =
michael@0 623 filtering ? ScaleFilterCols_C : ScaleCols_C;
michael@0 624 if (filtering && src_width >= 32768) {
michael@0 625 ScaleFilterCols = ScaleFilterCols64_C;
michael@0 626 }
michael@0 627 #if defined(HAS_SCALEFILTERCOLS_SSSE3)
michael@0 628 if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
michael@0 629 ScaleFilterCols = ScaleFilterCols_SSSE3;
michael@0 630 }
michael@0 631 #endif
michael@0 632 if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
michael@0 633 ScaleFilterCols = ScaleColsUp2_C;
michael@0 634 #if defined(HAS_SCALECOLS_SSE2)
michael@0 635 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8) &&
michael@0 636 IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16) &&
michael@0 637 IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
michael@0 638 ScaleFilterCols = ScaleColsUp2_SSE2;
michael@0 639 }
michael@0 640 #endif
michael@0 641 }
michael@0 642
michael@0 643 const int max_y = (src_height - 1) << 16;
michael@0 644 if (y > max_y) {
michael@0 645 y = max_y;
michael@0 646 }
michael@0 647 int yi = y >> 16;
michael@0 648 const uint8* src = src_ptr + yi * src_stride;
michael@0 649
michael@0 650 // Allocate 2 row buffers.
michael@0 651 const int kRowSize = (dst_width + 15) & ~15;
michael@0 652 align_buffer_64(row, kRowSize * 2);
michael@0 653
michael@0 654 uint8* rowptr = row;
michael@0 655 int rowstride = kRowSize;
michael@0 656 int lasty = yi;
michael@0 657
michael@0 658 ScaleFilterCols(rowptr, src, dst_width, x, dx);
michael@0 659 if (src_height > 1) {
michael@0 660 src += src_stride;
michael@0 661 }
michael@0 662 ScaleFilterCols(rowptr + rowstride, src, dst_width, x, dx);
michael@0 663 src += src_stride;
michael@0 664
michael@0 665 int j;
michael@0 666 for (j = 0; j < dst_height; ++j) {
michael@0 667 yi = y >> 16;
michael@0 668 if (yi != lasty) {
michael@0 669 if (y > max_y) {
michael@0 670 y = max_y;
michael@0 671 yi = y >> 16;
michael@0 672 src = src_ptr + yi * src_stride;
michael@0 673 }
michael@0 674 if (yi != lasty) {
michael@0 675 ScaleFilterCols(rowptr, src, dst_width, x, dx);
michael@0 676 rowptr += rowstride;
michael@0 677 rowstride = -rowstride;
michael@0 678 lasty = yi;
michael@0 679 src += src_stride;
michael@0 680 }
michael@0 681 }
michael@0 682 if (filtering == kFilterLinear) {
michael@0 683 InterpolateRow(dst_ptr, rowptr, 0, dst_width, 0);
michael@0 684 } else {
michael@0 685 int yf = (y >> 8) & 255;
michael@0 686 InterpolateRow(dst_ptr, rowptr, rowstride, dst_width, yf);
michael@0 687 }
michael@0 688 dst_ptr += dst_stride;
michael@0 689 y += dy;
michael@0 690 }
michael@0 691 free_aligned_buffer_64(row);
michael@0 692 }
michael@0 693
michael@0 694 // Scale Plane to/from any dimensions, without interpolation.
michael@0 695 // Fixed point math is used for performance: The upper 16 bits
michael@0 696 // of x and dx is the integer part of the source position and
michael@0 697 // the lower 16 bits are the fixed decimal part.
michael@0 698
michael@0 699 static void ScalePlaneSimple(int src_width, int src_height,
michael@0 700 int dst_width, int dst_height,
michael@0 701 int src_stride, int dst_stride,
michael@0 702 const uint8* src_ptr, uint8* dst_ptr) {
michael@0 703 // Initial source x/y coordinate and step values as 16.16 fixed point.
michael@0 704 int x = 0;
michael@0 705 int y = 0;
michael@0 706 int dx = 0;
michael@0 707 int dy = 0;
michael@0 708 ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterNone,
michael@0 709 &x, &y, &dx, &dy);
michael@0 710 src_width = Abs(src_width);
michael@0 711
michael@0 712 void (*ScaleCols)(uint8* dst_ptr, const uint8* src_ptr,
michael@0 713 int dst_width, int x, int dx) = ScaleCols_C;
michael@0 714 if (src_width * 2 == dst_width && x < 0x8000) {
michael@0 715 ScaleCols = ScaleColsUp2_C;
michael@0 716 #if defined(HAS_SCALECOLS_SSE2)
michael@0 717 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8) &&
michael@0 718 IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16) &&
michael@0 719 IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
michael@0 720 ScaleCols = ScaleColsUp2_SSE2;
michael@0 721 }
michael@0 722 #endif
michael@0 723 }
michael@0 724
michael@0 725 int i;
michael@0 726 for (i = 0; i < dst_height; ++i) {
michael@0 727 ScaleCols(dst_ptr, src_ptr + (y >> 16) * src_stride,
michael@0 728 dst_width, x, dx);
michael@0 729 dst_ptr += dst_stride;
michael@0 730 y += dy;
michael@0 731 }
michael@0 732 }
michael@0 733
michael@0 734 // Scale a plane.
michael@0 735 // This function dispatches to a specialized scaler based on scale factor.
michael@0 736
michael@0 737 LIBYUV_API
michael@0 738 void ScalePlane(const uint8* src, int src_stride,
michael@0 739 int src_width, int src_height,
michael@0 740 uint8* dst, int dst_stride,
michael@0 741 int dst_width, int dst_height,
michael@0 742 enum FilterMode filtering) {
michael@0 743 // Simplify filtering when possible.
michael@0 744 filtering = ScaleFilterReduce(src_width, src_height,
michael@0 745 dst_width, dst_height,
michael@0 746 filtering);
michael@0 747
michael@0 748 // Negative height means invert the image.
michael@0 749 if (src_height < 0) {
michael@0 750 src_height = -src_height;
michael@0 751 src = src + (src_height - 1) * src_stride;
michael@0 752 src_stride = -src_stride;
michael@0 753 }
michael@0 754
michael@0 755 // Use specialized scales to improve performance for common resolutions.
michael@0 756 // For example, all the 1/2 scalings will use ScalePlaneDown2()
michael@0 757 if (dst_width == src_width && dst_height == src_height) {
michael@0 758 // Straight copy.
michael@0 759 CopyPlane(src, src_stride, dst, dst_stride, dst_width, dst_height);
michael@0 760 return;
michael@0 761 }
michael@0 762 if (dst_width == src_width) {
michael@0 763 int dy = FixedDiv(src_height, dst_height);
michael@0 764 // Arbitrary scale vertically, but unscaled vertically.
michael@0 765 ScalePlaneVertical(src_height,
michael@0 766 dst_width, dst_height,
michael@0 767 src_stride, dst_stride, src, dst,
michael@0 768 0, 0, dy, 1, filtering);
michael@0 769 return;
michael@0 770 }
michael@0 771 if (dst_width <= Abs(src_width) && dst_height <= src_height) {
michael@0 772 // Scale down.
michael@0 773 if (4 * dst_width == 3 * src_width &&
michael@0 774 4 * dst_height == 3 * src_height) {
michael@0 775 // optimized, 3/4
michael@0 776 ScalePlaneDown34(src_width, src_height, dst_width, dst_height,
michael@0 777 src_stride, dst_stride, src, dst, filtering);
michael@0 778 return;
michael@0 779 }
michael@0 780 if (2 * dst_width == src_width && 2 * dst_height == src_height) {
michael@0 781 // optimized, 1/2
michael@0 782 ScalePlaneDown2(src_width, src_height, dst_width, dst_height,
michael@0 783 src_stride, dst_stride, src, dst, filtering);
michael@0 784 return;
michael@0 785 }
michael@0 786 // 3/8 rounded up for odd sized chroma height.
michael@0 787 if (8 * dst_width == 3 * src_width &&
michael@0 788 dst_height == ((src_height * 3 + 7) / 8)) {
michael@0 789 // optimized, 3/8
michael@0 790 ScalePlaneDown38(src_width, src_height, dst_width, dst_height,
michael@0 791 src_stride, dst_stride, src, dst, filtering);
michael@0 792 return;
michael@0 793 }
michael@0 794 if (4 * dst_width == src_width && 4 * dst_height == src_height &&
michael@0 795 filtering != kFilterBilinear) {
michael@0 796 // optimized, 1/4
michael@0 797 ScalePlaneDown4(src_width, src_height, dst_width, dst_height,
michael@0 798 src_stride, dst_stride, src, dst, filtering);
michael@0 799 return;
michael@0 800 }
michael@0 801 }
michael@0 802 if (filtering == kFilterBox && dst_height * 2 < src_height) {
michael@0 803 ScalePlaneBox(src_width, src_height, dst_width, dst_height,
michael@0 804 src_stride, dst_stride, src, dst);
michael@0 805 return;
michael@0 806 }
michael@0 807 if (filtering && dst_height > src_height) {
michael@0 808 ScalePlaneBilinearUp(src_width, src_height, dst_width, dst_height,
michael@0 809 src_stride, dst_stride, src, dst, filtering);
michael@0 810 return;
michael@0 811 }
michael@0 812 if (filtering) {
michael@0 813 ScalePlaneBilinearDown(src_width, src_height, dst_width, dst_height,
michael@0 814 src_stride, dst_stride, src, dst, filtering);
michael@0 815 return;
michael@0 816 }
michael@0 817 ScalePlaneSimple(src_width, src_height, dst_width, dst_height,
michael@0 818 src_stride, dst_stride, src, dst);
michael@0 819 }
michael@0 820
michael@0 821 // Scale an I420 image.
michael@0 822 // This function in turn calls a scaling function for each plane.
michael@0 823
michael@0 824 LIBYUV_API
michael@0 825 int I420Scale(const uint8* src_y, int src_stride_y,
michael@0 826 const uint8* src_u, int src_stride_u,
michael@0 827 const uint8* src_v, int src_stride_v,
michael@0 828 int src_width, int src_height,
michael@0 829 uint8* dst_y, int dst_stride_y,
michael@0 830 uint8* dst_u, int dst_stride_u,
michael@0 831 uint8* dst_v, int dst_stride_v,
michael@0 832 int dst_width, int dst_height,
michael@0 833 enum FilterMode filtering) {
michael@0 834 if (!src_y || !src_u || !src_v || src_width == 0 || src_height == 0 ||
michael@0 835 !dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0) {
michael@0 836 return -1;
michael@0 837 }
michael@0 838 int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
michael@0 839 int src_halfheight = SUBSAMPLE(src_height, 1, 1);
michael@0 840 int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
michael@0 841 int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
michael@0 842
michael@0 843 ScalePlane(src_y, src_stride_y, src_width, src_height,
michael@0 844 dst_y, dst_stride_y, dst_width, dst_height,
michael@0 845 filtering);
michael@0 846 ScalePlane(src_u, src_stride_u, src_halfwidth, src_halfheight,
michael@0 847 dst_u, dst_stride_u, dst_halfwidth, dst_halfheight,
michael@0 848 filtering);
michael@0 849 ScalePlane(src_v, src_stride_v, src_halfwidth, src_halfheight,
michael@0 850 dst_v, dst_stride_v, dst_halfwidth, dst_halfheight,
michael@0 851 filtering);
michael@0 852 return 0;
michael@0 853 }
michael@0 854
michael@0 855 // Deprecated api
michael@0 856 LIBYUV_API
michael@0 857 int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v,
michael@0 858 int src_stride_y, int src_stride_u, int src_stride_v,
michael@0 859 int src_width, int src_height,
michael@0 860 uint8* dst_y, uint8* dst_u, uint8* dst_v,
michael@0 861 int dst_stride_y, int dst_stride_u, int dst_stride_v,
michael@0 862 int dst_width, int dst_height,
michael@0 863 LIBYUV_BOOL interpolate) {
michael@0 864 return I420Scale(src_y, src_stride_y,
michael@0 865 src_u, src_stride_u,
michael@0 866 src_v, src_stride_v,
michael@0 867 src_width, src_height,
michael@0 868 dst_y, dst_stride_y,
michael@0 869 dst_u, dst_stride_u,
michael@0 870 dst_v, dst_stride_v,
michael@0 871 dst_width, dst_height,
michael@0 872 interpolate ? kFilterBox : kFilterNone);
michael@0 873 }
michael@0 874
michael@0 875 // Deprecated api
michael@0 876 LIBYUV_API
michael@0 877 int ScaleOffset(const uint8* src, int src_width, int src_height,
michael@0 878 uint8* dst, int dst_width, int dst_height, int dst_yoffset,
michael@0 879 LIBYUV_BOOL interpolate) {
michael@0 880 if (!src || src_width <= 0 || src_height <= 0 ||
michael@0 881 !dst || dst_width <= 0 || dst_height <= 0 || dst_yoffset < 0 ||
michael@0 882 dst_yoffset >= dst_height) {
michael@0 883 return -1;
michael@0 884 }
michael@0 885 dst_yoffset = dst_yoffset & ~1; // chroma requires offset to multiple of 2.
michael@0 886 int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
michael@0 887 int src_halfheight = SUBSAMPLE(src_height, 1, 1);
michael@0 888 int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
michael@0 889 int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
michael@0 890 int aheight = dst_height - dst_yoffset * 2; // actual output height
michael@0 891 const uint8* src_y = src;
michael@0 892 const uint8* src_u = src + src_width * src_height;
michael@0 893 const uint8* src_v = src + src_width * src_height +
michael@0 894 src_halfwidth * src_halfheight;
michael@0 895 uint8* dst_y = dst + dst_yoffset * dst_width;
michael@0 896 uint8* dst_u = dst + dst_width * dst_height +
michael@0 897 (dst_yoffset >> 1) * dst_halfwidth;
michael@0 898 uint8* dst_v = dst + dst_width * dst_height + dst_halfwidth * dst_halfheight +
michael@0 899 (dst_yoffset >> 1) * dst_halfwidth;
michael@0 900 return I420Scale(src_y, src_width,
michael@0 901 src_u, src_halfwidth,
michael@0 902 src_v, src_halfwidth,
michael@0 903 src_width, src_height,
michael@0 904 dst_y, dst_width,
michael@0 905 dst_u, dst_halfwidth,
michael@0 906 dst_v, dst_halfwidth,
michael@0 907 dst_width, aheight,
michael@0 908 interpolate ? kFilterBox : kFilterNone);
michael@0 909 }
michael@0 910
michael@0 911 #ifdef __cplusplus
michael@0 912 } // extern "C"
michael@0 913 } // namespace libyuv
michael@0 914 #endif

mercurial