media/libyuv/source/scale_common.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 2013 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 CopyARGB
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 static __inline int Abs(int v) {
michael@0 27 return v >= 0 ? v : -v;
michael@0 28 }
michael@0 29
michael@0 30 // CPU agnostic row functions
michael@0 31 void ScaleRowDown2_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 32 uint8* dst, int dst_width) {
michael@0 33 int x;
michael@0 34 for (x = 0; x < dst_width - 1; x += 2) {
michael@0 35 dst[0] = src_ptr[1];
michael@0 36 dst[1] = src_ptr[3];
michael@0 37 dst += 2;
michael@0 38 src_ptr += 4;
michael@0 39 }
michael@0 40 if (dst_width & 1) {
michael@0 41 dst[0] = src_ptr[1];
michael@0 42 }
michael@0 43 }
michael@0 44
michael@0 45 void ScaleRowDown2Linear_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 46 uint8* dst, int dst_width) {
michael@0 47 const uint8* s = src_ptr;
michael@0 48 int x;
michael@0 49 for (x = 0; x < dst_width - 1; x += 2) {
michael@0 50 dst[0] = (s[0] + s[1] + 1) >> 1;
michael@0 51 dst[1] = (s[2] + s[3] + 1) >> 1;
michael@0 52 dst += 2;
michael@0 53 s += 4;
michael@0 54 }
michael@0 55 if (dst_width & 1) {
michael@0 56 dst[0] = (s[0] + s[1] + 1) >> 1;
michael@0 57 }
michael@0 58 }
michael@0 59
michael@0 60 void ScaleRowDown2Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 61 uint8* dst, int dst_width) {
michael@0 62 const uint8* s = src_ptr;
michael@0 63 const uint8* t = src_ptr + src_stride;
michael@0 64 int x;
michael@0 65 for (x = 0; x < dst_width - 1; x += 2) {
michael@0 66 dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
michael@0 67 dst[1] = (s[2] + s[3] + t[2] + t[3] + 2) >> 2;
michael@0 68 dst += 2;
michael@0 69 s += 4;
michael@0 70 t += 4;
michael@0 71 }
michael@0 72 if (dst_width & 1) {
michael@0 73 dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
michael@0 74 }
michael@0 75 }
michael@0 76
michael@0 77 void ScaleRowDown4_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 78 uint8* dst, int dst_width) {
michael@0 79 int x;
michael@0 80 for (x = 0; x < dst_width - 1; x += 2) {
michael@0 81 dst[0] = src_ptr[2];
michael@0 82 dst[1] = src_ptr[6];
michael@0 83 dst += 2;
michael@0 84 src_ptr += 8;
michael@0 85 }
michael@0 86 if (dst_width & 1) {
michael@0 87 dst[0] = src_ptr[2];
michael@0 88 }
michael@0 89 }
michael@0 90
michael@0 91 void ScaleRowDown4Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 92 uint8* dst, int dst_width) {
michael@0 93 intptr_t stride = src_stride;
michael@0 94 int x;
michael@0 95 for (x = 0; x < dst_width - 1; x += 2) {
michael@0 96 dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] +
michael@0 97 src_ptr[stride + 0] + src_ptr[stride + 1] +
michael@0 98 src_ptr[stride + 2] + src_ptr[stride + 3] +
michael@0 99 src_ptr[stride * 2 + 0] + src_ptr[stride * 2 + 1] +
michael@0 100 src_ptr[stride * 2 + 2] + src_ptr[stride * 2 + 3] +
michael@0 101 src_ptr[stride * 3 + 0] + src_ptr[stride * 3 + 1] +
michael@0 102 src_ptr[stride * 3 + 2] + src_ptr[stride * 3 + 3] +
michael@0 103 8) >> 4;
michael@0 104 dst[1] = (src_ptr[4] + src_ptr[5] + src_ptr[6] + src_ptr[7] +
michael@0 105 src_ptr[stride + 4] + src_ptr[stride + 5] +
michael@0 106 src_ptr[stride + 6] + src_ptr[stride + 7] +
michael@0 107 src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5] +
michael@0 108 src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7] +
michael@0 109 src_ptr[stride * 3 + 4] + src_ptr[stride * 3 + 5] +
michael@0 110 src_ptr[stride * 3 + 6] + src_ptr[stride * 3 + 7] +
michael@0 111 8) >> 4;
michael@0 112 dst += 2;
michael@0 113 src_ptr += 8;
michael@0 114 }
michael@0 115 if (dst_width & 1) {
michael@0 116 dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] +
michael@0 117 src_ptr[stride + 0] + src_ptr[stride + 1] +
michael@0 118 src_ptr[stride + 2] + src_ptr[stride + 3] +
michael@0 119 src_ptr[stride * 2 + 0] + src_ptr[stride * 2 + 1] +
michael@0 120 src_ptr[stride * 2 + 2] + src_ptr[stride * 2 + 3] +
michael@0 121 src_ptr[stride * 3 + 0] + src_ptr[stride * 3 + 1] +
michael@0 122 src_ptr[stride * 3 + 2] + src_ptr[stride * 3 + 3] +
michael@0 123 8) >> 4;
michael@0 124 }
michael@0 125 }
michael@0 126
michael@0 127 void ScaleRowDown34_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 128 uint8* dst, int dst_width) {
michael@0 129 int x;
michael@0 130 assert((dst_width % 3 == 0) && (dst_width > 0));
michael@0 131 for (x = 0; x < dst_width; x += 3) {
michael@0 132 dst[0] = src_ptr[0];
michael@0 133 dst[1] = src_ptr[1];
michael@0 134 dst[2] = src_ptr[3];
michael@0 135 dst += 3;
michael@0 136 src_ptr += 4;
michael@0 137 }
michael@0 138 }
michael@0 139
michael@0 140 // Filter rows 0 and 1 together, 3 : 1
michael@0 141 void ScaleRowDown34_0_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 142 uint8* d, int dst_width) {
michael@0 143 const uint8* s = src_ptr;
michael@0 144 const uint8* t = src_ptr + src_stride;
michael@0 145 int x;
michael@0 146 assert((dst_width % 3 == 0) && (dst_width > 0));
michael@0 147 for (x = 0; x < dst_width; x += 3) {
michael@0 148 uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2;
michael@0 149 uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1;
michael@0 150 uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2;
michael@0 151 uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2;
michael@0 152 uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1;
michael@0 153 uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2;
michael@0 154 d[0] = (a0 * 3 + b0 + 2) >> 2;
michael@0 155 d[1] = (a1 * 3 + b1 + 2) >> 2;
michael@0 156 d[2] = (a2 * 3 + b2 + 2) >> 2;
michael@0 157 d += 3;
michael@0 158 s += 4;
michael@0 159 t += 4;
michael@0 160 }
michael@0 161 }
michael@0 162
michael@0 163 // Filter rows 1 and 2 together, 1 : 1
michael@0 164 void ScaleRowDown34_1_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 165 uint8* d, int dst_width) {
michael@0 166 const uint8* s = src_ptr;
michael@0 167 const uint8* t = src_ptr + src_stride;
michael@0 168 int x;
michael@0 169 assert((dst_width % 3 == 0) && (dst_width > 0));
michael@0 170 for (x = 0; x < dst_width; x += 3) {
michael@0 171 uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2;
michael@0 172 uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1;
michael@0 173 uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2;
michael@0 174 uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2;
michael@0 175 uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1;
michael@0 176 uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2;
michael@0 177 d[0] = (a0 + b0 + 1) >> 1;
michael@0 178 d[1] = (a1 + b1 + 1) >> 1;
michael@0 179 d[2] = (a2 + b2 + 1) >> 1;
michael@0 180 d += 3;
michael@0 181 s += 4;
michael@0 182 t += 4;
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 // Scales a single row of pixels using point sampling.
michael@0 187 void ScaleCols_C(uint8* dst_ptr, const uint8* src_ptr,
michael@0 188 int dst_width, int x, int dx) {
michael@0 189 int j;
michael@0 190 for (j = 0; j < dst_width - 1; j += 2) {
michael@0 191 dst_ptr[0] = src_ptr[x >> 16];
michael@0 192 x += dx;
michael@0 193 dst_ptr[1] = src_ptr[x >> 16];
michael@0 194 x += dx;
michael@0 195 dst_ptr += 2;
michael@0 196 }
michael@0 197 if (dst_width & 1) {
michael@0 198 dst_ptr[0] = src_ptr[x >> 16];
michael@0 199 }
michael@0 200 }
michael@0 201
michael@0 202 // Scales a single row of pixels up by 2x using point sampling.
michael@0 203 void ScaleColsUp2_C(uint8* dst_ptr, const uint8* src_ptr,
michael@0 204 int dst_width, int x, int dx) {
michael@0 205 int j;
michael@0 206 for (j = 0; j < dst_width - 1; j += 2) {
michael@0 207 dst_ptr[1] = dst_ptr[0] = src_ptr[0];
michael@0 208 src_ptr += 1;
michael@0 209 dst_ptr += 2;
michael@0 210 }
michael@0 211 if (dst_width & 1) {
michael@0 212 dst_ptr[0] = src_ptr[0];
michael@0 213 }
michael@0 214 }
michael@0 215
michael@0 216 // (1-f)a + fb can be replaced with a + f(b-a)
michael@0 217 #define BLENDER(a, b, f) (uint8)((int)(a) + \
michael@0 218 ((int)(f) * ((int)(b) - (int)(a)) >> 16))
michael@0 219
michael@0 220 void ScaleFilterCols_C(uint8* dst_ptr, const uint8* src_ptr,
michael@0 221 int dst_width, int x, int dx) {
michael@0 222 int j;
michael@0 223 for (j = 0; j < dst_width - 1; j += 2) {
michael@0 224 int xi = x >> 16;
michael@0 225 int a = src_ptr[xi];
michael@0 226 int b = src_ptr[xi + 1];
michael@0 227 dst_ptr[0] = BLENDER(a, b, x & 0xffff);
michael@0 228 x += dx;
michael@0 229 xi = x >> 16;
michael@0 230 a = src_ptr[xi];
michael@0 231 b = src_ptr[xi + 1];
michael@0 232 dst_ptr[1] = BLENDER(a, b, x & 0xffff);
michael@0 233 x += dx;
michael@0 234 dst_ptr += 2;
michael@0 235 }
michael@0 236 if (dst_width & 1) {
michael@0 237 int xi = x >> 16;
michael@0 238 int a = src_ptr[xi];
michael@0 239 int b = src_ptr[xi + 1];
michael@0 240 dst_ptr[0] = BLENDER(a, b, x & 0xffff);
michael@0 241 }
michael@0 242 }
michael@0 243
michael@0 244 void ScaleFilterCols64_C(uint8* dst_ptr, const uint8* src_ptr,
michael@0 245 int dst_width, int x32, int dx) {
michael@0 246 int64 x = (int64)(x32);
michael@0 247 int j;
michael@0 248 for (j = 0; j < dst_width - 1; j += 2) {
michael@0 249 int64 xi = x >> 16;
michael@0 250 int a = src_ptr[xi];
michael@0 251 int b = src_ptr[xi + 1];
michael@0 252 dst_ptr[0] = BLENDER(a, b, x & 0xffff);
michael@0 253 x += dx;
michael@0 254 xi = x >> 16;
michael@0 255 a = src_ptr[xi];
michael@0 256 b = src_ptr[xi + 1];
michael@0 257 dst_ptr[1] = BLENDER(a, b, x & 0xffff);
michael@0 258 x += dx;
michael@0 259 dst_ptr += 2;
michael@0 260 }
michael@0 261 if (dst_width & 1) {
michael@0 262 int64 xi = x >> 16;
michael@0 263 int a = src_ptr[xi];
michael@0 264 int b = src_ptr[xi + 1];
michael@0 265 dst_ptr[0] = BLENDER(a, b, x & 0xffff);
michael@0 266 }
michael@0 267 }
michael@0 268 #undef BLENDER
michael@0 269
michael@0 270 void ScaleRowDown38_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 271 uint8* dst, int dst_width) {
michael@0 272 int x;
michael@0 273 assert(dst_width % 3 == 0);
michael@0 274 for (x = 0; x < dst_width; x += 3) {
michael@0 275 dst[0] = src_ptr[0];
michael@0 276 dst[1] = src_ptr[3];
michael@0 277 dst[2] = src_ptr[6];
michael@0 278 dst += 3;
michael@0 279 src_ptr += 8;
michael@0 280 }
michael@0 281 }
michael@0 282
michael@0 283 // 8x3 -> 3x1
michael@0 284 void ScaleRowDown38_3_Box_C(const uint8* src_ptr,
michael@0 285 ptrdiff_t src_stride,
michael@0 286 uint8* dst_ptr, int dst_width) {
michael@0 287 intptr_t stride = src_stride;
michael@0 288 int i;
michael@0 289 assert((dst_width % 3 == 0) && (dst_width > 0));
michael@0 290 for (i = 0; i < dst_width; i += 3) {
michael@0 291 dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] +
michael@0 292 src_ptr[stride + 0] + src_ptr[stride + 1] +
michael@0 293 src_ptr[stride + 2] + src_ptr[stride * 2 + 0] +
michael@0 294 src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2]) *
michael@0 295 (65536 / 9) >> 16;
michael@0 296 dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] +
michael@0 297 src_ptr[stride + 3] + src_ptr[stride + 4] +
michael@0 298 src_ptr[stride + 5] + src_ptr[stride * 2 + 3] +
michael@0 299 src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5]) *
michael@0 300 (65536 / 9) >> 16;
michael@0 301 dst_ptr[2] = (src_ptr[6] + src_ptr[7] +
michael@0 302 src_ptr[stride + 6] + src_ptr[stride + 7] +
michael@0 303 src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7]) *
michael@0 304 (65536 / 6) >> 16;
michael@0 305 src_ptr += 8;
michael@0 306 dst_ptr += 3;
michael@0 307 }
michael@0 308 }
michael@0 309
michael@0 310 // 8x2 -> 3x1
michael@0 311 void ScaleRowDown38_2_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 312 uint8* dst_ptr, int dst_width) {
michael@0 313 intptr_t stride = src_stride;
michael@0 314 int i;
michael@0 315 assert((dst_width % 3 == 0) && (dst_width > 0));
michael@0 316 for (i = 0; i < dst_width; i += 3) {
michael@0 317 dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] +
michael@0 318 src_ptr[stride + 0] + src_ptr[stride + 1] +
michael@0 319 src_ptr[stride + 2]) * (65536 / 6) >> 16;
michael@0 320 dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] +
michael@0 321 src_ptr[stride + 3] + src_ptr[stride + 4] +
michael@0 322 src_ptr[stride + 5]) * (65536 / 6) >> 16;
michael@0 323 dst_ptr[2] = (src_ptr[6] + src_ptr[7] +
michael@0 324 src_ptr[stride + 6] + src_ptr[stride + 7]) *
michael@0 325 (65536 / 4) >> 16;
michael@0 326 src_ptr += 8;
michael@0 327 dst_ptr += 3;
michael@0 328 }
michael@0 329 }
michael@0 330
michael@0 331 void ScaleAddRows_C(const uint8* src_ptr, ptrdiff_t src_stride,
michael@0 332 uint16* dst_ptr, int src_width, int src_height) {
michael@0 333 int x;
michael@0 334 assert(src_width > 0);
michael@0 335 assert(src_height > 0);
michael@0 336 for (x = 0; x < src_width; ++x) {
michael@0 337 const uint8* s = src_ptr + x;
michael@0 338 unsigned int sum = 0u;
michael@0 339 int y;
michael@0 340 for (y = 0; y < src_height; ++y) {
michael@0 341 sum += s[0];
michael@0 342 s += src_stride;
michael@0 343 }
michael@0 344 // TODO(fbarchard): Consider limitting height to 256 to avoid overflow.
michael@0 345 dst_ptr[x] = sum < 65535u ? sum : 65535u;
michael@0 346 }
michael@0 347 }
michael@0 348
michael@0 349 void ScaleARGBRowDown2_C(const uint8* src_argb,
michael@0 350 ptrdiff_t src_stride,
michael@0 351 uint8* dst_argb, int dst_width) {
michael@0 352 const uint32* src = (const uint32*)(src_argb);
michael@0 353 uint32* dst = (uint32*)(dst_argb);
michael@0 354
michael@0 355 int x;
michael@0 356 for (x = 0; x < dst_width - 1; x += 2) {
michael@0 357 dst[0] = src[1];
michael@0 358 dst[1] = src[3];
michael@0 359 src += 4;
michael@0 360 dst += 2;
michael@0 361 }
michael@0 362 if (dst_width & 1) {
michael@0 363 dst[0] = src[1];
michael@0 364 }
michael@0 365 }
michael@0 366
michael@0 367 void ScaleARGBRowDown2Linear_C(const uint8* src_argb,
michael@0 368 ptrdiff_t src_stride,
michael@0 369 uint8* dst_argb, int dst_width) {
michael@0 370 int x;
michael@0 371 for (x = 0; x < dst_width; ++x) {
michael@0 372 dst_argb[0] = (src_argb[0] + src_argb[4] + 1) >> 1;
michael@0 373 dst_argb[1] = (src_argb[1] + src_argb[5] + 1) >> 1;
michael@0 374 dst_argb[2] = (src_argb[2] + src_argb[6] + 1) >> 1;
michael@0 375 dst_argb[3] = (src_argb[3] + src_argb[7] + 1) >> 1;
michael@0 376 src_argb += 8;
michael@0 377 dst_argb += 4;
michael@0 378 }
michael@0 379 }
michael@0 380
michael@0 381 void ScaleARGBRowDown2Box_C(const uint8* src_argb, ptrdiff_t src_stride,
michael@0 382 uint8* dst_argb, int dst_width) {
michael@0 383 int x;
michael@0 384 for (x = 0; x < dst_width; ++x) {
michael@0 385 dst_argb[0] = (src_argb[0] + src_argb[4] +
michael@0 386 src_argb[src_stride] + src_argb[src_stride + 4] + 2) >> 2;
michael@0 387 dst_argb[1] = (src_argb[1] + src_argb[5] +
michael@0 388 src_argb[src_stride + 1] + src_argb[src_stride + 5] + 2) >> 2;
michael@0 389 dst_argb[2] = (src_argb[2] + src_argb[6] +
michael@0 390 src_argb[src_stride + 2] + src_argb[src_stride + 6] + 2) >> 2;
michael@0 391 dst_argb[3] = (src_argb[3] + src_argb[7] +
michael@0 392 src_argb[src_stride + 3] + src_argb[src_stride + 7] + 2) >> 2;
michael@0 393 src_argb += 8;
michael@0 394 dst_argb += 4;
michael@0 395 }
michael@0 396 }
michael@0 397
michael@0 398 void ScaleARGBRowDownEven_C(const uint8* src_argb, ptrdiff_t src_stride,
michael@0 399 int src_stepx,
michael@0 400 uint8* dst_argb, int dst_width) {
michael@0 401 const uint32* src = (const uint32*)(src_argb);
michael@0 402 uint32* dst = (uint32*)(dst_argb);
michael@0 403
michael@0 404 int x;
michael@0 405 for (x = 0; x < dst_width - 1; x += 2) {
michael@0 406 dst[0] = src[0];
michael@0 407 dst[1] = src[src_stepx];
michael@0 408 src += src_stepx * 2;
michael@0 409 dst += 2;
michael@0 410 }
michael@0 411 if (dst_width & 1) {
michael@0 412 dst[0] = src[0];
michael@0 413 }
michael@0 414 }
michael@0 415
michael@0 416 void ScaleARGBRowDownEvenBox_C(const uint8* src_argb,
michael@0 417 ptrdiff_t src_stride,
michael@0 418 int src_stepx,
michael@0 419 uint8* dst_argb, int dst_width) {
michael@0 420 int x;
michael@0 421 for (x = 0; x < dst_width; ++x) {
michael@0 422 dst_argb[0] = (src_argb[0] + src_argb[4] +
michael@0 423 src_argb[src_stride] + src_argb[src_stride + 4] + 2) >> 2;
michael@0 424 dst_argb[1] = (src_argb[1] + src_argb[5] +
michael@0 425 src_argb[src_stride + 1] + src_argb[src_stride + 5] + 2) >> 2;
michael@0 426 dst_argb[2] = (src_argb[2] + src_argb[6] +
michael@0 427 src_argb[src_stride + 2] + src_argb[src_stride + 6] + 2) >> 2;
michael@0 428 dst_argb[3] = (src_argb[3] + src_argb[7] +
michael@0 429 src_argb[src_stride + 3] + src_argb[src_stride + 7] + 2) >> 2;
michael@0 430 src_argb += src_stepx * 4;
michael@0 431 dst_argb += 4;
michael@0 432 }
michael@0 433 }
michael@0 434
michael@0 435 // Scales a single row of pixels using point sampling.
michael@0 436 void ScaleARGBCols_C(uint8* dst_argb, const uint8* src_argb,
michael@0 437 int dst_width, int x, int dx) {
michael@0 438 const uint32* src = (const uint32*)(src_argb);
michael@0 439 uint32* dst = (uint32*)(dst_argb);
michael@0 440 int j;
michael@0 441 for (j = 0; j < dst_width - 1; j += 2) {
michael@0 442 dst[0] = src[x >> 16];
michael@0 443 x += dx;
michael@0 444 dst[1] = src[x >> 16];
michael@0 445 x += dx;
michael@0 446 dst += 2;
michael@0 447 }
michael@0 448 if (dst_width & 1) {
michael@0 449 dst[0] = src[x >> 16];
michael@0 450 }
michael@0 451 }
michael@0 452
michael@0 453 void ScaleARGBCols64_C(uint8* dst_argb, const uint8* src_argb,
michael@0 454 int dst_width, int x32, int dx) {
michael@0 455 int64 x = (int64)(x32);
michael@0 456 const uint32* src = (const uint32*)(src_argb);
michael@0 457 uint32* dst = (uint32*)(dst_argb);
michael@0 458 int j;
michael@0 459 for (j = 0; j < dst_width - 1; j += 2) {
michael@0 460 dst[0] = src[x >> 16];
michael@0 461 x += dx;
michael@0 462 dst[1] = src[x >> 16];
michael@0 463 x += dx;
michael@0 464 dst += 2;
michael@0 465 }
michael@0 466 if (dst_width & 1) {
michael@0 467 dst[0] = src[x >> 16];
michael@0 468 }
michael@0 469 }
michael@0 470
michael@0 471 // Scales a single row of pixels up by 2x using point sampling.
michael@0 472 void ScaleARGBColsUp2_C(uint8* dst_argb, const uint8* src_argb,
michael@0 473 int dst_width, int x, int dx) {
michael@0 474 const uint32* src = (const uint32*)(src_argb);
michael@0 475 uint32* dst = (uint32*)(dst_argb);
michael@0 476 int j;
michael@0 477 for (j = 0; j < dst_width - 1; j += 2) {
michael@0 478 dst[1] = dst[0] = src[0];
michael@0 479 src += 1;
michael@0 480 dst += 2;
michael@0 481 }
michael@0 482 if (dst_width & 1) {
michael@0 483 dst[0] = src[0];
michael@0 484 }
michael@0 485 }
michael@0 486
michael@0 487 // Mimics SSSE3 blender
michael@0 488 #define BLENDER1(a, b, f) ((a) * (0x7f ^ f) + (b) * f) >> 7
michael@0 489 #define BLENDERC(a, b, f, s) (uint32)( \
michael@0 490 BLENDER1(((a) >> s) & 255, ((b) >> s) & 255, f) << s)
michael@0 491 #define BLENDER(a, b, f) \
michael@0 492 BLENDERC(a, b, f, 24) | BLENDERC(a, b, f, 16) | \
michael@0 493 BLENDERC(a, b, f, 8) | BLENDERC(a, b, f, 0)
michael@0 494
michael@0 495 void ScaleARGBFilterCols_C(uint8* dst_argb, const uint8* src_argb,
michael@0 496 int dst_width, int x, int dx) {
michael@0 497 const uint32* src = (const uint32*)(src_argb);
michael@0 498 uint32* dst = (uint32*)(dst_argb);
michael@0 499 int j;
michael@0 500 for (j = 0; j < dst_width - 1; j += 2) {
michael@0 501 int xi = x >> 16;
michael@0 502 int xf = (x >> 9) & 0x7f;
michael@0 503 uint32 a = src[xi];
michael@0 504 uint32 b = src[xi + 1];
michael@0 505 dst[0] = BLENDER(a, b, xf);
michael@0 506 x += dx;
michael@0 507 xi = x >> 16;
michael@0 508 xf = (x >> 9) & 0x7f;
michael@0 509 a = src[xi];
michael@0 510 b = src[xi + 1];
michael@0 511 dst[1] = BLENDER(a, b, xf);
michael@0 512 x += dx;
michael@0 513 dst += 2;
michael@0 514 }
michael@0 515 if (dst_width & 1) {
michael@0 516 int xi = x >> 16;
michael@0 517 int xf = (x >> 9) & 0x7f;
michael@0 518 uint32 a = src[xi];
michael@0 519 uint32 b = src[xi + 1];
michael@0 520 dst[0] = BLENDER(a, b, xf);
michael@0 521 }
michael@0 522 }
michael@0 523
michael@0 524 void ScaleARGBFilterCols64_C(uint8* dst_argb, const uint8* src_argb,
michael@0 525 int dst_width, int x32, int dx) {
michael@0 526 int64 x = (int64)(x32);
michael@0 527 const uint32* src = (const uint32*)(src_argb);
michael@0 528 uint32* dst = (uint32*)(dst_argb);
michael@0 529 int j;
michael@0 530 for (j = 0; j < dst_width - 1; j += 2) {
michael@0 531 int64 xi = x >> 16;
michael@0 532 int xf = (x >> 9) & 0x7f;
michael@0 533 uint32 a = src[xi];
michael@0 534 uint32 b = src[xi + 1];
michael@0 535 dst[0] = BLENDER(a, b, xf);
michael@0 536 x += dx;
michael@0 537 xi = x >> 16;
michael@0 538 xf = (x >> 9) & 0x7f;
michael@0 539 a = src[xi];
michael@0 540 b = src[xi + 1];
michael@0 541 dst[1] = BLENDER(a, b, xf);
michael@0 542 x += dx;
michael@0 543 dst += 2;
michael@0 544 }
michael@0 545 if (dst_width & 1) {
michael@0 546 int64 xi = x >> 16;
michael@0 547 int xf = (x >> 9) & 0x7f;
michael@0 548 uint32 a = src[xi];
michael@0 549 uint32 b = src[xi + 1];
michael@0 550 dst[0] = BLENDER(a, b, xf);
michael@0 551 }
michael@0 552 }
michael@0 553 #undef BLENDER1
michael@0 554 #undef BLENDERC
michael@0 555 #undef BLENDER
michael@0 556
michael@0 557 // Scale plane vertically with bilinear interpolation.
michael@0 558 void ScalePlaneVertical(int src_height,
michael@0 559 int dst_width, int dst_height,
michael@0 560 int src_stride, int dst_stride,
michael@0 561 const uint8* src_argb, uint8* dst_argb,
michael@0 562 int x, int y, int dy,
michael@0 563 int bpp, enum FilterMode filtering) {
michael@0 564 // TODO(fbarchard): Allow higher bpp.
michael@0 565 int dst_width_bytes = dst_width * bpp;
michael@0 566 void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
michael@0 567 ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
michael@0 568 InterpolateRow_C;
michael@0 569 const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0;
michael@0 570 int j;
michael@0 571 assert(bpp >= 1 && bpp <= 4);
michael@0 572 assert(src_height != 0);
michael@0 573 assert(dst_width > 0);
michael@0 574 assert(dst_height > 0);
michael@0 575 src_argb += (x >> 16) * bpp;
michael@0 576 #if defined(HAS_INTERPOLATEROW_SSE2)
michael@0 577 if (TestCpuFlag(kCpuHasSSE2) && dst_width_bytes >= 16) {
michael@0 578 InterpolateRow = InterpolateRow_Any_SSE2;
michael@0 579 if (IS_ALIGNED(dst_width_bytes, 16)) {
michael@0 580 InterpolateRow = InterpolateRow_Unaligned_SSE2;
michael@0 581 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) &&
michael@0 582 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
michael@0 583 InterpolateRow = InterpolateRow_SSE2;
michael@0 584 }
michael@0 585 }
michael@0 586 }
michael@0 587 #endif
michael@0 588 #if defined(HAS_INTERPOLATEROW_SSSE3)
michael@0 589 if (TestCpuFlag(kCpuHasSSSE3) && dst_width_bytes >= 16) {
michael@0 590 InterpolateRow = InterpolateRow_Any_SSSE3;
michael@0 591 if (IS_ALIGNED(dst_width_bytes, 16)) {
michael@0 592 InterpolateRow = InterpolateRow_Unaligned_SSSE3;
michael@0 593 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) &&
michael@0 594 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
michael@0 595 InterpolateRow = InterpolateRow_SSSE3;
michael@0 596 }
michael@0 597 }
michael@0 598 }
michael@0 599 #endif
michael@0 600 #if defined(HAS_INTERPOLATEROW_AVX2)
michael@0 601 if (TestCpuFlag(kCpuHasAVX2) && dst_width_bytes >= 32) {
michael@0 602 InterpolateRow = InterpolateRow_Any_AVX2;
michael@0 603 if (IS_ALIGNED(dst_width_bytes, 32)) {
michael@0 604 InterpolateRow = InterpolateRow_AVX2;
michael@0 605 }
michael@0 606 }
michael@0 607 #endif
michael@0 608 #if defined(HAS_INTERPOLATEROW_NEON)
michael@0 609 if (TestCpuFlag(kCpuHasNEON) && dst_width_bytes >= 16) {
michael@0 610 InterpolateRow = InterpolateRow_Any_NEON;
michael@0 611 if (IS_ALIGNED(dst_width_bytes, 16)) {
michael@0 612 InterpolateRow = InterpolateRow_NEON;
michael@0 613 }
michael@0 614 }
michael@0 615 #endif
michael@0 616 #if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2)
michael@0 617 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_width_bytes >= 4 &&
michael@0 618 IS_ALIGNED(src_argb, 4) && IS_ALIGNED(src_stride, 4) &&
michael@0 619 IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride, 4)) {
michael@0 620 InterpolateRow = InterpolateRow_Any_MIPS_DSPR2;
michael@0 621 if (IS_ALIGNED(dst_width_bytes, 4)) {
michael@0 622 InterpolateRow = InterpolateRow_MIPS_DSPR2;
michael@0 623 }
michael@0 624 }
michael@0 625 #endif
michael@0 626 for (j = 0; j < dst_height; ++j) {
michael@0 627 int yi;
michael@0 628 int yf;
michael@0 629 if (y > max_y) {
michael@0 630 y = max_y;
michael@0 631 }
michael@0 632 yi = y >> 16;
michael@0 633 yf = filtering ? ((y >> 8) & 255) : 0;
michael@0 634 InterpolateRow(dst_argb, src_argb + yi * src_stride,
michael@0 635 src_stride, dst_width_bytes, yf);
michael@0 636 dst_argb += dst_stride;
michael@0 637 y += dy;
michael@0 638 }
michael@0 639 }
michael@0 640
michael@0 641 // Simplify the filtering based on scale factors.
michael@0 642 enum FilterMode ScaleFilterReduce(int src_width, int src_height,
michael@0 643 int dst_width, int dst_height,
michael@0 644 enum FilterMode filtering) {
michael@0 645 if (src_width < 0) {
michael@0 646 src_width = -src_width;
michael@0 647 }
michael@0 648 if (src_height < 0) {
michael@0 649 src_height = -src_height;
michael@0 650 }
michael@0 651 if (filtering == kFilterBox) {
michael@0 652 // If scaling both axis to 0.5 or larger, switch from Box to Bilinear.
michael@0 653 if (dst_width * 2 >= src_width && dst_height * 2 >= src_height) {
michael@0 654 filtering = kFilterBilinear;
michael@0 655 }
michael@0 656 // If scaling to larger, switch from Box to Bilinear.
michael@0 657 if (dst_width >= src_width || dst_height >= src_height) {
michael@0 658 filtering = kFilterBilinear;
michael@0 659 }
michael@0 660 }
michael@0 661 if (filtering == kFilterBilinear) {
michael@0 662 if (src_height == 1) {
michael@0 663 filtering = kFilterLinear;
michael@0 664 }
michael@0 665 // TODO(fbarchard): Detect any odd scale factor and reduce to Linear.
michael@0 666 if (dst_height == src_height || dst_height * 3 == src_height) {
michael@0 667 filtering = kFilterLinear;
michael@0 668 }
michael@0 669 // TODO(fbarchard): Remove 1 pixel wide filter restriction, which is to
michael@0 670 // avoid reading 2 pixels horizontally that causes memory exception.
michael@0 671 if (src_width == 1) {
michael@0 672 filtering = kFilterNone;
michael@0 673 }
michael@0 674 }
michael@0 675 if (filtering == kFilterLinear) {
michael@0 676 if (src_width == 1) {
michael@0 677 filtering = kFilterNone;
michael@0 678 }
michael@0 679 // TODO(fbarchard): Detect any odd scale factor and reduce to None.
michael@0 680 if (dst_width == src_width || dst_width * 3 == src_width) {
michael@0 681 filtering = kFilterNone;
michael@0 682 }
michael@0 683 }
michael@0 684 return filtering;
michael@0 685 }
michael@0 686
michael@0 687 // Divide num by div and return as 16.16 fixed point result.
michael@0 688 int FixedDiv_C(int num, int div) {
michael@0 689 return (int)(((int64)(num) << 16) / div);
michael@0 690 }
michael@0 691
michael@0 692 // Divide num by div and return as 16.16 fixed point result.
michael@0 693 int FixedDiv1_C(int num, int div) {
michael@0 694 return (int)((((int64)(num) << 16) - 0x00010001) /
michael@0 695 (div - 1));
michael@0 696 }
michael@0 697
michael@0 698 #define CENTERSTART(dx, s) (dx < 0) ? -((-dx >> 1) + s) : ((dx >> 1) + s)
michael@0 699
michael@0 700 // Compute slope values for stepping.
michael@0 701 void ScaleSlope(int src_width, int src_height,
michael@0 702 int dst_width, int dst_height,
michael@0 703 enum FilterMode filtering,
michael@0 704 int* x, int* y, int* dx, int* dy) {
michael@0 705 assert(x != NULL);
michael@0 706 assert(y != NULL);
michael@0 707 assert(dx != NULL);
michael@0 708 assert(dy != NULL);
michael@0 709 assert(src_width != 0);
michael@0 710 assert(src_height != 0);
michael@0 711 assert(dst_width > 0);
michael@0 712 assert(dst_height > 0);
michael@0 713 // Check for 1 pixel and avoid FixedDiv overflow.
michael@0 714 if (dst_width == 1 && src_width >= 32768) {
michael@0 715 dst_width = src_width;
michael@0 716 }
michael@0 717 if (dst_height == 1 && src_height >= 32768) {
michael@0 718 dst_height = src_height;
michael@0 719 }
michael@0 720 if (filtering == kFilterBox) {
michael@0 721 // Scale step for point sampling duplicates all pixels equally.
michael@0 722 *dx = FixedDiv(Abs(src_width), dst_width);
michael@0 723 *dy = FixedDiv(src_height, dst_height);
michael@0 724 *x = 0;
michael@0 725 *y = 0;
michael@0 726 } else if (filtering == kFilterBilinear) {
michael@0 727 // Scale step for bilinear sampling renders last pixel once for upsample.
michael@0 728 if (dst_width <= Abs(src_width)) {
michael@0 729 *dx = FixedDiv(Abs(src_width), dst_width);
michael@0 730 *x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter.
michael@0 731 } else if (dst_width > 1) {
michael@0 732 *dx = FixedDiv1(Abs(src_width), dst_width);
michael@0 733 *x = 0;
michael@0 734 }
michael@0 735 if (dst_height <= src_height) {
michael@0 736 *dy = FixedDiv(src_height, dst_height);
michael@0 737 *y = CENTERSTART(*dy, -32768); // Subtract 0.5 (32768) to center filter.
michael@0 738 } else if (dst_height > 1) {
michael@0 739 *dy = FixedDiv1(src_height, dst_height);
michael@0 740 *y = 0;
michael@0 741 }
michael@0 742 } else if (filtering == kFilterLinear) {
michael@0 743 // Scale step for bilinear sampling renders last pixel once for upsample.
michael@0 744 if (dst_width <= Abs(src_width)) {
michael@0 745 *dx = FixedDiv(Abs(src_width), dst_width);
michael@0 746 *x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter.
michael@0 747 } else if (dst_width > 1) {
michael@0 748 *dx = FixedDiv1(Abs(src_width), dst_width);
michael@0 749 *x = 0;
michael@0 750 }
michael@0 751 *dy = FixedDiv(src_height, dst_height);
michael@0 752 *y = *dy >> 1;
michael@0 753 } else {
michael@0 754 // Scale step for point sampling duplicates all pixels equally.
michael@0 755 *dx = FixedDiv(Abs(src_width), dst_width);
michael@0 756 *dy = FixedDiv(src_height, dst_height);
michael@0 757 *x = CENTERSTART(*dx, 0);
michael@0 758 *y = CENTERSTART(*dy, 0);
michael@0 759 }
michael@0 760 // Negative src_width means horizontally mirror.
michael@0 761 if (src_width < 0) {
michael@0 762 *x += (dst_width - 1) * *dx;
michael@0 763 *dx = -*dx;
michael@0 764 // src_width = -src_width; // Caller must do this.
michael@0 765 }
michael@0 766 }
michael@0 767 #undef CENTERSTART
michael@0 768
michael@0 769 #ifdef __cplusplus
michael@0 770 } // extern "C"
michael@0 771 } // namespace libyuv
michael@0 772 #endif

mercurial