media/libyuv/source/planar_functions.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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/planar_functions.h"
michael@0 12
michael@0 13 #include <string.h> // for memset()
michael@0 14
michael@0 15 #include "libyuv/cpu_id.h"
michael@0 16 #ifdef HAVE_JPEG
michael@0 17 #include "libyuv/mjpeg_decoder.h"
michael@0 18 #endif
michael@0 19 #include "libyuv/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 // Copy a plane of data
michael@0 27 LIBYUV_API
michael@0 28 void CopyPlane(const uint8* src_y, int src_stride_y,
michael@0 29 uint8* dst_y, int dst_stride_y,
michael@0 30 int width, int height) {
michael@0 31 int y;
michael@0 32 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
michael@0 33 // Coalesce rows.
michael@0 34 if (src_stride_y == width &&
michael@0 35 dst_stride_y == width) {
michael@0 36 width *= height;
michael@0 37 height = 1;
michael@0 38 src_stride_y = dst_stride_y = 0;
michael@0 39 }
michael@0 40 #if defined(HAS_COPYROW_X86)
michael@0 41 if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
michael@0 42 CopyRow = CopyRow_X86;
michael@0 43 }
michael@0 44 #endif
michael@0 45 #if defined(HAS_COPYROW_SSE2)
michael@0 46 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
michael@0 47 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
michael@0 48 IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
michael@0 49 CopyRow = CopyRow_SSE2;
michael@0 50 }
michael@0 51 #endif
michael@0 52 #if defined(HAS_COPYROW_ERMS)
michael@0 53 if (TestCpuFlag(kCpuHasERMS)) {
michael@0 54 CopyRow = CopyRow_ERMS;
michael@0 55 }
michael@0 56 #endif
michael@0 57 #if defined(HAS_COPYROW_NEON)
michael@0 58 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
michael@0 59 CopyRow = CopyRow_NEON;
michael@0 60 }
michael@0 61 #endif
michael@0 62 #if defined(HAS_COPYROW_MIPS)
michael@0 63 if (TestCpuFlag(kCpuHasMIPS)) {
michael@0 64 CopyRow = CopyRow_MIPS;
michael@0 65 }
michael@0 66 #endif
michael@0 67
michael@0 68 // Copy plane
michael@0 69 for (y = 0; y < height; ++y) {
michael@0 70 CopyRow(src_y, dst_y, width);
michael@0 71 src_y += src_stride_y;
michael@0 72 dst_y += dst_stride_y;
michael@0 73 }
michael@0 74 }
michael@0 75
michael@0 76 // Copy I422.
michael@0 77 LIBYUV_API
michael@0 78 int I422Copy(const uint8* src_y, int src_stride_y,
michael@0 79 const uint8* src_u, int src_stride_u,
michael@0 80 const uint8* src_v, int src_stride_v,
michael@0 81 uint8* dst_y, int dst_stride_y,
michael@0 82 uint8* dst_u, int dst_stride_u,
michael@0 83 uint8* dst_v, int dst_stride_v,
michael@0 84 int width, int height) {
michael@0 85 int halfwidth = (width + 1) >> 1;
michael@0 86 if (!src_y || !src_u || !src_v ||
michael@0 87 !dst_y || !dst_u || !dst_v ||
michael@0 88 width <= 0 || height == 0) {
michael@0 89 return -1;
michael@0 90 }
michael@0 91 // Negative height means invert the image.
michael@0 92 if (height < 0) {
michael@0 93 height = -height;
michael@0 94 src_y = src_y + (height - 1) * src_stride_y;
michael@0 95 src_u = src_u + (height - 1) * src_stride_u;
michael@0 96 src_v = src_v + (height - 1) * src_stride_v;
michael@0 97 src_stride_y = -src_stride_y;
michael@0 98 src_stride_u = -src_stride_u;
michael@0 99 src_stride_v = -src_stride_v;
michael@0 100 }
michael@0 101 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
michael@0 102 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height);
michael@0 103 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height);
michael@0 104 return 0;
michael@0 105 }
michael@0 106
michael@0 107 // Copy I444.
michael@0 108 LIBYUV_API
michael@0 109 int I444Copy(const uint8* src_y, int src_stride_y,
michael@0 110 const uint8* src_u, int src_stride_u,
michael@0 111 const uint8* src_v, int src_stride_v,
michael@0 112 uint8* dst_y, int dst_stride_y,
michael@0 113 uint8* dst_u, int dst_stride_u,
michael@0 114 uint8* dst_v, int dst_stride_v,
michael@0 115 int width, int height) {
michael@0 116 if (!src_y || !src_u || !src_v ||
michael@0 117 !dst_y || !dst_u || !dst_v ||
michael@0 118 width <= 0 || height == 0) {
michael@0 119 return -1;
michael@0 120 }
michael@0 121 // Negative height means invert the image.
michael@0 122 if (height < 0) {
michael@0 123 height = -height;
michael@0 124 src_y = src_y + (height - 1) * src_stride_y;
michael@0 125 src_u = src_u + (height - 1) * src_stride_u;
michael@0 126 src_v = src_v + (height - 1) * src_stride_v;
michael@0 127 src_stride_y = -src_stride_y;
michael@0 128 src_stride_u = -src_stride_u;
michael@0 129 src_stride_v = -src_stride_v;
michael@0 130 }
michael@0 131
michael@0 132 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
michael@0 133 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
michael@0 134 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
michael@0 135 return 0;
michael@0 136 }
michael@0 137
michael@0 138 // Copy I400.
michael@0 139 LIBYUV_API
michael@0 140 int I400ToI400(const uint8* src_y, int src_stride_y,
michael@0 141 uint8* dst_y, int dst_stride_y,
michael@0 142 int width, int height) {
michael@0 143 if (!src_y || !dst_y || width <= 0 || height == 0) {
michael@0 144 return -1;
michael@0 145 }
michael@0 146 // Negative height means invert the image.
michael@0 147 if (height < 0) {
michael@0 148 height = -height;
michael@0 149 src_y = src_y + (height - 1) * src_stride_y;
michael@0 150 src_stride_y = -src_stride_y;
michael@0 151 }
michael@0 152 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
michael@0 153 return 0;
michael@0 154 }
michael@0 155
michael@0 156 // Convert I420 to I400.
michael@0 157 LIBYUV_API
michael@0 158 int I420ToI400(const uint8* src_y, int src_stride_y,
michael@0 159 const uint8* src_u, int src_stride_u,
michael@0 160 const uint8* src_v, int src_stride_v,
michael@0 161 uint8* dst_y, int dst_stride_y,
michael@0 162 int width, int height) {
michael@0 163 if (!src_y || !dst_y || width <= 0 || height == 0) {
michael@0 164 return -1;
michael@0 165 }
michael@0 166 // Negative height means invert the image.
michael@0 167 if (height < 0) {
michael@0 168 height = -height;
michael@0 169 src_y = src_y + (height - 1) * src_stride_y;
michael@0 170 src_stride_y = -src_stride_y;
michael@0 171 }
michael@0 172 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
michael@0 173 return 0;
michael@0 174 }
michael@0 175
michael@0 176 // Mirror a plane of data.
michael@0 177 void MirrorPlane(const uint8* src_y, int src_stride_y,
michael@0 178 uint8* dst_y, int dst_stride_y,
michael@0 179 int width, int height) {
michael@0 180 int y;
michael@0 181 void (*MirrorRow)(const uint8* src, uint8* dst, int width) = MirrorRow_C;
michael@0 182 // Negative height means invert the image.
michael@0 183 if (height < 0) {
michael@0 184 height = -height;
michael@0 185 src_y = src_y + (height - 1) * src_stride_y;
michael@0 186 src_stride_y = -src_stride_y;
michael@0 187 }
michael@0 188 #if defined(HAS_MIRRORROW_NEON)
michael@0 189 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
michael@0 190 MirrorRow = MirrorRow_NEON;
michael@0 191 }
michael@0 192 #endif
michael@0 193 #if defined(HAS_MIRRORROW_SSE2)
michael@0 194 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16)) {
michael@0 195 MirrorRow = MirrorRow_SSE2;
michael@0 196 }
michael@0 197 #endif
michael@0 198 #if defined(HAS_MIRRORROW_SSSE3)
michael@0 199 if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16) &&
michael@0 200 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
michael@0 201 IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
michael@0 202 MirrorRow = MirrorRow_SSSE3;
michael@0 203 }
michael@0 204 #endif
michael@0 205 #if defined(HAS_MIRRORROW_AVX2)
michael@0 206 if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 32)) {
michael@0 207 MirrorRow = MirrorRow_AVX2;
michael@0 208 }
michael@0 209 #endif
michael@0 210
michael@0 211 // Mirror plane
michael@0 212 for (y = 0; y < height; ++y) {
michael@0 213 MirrorRow(src_y, dst_y, width);
michael@0 214 src_y += src_stride_y;
michael@0 215 dst_y += dst_stride_y;
michael@0 216 }
michael@0 217 }
michael@0 218
michael@0 219 // Convert YUY2 to I422.
michael@0 220 LIBYUV_API
michael@0 221 int YUY2ToI422(const uint8* src_yuy2, int src_stride_yuy2,
michael@0 222 uint8* dst_y, int dst_stride_y,
michael@0 223 uint8* dst_u, int dst_stride_u,
michael@0 224 uint8* dst_v, int dst_stride_v,
michael@0 225 int width, int height) {
michael@0 226 int y;
michael@0 227 void (*YUY2ToUV422Row)(const uint8* src_yuy2,
michael@0 228 uint8* dst_u, uint8* dst_v, int pix) =
michael@0 229 YUY2ToUV422Row_C;
michael@0 230 void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
michael@0 231 YUY2ToYRow_C;
michael@0 232 // Negative height means invert the image.
michael@0 233 if (height < 0) {
michael@0 234 height = -height;
michael@0 235 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
michael@0 236 src_stride_yuy2 = -src_stride_yuy2;
michael@0 237 }
michael@0 238 // Coalesce rows.
michael@0 239 if (src_stride_yuy2 == width * 2 &&
michael@0 240 dst_stride_y == width &&
michael@0 241 dst_stride_u * 2 == width &&
michael@0 242 dst_stride_v * 2 == width) {
michael@0 243 width *= height;
michael@0 244 height = 1;
michael@0 245 src_stride_yuy2 = dst_stride_y = dst_stride_u = dst_stride_v = 0;
michael@0 246 }
michael@0 247 #if defined(HAS_YUY2TOYROW_SSE2)
michael@0 248 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
michael@0 249 YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
michael@0 250 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
michael@0 251 if (IS_ALIGNED(width, 16)) {
michael@0 252 YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
michael@0 253 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
michael@0 254 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
michael@0 255 YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
michael@0 256 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
michael@0 257 YUY2ToYRow = YUY2ToYRow_SSE2;
michael@0 258 }
michael@0 259 }
michael@0 260 }
michael@0 261 }
michael@0 262 #endif
michael@0 263 #if defined(HAS_YUY2TOYROW_AVX2)
michael@0 264 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
michael@0 265 YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
michael@0 266 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
michael@0 267 if (IS_ALIGNED(width, 32)) {
michael@0 268 YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
michael@0 269 YUY2ToYRow = YUY2ToYRow_AVX2;
michael@0 270 }
michael@0 271 }
michael@0 272 #endif
michael@0 273 #if defined(HAS_YUY2TOYROW_NEON)
michael@0 274 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
michael@0 275 YUY2ToYRow = YUY2ToYRow_Any_NEON;
michael@0 276 if (width >= 16) {
michael@0 277 YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
michael@0 278 }
michael@0 279 if (IS_ALIGNED(width, 16)) {
michael@0 280 YUY2ToYRow = YUY2ToYRow_NEON;
michael@0 281 YUY2ToUV422Row = YUY2ToUV422Row_NEON;
michael@0 282 }
michael@0 283 }
michael@0 284 #endif
michael@0 285
michael@0 286 for (y = 0; y < height; ++y) {
michael@0 287 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
michael@0 288 YUY2ToYRow(src_yuy2, dst_y, width);
michael@0 289 src_yuy2 += src_stride_yuy2;
michael@0 290 dst_y += dst_stride_y;
michael@0 291 dst_u += dst_stride_u;
michael@0 292 dst_v += dst_stride_v;
michael@0 293 }
michael@0 294 return 0;
michael@0 295 }
michael@0 296
michael@0 297 // Convert UYVY to I422.
michael@0 298 LIBYUV_API
michael@0 299 int UYVYToI422(const uint8* src_uyvy, int src_stride_uyvy,
michael@0 300 uint8* dst_y, int dst_stride_y,
michael@0 301 uint8* dst_u, int dst_stride_u,
michael@0 302 uint8* dst_v, int dst_stride_v,
michael@0 303 int width, int height) {
michael@0 304 int y;
michael@0 305 void (*UYVYToUV422Row)(const uint8* src_uyvy,
michael@0 306 uint8* dst_u, uint8* dst_v, int pix) =
michael@0 307 UYVYToUV422Row_C;
michael@0 308 void (*UYVYToYRow)(const uint8* src_uyvy,
michael@0 309 uint8* dst_y, int pix) = UYVYToYRow_C;
michael@0 310 // Negative height means invert the image.
michael@0 311 if (height < 0) {
michael@0 312 height = -height;
michael@0 313 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
michael@0 314 src_stride_uyvy = -src_stride_uyvy;
michael@0 315 }
michael@0 316 // Coalesce rows.
michael@0 317 if (src_stride_uyvy == width * 2 &&
michael@0 318 dst_stride_y == width &&
michael@0 319 dst_stride_u * 2 == width &&
michael@0 320 dst_stride_v * 2 == width) {
michael@0 321 width *= height;
michael@0 322 height = 1;
michael@0 323 src_stride_uyvy = dst_stride_y = dst_stride_u = dst_stride_v = 0;
michael@0 324 }
michael@0 325 #if defined(HAS_UYVYTOYROW_SSE2)
michael@0 326 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
michael@0 327 UYVYToUV422Row = UYVYToUV422Row_Any_SSE2;
michael@0 328 UYVYToYRow = UYVYToYRow_Any_SSE2;
michael@0 329 if (IS_ALIGNED(width, 16)) {
michael@0 330 UYVYToUV422Row = UYVYToUV422Row_Unaligned_SSE2;
michael@0 331 UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
michael@0 332 if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
michael@0 333 UYVYToUV422Row = UYVYToUV422Row_SSE2;
michael@0 334 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
michael@0 335 UYVYToYRow = UYVYToYRow_SSE2;
michael@0 336 }
michael@0 337 }
michael@0 338 }
michael@0 339 }
michael@0 340 #endif
michael@0 341 #if defined(HAS_UYVYTOYROW_AVX2)
michael@0 342 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
michael@0 343 UYVYToUV422Row = UYVYToUV422Row_Any_AVX2;
michael@0 344 UYVYToYRow = UYVYToYRow_Any_AVX2;
michael@0 345 if (IS_ALIGNED(width, 32)) {
michael@0 346 UYVYToUV422Row = UYVYToUV422Row_AVX2;
michael@0 347 UYVYToYRow = UYVYToYRow_AVX2;
michael@0 348 }
michael@0 349 }
michael@0 350 #endif
michael@0 351 #if defined(HAS_UYVYTOYROW_NEON)
michael@0 352 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
michael@0 353 UYVYToYRow = UYVYToYRow_Any_NEON;
michael@0 354 if (width >= 16) {
michael@0 355 UYVYToUV422Row = UYVYToUV422Row_Any_NEON;
michael@0 356 }
michael@0 357 if (IS_ALIGNED(width, 16)) {
michael@0 358 UYVYToYRow = UYVYToYRow_NEON;
michael@0 359 UYVYToUV422Row = UYVYToUV422Row_NEON;
michael@0 360 }
michael@0 361 }
michael@0 362 #endif
michael@0 363
michael@0 364 for (y = 0; y < height; ++y) {
michael@0 365 UYVYToUV422Row(src_uyvy, dst_u, dst_v, width);
michael@0 366 UYVYToYRow(src_uyvy, dst_y, width);
michael@0 367 src_uyvy += src_stride_uyvy;
michael@0 368 dst_y += dst_stride_y;
michael@0 369 dst_u += dst_stride_u;
michael@0 370 dst_v += dst_stride_v;
michael@0 371 }
michael@0 372 return 0;
michael@0 373 }
michael@0 374
michael@0 375 // Mirror I400 with optional flipping
michael@0 376 LIBYUV_API
michael@0 377 int I400Mirror(const uint8* src_y, int src_stride_y,
michael@0 378 uint8* dst_y, int dst_stride_y,
michael@0 379 int width, int height) {
michael@0 380 if (!src_y || !dst_y ||
michael@0 381 width <= 0 || height == 0) {
michael@0 382 return -1;
michael@0 383 }
michael@0 384 // Negative height means invert the image.
michael@0 385 if (height < 0) {
michael@0 386 height = -height;
michael@0 387 src_y = src_y + (height - 1) * src_stride_y;
michael@0 388 src_stride_y = -src_stride_y;
michael@0 389 }
michael@0 390
michael@0 391 MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
michael@0 392 return 0;
michael@0 393 }
michael@0 394
michael@0 395 // Mirror I420 with optional flipping
michael@0 396 LIBYUV_API
michael@0 397 int I420Mirror(const uint8* src_y, int src_stride_y,
michael@0 398 const uint8* src_u, int src_stride_u,
michael@0 399 const uint8* src_v, int src_stride_v,
michael@0 400 uint8* dst_y, int dst_stride_y,
michael@0 401 uint8* dst_u, int dst_stride_u,
michael@0 402 uint8* dst_v, int dst_stride_v,
michael@0 403 int width, int height) {
michael@0 404 int halfwidth = (width + 1) >> 1;
michael@0 405 int halfheight = (height + 1) >> 1;
michael@0 406 if (!src_y || !src_u || !src_v || !dst_y || !dst_u || !dst_v ||
michael@0 407 width <= 0 || height == 0) {
michael@0 408 return -1;
michael@0 409 }
michael@0 410 // Negative height means invert the image.
michael@0 411 if (height < 0) {
michael@0 412 height = -height;
michael@0 413 halfheight = (height + 1) >> 1;
michael@0 414 src_y = src_y + (height - 1) * src_stride_y;
michael@0 415 src_u = src_u + (halfheight - 1) * src_stride_u;
michael@0 416 src_v = src_v + (halfheight - 1) * src_stride_v;
michael@0 417 src_stride_y = -src_stride_y;
michael@0 418 src_stride_u = -src_stride_u;
michael@0 419 src_stride_v = -src_stride_v;
michael@0 420 }
michael@0 421
michael@0 422 if (dst_y) {
michael@0 423 MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
michael@0 424 }
michael@0 425 MirrorPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
michael@0 426 MirrorPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
michael@0 427 return 0;
michael@0 428 }
michael@0 429
michael@0 430 // ARGB mirror.
michael@0 431 LIBYUV_API
michael@0 432 int ARGBMirror(const uint8* src_argb, int src_stride_argb,
michael@0 433 uint8* dst_argb, int dst_stride_argb,
michael@0 434 int width, int height) {
michael@0 435 int y;
michael@0 436 void (*ARGBMirrorRow)(const uint8* src, uint8* dst, int width) =
michael@0 437 ARGBMirrorRow_C;
michael@0 438 if (!src_argb || !dst_argb || width <= 0 || height == 0) {
michael@0 439 return -1;
michael@0 440 }
michael@0 441 // Negative height means invert the image.
michael@0 442 if (height < 0) {
michael@0 443 height = -height;
michael@0 444 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 445 src_stride_argb = -src_stride_argb;
michael@0 446 }
michael@0 447
michael@0 448 #if defined(HAS_ARGBMIRRORROW_SSSE3)
michael@0 449 if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4) &&
michael@0 450 IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
michael@0 451 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 452 ARGBMirrorRow = ARGBMirrorRow_SSSE3;
michael@0 453 }
michael@0 454 #endif
michael@0 455 #if defined(HAS_ARGBMIRRORROW_AVX2)
michael@0 456 if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 8)) {
michael@0 457 ARGBMirrorRow = ARGBMirrorRow_AVX2;
michael@0 458 }
michael@0 459 #endif
michael@0 460 #if defined(HAS_ARGBMIRRORROW_NEON)
michael@0 461 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 4)) {
michael@0 462 ARGBMirrorRow = ARGBMirrorRow_NEON;
michael@0 463 }
michael@0 464 #endif
michael@0 465
michael@0 466 // Mirror plane
michael@0 467 for (y = 0; y < height; ++y) {
michael@0 468 ARGBMirrorRow(src_argb, dst_argb, width);
michael@0 469 src_argb += src_stride_argb;
michael@0 470 dst_argb += dst_stride_argb;
michael@0 471 }
michael@0 472 return 0;
michael@0 473 }
michael@0 474
michael@0 475 // Get a blender that optimized for the CPU, alignment and pixel count.
michael@0 476 // As there are 6 blenders to choose from, the caller should try to use
michael@0 477 // the same blend function for all pixels if possible.
michael@0 478 LIBYUV_API
michael@0 479 ARGBBlendRow GetARGBBlend() {
michael@0 480 void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
michael@0 481 uint8* dst_argb, int width) = ARGBBlendRow_C;
michael@0 482 #if defined(HAS_ARGBBLENDROW_SSSE3)
michael@0 483 if (TestCpuFlag(kCpuHasSSSE3)) {
michael@0 484 ARGBBlendRow = ARGBBlendRow_SSSE3;
michael@0 485 return ARGBBlendRow;
michael@0 486 }
michael@0 487 #endif
michael@0 488 #if defined(HAS_ARGBBLENDROW_SSE2)
michael@0 489 if (TestCpuFlag(kCpuHasSSE2)) {
michael@0 490 ARGBBlendRow = ARGBBlendRow_SSE2;
michael@0 491 }
michael@0 492 #endif
michael@0 493 #if defined(HAS_ARGBBLENDROW_NEON)
michael@0 494 if (TestCpuFlag(kCpuHasNEON)) {
michael@0 495 ARGBBlendRow = ARGBBlendRow_NEON;
michael@0 496 }
michael@0 497 #endif
michael@0 498 return ARGBBlendRow;
michael@0 499 }
michael@0 500
michael@0 501 // Alpha Blend 2 ARGB images and store to destination.
michael@0 502 LIBYUV_API
michael@0 503 int ARGBBlend(const uint8* src_argb0, int src_stride_argb0,
michael@0 504 const uint8* src_argb1, int src_stride_argb1,
michael@0 505 uint8* dst_argb, int dst_stride_argb,
michael@0 506 int width, int height) {
michael@0 507 int y;
michael@0 508 void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
michael@0 509 uint8* dst_argb, int width) = GetARGBBlend();
michael@0 510 if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
michael@0 511 return -1;
michael@0 512 }
michael@0 513 // Negative height means invert the image.
michael@0 514 if (height < 0) {
michael@0 515 height = -height;
michael@0 516 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
michael@0 517 dst_stride_argb = -dst_stride_argb;
michael@0 518 }
michael@0 519 // Coalesce rows.
michael@0 520 if (src_stride_argb0 == width * 4 &&
michael@0 521 src_stride_argb1 == width * 4 &&
michael@0 522 dst_stride_argb == width * 4) {
michael@0 523 width *= height;
michael@0 524 height = 1;
michael@0 525 src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
michael@0 526 }
michael@0 527
michael@0 528 for (y = 0; y < height; ++y) {
michael@0 529 ARGBBlendRow(src_argb0, src_argb1, dst_argb, width);
michael@0 530 src_argb0 += src_stride_argb0;
michael@0 531 src_argb1 += src_stride_argb1;
michael@0 532 dst_argb += dst_stride_argb;
michael@0 533 }
michael@0 534 return 0;
michael@0 535 }
michael@0 536
michael@0 537 // Multiply 2 ARGB images and store to destination.
michael@0 538 LIBYUV_API
michael@0 539 int ARGBMultiply(const uint8* src_argb0, int src_stride_argb0,
michael@0 540 const uint8* src_argb1, int src_stride_argb1,
michael@0 541 uint8* dst_argb, int dst_stride_argb,
michael@0 542 int width, int height) {
michael@0 543 int y;
michael@0 544 void (*ARGBMultiplyRow)(const uint8* src0, const uint8* src1, uint8* dst,
michael@0 545 int width) = ARGBMultiplyRow_C;
michael@0 546 if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
michael@0 547 return -1;
michael@0 548 }
michael@0 549 // Negative height means invert the image.
michael@0 550 if (height < 0) {
michael@0 551 height = -height;
michael@0 552 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
michael@0 553 dst_stride_argb = -dst_stride_argb;
michael@0 554 }
michael@0 555 // Coalesce rows.
michael@0 556 if (src_stride_argb0 == width * 4 &&
michael@0 557 src_stride_argb1 == width * 4 &&
michael@0 558 dst_stride_argb == width * 4) {
michael@0 559 width *= height;
michael@0 560 height = 1;
michael@0 561 src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
michael@0 562 }
michael@0 563 #if defined(HAS_ARGBMULTIPLYROW_SSE2)
michael@0 564 if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
michael@0 565 ARGBMultiplyRow = ARGBMultiplyRow_Any_SSE2;
michael@0 566 if (IS_ALIGNED(width, 4)) {
michael@0 567 ARGBMultiplyRow = ARGBMultiplyRow_SSE2;
michael@0 568 }
michael@0 569 }
michael@0 570 #endif
michael@0 571 #if defined(HAS_ARGBMULTIPLYROW_AVX2)
michael@0 572 if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
michael@0 573 ARGBMultiplyRow = ARGBMultiplyRow_Any_AVX2;
michael@0 574 if (IS_ALIGNED(width, 8)) {
michael@0 575 ARGBMultiplyRow = ARGBMultiplyRow_AVX2;
michael@0 576 }
michael@0 577 }
michael@0 578 #endif
michael@0 579 #if defined(HAS_ARGBMULTIPLYROW_NEON)
michael@0 580 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
michael@0 581 ARGBMultiplyRow = ARGBMultiplyRow_Any_NEON;
michael@0 582 if (IS_ALIGNED(width, 8)) {
michael@0 583 ARGBMultiplyRow = ARGBMultiplyRow_NEON;
michael@0 584 }
michael@0 585 }
michael@0 586 #endif
michael@0 587
michael@0 588 // Multiply plane
michael@0 589 for (y = 0; y < height; ++y) {
michael@0 590 ARGBMultiplyRow(src_argb0, src_argb1, dst_argb, width);
michael@0 591 src_argb0 += src_stride_argb0;
michael@0 592 src_argb1 += src_stride_argb1;
michael@0 593 dst_argb += dst_stride_argb;
michael@0 594 }
michael@0 595 return 0;
michael@0 596 }
michael@0 597
michael@0 598 // Add 2 ARGB images and store to destination.
michael@0 599 LIBYUV_API
michael@0 600 int ARGBAdd(const uint8* src_argb0, int src_stride_argb0,
michael@0 601 const uint8* src_argb1, int src_stride_argb1,
michael@0 602 uint8* dst_argb, int dst_stride_argb,
michael@0 603 int width, int height) {
michael@0 604 int y;
michael@0 605 void (*ARGBAddRow)(const uint8* src0, const uint8* src1, uint8* dst,
michael@0 606 int width) = ARGBAddRow_C;
michael@0 607 if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
michael@0 608 return -1;
michael@0 609 }
michael@0 610 // Negative height means invert the image.
michael@0 611 if (height < 0) {
michael@0 612 height = -height;
michael@0 613 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
michael@0 614 dst_stride_argb = -dst_stride_argb;
michael@0 615 }
michael@0 616 // Coalesce rows.
michael@0 617 if (src_stride_argb0 == width * 4 &&
michael@0 618 src_stride_argb1 == width * 4 &&
michael@0 619 dst_stride_argb == width * 4) {
michael@0 620 width *= height;
michael@0 621 height = 1;
michael@0 622 src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
michael@0 623 }
michael@0 624 #if defined(HAS_ARGBADDROW_SSE2) && defined(_MSC_VER)
michael@0 625 if (TestCpuFlag(kCpuHasSSE2)) {
michael@0 626 ARGBAddRow = ARGBAddRow_SSE2;
michael@0 627 }
michael@0 628 #endif
michael@0 629 #if defined(HAS_ARGBADDROW_SSE2) && !defined(_MSC_VER)
michael@0 630 if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
michael@0 631 ARGBAddRow = ARGBAddRow_Any_SSE2;
michael@0 632 if (IS_ALIGNED(width, 4)) {
michael@0 633 ARGBAddRow = ARGBAddRow_SSE2;
michael@0 634 }
michael@0 635 }
michael@0 636 #endif
michael@0 637 #if defined(HAS_ARGBADDROW_AVX2)
michael@0 638 if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
michael@0 639 ARGBAddRow = ARGBAddRow_Any_AVX2;
michael@0 640 if (IS_ALIGNED(width, 8)) {
michael@0 641 ARGBAddRow = ARGBAddRow_AVX2;
michael@0 642 }
michael@0 643 }
michael@0 644 #endif
michael@0 645 #if defined(HAS_ARGBADDROW_NEON)
michael@0 646 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
michael@0 647 ARGBAddRow = ARGBAddRow_Any_NEON;
michael@0 648 if (IS_ALIGNED(width, 8)) {
michael@0 649 ARGBAddRow = ARGBAddRow_NEON;
michael@0 650 }
michael@0 651 }
michael@0 652 #endif
michael@0 653
michael@0 654 // Add plane
michael@0 655 for (y = 0; y < height; ++y) {
michael@0 656 ARGBAddRow(src_argb0, src_argb1, dst_argb, width);
michael@0 657 src_argb0 += src_stride_argb0;
michael@0 658 src_argb1 += src_stride_argb1;
michael@0 659 dst_argb += dst_stride_argb;
michael@0 660 }
michael@0 661 return 0;
michael@0 662 }
michael@0 663
michael@0 664 // Subtract 2 ARGB images and store to destination.
michael@0 665 LIBYUV_API
michael@0 666 int ARGBSubtract(const uint8* src_argb0, int src_stride_argb0,
michael@0 667 const uint8* src_argb1, int src_stride_argb1,
michael@0 668 uint8* dst_argb, int dst_stride_argb,
michael@0 669 int width, int height) {
michael@0 670 int y;
michael@0 671 void (*ARGBSubtractRow)(const uint8* src0, const uint8* src1, uint8* dst,
michael@0 672 int width) = ARGBSubtractRow_C;
michael@0 673 if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
michael@0 674 return -1;
michael@0 675 }
michael@0 676 // Negative height means invert the image.
michael@0 677 if (height < 0) {
michael@0 678 height = -height;
michael@0 679 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
michael@0 680 dst_stride_argb = -dst_stride_argb;
michael@0 681 }
michael@0 682 // Coalesce rows.
michael@0 683 if (src_stride_argb0 == width * 4 &&
michael@0 684 src_stride_argb1 == width * 4 &&
michael@0 685 dst_stride_argb == width * 4) {
michael@0 686 width *= height;
michael@0 687 height = 1;
michael@0 688 src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
michael@0 689 }
michael@0 690 #if defined(HAS_ARGBSUBTRACTROW_SSE2)
michael@0 691 if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
michael@0 692 ARGBSubtractRow = ARGBSubtractRow_Any_SSE2;
michael@0 693 if (IS_ALIGNED(width, 4)) {
michael@0 694 ARGBSubtractRow = ARGBSubtractRow_SSE2;
michael@0 695 }
michael@0 696 }
michael@0 697 #endif
michael@0 698 #if defined(HAS_ARGBSUBTRACTROW_AVX2)
michael@0 699 if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
michael@0 700 ARGBSubtractRow = ARGBSubtractRow_Any_AVX2;
michael@0 701 if (IS_ALIGNED(width, 8)) {
michael@0 702 ARGBSubtractRow = ARGBSubtractRow_AVX2;
michael@0 703 }
michael@0 704 }
michael@0 705 #endif
michael@0 706 #if defined(HAS_ARGBSUBTRACTROW_NEON)
michael@0 707 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
michael@0 708 ARGBSubtractRow = ARGBSubtractRow_Any_NEON;
michael@0 709 if (IS_ALIGNED(width, 8)) {
michael@0 710 ARGBSubtractRow = ARGBSubtractRow_NEON;
michael@0 711 }
michael@0 712 }
michael@0 713 #endif
michael@0 714
michael@0 715 // Subtract plane
michael@0 716 for (y = 0; y < height; ++y) {
michael@0 717 ARGBSubtractRow(src_argb0, src_argb1, dst_argb, width);
michael@0 718 src_argb0 += src_stride_argb0;
michael@0 719 src_argb1 += src_stride_argb1;
michael@0 720 dst_argb += dst_stride_argb;
michael@0 721 }
michael@0 722 return 0;
michael@0 723 }
michael@0 724
michael@0 725 // Convert I422 to BGRA.
michael@0 726 LIBYUV_API
michael@0 727 int I422ToBGRA(const uint8* src_y, int src_stride_y,
michael@0 728 const uint8* src_u, int src_stride_u,
michael@0 729 const uint8* src_v, int src_stride_v,
michael@0 730 uint8* dst_bgra, int dst_stride_bgra,
michael@0 731 int width, int height) {
michael@0 732 int y;
michael@0 733 void (*I422ToBGRARow)(const uint8* y_buf,
michael@0 734 const uint8* u_buf,
michael@0 735 const uint8* v_buf,
michael@0 736 uint8* rgb_buf,
michael@0 737 int width) = I422ToBGRARow_C;
michael@0 738 if (!src_y || !src_u || !src_v ||
michael@0 739 !dst_bgra ||
michael@0 740 width <= 0 || height == 0) {
michael@0 741 return -1;
michael@0 742 }
michael@0 743 // Negative height means invert the image.
michael@0 744 if (height < 0) {
michael@0 745 height = -height;
michael@0 746 dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra;
michael@0 747 dst_stride_bgra = -dst_stride_bgra;
michael@0 748 }
michael@0 749 // Coalesce rows.
michael@0 750 if (src_stride_y == width &&
michael@0 751 src_stride_u * 2 == width &&
michael@0 752 src_stride_v * 2 == width &&
michael@0 753 dst_stride_bgra == width * 4) {
michael@0 754 width *= height;
michael@0 755 height = 1;
michael@0 756 src_stride_y = src_stride_u = src_stride_v = dst_stride_bgra = 0;
michael@0 757 }
michael@0 758 #if defined(HAS_I422TOBGRAROW_NEON)
michael@0 759 if (TestCpuFlag(kCpuHasNEON)) {
michael@0 760 I422ToBGRARow = I422ToBGRARow_Any_NEON;
michael@0 761 if (IS_ALIGNED(width, 16)) {
michael@0 762 I422ToBGRARow = I422ToBGRARow_NEON;
michael@0 763 }
michael@0 764 }
michael@0 765 #elif defined(HAS_I422TOBGRAROW_SSSE3)
michael@0 766 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
michael@0 767 I422ToBGRARow = I422ToBGRARow_Any_SSSE3;
michael@0 768 if (IS_ALIGNED(width, 8)) {
michael@0 769 I422ToBGRARow = I422ToBGRARow_Unaligned_SSSE3;
michael@0 770 if (IS_ALIGNED(dst_bgra, 16) && IS_ALIGNED(dst_stride_bgra, 16)) {
michael@0 771 I422ToBGRARow = I422ToBGRARow_SSSE3;
michael@0 772 }
michael@0 773 }
michael@0 774 }
michael@0 775 #elif defined(HAS_I422TOBGRAROW_MIPS_DSPR2)
michael@0 776 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
michael@0 777 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
michael@0 778 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
michael@0 779 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
michael@0 780 IS_ALIGNED(dst_bgra, 4) && IS_ALIGNED(dst_stride_bgra, 4)) {
michael@0 781 I422ToBGRARow = I422ToBGRARow_MIPS_DSPR2;
michael@0 782 }
michael@0 783 #endif
michael@0 784
michael@0 785 for (y = 0; y < height; ++y) {
michael@0 786 I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width);
michael@0 787 dst_bgra += dst_stride_bgra;
michael@0 788 src_y += src_stride_y;
michael@0 789 src_u += src_stride_u;
michael@0 790 src_v += src_stride_v;
michael@0 791 }
michael@0 792 return 0;
michael@0 793 }
michael@0 794
michael@0 795 // Convert I422 to ABGR.
michael@0 796 LIBYUV_API
michael@0 797 int I422ToABGR(const uint8* src_y, int src_stride_y,
michael@0 798 const uint8* src_u, int src_stride_u,
michael@0 799 const uint8* src_v, int src_stride_v,
michael@0 800 uint8* dst_abgr, int dst_stride_abgr,
michael@0 801 int width, int height) {
michael@0 802 int y;
michael@0 803 void (*I422ToABGRRow)(const uint8* y_buf,
michael@0 804 const uint8* u_buf,
michael@0 805 const uint8* v_buf,
michael@0 806 uint8* rgb_buf,
michael@0 807 int width) = I422ToABGRRow_C;
michael@0 808 if (!src_y || !src_u || !src_v ||
michael@0 809 !dst_abgr ||
michael@0 810 width <= 0 || height == 0) {
michael@0 811 return -1;
michael@0 812 }
michael@0 813 // Negative height means invert the image.
michael@0 814 if (height < 0) {
michael@0 815 height = -height;
michael@0 816 dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr;
michael@0 817 dst_stride_abgr = -dst_stride_abgr;
michael@0 818 }
michael@0 819 // Coalesce rows.
michael@0 820 if (src_stride_y == width &&
michael@0 821 src_stride_u * 2 == width &&
michael@0 822 src_stride_v * 2 == width &&
michael@0 823 dst_stride_abgr == width * 4) {
michael@0 824 width *= height;
michael@0 825 height = 1;
michael@0 826 src_stride_y = src_stride_u = src_stride_v = dst_stride_abgr = 0;
michael@0 827 }
michael@0 828 #if defined(HAS_I422TOABGRROW_NEON)
michael@0 829 if (TestCpuFlag(kCpuHasNEON)) {
michael@0 830 I422ToABGRRow = I422ToABGRRow_Any_NEON;
michael@0 831 if (IS_ALIGNED(width, 16)) {
michael@0 832 I422ToABGRRow = I422ToABGRRow_NEON;
michael@0 833 }
michael@0 834 }
michael@0 835 #elif defined(HAS_I422TOABGRROW_SSSE3)
michael@0 836 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
michael@0 837 I422ToABGRRow = I422ToABGRRow_Any_SSSE3;
michael@0 838 if (IS_ALIGNED(width, 8)) {
michael@0 839 I422ToABGRRow = I422ToABGRRow_Unaligned_SSSE3;
michael@0 840 if (IS_ALIGNED(dst_abgr, 16) && IS_ALIGNED(dst_stride_abgr, 16)) {
michael@0 841 I422ToABGRRow = I422ToABGRRow_SSSE3;
michael@0 842 }
michael@0 843 }
michael@0 844 }
michael@0 845 #endif
michael@0 846
michael@0 847 for (y = 0; y < height; ++y) {
michael@0 848 I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width);
michael@0 849 dst_abgr += dst_stride_abgr;
michael@0 850 src_y += src_stride_y;
michael@0 851 src_u += src_stride_u;
michael@0 852 src_v += src_stride_v;
michael@0 853 }
michael@0 854 return 0;
michael@0 855 }
michael@0 856
michael@0 857 // Convert I422 to RGBA.
michael@0 858 LIBYUV_API
michael@0 859 int I422ToRGBA(const uint8* src_y, int src_stride_y,
michael@0 860 const uint8* src_u, int src_stride_u,
michael@0 861 const uint8* src_v, int src_stride_v,
michael@0 862 uint8* dst_rgba, int dst_stride_rgba,
michael@0 863 int width, int height) {
michael@0 864 int y;
michael@0 865 void (*I422ToRGBARow)(const uint8* y_buf,
michael@0 866 const uint8* u_buf,
michael@0 867 const uint8* v_buf,
michael@0 868 uint8* rgb_buf,
michael@0 869 int width) = I422ToRGBARow_C;
michael@0 870 if (!src_y || !src_u || !src_v ||
michael@0 871 !dst_rgba ||
michael@0 872 width <= 0 || height == 0) {
michael@0 873 return -1;
michael@0 874 }
michael@0 875 // Negative height means invert the image.
michael@0 876 if (height < 0) {
michael@0 877 height = -height;
michael@0 878 dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
michael@0 879 dst_stride_rgba = -dst_stride_rgba;
michael@0 880 }
michael@0 881 // Coalesce rows.
michael@0 882 if (src_stride_y == width &&
michael@0 883 src_stride_u * 2 == width &&
michael@0 884 src_stride_v * 2 == width &&
michael@0 885 dst_stride_rgba == width * 4) {
michael@0 886 width *= height;
michael@0 887 height = 1;
michael@0 888 src_stride_y = src_stride_u = src_stride_v = dst_stride_rgba = 0;
michael@0 889 }
michael@0 890 #if defined(HAS_I422TORGBAROW_NEON)
michael@0 891 if (TestCpuFlag(kCpuHasNEON)) {
michael@0 892 I422ToRGBARow = I422ToRGBARow_Any_NEON;
michael@0 893 if (IS_ALIGNED(width, 16)) {
michael@0 894 I422ToRGBARow = I422ToRGBARow_NEON;
michael@0 895 }
michael@0 896 }
michael@0 897 #elif defined(HAS_I422TORGBAROW_SSSE3)
michael@0 898 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
michael@0 899 I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
michael@0 900 if (IS_ALIGNED(width, 8)) {
michael@0 901 I422ToRGBARow = I422ToRGBARow_Unaligned_SSSE3;
michael@0 902 if (IS_ALIGNED(dst_rgba, 16) && IS_ALIGNED(dst_stride_rgba, 16)) {
michael@0 903 I422ToRGBARow = I422ToRGBARow_SSSE3;
michael@0 904 }
michael@0 905 }
michael@0 906 }
michael@0 907 #endif
michael@0 908
michael@0 909 for (y = 0; y < height; ++y) {
michael@0 910 I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width);
michael@0 911 dst_rgba += dst_stride_rgba;
michael@0 912 src_y += src_stride_y;
michael@0 913 src_u += src_stride_u;
michael@0 914 src_v += src_stride_v;
michael@0 915 }
michael@0 916 return 0;
michael@0 917 }
michael@0 918
michael@0 919 // Convert NV12 to RGB565.
michael@0 920 LIBYUV_API
michael@0 921 int NV12ToRGB565(const uint8* src_y, int src_stride_y,
michael@0 922 const uint8* src_uv, int src_stride_uv,
michael@0 923 uint8* dst_rgb565, int dst_stride_rgb565,
michael@0 924 int width, int height) {
michael@0 925 int y;
michael@0 926 void (*NV12ToRGB565Row)(const uint8* y_buf,
michael@0 927 const uint8* uv_buf,
michael@0 928 uint8* rgb_buf,
michael@0 929 int width) = NV12ToRGB565Row_C;
michael@0 930 if (!src_y || !src_uv || !dst_rgb565 ||
michael@0 931 width <= 0 || height == 0) {
michael@0 932 return -1;
michael@0 933 }
michael@0 934 // Negative height means invert the image.
michael@0 935 if (height < 0) {
michael@0 936 height = -height;
michael@0 937 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
michael@0 938 dst_stride_rgb565 = -dst_stride_rgb565;
michael@0 939 }
michael@0 940 #if defined(HAS_NV12TORGB565ROW_SSSE3)
michael@0 941 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
michael@0 942 NV12ToRGB565Row = NV12ToRGB565Row_Any_SSSE3;
michael@0 943 if (IS_ALIGNED(width, 8)) {
michael@0 944 NV12ToRGB565Row = NV12ToRGB565Row_SSSE3;
michael@0 945 }
michael@0 946 }
michael@0 947 #elif defined(HAS_NV12TORGB565ROW_NEON)
michael@0 948 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
michael@0 949 NV12ToRGB565Row = NV12ToRGB565Row_Any_NEON;
michael@0 950 if (IS_ALIGNED(width, 8)) {
michael@0 951 NV12ToRGB565Row = NV12ToRGB565Row_NEON;
michael@0 952 }
michael@0 953 }
michael@0 954 #endif
michael@0 955
michael@0 956 for (y = 0; y < height; ++y) {
michael@0 957 NV12ToRGB565Row(src_y, src_uv, dst_rgb565, width);
michael@0 958 dst_rgb565 += dst_stride_rgb565;
michael@0 959 src_y += src_stride_y;
michael@0 960 if (y & 1) {
michael@0 961 src_uv += src_stride_uv;
michael@0 962 }
michael@0 963 }
michael@0 964 return 0;
michael@0 965 }
michael@0 966
michael@0 967 // Convert NV21 to RGB565.
michael@0 968 LIBYUV_API
michael@0 969 int NV21ToRGB565(const uint8* src_y, int src_stride_y,
michael@0 970 const uint8* src_vu, int src_stride_vu,
michael@0 971 uint8* dst_rgb565, int dst_stride_rgb565,
michael@0 972 int width, int height) {
michael@0 973 int y;
michael@0 974 void (*NV21ToRGB565Row)(const uint8* y_buf,
michael@0 975 const uint8* src_vu,
michael@0 976 uint8* rgb_buf,
michael@0 977 int width) = NV21ToRGB565Row_C;
michael@0 978 if (!src_y || !src_vu || !dst_rgb565 ||
michael@0 979 width <= 0 || height == 0) {
michael@0 980 return -1;
michael@0 981 }
michael@0 982 // Negative height means invert the image.
michael@0 983 if (height < 0) {
michael@0 984 height = -height;
michael@0 985 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
michael@0 986 dst_stride_rgb565 = -dst_stride_rgb565;
michael@0 987 }
michael@0 988 #if defined(HAS_NV21TORGB565ROW_SSSE3)
michael@0 989 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
michael@0 990 NV21ToRGB565Row = NV21ToRGB565Row_Any_SSSE3;
michael@0 991 if (IS_ALIGNED(width, 8)) {
michael@0 992 NV21ToRGB565Row = NV21ToRGB565Row_SSSE3;
michael@0 993 }
michael@0 994 }
michael@0 995 #elif defined(HAS_NV21TORGB565ROW_NEON)
michael@0 996 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
michael@0 997 NV21ToRGB565Row = NV21ToRGB565Row_Any_NEON;
michael@0 998 if (IS_ALIGNED(width, 8)) {
michael@0 999 NV21ToRGB565Row = NV21ToRGB565Row_NEON;
michael@0 1000 }
michael@0 1001 }
michael@0 1002 #endif
michael@0 1003
michael@0 1004 for (y = 0; y < height; ++y) {
michael@0 1005 NV21ToRGB565Row(src_y, src_vu, dst_rgb565, width);
michael@0 1006 dst_rgb565 += dst_stride_rgb565;
michael@0 1007 src_y += src_stride_y;
michael@0 1008 if (y & 1) {
michael@0 1009 src_vu += src_stride_vu;
michael@0 1010 }
michael@0 1011 }
michael@0 1012 return 0;
michael@0 1013 }
michael@0 1014
michael@0 1015 LIBYUV_API
michael@0 1016 void SetPlane(uint8* dst_y, int dst_stride_y,
michael@0 1017 int width, int height,
michael@0 1018 uint32 value) {
michael@0 1019 int y;
michael@0 1020 uint32 v32 = value | (value << 8) | (value << 16) | (value << 24);
michael@0 1021 void (*SetRow)(uint8* dst, uint32 value, int pix) = SetRow_C;
michael@0 1022 // Coalesce rows.
michael@0 1023 if (dst_stride_y == width) {
michael@0 1024 width *= height;
michael@0 1025 height = 1;
michael@0 1026 dst_stride_y = 0;
michael@0 1027 }
michael@0 1028 #if defined(HAS_SETROW_NEON)
michael@0 1029 if (TestCpuFlag(kCpuHasNEON) &&
michael@0 1030 IS_ALIGNED(width, 16) &&
michael@0 1031 IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
michael@0 1032 SetRow = SetRow_NEON;
michael@0 1033 }
michael@0 1034 #endif
michael@0 1035 #if defined(HAS_SETROW_X86)
michael@0 1036 if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
michael@0 1037 SetRow = SetRow_X86;
michael@0 1038 }
michael@0 1039 #endif
michael@0 1040
michael@0 1041 // Set plane
michael@0 1042 for (y = 0; y < height; ++y) {
michael@0 1043 SetRow(dst_y, v32, width);
michael@0 1044 dst_y += dst_stride_y;
michael@0 1045 }
michael@0 1046 }
michael@0 1047
michael@0 1048 // Draw a rectangle into I420
michael@0 1049 LIBYUV_API
michael@0 1050 int I420Rect(uint8* dst_y, int dst_stride_y,
michael@0 1051 uint8* dst_u, int dst_stride_u,
michael@0 1052 uint8* dst_v, int dst_stride_v,
michael@0 1053 int x, int y,
michael@0 1054 int width, int height,
michael@0 1055 int value_y, int value_u, int value_v) {
michael@0 1056 int halfwidth = (width + 1) >> 1;
michael@0 1057 int halfheight = (height + 1) >> 1;
michael@0 1058 uint8* start_y = dst_y + y * dst_stride_y + x;
michael@0 1059 uint8* start_u = dst_u + (y / 2) * dst_stride_u + (x / 2);
michael@0 1060 uint8* start_v = dst_v + (y / 2) * dst_stride_v + (x / 2);
michael@0 1061 if (!dst_y || !dst_u || !dst_v ||
michael@0 1062 width <= 0 || height <= 0 ||
michael@0 1063 x < 0 || y < 0 ||
michael@0 1064 value_y < 0 || value_y > 255 ||
michael@0 1065 value_u < 0 || value_u > 255 ||
michael@0 1066 value_v < 0 || value_v > 255) {
michael@0 1067 return -1;
michael@0 1068 }
michael@0 1069
michael@0 1070 SetPlane(start_y, dst_stride_y, width, height, value_y);
michael@0 1071 SetPlane(start_u, dst_stride_u, halfwidth, halfheight, value_u);
michael@0 1072 SetPlane(start_v, dst_stride_v, halfwidth, halfheight, value_v);
michael@0 1073 return 0;
michael@0 1074 }
michael@0 1075
michael@0 1076 // Draw a rectangle into ARGB
michael@0 1077 LIBYUV_API
michael@0 1078 int ARGBRect(uint8* dst_argb, int dst_stride_argb,
michael@0 1079 int dst_x, int dst_y,
michael@0 1080 int width, int height,
michael@0 1081 uint32 value) {
michael@0 1082 if (!dst_argb ||
michael@0 1083 width <= 0 || height <= 0 ||
michael@0 1084 dst_x < 0 || dst_y < 0) {
michael@0 1085 return -1;
michael@0 1086 }
michael@0 1087 dst_argb += dst_y * dst_stride_argb + dst_x * 4;
michael@0 1088 // Coalesce rows.
michael@0 1089 if (dst_stride_argb == width * 4) {
michael@0 1090 width *= height;
michael@0 1091 height = 1;
michael@0 1092 dst_stride_argb = 0;
michael@0 1093 }
michael@0 1094 #if defined(HAS_SETROW_NEON)
michael@0 1095 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16) &&
michael@0 1096 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1097 ARGBSetRows_NEON(dst_argb, value, width, dst_stride_argb, height);
michael@0 1098 return 0;
michael@0 1099 }
michael@0 1100 #endif
michael@0 1101 #if defined(HAS_SETROW_X86)
michael@0 1102 if (TestCpuFlag(kCpuHasX86)) {
michael@0 1103 ARGBSetRows_X86(dst_argb, value, width, dst_stride_argb, height);
michael@0 1104 return 0;
michael@0 1105 }
michael@0 1106 #endif
michael@0 1107 ARGBSetRows_C(dst_argb, value, width, dst_stride_argb, height);
michael@0 1108 return 0;
michael@0 1109 }
michael@0 1110
michael@0 1111 // Convert unattentuated ARGB to preattenuated ARGB.
michael@0 1112 // An unattenutated ARGB alpha blend uses the formula
michael@0 1113 // p = a * f + (1 - a) * b
michael@0 1114 // where
michael@0 1115 // p is output pixel
michael@0 1116 // f is foreground pixel
michael@0 1117 // b is background pixel
michael@0 1118 // a is alpha value from foreground pixel
michael@0 1119 // An preattenutated ARGB alpha blend uses the formula
michael@0 1120 // p = f + (1 - a) * b
michael@0 1121 // where
michael@0 1122 // f is foreground pixel premultiplied by alpha
michael@0 1123
michael@0 1124 LIBYUV_API
michael@0 1125 int ARGBAttenuate(const uint8* src_argb, int src_stride_argb,
michael@0 1126 uint8* dst_argb, int dst_stride_argb,
michael@0 1127 int width, int height) {
michael@0 1128 int y;
michael@0 1129 void (*ARGBAttenuateRow)(const uint8* src_argb, uint8* dst_argb,
michael@0 1130 int width) = ARGBAttenuateRow_C;
michael@0 1131 if (!src_argb || !dst_argb || width <= 0 || height == 0) {
michael@0 1132 return -1;
michael@0 1133 }
michael@0 1134 if (height < 0) {
michael@0 1135 height = -height;
michael@0 1136 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 1137 src_stride_argb = -src_stride_argb;
michael@0 1138 }
michael@0 1139 // Coalesce rows.
michael@0 1140 if (src_stride_argb == width * 4 &&
michael@0 1141 dst_stride_argb == width * 4) {
michael@0 1142 width *= height;
michael@0 1143 height = 1;
michael@0 1144 src_stride_argb = dst_stride_argb = 0;
michael@0 1145 }
michael@0 1146 #if defined(HAS_ARGBATTENUATEROW_SSE2)
michael@0 1147 if (TestCpuFlag(kCpuHasSSE2) && width >= 4 &&
michael@0 1148 IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
michael@0 1149 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1150 ARGBAttenuateRow = ARGBAttenuateRow_Any_SSE2;
michael@0 1151 if (IS_ALIGNED(width, 4)) {
michael@0 1152 ARGBAttenuateRow = ARGBAttenuateRow_SSE2;
michael@0 1153 }
michael@0 1154 }
michael@0 1155 #endif
michael@0 1156 #if defined(HAS_ARGBATTENUATEROW_SSSE3)
michael@0 1157 if (TestCpuFlag(kCpuHasSSSE3) && width >= 4) {
michael@0 1158 ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
michael@0 1159 if (IS_ALIGNED(width, 4)) {
michael@0 1160 ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
michael@0 1161 }
michael@0 1162 }
michael@0 1163 #endif
michael@0 1164 #if defined(HAS_ARGBATTENUATEROW_AVX2)
michael@0 1165 if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
michael@0 1166 ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
michael@0 1167 if (IS_ALIGNED(width, 8)) {
michael@0 1168 ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
michael@0 1169 }
michael@0 1170 }
michael@0 1171 #endif
michael@0 1172 #if defined(HAS_ARGBATTENUATEROW_NEON)
michael@0 1173 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
michael@0 1174 ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
michael@0 1175 if (IS_ALIGNED(width, 8)) {
michael@0 1176 ARGBAttenuateRow = ARGBAttenuateRow_NEON;
michael@0 1177 }
michael@0 1178 }
michael@0 1179 #endif
michael@0 1180
michael@0 1181 for (y = 0; y < height; ++y) {
michael@0 1182 ARGBAttenuateRow(src_argb, dst_argb, width);
michael@0 1183 src_argb += src_stride_argb;
michael@0 1184 dst_argb += dst_stride_argb;
michael@0 1185 }
michael@0 1186 return 0;
michael@0 1187 }
michael@0 1188
michael@0 1189 // Convert preattentuated ARGB to unattenuated ARGB.
michael@0 1190 LIBYUV_API
michael@0 1191 int ARGBUnattenuate(const uint8* src_argb, int src_stride_argb,
michael@0 1192 uint8* dst_argb, int dst_stride_argb,
michael@0 1193 int width, int height) {
michael@0 1194 int y;
michael@0 1195 void (*ARGBUnattenuateRow)(const uint8* src_argb, uint8* dst_argb,
michael@0 1196 int width) = ARGBUnattenuateRow_C;
michael@0 1197 if (!src_argb || !dst_argb || width <= 0 || height == 0) {
michael@0 1198 return -1;
michael@0 1199 }
michael@0 1200 if (height < 0) {
michael@0 1201 height = -height;
michael@0 1202 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 1203 src_stride_argb = -src_stride_argb;
michael@0 1204 }
michael@0 1205 // Coalesce rows.
michael@0 1206 if (src_stride_argb == width * 4 &&
michael@0 1207 dst_stride_argb == width * 4) {
michael@0 1208 width *= height;
michael@0 1209 height = 1;
michael@0 1210 src_stride_argb = dst_stride_argb = 0;
michael@0 1211 }
michael@0 1212 #if defined(HAS_ARGBUNATTENUATEROW_SSE2)
michael@0 1213 if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
michael@0 1214 ARGBUnattenuateRow = ARGBUnattenuateRow_Any_SSE2;
michael@0 1215 if (IS_ALIGNED(width, 4)) {
michael@0 1216 ARGBUnattenuateRow = ARGBUnattenuateRow_SSE2;
michael@0 1217 }
michael@0 1218 }
michael@0 1219 #endif
michael@0 1220 #if defined(HAS_ARGBUNATTENUATEROW_AVX2)
michael@0 1221 if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
michael@0 1222 ARGBUnattenuateRow = ARGBUnattenuateRow_Any_AVX2;
michael@0 1223 if (IS_ALIGNED(width, 8)) {
michael@0 1224 ARGBUnattenuateRow = ARGBUnattenuateRow_AVX2;
michael@0 1225 }
michael@0 1226 }
michael@0 1227 #endif
michael@0 1228 // TODO(fbarchard): Neon version.
michael@0 1229
michael@0 1230 for (y = 0; y < height; ++y) {
michael@0 1231 ARGBUnattenuateRow(src_argb, dst_argb, width);
michael@0 1232 src_argb += src_stride_argb;
michael@0 1233 dst_argb += dst_stride_argb;
michael@0 1234 }
michael@0 1235 return 0;
michael@0 1236 }
michael@0 1237
michael@0 1238 // Convert ARGB to Grayed ARGB.
michael@0 1239 LIBYUV_API
michael@0 1240 int ARGBGrayTo(const uint8* src_argb, int src_stride_argb,
michael@0 1241 uint8* dst_argb, int dst_stride_argb,
michael@0 1242 int width, int height) {
michael@0 1243 int y;
michael@0 1244 void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb,
michael@0 1245 int width) = ARGBGrayRow_C;
michael@0 1246 if (!src_argb || !dst_argb || width <= 0 || height == 0) {
michael@0 1247 return -1;
michael@0 1248 }
michael@0 1249 if (height < 0) {
michael@0 1250 height = -height;
michael@0 1251 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 1252 src_stride_argb = -src_stride_argb;
michael@0 1253 }
michael@0 1254 // Coalesce rows.
michael@0 1255 if (src_stride_argb == width * 4 &&
michael@0 1256 dst_stride_argb == width * 4) {
michael@0 1257 width *= height;
michael@0 1258 height = 1;
michael@0 1259 src_stride_argb = dst_stride_argb = 0;
michael@0 1260 }
michael@0 1261 #if defined(HAS_ARGBGRAYROW_SSSE3)
michael@0 1262 if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
michael@0 1263 IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
michael@0 1264 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1265 ARGBGrayRow = ARGBGrayRow_SSSE3;
michael@0 1266 }
michael@0 1267 #elif defined(HAS_ARGBGRAYROW_NEON)
michael@0 1268 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
michael@0 1269 ARGBGrayRow = ARGBGrayRow_NEON;
michael@0 1270 }
michael@0 1271 #endif
michael@0 1272
michael@0 1273 for (y = 0; y < height; ++y) {
michael@0 1274 ARGBGrayRow(src_argb, dst_argb, width);
michael@0 1275 src_argb += src_stride_argb;
michael@0 1276 dst_argb += dst_stride_argb;
michael@0 1277 }
michael@0 1278 return 0;
michael@0 1279 }
michael@0 1280
michael@0 1281 // Make a rectangle of ARGB gray scale.
michael@0 1282 LIBYUV_API
michael@0 1283 int ARGBGray(uint8* dst_argb, int dst_stride_argb,
michael@0 1284 int dst_x, int dst_y,
michael@0 1285 int width, int height) {
michael@0 1286 int y;
michael@0 1287 void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb,
michael@0 1288 int width) = ARGBGrayRow_C;
michael@0 1289 uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
michael@0 1290 if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
michael@0 1291 return -1;
michael@0 1292 }
michael@0 1293 // Coalesce rows.
michael@0 1294 if (dst_stride_argb == width * 4) {
michael@0 1295 width *= height;
michael@0 1296 height = 1;
michael@0 1297 dst_stride_argb = 0;
michael@0 1298 }
michael@0 1299 #if defined(HAS_ARGBGRAYROW_SSSE3)
michael@0 1300 if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
michael@0 1301 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1302 ARGBGrayRow = ARGBGrayRow_SSSE3;
michael@0 1303 }
michael@0 1304 #elif defined(HAS_ARGBGRAYROW_NEON)
michael@0 1305 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
michael@0 1306 ARGBGrayRow = ARGBGrayRow_NEON;
michael@0 1307 }
michael@0 1308 #endif
michael@0 1309 for (y = 0; y < height; ++y) {
michael@0 1310 ARGBGrayRow(dst, dst, width);
michael@0 1311 dst += dst_stride_argb;
michael@0 1312 }
michael@0 1313 return 0;
michael@0 1314 }
michael@0 1315
michael@0 1316 // Make a rectangle of ARGB Sepia tone.
michael@0 1317 LIBYUV_API
michael@0 1318 int ARGBSepia(uint8* dst_argb, int dst_stride_argb,
michael@0 1319 int dst_x, int dst_y, int width, int height) {
michael@0 1320 int y;
michael@0 1321 void (*ARGBSepiaRow)(uint8* dst_argb, int width) = ARGBSepiaRow_C;
michael@0 1322 uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
michael@0 1323 if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
michael@0 1324 return -1;
michael@0 1325 }
michael@0 1326 // Coalesce rows.
michael@0 1327 if (dst_stride_argb == width * 4) {
michael@0 1328 width *= height;
michael@0 1329 height = 1;
michael@0 1330 dst_stride_argb = 0;
michael@0 1331 }
michael@0 1332 #if defined(HAS_ARGBSEPIAROW_SSSE3)
michael@0 1333 if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
michael@0 1334 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1335 ARGBSepiaRow = ARGBSepiaRow_SSSE3;
michael@0 1336 }
michael@0 1337 #elif defined(HAS_ARGBSEPIAROW_NEON)
michael@0 1338 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
michael@0 1339 ARGBSepiaRow = ARGBSepiaRow_NEON;
michael@0 1340 }
michael@0 1341 #endif
michael@0 1342 for (y = 0; y < height; ++y) {
michael@0 1343 ARGBSepiaRow(dst, width);
michael@0 1344 dst += dst_stride_argb;
michael@0 1345 }
michael@0 1346 return 0;
michael@0 1347 }
michael@0 1348
michael@0 1349 // Apply a 4x4 matrix to each ARGB pixel.
michael@0 1350 // Note: Normally for shading, but can be used to swizzle or invert.
michael@0 1351 LIBYUV_API
michael@0 1352 int ARGBColorMatrix(const uint8* src_argb, int src_stride_argb,
michael@0 1353 uint8* dst_argb, int dst_stride_argb,
michael@0 1354 const int8* matrix_argb,
michael@0 1355 int width, int height) {
michael@0 1356 int y;
michael@0 1357 void (*ARGBColorMatrixRow)(const uint8* src_argb, uint8* dst_argb,
michael@0 1358 const int8* matrix_argb, int width) = ARGBColorMatrixRow_C;
michael@0 1359 if (!src_argb || !dst_argb || !matrix_argb || width <= 0 || height == 0) {
michael@0 1360 return -1;
michael@0 1361 }
michael@0 1362 if (height < 0) {
michael@0 1363 height = -height;
michael@0 1364 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 1365 src_stride_argb = -src_stride_argb;
michael@0 1366 }
michael@0 1367 // Coalesce rows.
michael@0 1368 if (src_stride_argb == width * 4 &&
michael@0 1369 dst_stride_argb == width * 4) {
michael@0 1370 width *= height;
michael@0 1371 height = 1;
michael@0 1372 src_stride_argb = dst_stride_argb = 0;
michael@0 1373 }
michael@0 1374 #if defined(HAS_ARGBCOLORMATRIXROW_SSSE3)
michael@0 1375 if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
michael@0 1376 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1377 ARGBColorMatrixRow = ARGBColorMatrixRow_SSSE3;
michael@0 1378 }
michael@0 1379 #elif defined(HAS_ARGBCOLORMATRIXROW_NEON)
michael@0 1380 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
michael@0 1381 ARGBColorMatrixRow = ARGBColorMatrixRow_NEON;
michael@0 1382 }
michael@0 1383 #endif
michael@0 1384 for (y = 0; y < height; ++y) {
michael@0 1385 ARGBColorMatrixRow(src_argb, dst_argb, matrix_argb, width);
michael@0 1386 src_argb += src_stride_argb;
michael@0 1387 dst_argb += dst_stride_argb;
michael@0 1388 }
michael@0 1389 return 0;
michael@0 1390 }
michael@0 1391
michael@0 1392 // Apply a 4x3 matrix to each ARGB pixel.
michael@0 1393 // Deprecated.
michael@0 1394 LIBYUV_API
michael@0 1395 int RGBColorMatrix(uint8* dst_argb, int dst_stride_argb,
michael@0 1396 const int8* matrix_rgb,
michael@0 1397 int dst_x, int dst_y, int width, int height) {
michael@0 1398 SIMD_ALIGNED(int8 matrix_argb[16]);
michael@0 1399 uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
michael@0 1400 if (!dst_argb || !matrix_rgb || width <= 0 || height <= 0 ||
michael@0 1401 dst_x < 0 || dst_y < 0) {
michael@0 1402 return -1;
michael@0 1403 }
michael@0 1404
michael@0 1405 // Convert 4x3 7 bit matrix to 4x4 6 bit matrix.
michael@0 1406 matrix_argb[0] = matrix_rgb[0] / 2;
michael@0 1407 matrix_argb[1] = matrix_rgb[1] / 2;
michael@0 1408 matrix_argb[2] = matrix_rgb[2] / 2;
michael@0 1409 matrix_argb[3] = matrix_rgb[3] / 2;
michael@0 1410 matrix_argb[4] = matrix_rgb[4] / 2;
michael@0 1411 matrix_argb[5] = matrix_rgb[5] / 2;
michael@0 1412 matrix_argb[6] = matrix_rgb[6] / 2;
michael@0 1413 matrix_argb[7] = matrix_rgb[7] / 2;
michael@0 1414 matrix_argb[8] = matrix_rgb[8] / 2;
michael@0 1415 matrix_argb[9] = matrix_rgb[9] / 2;
michael@0 1416 matrix_argb[10] = matrix_rgb[10] / 2;
michael@0 1417 matrix_argb[11] = matrix_rgb[11] / 2;
michael@0 1418 matrix_argb[14] = matrix_argb[13] = matrix_argb[12] = 0;
michael@0 1419 matrix_argb[15] = 64; // 1.0
michael@0 1420
michael@0 1421 return ARGBColorMatrix((const uint8*)(dst), dst_stride_argb,
michael@0 1422 dst, dst_stride_argb,
michael@0 1423 &matrix_argb[0], width, height);
michael@0 1424 }
michael@0 1425
michael@0 1426 // Apply a color table each ARGB pixel.
michael@0 1427 // Table contains 256 ARGB values.
michael@0 1428 LIBYUV_API
michael@0 1429 int ARGBColorTable(uint8* dst_argb, int dst_stride_argb,
michael@0 1430 const uint8* table_argb,
michael@0 1431 int dst_x, int dst_y, int width, int height) {
michael@0 1432 int y;
michael@0 1433 void (*ARGBColorTableRow)(uint8* dst_argb, const uint8* table_argb,
michael@0 1434 int width) = ARGBColorTableRow_C;
michael@0 1435 uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
michael@0 1436 if (!dst_argb || !table_argb || width <= 0 || height <= 0 ||
michael@0 1437 dst_x < 0 || dst_y < 0) {
michael@0 1438 return -1;
michael@0 1439 }
michael@0 1440 // Coalesce rows.
michael@0 1441 if (dst_stride_argb == width * 4) {
michael@0 1442 width *= height;
michael@0 1443 height = 1;
michael@0 1444 dst_stride_argb = 0;
michael@0 1445 }
michael@0 1446 #if defined(HAS_ARGBCOLORTABLEROW_X86)
michael@0 1447 if (TestCpuFlag(kCpuHasX86)) {
michael@0 1448 ARGBColorTableRow = ARGBColorTableRow_X86;
michael@0 1449 }
michael@0 1450 #endif
michael@0 1451 for (y = 0; y < height; ++y) {
michael@0 1452 ARGBColorTableRow(dst, table_argb, width);
michael@0 1453 dst += dst_stride_argb;
michael@0 1454 }
michael@0 1455 return 0;
michael@0 1456 }
michael@0 1457
michael@0 1458 // Apply a color table each ARGB pixel but preserve destination alpha.
michael@0 1459 // Table contains 256 ARGB values.
michael@0 1460 LIBYUV_API
michael@0 1461 int RGBColorTable(uint8* dst_argb, int dst_stride_argb,
michael@0 1462 const uint8* table_argb,
michael@0 1463 int dst_x, int dst_y, int width, int height) {
michael@0 1464 int y;
michael@0 1465 void (*RGBColorTableRow)(uint8* dst_argb, const uint8* table_argb,
michael@0 1466 int width) = RGBColorTableRow_C;
michael@0 1467 uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
michael@0 1468 if (!dst_argb || !table_argb || width <= 0 || height <= 0 ||
michael@0 1469 dst_x < 0 || dst_y < 0) {
michael@0 1470 return -1;
michael@0 1471 }
michael@0 1472 // Coalesce rows.
michael@0 1473 if (dst_stride_argb == width * 4) {
michael@0 1474 width *= height;
michael@0 1475 height = 1;
michael@0 1476 dst_stride_argb = 0;
michael@0 1477 }
michael@0 1478 #if defined(HAS_RGBCOLORTABLEROW_X86)
michael@0 1479 if (TestCpuFlag(kCpuHasX86)) {
michael@0 1480 RGBColorTableRow = RGBColorTableRow_X86;
michael@0 1481 }
michael@0 1482 #endif
michael@0 1483 for (y = 0; y < height; ++y) {
michael@0 1484 RGBColorTableRow(dst, table_argb, width);
michael@0 1485 dst += dst_stride_argb;
michael@0 1486 }
michael@0 1487 return 0;
michael@0 1488 }
michael@0 1489
michael@0 1490 // ARGBQuantize is used to posterize art.
michael@0 1491 // e.g. rgb / qvalue * qvalue + qvalue / 2
michael@0 1492 // But the low levels implement efficiently with 3 parameters, and could be
michael@0 1493 // used for other high level operations.
michael@0 1494 // dst_argb[0] = (b * scale >> 16) * interval_size + interval_offset;
michael@0 1495 // where scale is 1 / interval_size as a fixed point value.
michael@0 1496 // The divide is replaces with a multiply by reciprocal fixed point multiply.
michael@0 1497 // Caveat - although SSE2 saturates, the C function does not and should be used
michael@0 1498 // with care if doing anything but quantization.
michael@0 1499 LIBYUV_API
michael@0 1500 int ARGBQuantize(uint8* dst_argb, int dst_stride_argb,
michael@0 1501 int scale, int interval_size, int interval_offset,
michael@0 1502 int dst_x, int dst_y, int width, int height) {
michael@0 1503 int y;
michael@0 1504 void (*ARGBQuantizeRow)(uint8* dst_argb, int scale, int interval_size,
michael@0 1505 int interval_offset, int width) = ARGBQuantizeRow_C;
michael@0 1506 uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
michael@0 1507 if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0 ||
michael@0 1508 interval_size < 1 || interval_size > 255) {
michael@0 1509 return -1;
michael@0 1510 }
michael@0 1511 // Coalesce rows.
michael@0 1512 if (dst_stride_argb == width * 4) {
michael@0 1513 width *= height;
michael@0 1514 height = 1;
michael@0 1515 dst_stride_argb = 0;
michael@0 1516 }
michael@0 1517 #if defined(HAS_ARGBQUANTIZEROW_SSE2)
michael@0 1518 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4) &&
michael@0 1519 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1520 ARGBQuantizeRow = ARGBQuantizeRow_SSE2;
michael@0 1521 }
michael@0 1522 #elif defined(HAS_ARGBQUANTIZEROW_NEON)
michael@0 1523 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
michael@0 1524 ARGBQuantizeRow = ARGBQuantizeRow_NEON;
michael@0 1525 }
michael@0 1526 #endif
michael@0 1527 for (y = 0; y < height; ++y) {
michael@0 1528 ARGBQuantizeRow(dst, scale, interval_size, interval_offset, width);
michael@0 1529 dst += dst_stride_argb;
michael@0 1530 }
michael@0 1531 return 0;
michael@0 1532 }
michael@0 1533
michael@0 1534 // Computes table of cumulative sum for image where the value is the sum
michael@0 1535 // of all values above and to the left of the entry. Used by ARGBBlur.
michael@0 1536 LIBYUV_API
michael@0 1537 int ARGBComputeCumulativeSum(const uint8* src_argb, int src_stride_argb,
michael@0 1538 int32* dst_cumsum, int dst_stride32_cumsum,
michael@0 1539 int width, int height) {
michael@0 1540 int y;
michael@0 1541 void (*ComputeCumulativeSumRow)(const uint8* row, int32* cumsum,
michael@0 1542 const int32* previous_cumsum, int width) = ComputeCumulativeSumRow_C;
michael@0 1543 int32* previous_cumsum = dst_cumsum;
michael@0 1544 if (!dst_cumsum || !src_argb || width <= 0 || height <= 0) {
michael@0 1545 return -1;
michael@0 1546 }
michael@0 1547 #if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
michael@0 1548 if (TestCpuFlag(kCpuHasSSE2)) {
michael@0 1549 ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
michael@0 1550 }
michael@0 1551 #endif
michael@0 1552 memset(dst_cumsum, 0, width * sizeof(dst_cumsum[0]) * 4); // 4 int per pixel.
michael@0 1553 for (y = 0; y < height; ++y) {
michael@0 1554 ComputeCumulativeSumRow(src_argb, dst_cumsum, previous_cumsum, width);
michael@0 1555 previous_cumsum = dst_cumsum;
michael@0 1556 dst_cumsum += dst_stride32_cumsum;
michael@0 1557 src_argb += src_stride_argb;
michael@0 1558 }
michael@0 1559 return 0;
michael@0 1560 }
michael@0 1561
michael@0 1562 // Blur ARGB image.
michael@0 1563 // Caller should allocate CumulativeSum table of width * height * 16 bytes
michael@0 1564 // aligned to 16 byte boundary. height can be radius * 2 + 2 to save memory
michael@0 1565 // as the buffer is treated as circular.
michael@0 1566 LIBYUV_API
michael@0 1567 int ARGBBlur(const uint8* src_argb, int src_stride_argb,
michael@0 1568 uint8* dst_argb, int dst_stride_argb,
michael@0 1569 int32* dst_cumsum, int dst_stride32_cumsum,
michael@0 1570 int width, int height, int radius) {
michael@0 1571 int y;
michael@0 1572 void (*ComputeCumulativeSumRow)(const uint8 *row, int32 *cumsum,
michael@0 1573 const int32* previous_cumsum, int width) = ComputeCumulativeSumRow_C;
michael@0 1574 void (*CumulativeSumToAverageRow)(const int32* topleft, const int32* botleft,
michael@0 1575 int width, int area, uint8* dst, int count) = CumulativeSumToAverageRow_C;
michael@0 1576 int32* cumsum_bot_row;
michael@0 1577 int32* max_cumsum_bot_row;
michael@0 1578 int32* cumsum_top_row;
michael@0 1579
michael@0 1580 if (!src_argb || !dst_argb || width <= 0 || height == 0) {
michael@0 1581 return -1;
michael@0 1582 }
michael@0 1583 if (height < 0) {
michael@0 1584 height = -height;
michael@0 1585 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 1586 src_stride_argb = -src_stride_argb;
michael@0 1587 }
michael@0 1588 if (radius > height) {
michael@0 1589 radius = height;
michael@0 1590 }
michael@0 1591 if (radius > (width / 2 - 1)) {
michael@0 1592 radius = width / 2 - 1;
michael@0 1593 }
michael@0 1594 if (radius <= 0) {
michael@0 1595 return -1;
michael@0 1596 }
michael@0 1597 #if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
michael@0 1598 if (TestCpuFlag(kCpuHasSSE2)) {
michael@0 1599 ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
michael@0 1600 CumulativeSumToAverageRow = CumulativeSumToAverageRow_SSE2;
michael@0 1601 }
michael@0 1602 #endif
michael@0 1603 // Compute enough CumulativeSum for first row to be blurred. After this
michael@0 1604 // one row of CumulativeSum is updated at a time.
michael@0 1605 ARGBComputeCumulativeSum(src_argb, src_stride_argb,
michael@0 1606 dst_cumsum, dst_stride32_cumsum,
michael@0 1607 width, radius);
michael@0 1608
michael@0 1609 src_argb = src_argb + radius * src_stride_argb;
michael@0 1610 cumsum_bot_row = &dst_cumsum[(radius - 1) * dst_stride32_cumsum];
michael@0 1611
michael@0 1612 max_cumsum_bot_row = &dst_cumsum[(radius * 2 + 2) * dst_stride32_cumsum];
michael@0 1613 cumsum_top_row = &dst_cumsum[0];
michael@0 1614
michael@0 1615 for (y = 0; y < height; ++y) {
michael@0 1616 int top_y = ((y - radius - 1) >= 0) ? (y - radius - 1) : 0;
michael@0 1617 int bot_y = ((y + radius) < height) ? (y + radius) : (height - 1);
michael@0 1618 int area = radius * (bot_y - top_y);
michael@0 1619 int boxwidth = radius * 4;
michael@0 1620 int x;
michael@0 1621 int n;
michael@0 1622
michael@0 1623 // Increment cumsum_top_row pointer with circular buffer wrap around.
michael@0 1624 if (top_y) {
michael@0 1625 cumsum_top_row += dst_stride32_cumsum;
michael@0 1626 if (cumsum_top_row >= max_cumsum_bot_row) {
michael@0 1627 cumsum_top_row = dst_cumsum;
michael@0 1628 }
michael@0 1629 }
michael@0 1630 // Increment cumsum_bot_row pointer with circular buffer wrap around and
michael@0 1631 // then fill in a row of CumulativeSum.
michael@0 1632 if ((y + radius) < height) {
michael@0 1633 const int32* prev_cumsum_bot_row = cumsum_bot_row;
michael@0 1634 cumsum_bot_row += dst_stride32_cumsum;
michael@0 1635 if (cumsum_bot_row >= max_cumsum_bot_row) {
michael@0 1636 cumsum_bot_row = dst_cumsum;
michael@0 1637 }
michael@0 1638 ComputeCumulativeSumRow(src_argb, cumsum_bot_row, prev_cumsum_bot_row,
michael@0 1639 width);
michael@0 1640 src_argb += src_stride_argb;
michael@0 1641 }
michael@0 1642
michael@0 1643 // Left clipped.
michael@0 1644 for (x = 0; x < radius + 1; ++x) {
michael@0 1645 CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row,
michael@0 1646 boxwidth, area, &dst_argb[x * 4], 1);
michael@0 1647 area += (bot_y - top_y);
michael@0 1648 boxwidth += 4;
michael@0 1649 }
michael@0 1650
michael@0 1651 // Middle unclipped.
michael@0 1652 n = (width - 1) - radius - x + 1;
michael@0 1653 CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row,
michael@0 1654 boxwidth, area, &dst_argb[x * 4], n);
michael@0 1655
michael@0 1656 // Right clipped.
michael@0 1657 for (x += n; x <= width - 1; ++x) {
michael@0 1658 area -= (bot_y - top_y);
michael@0 1659 boxwidth -= 4;
michael@0 1660 CumulativeSumToAverageRow(cumsum_top_row + (x - radius - 1) * 4,
michael@0 1661 cumsum_bot_row + (x - radius - 1) * 4,
michael@0 1662 boxwidth, area, &dst_argb[x * 4], 1);
michael@0 1663 }
michael@0 1664 dst_argb += dst_stride_argb;
michael@0 1665 }
michael@0 1666 return 0;
michael@0 1667 }
michael@0 1668
michael@0 1669 // Multiply ARGB image by a specified ARGB value.
michael@0 1670 LIBYUV_API
michael@0 1671 int ARGBShade(const uint8* src_argb, int src_stride_argb,
michael@0 1672 uint8* dst_argb, int dst_stride_argb,
michael@0 1673 int width, int height, uint32 value) {
michael@0 1674 int y;
michael@0 1675 void (*ARGBShadeRow)(const uint8* src_argb, uint8* dst_argb,
michael@0 1676 int width, uint32 value) = ARGBShadeRow_C;
michael@0 1677 if (!src_argb || !dst_argb || width <= 0 || height == 0 || value == 0u) {
michael@0 1678 return -1;
michael@0 1679 }
michael@0 1680 if (height < 0) {
michael@0 1681 height = -height;
michael@0 1682 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 1683 src_stride_argb = -src_stride_argb;
michael@0 1684 }
michael@0 1685 // Coalesce rows.
michael@0 1686 if (src_stride_argb == width * 4 &&
michael@0 1687 dst_stride_argb == width * 4) {
michael@0 1688 width *= height;
michael@0 1689 height = 1;
michael@0 1690 src_stride_argb = dst_stride_argb = 0;
michael@0 1691 }
michael@0 1692 #if defined(HAS_ARGBSHADEROW_SSE2)
michael@0 1693 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4) &&
michael@0 1694 IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
michael@0 1695 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1696 ARGBShadeRow = ARGBShadeRow_SSE2;
michael@0 1697 }
michael@0 1698 #elif defined(HAS_ARGBSHADEROW_NEON)
michael@0 1699 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
michael@0 1700 ARGBShadeRow = ARGBShadeRow_NEON;
michael@0 1701 }
michael@0 1702 #endif
michael@0 1703
michael@0 1704 for (y = 0; y < height; ++y) {
michael@0 1705 ARGBShadeRow(src_argb, dst_argb, width, value);
michael@0 1706 src_argb += src_stride_argb;
michael@0 1707 dst_argb += dst_stride_argb;
michael@0 1708 }
michael@0 1709 return 0;
michael@0 1710 }
michael@0 1711
michael@0 1712 // Interpolate 2 ARGB images by specified amount (0 to 255).
michael@0 1713 LIBYUV_API
michael@0 1714 int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
michael@0 1715 const uint8* src_argb1, int src_stride_argb1,
michael@0 1716 uint8* dst_argb, int dst_stride_argb,
michael@0 1717 int width, int height, int interpolation) {
michael@0 1718 int y;
michael@0 1719 void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
michael@0 1720 ptrdiff_t src_stride, int dst_width,
michael@0 1721 int source_y_fraction) = InterpolateRow_C;
michael@0 1722 if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
michael@0 1723 return -1;
michael@0 1724 }
michael@0 1725 // Negative height means invert the image.
michael@0 1726 if (height < 0) {
michael@0 1727 height = -height;
michael@0 1728 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
michael@0 1729 dst_stride_argb = -dst_stride_argb;
michael@0 1730 }
michael@0 1731 // Coalesce rows.
michael@0 1732 if (src_stride_argb0 == width * 4 &&
michael@0 1733 src_stride_argb1 == width * 4 &&
michael@0 1734 dst_stride_argb == width * 4) {
michael@0 1735 width *= height;
michael@0 1736 height = 1;
michael@0 1737 src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
michael@0 1738 }
michael@0 1739 #if defined(HAS_INTERPOLATEROW_SSE2)
michael@0 1740 if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
michael@0 1741 InterpolateRow = InterpolateRow_Any_SSE2;
michael@0 1742 if (IS_ALIGNED(width, 4)) {
michael@0 1743 InterpolateRow = InterpolateRow_Unaligned_SSE2;
michael@0 1744 if (IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
michael@0 1745 IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
michael@0 1746 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1747 InterpolateRow = InterpolateRow_SSE2;
michael@0 1748 }
michael@0 1749 }
michael@0 1750 }
michael@0 1751 #endif
michael@0 1752 #if defined(HAS_INTERPOLATEROW_SSSE3)
michael@0 1753 if (TestCpuFlag(kCpuHasSSSE3) && width >= 4) {
michael@0 1754 InterpolateRow = InterpolateRow_Any_SSSE3;
michael@0 1755 if (IS_ALIGNED(width, 4)) {
michael@0 1756 InterpolateRow = InterpolateRow_Unaligned_SSSE3;
michael@0 1757 if (IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
michael@0 1758 IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
michael@0 1759 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1760 InterpolateRow = InterpolateRow_SSSE3;
michael@0 1761 }
michael@0 1762 }
michael@0 1763 }
michael@0 1764 #endif
michael@0 1765 #if defined(HAS_INTERPOLATEROW_AVX2)
michael@0 1766 if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
michael@0 1767 InterpolateRow = InterpolateRow_Any_AVX2;
michael@0 1768 if (IS_ALIGNED(width, 8)) {
michael@0 1769 InterpolateRow = InterpolateRow_AVX2;
michael@0 1770 }
michael@0 1771 }
michael@0 1772 #endif
michael@0 1773 #if defined(HAS_INTERPOLATEROW_NEON)
michael@0 1774 if (TestCpuFlag(kCpuHasNEON) && width >= 4) {
michael@0 1775 InterpolateRow = InterpolateRow_Any_NEON;
michael@0 1776 if (IS_ALIGNED(width, 4)) {
michael@0 1777 InterpolateRow = InterpolateRow_NEON;
michael@0 1778 }
michael@0 1779 }
michael@0 1780 #endif
michael@0 1781 #if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2)
michael@0 1782 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && width >= 1 &&
michael@0 1783 IS_ALIGNED(src_argb0, 4) && IS_ALIGNED(src_stride_argb0, 4) &&
michael@0 1784 IS_ALIGNED(src_argb1, 4) && IS_ALIGNED(src_stride_argb1, 4) &&
michael@0 1785 IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
michael@0 1786 ScaleARGBFilterRows = InterpolateRow_MIPS_DSPR2;
michael@0 1787 }
michael@0 1788 #endif
michael@0 1789
michael@0 1790 for (y = 0; y < height; ++y) {
michael@0 1791 InterpolateRow(dst_argb, src_argb0, src_argb1 - src_argb0,
michael@0 1792 width * 4, interpolation);
michael@0 1793 src_argb0 += src_stride_argb0;
michael@0 1794 src_argb1 += src_stride_argb1;
michael@0 1795 dst_argb += dst_stride_argb;
michael@0 1796 }
michael@0 1797 return 0;
michael@0 1798 }
michael@0 1799
michael@0 1800 // Shuffle ARGB channel order. e.g. BGRA to ARGB.
michael@0 1801 LIBYUV_API
michael@0 1802 int ARGBShuffle(const uint8* src_bgra, int src_stride_bgra,
michael@0 1803 uint8* dst_argb, int dst_stride_argb,
michael@0 1804 const uint8* shuffler, int width, int height) {
michael@0 1805 int y;
michael@0 1806 void (*ARGBShuffleRow)(const uint8* src_bgra, uint8* dst_argb,
michael@0 1807 const uint8* shuffler, int pix) = ARGBShuffleRow_C;
michael@0 1808 if (!src_bgra || !dst_argb ||
michael@0 1809 width <= 0 || height == 0) {
michael@0 1810 return -1;
michael@0 1811 }
michael@0 1812 // Negative height means invert the image.
michael@0 1813 if (height < 0) {
michael@0 1814 height = -height;
michael@0 1815 src_bgra = src_bgra + (height - 1) * src_stride_bgra;
michael@0 1816 src_stride_bgra = -src_stride_bgra;
michael@0 1817 }
michael@0 1818 // Coalesce rows.
michael@0 1819 if (src_stride_bgra == width * 4 &&
michael@0 1820 dst_stride_argb == width * 4) {
michael@0 1821 width *= height;
michael@0 1822 height = 1;
michael@0 1823 src_stride_bgra = dst_stride_argb = 0;
michael@0 1824 }
michael@0 1825 #if defined(HAS_ARGBSHUFFLEROW_SSE2)
michael@0 1826 if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
michael@0 1827 ARGBShuffleRow = ARGBShuffleRow_Any_SSE2;
michael@0 1828 if (IS_ALIGNED(width, 4)) {
michael@0 1829 ARGBShuffleRow = ARGBShuffleRow_SSE2;
michael@0 1830 }
michael@0 1831 }
michael@0 1832 #endif
michael@0 1833 #if defined(HAS_ARGBSHUFFLEROW_SSSE3)
michael@0 1834 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
michael@0 1835 ARGBShuffleRow = ARGBShuffleRow_Any_SSSE3;
michael@0 1836 if (IS_ALIGNED(width, 8)) {
michael@0 1837 ARGBShuffleRow = ARGBShuffleRow_Unaligned_SSSE3;
michael@0 1838 if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16) &&
michael@0 1839 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 1840 ARGBShuffleRow = ARGBShuffleRow_SSSE3;
michael@0 1841 }
michael@0 1842 }
michael@0 1843 }
michael@0 1844 #endif
michael@0 1845 #if defined(HAS_ARGBSHUFFLEROW_AVX2)
michael@0 1846 if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
michael@0 1847 ARGBShuffleRow = ARGBShuffleRow_Any_AVX2;
michael@0 1848 if (IS_ALIGNED(width, 16)) {
michael@0 1849 ARGBShuffleRow = ARGBShuffleRow_AVX2;
michael@0 1850 }
michael@0 1851 }
michael@0 1852 #endif
michael@0 1853 #if defined(HAS_ARGBSHUFFLEROW_NEON)
michael@0 1854 if (TestCpuFlag(kCpuHasNEON) && width >= 4) {
michael@0 1855 ARGBShuffleRow = ARGBShuffleRow_Any_NEON;
michael@0 1856 if (IS_ALIGNED(width, 4)) {
michael@0 1857 ARGBShuffleRow = ARGBShuffleRow_NEON;
michael@0 1858 }
michael@0 1859 }
michael@0 1860 #endif
michael@0 1861
michael@0 1862 for (y = 0; y < height; ++y) {
michael@0 1863 ARGBShuffleRow(src_bgra, dst_argb, shuffler, width);
michael@0 1864 src_bgra += src_stride_bgra;
michael@0 1865 dst_argb += dst_stride_argb;
michael@0 1866 }
michael@0 1867 return 0;
michael@0 1868 }
michael@0 1869
michael@0 1870 // Sobel ARGB effect.
michael@0 1871 static int ARGBSobelize(const uint8* src_argb, int src_stride_argb,
michael@0 1872 uint8* dst_argb, int dst_stride_argb,
michael@0 1873 int width, int height,
michael@0 1874 void (*SobelRow)(const uint8* src_sobelx,
michael@0 1875 const uint8* src_sobely,
michael@0 1876 uint8* dst, int width)) {
michael@0 1877 int y;
michael@0 1878 void (*ARGBToBayerRow)(const uint8* src_argb, uint8* dst_bayer,
michael@0 1879 uint32 selector, int pix) = ARGBToBayerGGRow_C;
michael@0 1880 void (*SobelYRow)(const uint8* src_y0, const uint8* src_y1,
michael@0 1881 uint8* dst_sobely, int width) = SobelYRow_C;
michael@0 1882 void (*SobelXRow)(const uint8* src_y0, const uint8* src_y1,
michael@0 1883 const uint8* src_y2, uint8* dst_sobely, int width) =
michael@0 1884 SobelXRow_C;
michael@0 1885 const int kEdge = 16; // Extra pixels at start of row for extrude/align.
michael@0 1886 if (!src_argb || !dst_argb || width <= 0 || height == 0) {
michael@0 1887 return -1;
michael@0 1888 }
michael@0 1889 // Negative height means invert the image.
michael@0 1890 if (height < 0) {
michael@0 1891 height = -height;
michael@0 1892 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 1893 src_stride_argb = -src_stride_argb;
michael@0 1894 }
michael@0 1895 // ARGBToBayer used to select G channel from ARGB.
michael@0 1896 #if defined(HAS_ARGBTOBAYERGGROW_SSE2)
michael@0 1897 if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
michael@0 1898 IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
michael@0 1899 ARGBToBayerRow = ARGBToBayerGGRow_Any_SSE2;
michael@0 1900 if (IS_ALIGNED(width, 8)) {
michael@0 1901 ARGBToBayerRow = ARGBToBayerGGRow_SSE2;
michael@0 1902 }
michael@0 1903 }
michael@0 1904 #endif
michael@0 1905 #if defined(HAS_ARGBTOBAYERROW_SSSE3)
michael@0 1906 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8 &&
michael@0 1907 IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
michael@0 1908 ARGBToBayerRow = ARGBToBayerRow_Any_SSSE3;
michael@0 1909 if (IS_ALIGNED(width, 8)) {
michael@0 1910 ARGBToBayerRow = ARGBToBayerRow_SSSE3;
michael@0 1911 }
michael@0 1912 }
michael@0 1913 #endif
michael@0 1914 #if defined(HAS_ARGBTOBAYERGGROW_NEON)
michael@0 1915 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
michael@0 1916 ARGBToBayerRow = ARGBToBayerGGRow_Any_NEON;
michael@0 1917 if (IS_ALIGNED(width, 8)) {
michael@0 1918 ARGBToBayerRow = ARGBToBayerGGRow_NEON;
michael@0 1919 }
michael@0 1920 }
michael@0 1921 #endif
michael@0 1922 #if defined(HAS_SOBELYROW_SSE2)
michael@0 1923 if (TestCpuFlag(kCpuHasSSE2)) {
michael@0 1924 SobelYRow = SobelYRow_SSE2;
michael@0 1925 }
michael@0 1926 #endif
michael@0 1927 #if defined(HAS_SOBELYROW_NEON)
michael@0 1928 if (TestCpuFlag(kCpuHasNEON)) {
michael@0 1929 SobelYRow = SobelYRow_NEON;
michael@0 1930 }
michael@0 1931 #endif
michael@0 1932 #if defined(HAS_SOBELXROW_SSE2)
michael@0 1933 if (TestCpuFlag(kCpuHasSSE2)) {
michael@0 1934 SobelXRow = SobelXRow_SSE2;
michael@0 1935 }
michael@0 1936 #endif
michael@0 1937 #if defined(HAS_SOBELXROW_NEON)
michael@0 1938 if (TestCpuFlag(kCpuHasNEON)) {
michael@0 1939 SobelXRow = SobelXRow_NEON;
michael@0 1940 }
michael@0 1941 #endif
michael@0 1942 {
michael@0 1943 // 3 rows with edges before/after.
michael@0 1944 const int kRowSize = (width + kEdge + 15) & ~15;
michael@0 1945 align_buffer_64(rows, kRowSize * 2 + (kEdge + kRowSize * 3 + kEdge));
michael@0 1946 uint8* row_sobelx = rows;
michael@0 1947 uint8* row_sobely = rows + kRowSize;
michael@0 1948 uint8* row_y = rows + kRowSize * 2;
michael@0 1949
michael@0 1950 // Convert first row.
michael@0 1951 uint8* row_y0 = row_y + kEdge;
michael@0 1952 uint8* row_y1 = row_y0 + kRowSize;
michael@0 1953 uint8* row_y2 = row_y1 + kRowSize;
michael@0 1954 ARGBToBayerRow(src_argb, row_y0, 0x0d090501, width);
michael@0 1955 row_y0[-1] = row_y0[0];
michael@0 1956 memset(row_y0 + width, row_y0[width - 1], 16); // Extrude 16 for valgrind.
michael@0 1957 ARGBToBayerRow(src_argb, row_y1, 0x0d090501, width);
michael@0 1958 row_y1[-1] = row_y1[0];
michael@0 1959 memset(row_y1 + width, row_y1[width - 1], 16);
michael@0 1960 memset(row_y2 + width, 0, 16);
michael@0 1961
michael@0 1962 for (y = 0; y < height; ++y) {
michael@0 1963 // Convert next row of ARGB to Y.
michael@0 1964 if (y < (height - 1)) {
michael@0 1965 src_argb += src_stride_argb;
michael@0 1966 }
michael@0 1967 ARGBToBayerRow(src_argb, row_y2, 0x0d090501, width);
michael@0 1968 row_y2[-1] = row_y2[0];
michael@0 1969 row_y2[width] = row_y2[width - 1];
michael@0 1970
michael@0 1971 SobelXRow(row_y0 - 1, row_y1 - 1, row_y2 - 1, row_sobelx, width);
michael@0 1972 SobelYRow(row_y0 - 1, row_y2 - 1, row_sobely, width);
michael@0 1973 SobelRow(row_sobelx, row_sobely, dst_argb, width);
michael@0 1974
michael@0 1975 // Cycle thru circular queue of 3 row_y buffers.
michael@0 1976 {
michael@0 1977 uint8* row_yt = row_y0;
michael@0 1978 row_y0 = row_y1;
michael@0 1979 row_y1 = row_y2;
michael@0 1980 row_y2 = row_yt;
michael@0 1981 }
michael@0 1982
michael@0 1983 dst_argb += dst_stride_argb;
michael@0 1984 }
michael@0 1985 free_aligned_buffer_64(rows);
michael@0 1986 }
michael@0 1987 return 0;
michael@0 1988 }
michael@0 1989
michael@0 1990 // Sobel ARGB effect.
michael@0 1991 LIBYUV_API
michael@0 1992 int ARGBSobel(const uint8* src_argb, int src_stride_argb,
michael@0 1993 uint8* dst_argb, int dst_stride_argb,
michael@0 1994 int width, int height) {
michael@0 1995 void (*SobelRow)(const uint8* src_sobelx, const uint8* src_sobely,
michael@0 1996 uint8* dst_argb, int width) = SobelRow_C;
michael@0 1997 #if defined(HAS_SOBELROW_SSE2)
michael@0 1998 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
michael@0 1999 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 2000 SobelRow = SobelRow_SSE2;
michael@0 2001 }
michael@0 2002 #endif
michael@0 2003 #if defined(HAS_SOBELROW_NEON)
michael@0 2004 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
michael@0 2005 SobelRow = SobelRow_NEON;
michael@0 2006 }
michael@0 2007 #endif
michael@0 2008 return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
michael@0 2009 width, height, SobelRow);
michael@0 2010 }
michael@0 2011
michael@0 2012 // Sobel ARGB effect with planar output.
michael@0 2013 LIBYUV_API
michael@0 2014 int ARGBSobelToPlane(const uint8* src_argb, int src_stride_argb,
michael@0 2015 uint8* dst_y, int dst_stride_y,
michael@0 2016 int width, int height) {
michael@0 2017 void (*SobelToPlaneRow)(const uint8* src_sobelx, const uint8* src_sobely,
michael@0 2018 uint8* dst_, int width) = SobelToPlaneRow_C;
michael@0 2019 #if defined(HAS_SOBELTOPLANEROW_SSE2)
michael@0 2020 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
michael@0 2021 IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
michael@0 2022 SobelToPlaneRow = SobelToPlaneRow_SSE2;
michael@0 2023 }
michael@0 2024 #endif
michael@0 2025 #if defined(HAS_SOBELTOPLANEROW_NEON)
michael@0 2026 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
michael@0 2027 SobelToPlaneRow = SobelToPlaneRow_NEON;
michael@0 2028 }
michael@0 2029 #endif
michael@0 2030 return ARGBSobelize(src_argb, src_stride_argb, dst_y, dst_stride_y,
michael@0 2031 width, height, SobelToPlaneRow);
michael@0 2032 }
michael@0 2033
michael@0 2034 // SobelXY ARGB effect.
michael@0 2035 // Similar to Sobel, but also stores Sobel X in R and Sobel Y in B. G = Sobel.
michael@0 2036 LIBYUV_API
michael@0 2037 int ARGBSobelXY(const uint8* src_argb, int src_stride_argb,
michael@0 2038 uint8* dst_argb, int dst_stride_argb,
michael@0 2039 int width, int height) {
michael@0 2040 void (*SobelXYRow)(const uint8* src_sobelx, const uint8* src_sobely,
michael@0 2041 uint8* dst_argb, int width) = SobelXYRow_C;
michael@0 2042 #if defined(HAS_SOBELXYROW_SSE2)
michael@0 2043 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
michael@0 2044 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
michael@0 2045 SobelXYRow = SobelXYRow_SSE2;
michael@0 2046 }
michael@0 2047 #endif
michael@0 2048 #if defined(HAS_SOBELXYROW_NEON)
michael@0 2049 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
michael@0 2050 SobelXYRow = SobelXYRow_NEON;
michael@0 2051 }
michael@0 2052 #endif
michael@0 2053 return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
michael@0 2054 width, height, SobelXYRow);
michael@0 2055 }
michael@0 2056
michael@0 2057 // Apply a 4x4 polynomial to each ARGB pixel.
michael@0 2058 LIBYUV_API
michael@0 2059 int ARGBPolynomial(const uint8* src_argb, int src_stride_argb,
michael@0 2060 uint8* dst_argb, int dst_stride_argb,
michael@0 2061 const float* poly,
michael@0 2062 int width, int height) {
michael@0 2063 int y;
michael@0 2064 void (*ARGBPolynomialRow)(const uint8* src_argb,
michael@0 2065 uint8* dst_argb, const float* poly,
michael@0 2066 int width) = ARGBPolynomialRow_C;
michael@0 2067 if (!src_argb || !dst_argb || !poly || width <= 0 || height == 0) {
michael@0 2068 return -1;
michael@0 2069 }
michael@0 2070 // Negative height means invert the image.
michael@0 2071 if (height < 0) {
michael@0 2072 height = -height;
michael@0 2073 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 2074 src_stride_argb = -src_stride_argb;
michael@0 2075 }
michael@0 2076 // Coalesce rows.
michael@0 2077 if (src_stride_argb == width * 4 &&
michael@0 2078 dst_stride_argb == width * 4) {
michael@0 2079 width *= height;
michael@0 2080 height = 1;
michael@0 2081 src_stride_argb = dst_stride_argb = 0;
michael@0 2082 }
michael@0 2083 #if defined(HAS_ARGBPOLYNOMIALROW_SSE2)
michael@0 2084 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 2)) {
michael@0 2085 ARGBPolynomialRow = ARGBPolynomialRow_SSE2;
michael@0 2086 }
michael@0 2087 #endif
michael@0 2088 #if defined(HAS_ARGBPOLYNOMIALROW_AVX2)
michael@0 2089 if (TestCpuFlag(kCpuHasAVX2) && TestCpuFlag(kCpuHasFMA3) &&
michael@0 2090 IS_ALIGNED(width, 2)) {
michael@0 2091 ARGBPolynomialRow = ARGBPolynomialRow_AVX2;
michael@0 2092 }
michael@0 2093 #endif
michael@0 2094
michael@0 2095 for (y = 0; y < height; ++y) {
michael@0 2096 ARGBPolynomialRow(src_argb, dst_argb, poly, width);
michael@0 2097 src_argb += src_stride_argb;
michael@0 2098 dst_argb += dst_stride_argb;
michael@0 2099 }
michael@0 2100 return 0;
michael@0 2101 }
michael@0 2102
michael@0 2103 // Apply a lumacolortable to each ARGB pixel.
michael@0 2104 LIBYUV_API
michael@0 2105 int ARGBLumaColorTable(const uint8* src_argb, int src_stride_argb,
michael@0 2106 uint8* dst_argb, int dst_stride_argb,
michael@0 2107 const uint8* luma,
michael@0 2108 int width, int height) {
michael@0 2109 int y;
michael@0 2110 void (*ARGBLumaColorTableRow)(const uint8* src_argb, uint8* dst_argb,
michael@0 2111 int width, const uint8* luma, const uint32 lumacoeff) =
michael@0 2112 ARGBLumaColorTableRow_C;
michael@0 2113 if (!src_argb || !dst_argb || !luma || width <= 0 || height == 0) {
michael@0 2114 return -1;
michael@0 2115 }
michael@0 2116 // Negative height means invert the image.
michael@0 2117 if (height < 0) {
michael@0 2118 height = -height;
michael@0 2119 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 2120 src_stride_argb = -src_stride_argb;
michael@0 2121 }
michael@0 2122 // Coalesce rows.
michael@0 2123 if (src_stride_argb == width * 4 &&
michael@0 2124 dst_stride_argb == width * 4) {
michael@0 2125 width *= height;
michael@0 2126 height = 1;
michael@0 2127 src_stride_argb = dst_stride_argb = 0;
michael@0 2128 }
michael@0 2129 #if defined(HAS_ARGBLUMACOLORTABLEROW_SSSE3)
michael@0 2130 if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4)) {
michael@0 2131 ARGBLumaColorTableRow = ARGBLumaColorTableRow_SSSE3;
michael@0 2132 }
michael@0 2133 #endif
michael@0 2134
michael@0 2135 for (y = 0; y < height; ++y) {
michael@0 2136 ARGBLumaColorTableRow(src_argb, dst_argb, width, luma, 0x00264b0f);
michael@0 2137 src_argb += src_stride_argb;
michael@0 2138 dst_argb += dst_stride_argb;
michael@0 2139 }
michael@0 2140 return 0;
michael@0 2141 }
michael@0 2142
michael@0 2143 // Copy Alpha from one ARGB image to another.
michael@0 2144 LIBYUV_API
michael@0 2145 int ARGBCopyAlpha(const uint8* src_argb, int src_stride_argb,
michael@0 2146 uint8* dst_argb, int dst_stride_argb,
michael@0 2147 int width, int height) {
michael@0 2148 int y;
michael@0 2149 void (*ARGBCopyAlphaRow)(const uint8* src_argb, uint8* dst_argb, int width) =
michael@0 2150 ARGBCopyAlphaRow_C;
michael@0 2151 if (!src_argb || !dst_argb || width <= 0 || height == 0) {
michael@0 2152 return -1;
michael@0 2153 }
michael@0 2154 // Negative height means invert the image.
michael@0 2155 if (height < 0) {
michael@0 2156 height = -height;
michael@0 2157 src_argb = src_argb + (height - 1) * src_stride_argb;
michael@0 2158 src_stride_argb = -src_stride_argb;
michael@0 2159 }
michael@0 2160 // Coalesce rows.
michael@0 2161 if (src_stride_argb == width * 4 &&
michael@0 2162 dst_stride_argb == width * 4) {
michael@0 2163 width *= height;
michael@0 2164 height = 1;
michael@0 2165 src_stride_argb = dst_stride_argb = 0;
michael@0 2166 }
michael@0 2167 #if defined(HAS_ARGBCOPYALPHAROW_SSE2)
michael@0 2168 if (TestCpuFlag(kCpuHasSSE2) &&
michael@0 2169 IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
michael@0 2170 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16) &&
michael@0 2171 IS_ALIGNED(width, 8)) {
michael@0 2172 ARGBCopyAlphaRow = ARGBCopyAlphaRow_SSE2;
michael@0 2173 }
michael@0 2174 #endif
michael@0 2175 #if defined(HAS_ARGBCOPYALPHAROW_AVX2)
michael@0 2176 if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 16)) {
michael@0 2177 ARGBCopyAlphaRow = ARGBCopyAlphaRow_AVX2;
michael@0 2178 }
michael@0 2179 #endif
michael@0 2180
michael@0 2181 for (y = 0; y < height; ++y) {
michael@0 2182 ARGBCopyAlphaRow(src_argb, dst_argb, width);
michael@0 2183 src_argb += src_stride_argb;
michael@0 2184 dst_argb += dst_stride_argb;
michael@0 2185 }
michael@0 2186 return 0;
michael@0 2187 }
michael@0 2188
michael@0 2189 // Copy a planar Y channel to the alpha channel of a destination ARGB image.
michael@0 2190 LIBYUV_API
michael@0 2191 int ARGBCopyYToAlpha(const uint8* src_y, int src_stride_y,
michael@0 2192 uint8* dst_argb, int dst_stride_argb,
michael@0 2193 int width, int height) {
michael@0 2194 int y;
michael@0 2195 void (*ARGBCopyYToAlphaRow)(const uint8* src_y, uint8* dst_argb, int width) =
michael@0 2196 ARGBCopyYToAlphaRow_C;
michael@0 2197 if (!src_y || !dst_argb || width <= 0 || height == 0) {
michael@0 2198 return -1;
michael@0 2199 }
michael@0 2200 // Negative height means invert the image.
michael@0 2201 if (height < 0) {
michael@0 2202 height = -height;
michael@0 2203 src_y = src_y + (height - 1) * src_stride_y;
michael@0 2204 src_stride_y = -src_stride_y;
michael@0 2205 }
michael@0 2206 // Coalesce rows.
michael@0 2207 if (src_stride_y == width &&
michael@0 2208 dst_stride_argb == width * 4) {
michael@0 2209 width *= height;
michael@0 2210 height = 1;
michael@0 2211 src_stride_y = dst_stride_argb = 0;
michael@0 2212 }
michael@0 2213 #if defined(HAS_ARGBCOPYYTOALPHAROW_SSE2)
michael@0 2214 if (TestCpuFlag(kCpuHasSSE2) &&
michael@0 2215 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
michael@0 2216 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16) &&
michael@0 2217 IS_ALIGNED(width, 8)) {
michael@0 2218 ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_SSE2;
michael@0 2219 }
michael@0 2220 #endif
michael@0 2221 #if defined(HAS_ARGBCOPYYTOALPHAROW_AVX2)
michael@0 2222 if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 16)) {
michael@0 2223 ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_AVX2;
michael@0 2224 }
michael@0 2225 #endif
michael@0 2226
michael@0 2227 for (y = 0; y < height; ++y) {
michael@0 2228 ARGBCopyYToAlphaRow(src_y, dst_argb, width);
michael@0 2229 src_y += src_stride_y;
michael@0 2230 dst_argb += dst_stride_argb;
michael@0 2231 }
michael@0 2232 return 0;
michael@0 2233 }
michael@0 2234
michael@0 2235 #ifdef __cplusplus
michael@0 2236 } // extern "C"
michael@0 2237 } // namespace libyuv
michael@0 2238 #endif

mercurial