1aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org/*
2b0c97975894a5eebebf9d93147cdd941a3accb63fbarchard@google.com *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
3aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org *
4aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org *  Use of this source code is governed by a BSD-style license
5aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org *  that can be found in the LICENSE file in the root of the source
6aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org *  tree. An additional intellectual property rights grant can be found
7cde587092fef0dbed2c35602f30b79e7b892e766fbarchard@google.com *  in the file PATENTS. All contributing project authors may
8aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org */
10aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org
11a1280730c24b5c94ef16949777f65e597719488efbarchard@google.com#include "libyuv/planar_functions.h"
12aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org
130ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com#include <string.h>  // for memset()
142842f2536d63eafb45f42052082225ab5fcb1e64fbarchard@google.com
15a1280730c24b5c94ef16949777f65e597719488efbarchard@google.com#include "libyuv/cpu_id.h"
167c8e16f82ae94e09c9657276a0ceedafbf036315fbarchard@google.com#ifdef HAVE_JPEG
177c8e16f82ae94e09c9657276a0ceedafbf036315fbarchard@google.com#include "libyuv/mjpeg_decoder.h"
187c8e16f82ae94e09c9657276a0ceedafbf036315fbarchard@google.com#endif
19142f6c4ed5eaeec0176f255e64bac8d8c70b42e1fbarchard@google.com#include "libyuv/row.h"
20aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org
21fe5ff7ed5451496281697bda9cb85084c532926cfbarchard@google.com#ifdef __cplusplus
22aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.orgnamespace libyuv {
23fe5ff7ed5451496281697bda9cb85084c532926cfbarchard@google.comextern "C" {
24fe5ff7ed5451496281697bda9cb85084c532926cfbarchard@google.com#endif
25aed1cc94c105736a5e6010e9c84cc32910b865d6mikhal@webrtc.org
262d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com// Copy a plane of data
27fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
282d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.comvoid CopyPlane(const uint8* src_y, int src_stride_y,
292d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com               uint8* dst_y, int dst_stride_y,
302d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com               int width, int height) {
3170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
3270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
33095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
34518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com  if (src_stride_y == width &&
35518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      dst_stride_y == width) {
36095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
37095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
38095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_y = dst_stride_y = 0;
39ba45bbff3419ad2004ebcb1ef7b878662341283bfbarchard@google.com  }
40a9ff15b7bbd7b2a646f94328ff702091acde225afbarchard@google.com  // Nothing to do.
41a9ff15b7bbd7b2a646f94328ff702091acde225afbarchard@google.com  if (src_y == dst_y && src_stride_y == dst_stride_y) {
42a9ff15b7bbd7b2a646f94328ff702091acde225afbarchard@google.com    return;
43a9ff15b7bbd7b2a646f94328ff702091acde225afbarchard@google.com  }
44c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com#if defined(HAS_COPYROW_X86)
45c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com  if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
462d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    CopyRow = CopyRow_X86;
47c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com  }
48ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com#endif
49c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com#if defined(HAS_COPYROW_SSE2)
50c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
51c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com      IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
52c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com      IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
53c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com    CopyRow = CopyRow_SSE2;
54ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com  }
5519932f8dbc5ca3123d87b5b8369e7d7bf3469a97fbarchard@google.com#endif
56aa7988ff733b13d7bfd3c755bf0c18f93b9e8f6efbarchard@google.com#if defined(HAS_COPYROW_ERMS)
57aa7988ff733b13d7bfd3c755bf0c18f93b9e8f6efbarchard@google.com  if (TestCpuFlag(kCpuHasERMS)) {
58aa7988ff733b13d7bfd3c755bf0c18f93b9e8f6efbarchard@google.com    CopyRow = CopyRow_ERMS;
59b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  }
60b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#endif
61b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#if defined(HAS_COPYROW_NEON)
62b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
63b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    CopyRow = CopyRow_NEON;
64b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  }
65b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#endif
666c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com#if defined(HAS_COPYROW_MIPS)
676c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com  if (TestCpuFlag(kCpuHasMIPS)) {
686c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com    CopyRow = CopyRow_MIPS;
696c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com  }
706c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com#endif
719eefb2e8dd2c40a8b6bd0f02d794fe78332fc08ffbarchard@google.com
722d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com  // Copy plane
7370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
742d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    CopyRow(src_y, dst_y, width);
75ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com    src_y += src_stride_y;
762d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    dst_y += dst_stride_y;
77ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com  }
78ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com}
79ecb3f4cc4e0a6e17daaebea1c1da63df9042984ffbarchard@google.com
80b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.comLIBYUV_API
81b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.comvoid CopyPlane_16(const uint16* src_y, int src_stride_y,
82b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com                  uint16* dst_y, int dst_stride_y,
83b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com                  int width, int height) {
84b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  int y;
85b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  void (*CopyRow)(const uint16* src, uint16* dst, int width) = CopyRow_16_C;
86b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  // Coalesce rows.
87b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  if (src_stride_y == width &&
88b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com      dst_stride_y == width) {
89b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    width *= height;
90b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    height = 1;
91b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    src_stride_y = dst_stride_y = 0;
92b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  }
93b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#if defined(HAS_COPYROW_16_X86)
94b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
95b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    CopyRow = CopyRow_16_X86;
96b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  }
97b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#endif
98b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#if defined(HAS_COPYROW_16_SSE2)
99b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
100b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com      IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
101b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com      IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
102b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    CopyRow = CopyRow_16_SSE2;
103b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  }
104b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#endif
105b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#if defined(HAS_COPYROW_16_ERMS)
106b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  if (TestCpuFlag(kCpuHasERMS)) {
107b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    CopyRow = CopyRow_16_ERMS;
108b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  }
109b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#endif
110b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#if defined(HAS_COPYROW_16_NEON)
111b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
112b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    CopyRow = CopyRow_16_NEON;
113b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  }
114b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#endif
115b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#if defined(HAS_COPYROW_16_MIPS)
116b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  if (TestCpuFlag(kCpuHasMIPS)) {
117b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    CopyRow = CopyRow_16_MIPS;
118b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  }
119b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com#endif
120b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com
121b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  // Copy plane
122b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  for (y = 0; y < height; ++y) {
123b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    CopyRow(src_y, dst_y, width);
124b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    src_y += src_stride_y;
125b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com    dst_y += dst_stride_y;
126b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com  }
127b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com}
128b18413e568ae742114eabb8450b180db98a83be0fbarchard@google.com
129a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com// Copy I422.
130a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.comLIBYUV_API
131a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.comint I422Copy(const uint8* src_y, int src_stride_y,
132a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             const uint8* src_u, int src_stride_u,
133a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             const uint8* src_v, int src_stride_v,
134a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             uint8* dst_y, int dst_stride_y,
135a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             uint8* dst_u, int dst_stride_u,
136a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             uint8* dst_v, int dst_stride_v,
137a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             int width, int height) {
13870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int halfwidth = (width + 1) >> 1;
139a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  if (!src_y || !src_u || !src_v ||
140a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com      !dst_y || !dst_u || !dst_v ||
141a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com      width <= 0 || height == 0) {
142a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    return -1;
143a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  }
144a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  // Negative height means invert the image.
145a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  if (height < 0) {
146a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    height = -height;
147a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_y = src_y + (height - 1) * src_stride_y;
148a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_u = src_u + (height - 1) * src_stride_u;
149a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_v = src_v + (height - 1) * src_stride_v;
150a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_stride_y = -src_stride_y;
151a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_stride_u = -src_stride_u;
152a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_stride_v = -src_stride_v;
153a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  }
154a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
155a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height);
156a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height);
157a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  return 0;
158a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com}
159a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com
160a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com// Copy I444.
161a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.comLIBYUV_API
162a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.comint I444Copy(const uint8* src_y, int src_stride_y,
163a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             const uint8* src_u, int src_stride_u,
164a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             const uint8* src_v, int src_stride_v,
165a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             uint8* dst_y, int dst_stride_y,
166a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             uint8* dst_u, int dst_stride_u,
167a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             uint8* dst_v, int dst_stride_v,
168a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com             int width, int height) {
169a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  if (!src_y || !src_u || !src_v ||
170a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com      !dst_y || !dst_u || !dst_v ||
171a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com      width <= 0 || height == 0) {
172a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    return -1;
173a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  }
174a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  // Negative height means invert the image.
175a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  if (height < 0) {
176a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    height = -height;
177a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_y = src_y + (height - 1) * src_stride_y;
178a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_u = src_u + (height - 1) * src_stride_u;
179a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_v = src_v + (height - 1) * src_stride_v;
180a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_stride_y = -src_stride_y;
181a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_stride_u = -src_stride_u;
182a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com    src_stride_v = -src_stride_v;
183a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  }
184a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com
185a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
186a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
187a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
188a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com  return 0;
189a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com}
190a00da62e52167966bde5bc11cc0470e87136b652fbarchard@google.com
1916b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com// Copy I400.
1926b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.comLIBYUV_API
1936b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.comint I400ToI400(const uint8* src_y, int src_stride_y,
1946b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com               uint8* dst_y, int dst_stride_y,
1956b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com               int width, int height) {
1966b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com  if (!src_y || !dst_y || width <= 0 || height == 0) {
1976b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com    return -1;
1986b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com  }
1996b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com  // Negative height means invert the image.
2006b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com  if (height < 0) {
2016b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com    height = -height;
2026b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com    src_y = src_y + (height - 1) * src_stride_y;
2036b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com    src_stride_y = -src_stride_y;
2046b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com  }
2056b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com  CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
2066b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com  return 0;
2076b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com}
2086b5a8efff7759c941f5a11ead2f67330dea2f14cfbarchard@google.com
209bf8b0f0e2ba4e647efa88e44833c7fd383a1becefbarchard@google.com// Convert I420 to I400.
210fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
211e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.comint I420ToI400(const uint8* src_y, int src_stride_y,
2121f923e3ea6de7afd9380c73f60a2f3e7b0588811fbarchard@google.com               const uint8* src_u, int src_stride_u,
2131f923e3ea6de7afd9380c73f60a2f3e7b0588811fbarchard@google.com               const uint8* src_v, int src_stride_v,
214e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com               uint8* dst_y, int dst_stride_y,
215e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com               int width, int height) {
216c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (!src_y || !dst_y || width <= 0 || height == 0) {
217e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com    return -1;
218e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com  }
219e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com  // Negative height means invert the image.
220e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com  if (height < 0) {
221e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com    height = -height;
222e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com    src_y = src_y + (height - 1) * src_stride_y;
223e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com    src_stride_y = -src_stride_y;
224e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com  }
225e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com  CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
226e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com  return 0;
227e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com}
228e214fe3f070d47d34e3cfbf4431994f97c9e0d1bfbarchard@google.com
229aae7deb5cf7269144e04045d3e0fa05054759dbefbarchard@google.com// Mirror a plane of data.
2302d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.comvoid MirrorPlane(const uint8* src_y, int src_stride_y,
2312d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com                 uint8* dst_y, int dst_stride_y,
232ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com                 int width, int height) {
23370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
23470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*MirrorRow)(const uint8* src, uint8* dst, int width) = MirrorRow_C;
235aae7deb5cf7269144e04045d3e0fa05054759dbefbarchard@google.com  // Negative height means invert the image.
236aae7deb5cf7269144e04045d3e0fa05054759dbefbarchard@google.com  if (height < 0) {
237aae7deb5cf7269144e04045d3e0fa05054759dbefbarchard@google.com    height = -height;
238aae7deb5cf7269144e04045d3e0fa05054759dbefbarchard@google.com    src_y = src_y + (height - 1) * src_stride_y;
239aae7deb5cf7269144e04045d3e0fa05054759dbefbarchard@google.com    src_stride_y = -src_stride_y;
240aae7deb5cf7269144e04045d3e0fa05054759dbefbarchard@google.com  }
2412d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com#if defined(HAS_MIRRORROW_NEON)
2422d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
2432d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    MirrorRow = MirrorRow_NEON;
2440ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com  }
2459eefb2e8dd2c40a8b6bd0f02d794fe78332fc08ffbarchard@google.com#endif
2462d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com#if defined(HAS_MIRRORROW_SSE2)
2472d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16)) {
2482d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    MirrorRow = MirrorRow_SSE2;
2493e46444727a0524d2f1d81117e0b1404148ac910fbarchard@google.com  }
2503e46444727a0524d2f1d81117e0b1404148ac910fbarchard@google.com#endif
2510ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com#if defined(HAS_MIRRORROW_SSSE3)
252b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16) &&
253b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com      IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
254b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com      IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
255b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    MirrorRow = MirrorRow_SSSE3;
256b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  }
2570ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com#endif
2582007dca6dcfee6828f604068d7d17842fbe5d646fbarchard@google.com#if defined(HAS_MIRRORROW_AVX2)
2592007dca6dcfee6828f604068d7d17842fbe5d646fbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 32)) {
2602007dca6dcfee6828f604068d7d17842fbe5d646fbarchard@google.com    MirrorRow = MirrorRow_AVX2;
2612007dca6dcfee6828f604068d7d17842fbe5d646fbarchard@google.com  }
2622007dca6dcfee6828f604068d7d17842fbe5d646fbarchard@google.com#endif
2639eefb2e8dd2c40a8b6bd0f02d794fe78332fc08ffbarchard@google.com
2642d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com  // Mirror plane
26570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
2662d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    MirrorRow(src_y, dst_y, width);
267ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com    src_y += src_stride_y;
2682d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    dst_y += dst_stride_y;
269ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com  }
270ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com}
271ecb3f4cc4e0a6e17daaebea1c1da63df9042984ffbarchard@google.com
27264ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com// Convert YUY2 to I422.
27364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.comLIBYUV_API
27464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.comint YUY2ToI422(const uint8* src_yuy2, int src_stride_yuy2,
27564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com               uint8* dst_y, int dst_stride_y,
27664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com               uint8* dst_u, int dst_stride_u,
27764ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com               uint8* dst_v, int dst_stride_v,
27864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com               int width, int height) {
27970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
28070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*YUY2ToUV422Row)(const uint8* src_yuy2,
28170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                         uint8* dst_u, uint8* dst_v, int pix) =
28270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      YUY2ToUV422Row_C;
28370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
28470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      YUY2ToYRow_C;
28564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  // Negative height means invert the image.
28664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  if (height < 0) {
28764ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    height = -height;
28864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
28964ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    src_stride_yuy2 = -src_stride_yuy2;
29064ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  }
291095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
292518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com  if (src_stride_yuy2 == width * 2 &&
29311a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_y == width &&
294518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      dst_stride_u * 2 == width &&
295518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      dst_stride_v * 2 == width) {
296095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
297095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
298095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_yuy2 = dst_stride_y = dst_stride_u = dst_stride_v = 0;
29911a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
30064ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com#if defined(HAS_YUY2TOYROW_SSE2)
301b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
302b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
303b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    YUY2ToYRow = YUY2ToYRow_Any_SSE2;
30464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    if (IS_ALIGNED(width, 16)) {
30564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
30664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
30764ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
30864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com        YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
30964ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com        if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
31064ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com          YUY2ToYRow = YUY2ToYRow_SSE2;
31164ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com        }
31264ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      }
31364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    }
31464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  }
315b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#endif
316b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#if defined(HAS_YUY2TOYROW_AVX2)
317b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
318b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
319b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    YUY2ToYRow = YUY2ToYRow_Any_AVX2;
320b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    if (IS_ALIGNED(width, 32)) {
321b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com      YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
322b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com      YUY2ToYRow = YUY2ToYRow_AVX2;
323b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    }
324b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  }
325b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#endif
326b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#if defined(HAS_YUY2TOYROW_NEON)
327b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
328b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    YUY2ToYRow = YUY2ToYRow_Any_NEON;
329b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    if (width >= 16) {
330b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com      YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
33164ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    }
33264ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    if (IS_ALIGNED(width, 16)) {
33364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      YUY2ToYRow = YUY2ToYRow_NEON;
33464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      YUY2ToUV422Row = YUY2ToUV422Row_NEON;
33564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    }
33664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  }
33764ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com#endif
33864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com
33970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
34064ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
34164ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    YUY2ToYRow(src_yuy2, dst_y, width);
34264ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    src_yuy2 += src_stride_yuy2;
34364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    dst_y += dst_stride_y;
34464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    dst_u += dst_stride_u;
34564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    dst_v += dst_stride_v;
34664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  }
34764ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  return 0;
34864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com}
34964ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com
35064ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com// Convert UYVY to I422.
35164ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.comLIBYUV_API
35264ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.comint UYVYToI422(const uint8* src_uyvy, int src_stride_uyvy,
35364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com               uint8* dst_y, int dst_stride_y,
35464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com               uint8* dst_u, int dst_stride_u,
35564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com               uint8* dst_v, int dst_stride_v,
35664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com               int width, int height) {
35770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
35870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*UYVYToUV422Row)(const uint8* src_uyvy,
35970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                         uint8* dst_u, uint8* dst_v, int pix) =
36070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      UYVYToUV422Row_C;
36170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*UYVYToYRow)(const uint8* src_uyvy,
36270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                     uint8* dst_y, int pix) = UYVYToYRow_C;
36364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  // Negative height means invert the image.
36464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  if (height < 0) {
36564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    height = -height;
36664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
36764ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    src_stride_uyvy = -src_stride_uyvy;
36864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  }
369095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
370518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com  if (src_stride_uyvy == width * 2 &&
37111a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_y == width &&
372518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      dst_stride_u * 2 == width &&
373518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      dst_stride_v * 2 == width) {
374095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
375095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
376095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_uyvy = dst_stride_y = dst_stride_u = dst_stride_v = 0;
37711a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
37864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com#if defined(HAS_UYVYTOYROW_SSE2)
379b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
380b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    UYVYToUV422Row = UYVYToUV422Row_Any_SSE2;
381b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    UYVYToYRow = UYVYToYRow_Any_SSE2;
38264ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    if (IS_ALIGNED(width, 16)) {
38364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      UYVYToUV422Row = UYVYToUV422Row_Unaligned_SSE2;
38464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
38564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
38664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com        UYVYToUV422Row = UYVYToUV422Row_SSE2;
38764ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com        if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
38864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com          UYVYToYRow = UYVYToYRow_SSE2;
38964ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com        }
39064ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      }
39164ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    }
39264ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  }
393b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#endif
394b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#if defined(HAS_UYVYTOYROW_AVX2)
395b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
396b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    UYVYToUV422Row = UYVYToUV422Row_Any_AVX2;
397b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    UYVYToYRow = UYVYToYRow_Any_AVX2;
398b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    if (IS_ALIGNED(width, 32)) {
399b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com      UYVYToUV422Row = UYVYToUV422Row_AVX2;
400b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com      UYVYToYRow = UYVYToYRow_AVX2;
401b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    }
402b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  }
403b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#endif
404b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com#if defined(HAS_UYVYTOYROW_NEON)
405b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
406b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    UYVYToYRow = UYVYToYRow_Any_NEON;
407b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com    if (width >= 16) {
408b444bae883e97c1e4579f2e1148cf14f9c7c18fbfbarchard@google.com      UYVYToUV422Row = UYVYToUV422Row_Any_NEON;
40964ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    }
41064ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    if (IS_ALIGNED(width, 16)) {
41164ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      UYVYToYRow = UYVYToYRow_NEON;
41264ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com      UYVYToUV422Row = UYVYToUV422Row_NEON;
41364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    }
41464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  }
41564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com#endif
41664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com
41770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
41864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    UYVYToUV422Row(src_uyvy, dst_u, dst_v, width);
41964ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    UYVYToYRow(src_uyvy, dst_y, width);
42064ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    src_uyvy += src_stride_uyvy;
42164ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    dst_y += dst_stride_y;
42264ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    dst_u += dst_stride_u;
42364ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com    dst_v += dst_stride_v;
42464ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  }
42564ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  return 0;
42664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com}
42764ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com
4286bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com// Mirror I400 with optional flipping
4296bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.comLIBYUV_API
4306bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.comint I400Mirror(const uint8* src_y, int src_stride_y,
4316bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com               uint8* dst_y, int dst_stride_y,
4326bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com               int width, int height) {
4336bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com  if (!src_y || !dst_y ||
4346bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com      width <= 0 || height == 0) {
4356bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com    return -1;
4366bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com  }
4376bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com  // Negative height means invert the image.
4386bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com  if (height < 0) {
4396bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com    height = -height;
4406bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com    src_y = src_y + (height - 1) * src_stride_y;
4416bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com    src_stride_y = -src_stride_y;
4426bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com  }
4436bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com
4446bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com  MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
4456bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com  return 0;
4466bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com}
4476bb9f53f4fcf1d40fdb345323a084057e67a508dfbarchard@google.com
4482d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com// Mirror I420 with optional flipping
449fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
4502d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.comint I420Mirror(const uint8* src_y, int src_stride_y,
4512d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com               const uint8* src_u, int src_stride_u,
4522d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com               const uint8* src_v, int src_stride_v,
4532d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com               uint8* dst_y, int dst_stride_y,
4542d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com               uint8* dst_u, int dst_stride_u,
4552d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com               uint8* dst_v, int dst_stride_v,
4562d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com               int width, int height) {
45770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int halfwidth = (width + 1) >> 1;
45870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int halfheight = (height + 1) >> 1;
459c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (!src_y || !src_u || !src_v || !dst_y || !dst_u || !dst_v ||
4602d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com      width <= 0 || height == 0) {
4612d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    return -1;
4622d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com  }
463ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com  // Negative height means invert the image.
464ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com  if (height < 0) {
465ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com    height = -height;
46670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    halfheight = (height + 1) >> 1;
4672d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    src_y = src_y + (height - 1) * src_stride_y;
4682d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    src_u = src_u + (halfheight - 1) * src_stride_u;
4692d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    src_v = src_v + (halfheight - 1) * src_stride_v;
4702d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    src_stride_y = -src_stride_y;
4712d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    src_stride_u = -src_stride_u;
4722d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    src_stride_v = -src_stride_v;
473ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com  }
4749eefb2e8dd2c40a8b6bd0f02d794fe78332fc08ffbarchard@google.com
4752d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com  if (dst_y) {
4762d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com    MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
477ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com  }
4782d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com  MirrorPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
4792d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com  MirrorPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
480ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com  return 0;
481ba1f52692605bbf8fedb8a915275c71fa186d291fbarchard@google.com}
4829eefb2e8dd2c40a8b6bd0f02d794fe78332fc08ffbarchard@google.com
48327d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com// ARGB mirror.
484fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
48527d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.comint ARGBMirror(const uint8* src_argb, int src_stride_argb,
48627d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com               uint8* dst_argb, int dst_stride_argb,
48727d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com               int width, int height) {
48870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
48970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBMirrorRow)(const uint8* src, uint8* dst, int width) =
49070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      ARGBMirrorRow_C;
491c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (!src_argb || !dst_argb || width <= 0 || height == 0) {
49227d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com    return -1;
49327d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com  }
49427d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com  // Negative height means invert the image.
49527d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com  if (height < 0) {
49627d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com    height = -height;
49727d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com    src_argb = src_argb + (height - 1) * src_stride_argb;
49827d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com    src_stride_argb = -src_stride_argb;
49927d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com  }
50027d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com
50127d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com#if defined(HAS_ARGBMIRRORROW_SSSE3)
50227d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4) &&
50327d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com      IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
50427d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
50527d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com    ARGBMirrorRow = ARGBMirrorRow_SSSE3;
50627d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com  }
50751398e0be5004b8818df4a4ccda9fe77bcfaf141fbarchard@google.com#endif
50851398e0be5004b8818df4a4ccda9fe77bcfaf141fbarchard@google.com#if defined(HAS_ARGBMIRRORROW_AVX2)
50951398e0be5004b8818df4a4ccda9fe77bcfaf141fbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 8)) {
51051398e0be5004b8818df4a4ccda9fe77bcfaf141fbarchard@google.com    ARGBMirrorRow = ARGBMirrorRow_AVX2;
51151398e0be5004b8818df4a4ccda9fe77bcfaf141fbarchard@google.com  }
51251398e0be5004b8818df4a4ccda9fe77bcfaf141fbarchard@google.com#endif
51351398e0be5004b8818df4a4ccda9fe77bcfaf141fbarchard@google.com#if defined(HAS_ARGBMIRRORROW_NEON)
5143e46444727a0524d2f1d81117e0b1404148ac910fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 4)) {
5153e46444727a0524d2f1d81117e0b1404148ac910fbarchard@google.com    ARGBMirrorRow = ARGBMirrorRow_NEON;
5163e46444727a0524d2f1d81117e0b1404148ac910fbarchard@google.com  }
51727d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com#endif
51827d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com
51927d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com  // Mirror plane
52070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
52127d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com    ARGBMirrorRow(src_argb, dst_argb, width);
52227d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com    src_argb += src_stride_argb;
52327d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com    dst_argb += dst_stride_argb;
52427d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com  }
52527d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com  return 0;
52627d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com}
52727d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com
528d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.com// Get a blender that optimized for the CPU, alignment and pixel count.
529d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.com// As there are 6 blenders to choose from, the caller should try to use
530d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.com// the same blend function for all pixels if possible.
531fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
532bac5f2c3ee12535817448e606c7a7704bbae8321fbarchard@google.comARGBBlendRow GetARGBBlend() {
533d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.com  void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
534d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.com                       uint8* dst_argb, int width) = ARGBBlendRow_C;
5355ff3a8fec5fa54bca8905f1eb6eb69c14d5fb79ffbarchard@google.com#if defined(HAS_ARGBBLENDROW_SSSE3)
536bac5f2c3ee12535817448e606c7a7704bbae8321fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3)) {
537bac5f2c3ee12535817448e606c7a7704bbae8321fbarchard@google.com    ARGBBlendRow = ARGBBlendRow_SSSE3;
5385ff3a8fec5fa54bca8905f1eb6eb69c14d5fb79ffbarchard@google.com    return ARGBBlendRow;
5395ff3a8fec5fa54bca8905f1eb6eb69c14d5fb79ffbarchard@google.com  }
5405ff3a8fec5fa54bca8905f1eb6eb69c14d5fb79ffbarchard@google.com#endif
541da5cc4274b69efe633293a489e7c9550733daf5cfbarchard@google.com#if defined(HAS_ARGBBLENDROW_SSE2)
542bac5f2c3ee12535817448e606c7a7704bbae8321fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2)) {
543bac5f2c3ee12535817448e606c7a7704bbae8321fbarchard@google.com    ARGBBlendRow = ARGBBlendRow_SSE2;
544965fb914ea3f5057cd186763c9af5d3110c44acdfbarchard@google.com  }
545965fb914ea3f5057cd186763c9af5d3110c44acdfbarchard@google.com#endif
5468f506332af217882648eed166a257557855b9fdbfbarchard@google.com#if defined(HAS_ARGBBLENDROW_NEON)
5478f506332af217882648eed166a257557855b9fdbfbarchard@google.com  if (TestCpuFlag(kCpuHasNEON)) {
5488f506332af217882648eed166a257557855b9fdbfbarchard@google.com    ARGBBlendRow = ARGBBlendRow_NEON;
5498f506332af217882648eed166a257557855b9fdbfbarchard@google.com  }
5508f506332af217882648eed166a257557855b9fdbfbarchard@google.com#endif
551d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.com  return ARGBBlendRow;
552c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com}
553c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com
554c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com// Alpha Blend 2 ARGB images and store to destination.
555fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
556d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.comint ARGBBlend(const uint8* src_argb0, int src_stride_argb0,
55727d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com              const uint8* src_argb1, int src_stride_argb1,
55827d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com              uint8* dst_argb, int dst_stride_argb,
55927d42c7ff6452c53643bc57ee8b7b17afbe8dfd0fbarchard@google.com              int width, int height) {
56070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
56170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
56270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                       uint8* dst_argb, int width) = GetARGBBlend();
563c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com  if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
564c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com    return -1;
565c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com  }
566c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com  // Negative height means invert the image.
567c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com  if (height < 0) {
568c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com    height = -height;
569c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
570c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com    dst_stride_argb = -dst_stride_argb;
571c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com  }
572095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
57311a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (src_stride_argb0 == width * 4 &&
57411a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      src_stride_argb1 == width * 4 &&
57511a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_argb == width * 4) {
576095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
577095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
578095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
57911a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
580c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com
58170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
582d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.com    ARGBBlendRow(src_argb0, src_argb1, dst_argb, width);
583c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com    src_argb0 += src_stride_argb0;
584c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com    src_argb1 += src_stride_argb1;
585c757f308eab211f9d5467a089052e7d84606f6c1fbarchard@google.com    dst_argb += dst_stride_argb;
586965fb914ea3f5057cd186763c9af5d3110c44acdfbarchard@google.com  }
587965fb914ea3f5057cd186763c9af5d3110c44acdfbarchard@google.com  return 0;
588965fb914ea3f5057cd186763c9af5d3110c44acdfbarchard@google.com}
589965fb914ea3f5057cd186763c9af5d3110c44acdfbarchard@google.com
59051d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com// Multiply 2 ARGB images and store to destination.
5918fa76349948802d728dd244a7b54051d751d8696fbarchard@google.comLIBYUV_API
5928fa76349948802d728dd244a7b54051d751d8696fbarchard@google.comint ARGBMultiply(const uint8* src_argb0, int src_stride_argb0,
5938fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com                 const uint8* src_argb1, int src_stride_argb1,
5948fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com                 uint8* dst_argb, int dst_stride_argb,
5958fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com                 int width, int height) {
59670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
59770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBMultiplyRow)(const uint8* src0, const uint8* src1, uint8* dst,
59870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                          int width) = ARGBMultiplyRow_C;
5998fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
6008fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    return -1;
6018fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  }
6028fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  // Negative height means invert the image.
6038fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  if (height < 0) {
6048fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    height = -height;
6058fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
6068fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    dst_stride_argb = -dst_stride_argb;
6078fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  }
608095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
60951d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  if (src_stride_argb0 == width * 4 &&
61051d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com      src_stride_argb1 == width * 4 &&
61151d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com      dst_stride_argb == width * 4) {
612095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
613095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
614095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
61551d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  }
6168fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com#if defined(HAS_ARGBMULTIPLYROW_SSE2)
617bb92acade0cd17a83ad32177da6a449b2962066efbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
6188fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    ARGBMultiplyRow = ARGBMultiplyRow_Any_SSE2;
6198fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    if (IS_ALIGNED(width, 4)) {
6208fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com      ARGBMultiplyRow = ARGBMultiplyRow_SSE2;
6218fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    }
6228fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  }
62351d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#endif
62451d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#if defined(HAS_ARGBMULTIPLYROW_AVX2)
62551d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
62651d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com    ARGBMultiplyRow = ARGBMultiplyRow_Any_AVX2;
62751d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com    if (IS_ALIGNED(width, 8)) {
62851d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com      ARGBMultiplyRow = ARGBMultiplyRow_AVX2;
62951d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com    }
63051d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  }
63151d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#endif
63251d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#if defined(HAS_ARGBMULTIPLYROW_NEON)
6335b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
6345b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com    ARGBMultiplyRow = ARGBMultiplyRow_Any_NEON;
6355b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
6365b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com      ARGBMultiplyRow = ARGBMultiplyRow_NEON;
6375b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com    }
6388fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  }
6398fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com#endif
6408fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com
6418fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  // Multiply plane
64270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
6438fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    ARGBMultiplyRow(src_argb0, src_argb1, dst_argb, width);
6448fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    src_argb0 += src_stride_argb0;
6458fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    src_argb1 += src_stride_argb1;
6468fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com    dst_argb += dst_stride_argb;
6478fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  }
6488fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com  return 0;
6498fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com}
6508fa76349948802d728dd244a7b54051d751d8696fbarchard@google.com
65151d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com// Add 2 ARGB images and store to destination.
65283e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.comLIBYUV_API
65383e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.comint ARGBAdd(const uint8* src_argb0, int src_stride_argb0,
65483e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com            const uint8* src_argb1, int src_stride_argb1,
65583e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com            uint8* dst_argb, int dst_stride_argb,
65683e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com            int width, int height) {
65770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
65870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBAddRow)(const uint8* src0, const uint8* src1, uint8* dst,
65970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                     int width) = ARGBAddRow_C;
66083e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
66183e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    return -1;
66283e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  }
66383e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  // Negative height means invert the image.
66483e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  if (height < 0) {
66583e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    height = -height;
66683e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
66783e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    dst_stride_argb = -dst_stride_argb;
66883e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  }
669095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
67051d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  if (src_stride_argb0 == width * 4 &&
67151d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com      src_stride_argb1 == width * 4 &&
67251d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com      dst_stride_argb == width * 4) {
673095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
674095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
675095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
67651d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  }
677bb92acade0cd17a83ad32177da6a449b2962066efbarchard@google.com#if defined(HAS_ARGBADDROW_SSE2) && defined(_MSC_VER)
678bb92acade0cd17a83ad32177da6a449b2962066efbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2)) {
679bb92acade0cd17a83ad32177da6a449b2962066efbarchard@google.com    ARGBAddRow = ARGBAddRow_SSE2;
680bb92acade0cd17a83ad32177da6a449b2962066efbarchard@google.com  }
681bb92acade0cd17a83ad32177da6a449b2962066efbarchard@google.com#endif
682bb92acade0cd17a83ad32177da6a449b2962066efbarchard@google.com#if defined(HAS_ARGBADDROW_SSE2) && !defined(_MSC_VER)
683bb92acade0cd17a83ad32177da6a449b2962066efbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
68483e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    ARGBAddRow = ARGBAddRow_Any_SSE2;
68583e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    if (IS_ALIGNED(width, 4)) {
68683e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com      ARGBAddRow = ARGBAddRow_SSE2;
68783e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    }
68883e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  }
68951d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#endif
69051d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#if defined(HAS_ARGBADDROW_AVX2)
69151d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
69251d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com    ARGBAddRow = ARGBAddRow_Any_AVX2;
69351d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com    if (IS_ALIGNED(width, 8)) {
69451d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com      ARGBAddRow = ARGBAddRow_AVX2;
69551d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com    }
69651d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  }
69751d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#endif
69851d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#if defined(HAS_ARGBADDROW_NEON)
6995b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
7005b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com    ARGBAddRow = ARGBAddRow_Any_NEON;
7015b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
7025b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com      ARGBAddRow = ARGBAddRow_NEON;
7035b0f7e1132bbf79dc3d70dcf225646fcbc5875e2fbarchard@google.com    }
70483e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  }
70583e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com#endif
70683e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com
70783e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  // Add plane
70870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
70983e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    ARGBAddRow(src_argb0, src_argb1, dst_argb, width);
71083e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    src_argb0 += src_stride_argb0;
71183e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    src_argb1 += src_stride_argb1;
71283e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com    dst_argb += dst_stride_argb;
71383e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  }
71483e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com  return 0;
71583e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com}
71683e1b17cc0b1840c7b5e361fa19e7263fca2b32bfbarchard@google.com
717573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com// Subtract 2 ARGB images and store to destination.
718573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.comLIBYUV_API
719573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.comint ARGBSubtract(const uint8* src_argb0, int src_stride_argb0,
720573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com                 const uint8* src_argb1, int src_stride_argb1,
721573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com                 uint8* dst_argb, int dst_stride_argb,
722573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com                 int width, int height) {
72370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
72470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBSubtractRow)(const uint8* src0, const uint8* src1, uint8* dst,
72570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                          int width) = ARGBSubtractRow_C;
726573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
727573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    return -1;
728573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  }
729573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  // Negative height means invert the image.
730573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  if (height < 0) {
731573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    height = -height;
732573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
733573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    dst_stride_argb = -dst_stride_argb;
734573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  }
735095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
73651d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  if (src_stride_argb0 == width * 4 &&
73751d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com      src_stride_argb1 == width * 4 &&
73851d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com      dst_stride_argb == width * 4) {
739095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
740095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
741095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
74251d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  }
743573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com#if defined(HAS_ARGBSUBTRACTROW_SSE2)
744bb92acade0cd17a83ad32177da6a449b2962066efbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
745573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    ARGBSubtractRow = ARGBSubtractRow_Any_SSE2;
746573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    if (IS_ALIGNED(width, 4)) {
747573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com      ARGBSubtractRow = ARGBSubtractRow_SSE2;
748573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    }
749573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  }
75051d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#endif
75151d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#if defined(HAS_ARGBSUBTRACTROW_AVX2)
75251d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
75351d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com    ARGBSubtractRow = ARGBSubtractRow_Any_AVX2;
75451d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com    if (IS_ALIGNED(width, 8)) {
75551d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com      ARGBSubtractRow = ARGBSubtractRow_AVX2;
75651d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com    }
75751d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com  }
75851d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#endif
75951d3e236cb5923c60ba818b6e825c2658b565afefbarchard@google.com#if defined(HAS_ARGBSUBTRACTROW_NEON)
760573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
761573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    ARGBSubtractRow = ARGBSubtractRow_Any_NEON;
762573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
763573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com      ARGBSubtractRow = ARGBSubtractRow_NEON;
764573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    }
765573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  }
766573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com#endif
767573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com
768573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  // Subtract plane
76970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
770573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    ARGBSubtractRow(src_argb0, src_argb1, dst_argb, width);
771573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    src_argb0 += src_stride_argb0;
772573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    src_argb1 += src_stride_argb1;
773573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com    dst_argb += dst_stride_argb;
774573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  }
775573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com  return 0;
776573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com}
777573a883dd65c94a10422e6e9e0d453e2a5d45227fbarchard@google.com
778cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com// Convert I422 to BGRA.
779fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
780cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.comint I422ToBGRA(const uint8* src_y, int src_stride_y,
781cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               const uint8* src_u, int src_stride_u,
782cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               const uint8* src_v, int src_stride_v,
783cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               uint8* dst_bgra, int dst_stride_bgra,
784cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               int width, int height) {
78570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
78670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*I422ToBGRARow)(const uint8* y_buf,
78770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        const uint8* u_buf,
78870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        const uint8* v_buf,
78970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        uint8* rgb_buf,
79070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        int width) = I422ToBGRARow_C;
791cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (!src_y || !src_u || !src_v ||
792cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      !dst_bgra ||
793cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      width <= 0 || height == 0) {
794cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    return -1;
795cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
796cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  // Negative height means invert the image.
797cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (height < 0) {
798cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    height = -height;
799cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra;
800cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    dst_stride_bgra = -dst_stride_bgra;
801cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
802095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
803518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com  if (src_stride_y == width &&
804518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      src_stride_u * 2 == width &&
805518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      src_stride_v * 2 == width &&
80611a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_bgra == width * 4) {
807095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
808095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
809095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_y = src_stride_u = src_stride_v = dst_stride_bgra = 0;
81011a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
811cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com#if defined(HAS_I422TOBGRAROW_NEON)
812cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON)) {
813cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    I422ToBGRARow = I422ToBGRARow_Any_NEON;
814cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    if (IS_ALIGNED(width, 16)) {
815cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      I422ToBGRARow = I422ToBGRARow_NEON;
816cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    }
817cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
818cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com#elif defined(HAS_I422TOBGRAROW_SSSE3)
819cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
820cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    I422ToBGRARow = I422ToBGRARow_Any_SSSE3;
821cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
822cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      I422ToBGRARow = I422ToBGRARow_Unaligned_SSSE3;
823cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      if (IS_ALIGNED(dst_bgra, 16) && IS_ALIGNED(dst_stride_bgra, 16)) {
824cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com        I422ToBGRARow = I422ToBGRARow_SSSE3;
825cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      }
826cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    }
827cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
8286c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com#elif defined(HAS_I422TOBGRAROW_MIPS_DSPR2)
8296c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com  if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
8306c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com      IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
8316c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com      IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
8326c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com      IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
8336c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com      IS_ALIGNED(dst_bgra, 4) && IS_ALIGNED(dst_stride_bgra, 4)) {
8346c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com    I422ToBGRARow = I422ToBGRARow_MIPS_DSPR2;
8356c1b2d38c685e769cf7db2806e27c8ec4c028fe3fbarchard@google.com  }
836cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com#endif
837cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com
83870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
839cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width);
840cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    dst_bgra += dst_stride_bgra;
841cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    src_y += src_stride_y;
842cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    src_u += src_stride_u;
843cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    src_v += src_stride_v;
844cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
845cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  return 0;
846cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com}
847cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com
848cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com// Convert I422 to ABGR.
849fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
850cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.comint I422ToABGR(const uint8* src_y, int src_stride_y,
851cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               const uint8* src_u, int src_stride_u,
852cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               const uint8* src_v, int src_stride_v,
853cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               uint8* dst_abgr, int dst_stride_abgr,
854cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               int width, int height) {
85570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
85670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*I422ToABGRRow)(const uint8* y_buf,
85770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        const uint8* u_buf,
85870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        const uint8* v_buf,
85970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        uint8* rgb_buf,
86070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        int width) = I422ToABGRRow_C;
861cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (!src_y || !src_u || !src_v ||
862cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      !dst_abgr ||
863cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      width <= 0 || height == 0) {
864cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    return -1;
865cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
866cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  // Negative height means invert the image.
867cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (height < 0) {
868cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    height = -height;
869cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr;
870cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    dst_stride_abgr = -dst_stride_abgr;
871cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
872095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
873518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com  if (src_stride_y == width &&
874518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      src_stride_u * 2 == width &&
875518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      src_stride_v * 2 == width &&
87611a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_abgr == width * 4) {
877095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
878095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
879095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_y = src_stride_u = src_stride_v = dst_stride_abgr = 0;
88011a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
881cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com#if defined(HAS_I422TOABGRROW_NEON)
882cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON)) {
883cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    I422ToABGRRow = I422ToABGRRow_Any_NEON;
884cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    if (IS_ALIGNED(width, 16)) {
885cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      I422ToABGRRow = I422ToABGRRow_NEON;
886cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    }
887cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
888cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com#elif defined(HAS_I422TOABGRROW_SSSE3)
889cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
890cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    I422ToABGRRow = I422ToABGRRow_Any_SSSE3;
891cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
892cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      I422ToABGRRow = I422ToABGRRow_Unaligned_SSSE3;
893cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      if (IS_ALIGNED(dst_abgr, 16) && IS_ALIGNED(dst_stride_abgr, 16)) {
894cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com        I422ToABGRRow = I422ToABGRRow_SSSE3;
895cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      }
896cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    }
897cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
898cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com#endif
899cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com
90070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
901cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width);
902cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    dst_abgr += dst_stride_abgr;
903cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    src_y += src_stride_y;
904cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    src_u += src_stride_u;
905cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    src_v += src_stride_v;
906cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
907cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  return 0;
908cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com}
909cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com
910cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com// Convert I422 to RGBA.
911fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
912cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.comint I422ToRGBA(const uint8* src_y, int src_stride_y,
913cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               const uint8* src_u, int src_stride_u,
914cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               const uint8* src_v, int src_stride_v,
915cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               uint8* dst_rgba, int dst_stride_rgba,
916cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com               int width, int height) {
91770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
91870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*I422ToRGBARow)(const uint8* y_buf,
91970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        const uint8* u_buf,
92070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        const uint8* v_buf,
92170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        uint8* rgb_buf,
92270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                        int width) = I422ToRGBARow_C;
923cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (!src_y || !src_u || !src_v ||
924cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      !dst_rgba ||
925cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      width <= 0 || height == 0) {
926cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    return -1;
927cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
928cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  // Negative height means invert the image.
929cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (height < 0) {
930cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    height = -height;
931cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
932cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    dst_stride_rgba = -dst_stride_rgba;
933cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
934095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
935518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com  if (src_stride_y == width &&
936518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      src_stride_u * 2 == width &&
937518833b9833a52b715b487445e6ccfe4f8881903fbarchard@google.com      src_stride_v * 2 == width &&
93811a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_rgba == width * 4) {
939095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
940095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
941095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_y = src_stride_u = src_stride_v = dst_stride_rgba = 0;
94211a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
943cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com#if defined(HAS_I422TORGBAROW_NEON)
944cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON)) {
945cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    I422ToRGBARow = I422ToRGBARow_Any_NEON;
946cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    if (IS_ALIGNED(width, 16)) {
947cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      I422ToRGBARow = I422ToRGBARow_NEON;
948cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    }
949cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
950cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com#elif defined(HAS_I422TORGBAROW_SSSE3)
951cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
952cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
953cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
954cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      I422ToRGBARow = I422ToRGBARow_Unaligned_SSSE3;
955cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      if (IS_ALIGNED(dst_rgba, 16) && IS_ALIGNED(dst_stride_rgba, 16)) {
956cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com        I422ToRGBARow = I422ToRGBARow_SSSE3;
957cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com      }
958cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    }
959cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
960cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com#endif
961cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com
96270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
963cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width);
964cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    dst_rgba += dst_stride_rgba;
965cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    src_y += src_stride_y;
966cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    src_u += src_stride_u;
967cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com    src_v += src_stride_v;
968cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  }
969cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com  return 0;
970cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com}
971cad0ad303cc84195646fbb57014aa73bbe986c48fbarchard@google.com
9722d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com// Convert NV12 to RGB565.
973fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
9742d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.comint NV12ToRGB565(const uint8* src_y, int src_stride_y,
9752d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com                 const uint8* src_uv, int src_stride_uv,
9762d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com                 uint8* dst_rgb565, int dst_stride_rgb565,
9772d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com                 int width, int height) {
97870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
97970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*NV12ToRGB565Row)(const uint8* y_buf,
98070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                          const uint8* uv_buf,
98170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                          uint8* rgb_buf,
98270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                          int width) = NV12ToRGB565Row_C;
9839f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com  if (!src_y || !src_uv || !dst_rgb565 ||
9849f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com      width <= 0 || height == 0) {
985c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    return -1;
986c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  }
9872d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  // Negative height means invert the image.
9882d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  if (height < 0) {
9892d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    height = -height;
9902d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
9912d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    dst_stride_rgb565 = -dst_stride_rgb565;
9922d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  }
9939f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com#if defined(HAS_NV12TORGB565ROW_SSSE3)
994b2a51d042d9ccc49de6180880e5fed3d07067d95fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
9959f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com    NV12ToRGB565Row = NV12ToRGB565Row_Any_SSSE3;
99615449263c4bba75bc396dc3d60266efee6ab6c66fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
9979f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com      NV12ToRGB565Row = NV12ToRGB565Row_SSSE3;
99815449263c4bba75bc396dc3d60266efee6ab6c66fbarchard@google.com    }
9992d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  }
10009f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com#elif defined(HAS_NV12TORGB565ROW_NEON)
100115449263c4bba75bc396dc3d60266efee6ab6c66fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
10029f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com    NV12ToRGB565Row = NV12ToRGB565Row_Any_NEON;
100315449263c4bba75bc396dc3d60266efee6ab6c66fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
10049f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com      NV12ToRGB565Row = NV12ToRGB565Row_NEON;
10058d37dd5c205216e0ad13c5091061908cb981c5f9fbarchard@google.com    }
1006fc99814a9271b1981fb21e8235f9d73161a4109ffbarchard@google.com  }
10070ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com#endif
1008fc99814a9271b1981fb21e8235f9d73161a4109ffbarchard@google.com
100970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
10109f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com    NV12ToRGB565Row(src_y, src_uv, dst_rgb565, width);
10112d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    dst_rgb565 += dst_stride_rgb565;
10122d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    src_y += src_stride_y;
10132d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    if (y & 1) {
1014fc99814a9271b1981fb21e8235f9d73161a4109ffbarchard@google.com      src_uv += src_stride_uv;
1015fc99814a9271b1981fb21e8235f9d73161a4109ffbarchard@google.com    }
10162d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  }
10172d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  return 0;
10182d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com}
10192d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com
10202d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com// Convert NV21 to RGB565.
1021fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
10222d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.comint NV21ToRGB565(const uint8* src_y, int src_stride_y,
10239f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com                 const uint8* src_vu, int src_stride_vu,
10242d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com                 uint8* dst_rgb565, int dst_stride_rgb565,
10252d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com                 int width, int height) {
102670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
102770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*NV21ToRGB565Row)(const uint8* y_buf,
102870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                          const uint8* src_vu,
102970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                          uint8* rgb_buf,
103070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                          int width) = NV21ToRGB565Row_C;
10319f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com  if (!src_y || !src_vu || !dst_rgb565 ||
10329f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com      width <= 0 || height == 0) {
1033c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    return -1;
1034c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  }
10352d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  // Negative height means invert the image.
10362d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  if (height < 0) {
10372d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    height = -height;
10382d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
10392d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    dst_stride_rgb565 = -dst_stride_rgb565;
10402d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  }
10419f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com#if defined(HAS_NV21TORGB565ROW_SSSE3)
1042b2a51d042d9ccc49de6180880e5fed3d07067d95fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
10439f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com    NV21ToRGB565Row = NV21ToRGB565Row_Any_SSSE3;
104415449263c4bba75bc396dc3d60266efee6ab6c66fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
10459f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com      NV21ToRGB565Row = NV21ToRGB565Row_SSSE3;
104615449263c4bba75bc396dc3d60266efee6ab6c66fbarchard@google.com    }
10472d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  }
10489f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com#elif defined(HAS_NV21TORGB565ROW_NEON)
104915449263c4bba75bc396dc3d60266efee6ab6c66fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
10509f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com    NV21ToRGB565Row = NV21ToRGB565Row_Any_NEON;
105115449263c4bba75bc396dc3d60266efee6ab6c66fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
10529f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com      NV21ToRGB565Row = NV21ToRGB565Row_NEON;
10538d37dd5c205216e0ad13c5091061908cb981c5f9fbarchard@google.com    }
10542d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com  }
10552d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com#endif
10562d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com
105770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
10589f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com    NV21ToRGB565Row(src_y, src_vu, dst_rgb565, width);
10592d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    dst_rgb565 += dst_stride_rgb565;
1060fc99814a9271b1981fb21e8235f9d73161a4109ffbarchard@google.com    src_y += src_stride_y;
10612d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    if (y & 1) {
10629f2d404145e8a69d209eb130975442ab3f29d5a7fbarchard@google.com      src_vu += src_stride_vu;
10632d9fe08225ab28f62b515b2b914accc6a7b060fbfbarchard@google.com    }
1064fc99814a9271b1981fb21e8235f9d73161a4109ffbarchard@google.com  }
1065fc99814a9271b1981fb21e8235f9d73161a4109ffbarchard@google.com  return 0;
1066fc99814a9271b1981fb21e8235f9d73161a4109ffbarchard@google.com}
1067fc99814a9271b1981fb21e8235f9d73161a4109ffbarchard@google.com
1068fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
10692d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.comvoid SetPlane(uint8* dst_y, int dst_stride_y,
10702d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com              int width, int height,
10712d11d43a6e21865b904705acce6535ae4c2d3caffbarchard@google.com              uint32 value) {
107270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
107370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint32 v32 = value | (value << 8) | (value << 16) | (value << 24);
107470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*SetRow)(uint8* dst, uint32 value, int pix) = SetRow_C;
1075095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
107611a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (dst_stride_y == width) {
1077095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1078095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1079095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    dst_stride_y = 0;
108011a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
10813e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com#if defined(HAS_SETROW_NEON)
10823e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) &&
10833e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com      IS_ALIGNED(width, 16) &&
10843e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com      IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1085f08ac6bb095348565b5259f2fab95f259ef47edefbarchard@google.com    SetRow = SetRow_NEON;
10860ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com  }
1087c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com#endif
1088c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com#if defined(HAS_SETROW_X86)
1089c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com  if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
1090f08ac6bb095348565b5259f2fab95f259ef47edefbarchard@google.com    SetRow = SetRow_X86;
1091c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com  }
1092c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com#endif
10933e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com
10943e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  // Set plane
109570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
10963e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com    SetRow(dst_y, v32, width);
10973e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com    dst_y += dst_stride_y;
10983e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  }
10993e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com}
11003e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com
11013e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com// Draw a rectangle into I420
1102fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
11033e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.comint I420Rect(uint8* dst_y, int dst_stride_y,
11043e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com             uint8* dst_u, int dst_stride_u,
11053e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com             uint8* dst_v, int dst_stride_v,
11063e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com             int x, int y,
11073e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com             int width, int height,
11083e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com             int value_y, int value_u, int value_v) {
110970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int halfwidth = (width + 1) >> 1;
111070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int halfheight = (height + 1) >> 1;
111170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint8* start_y = dst_y + y * dst_stride_y + x;
111270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint8* start_u = dst_u + (y / 2) * dst_stride_u + (x / 2);
111370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint8* start_v = dst_v + (y / 2) * dst_stride_v + (x / 2);
11143e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  if (!dst_y || !dst_u || !dst_v ||
11153e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com      width <= 0 || height <= 0 ||
11163e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com      x < 0 || y < 0 ||
11173e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com      value_y < 0 || value_y > 255 ||
11183e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com      value_u < 0 || value_u > 255 ||
11193e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com      value_v < 0 || value_v > 255) {
11203e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com    return -1;
11213e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  }
11223e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com
11233e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  SetPlane(start_y, dst_stride_y, width, height, value_y);
11243e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  SetPlane(start_u, dst_stride_u, halfwidth, halfheight, value_u);
11253e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  SetPlane(start_v, dst_stride_v, halfwidth, halfheight, value_v);
11263e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  return 0;
11273e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com}
11283e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com
11293e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com// Draw a rectangle into ARGB
1130fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
11313e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.comint ARGBRect(uint8* dst_argb, int dst_stride_argb,
1132120b8d7ee72bb07c0f58fa2a2245cd6436736579fbarchard@google.com             int dst_x, int dst_y,
11333e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com             int width, int height,
11343e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com             uint32 value) {
11353e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  if (!dst_argb ||
11363e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com      width <= 0 || height <= 0 ||
1137120b8d7ee72bb07c0f58fa2a2245cd6436736579fbarchard@google.com      dst_x < 0 || dst_y < 0) {
11383e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com    return -1;
11393e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com  }
1140095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  dst_argb += dst_y * dst_stride_argb + dst_x * 4;
1141095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
114211a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (dst_stride_argb == width * 4) {
1143095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1144095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1145095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    dst_stride_argb = 0;
114611a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
1147d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.com#if defined(HAS_SETROW_NEON)
11480ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16) &&
1149095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
1150095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    ARGBSetRows_NEON(dst_argb, value, width, dst_stride_argb, height);
11510ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com    return 0;
11520ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com  }
1153d2f4413d29d15b94d971630ba555dd0cd8fcc8c2fbarchard@google.com#endif
1154c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com#if defined(HAS_SETROW_X86)
1155c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com  if (TestCpuFlag(kCpuHasX86)) {
1156095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    ARGBSetRows_X86(dst_argb, value, width, dst_stride_argb, height);
1157c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com    return 0;
1158c5d44a0c5e3f67ebd64626a92d71478876ba4ff2fbarchard@google.com  }
11590ab54406939b220e46eaee03f410ac88cc796762fbarchard@google.com#endif
1160095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  ARGBSetRows_C(dst_argb, value, width, dst_stride_argb, height);
11614f59bcc102643b700102fe5e55c5fc0e1159a00cfbarchard@google.com  return 0;
11623e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com}
11633e8a577bb383154f2a4e978ef615eaafed746e1dfbarchard@google.com
1164da5cc4274b69efe633293a489e7c9550733daf5cfbarchard@google.com// Convert unattentuated ARGB to preattenuated ARGB.
1165829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com// An unattenutated ARGB alpha blend uses the formula
1166829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com// p = a * f + (1 - a) * b
1167829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com// where
1168829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com//   p is output pixel
1169829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com//   f is foreground pixel
1170829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com//   b is background pixel
1171829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com//   a is alpha value from foreground pixel
1172829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com// An preattenutated ARGB alpha blend uses the formula
1173829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com// p = f + (1 - a) * b
1174829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com// where
1175829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com//   f is foreground pixel premultiplied by alpha
1176829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com
1177fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1178829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.comint ARGBAttenuate(const uint8* src_argb, int src_stride_argb,
1179829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com                  uint8* dst_argb, int dst_stride_argb,
1180829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com                  int width, int height) {
118170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
118270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBAttenuateRow)(const uint8* src_argb, uint8* dst_argb,
118370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                           int width) = ARGBAttenuateRow_C;
1184c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (!src_argb || !dst_argb || width <= 0 || height == 0) {
1185c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    return -1;
1186c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  }
1187829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com  if (height < 0) {
1188829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    height = -height;
1189829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    src_argb = src_argb + (height - 1) * src_stride_argb;
1190829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    src_stride_argb = -src_stride_argb;
1191829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com  }
1192095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
119311a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (src_stride_argb == width * 4 &&
119411a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_argb == width * 4) {
1195095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1196095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1197095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb = dst_stride_argb = 0;
119811a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
11991d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com#if defined(HAS_ARGBATTENUATEROW_SSE2)
12001d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 4 &&
12018ed54222e723037322579f15c36d4faddb924e91fbarchard@google.com      IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
12028ed54222e723037322579f15c36d4faddb924e91fbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
12031d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com    ARGBAttenuateRow = ARGBAttenuateRow_Any_SSE2;
12041d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com    if (IS_ALIGNED(width, 4)) {
12051d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com      ARGBAttenuateRow = ARGBAttenuateRow_SSE2;
12061d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com    }
12078ed54222e723037322579f15c36d4faddb924e91fbarchard@google.com  }
12088ed54222e723037322579f15c36d4faddb924e91fbarchard@google.com#endif
1209eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com#if defined(HAS_ARGBATTENUATEROW_SSSE3)
121038157bdc719c403a620218bc2a35af0f9b4adc85fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && width >= 4) {
12111d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com    ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
12121d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com    if (IS_ALIGNED(width, 4)) {
12131d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com      ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
12141d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com    }
12151d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com  }
12161d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com#endif
1217d5ee3dc9123c9fa4e90ec6b90a5c45f8434cac3ffbarchard@google.com#if defined(HAS_ARGBATTENUATEROW_AVX2)
1218c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
1219c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com    ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
1220c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
1221c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com      ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
1222c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com    }
1223d5ee3dc9123c9fa4e90ec6b90a5c45f8434cac3ffbarchard@google.com  }
1224d5ee3dc9123c9fa4e90ec6b90a5c45f8434cac3ffbarchard@google.com#endif
12251d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com#if defined(HAS_ARGBATTENUATEROW_NEON)
12261d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
12271d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com    ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
12281d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
12291d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com      ARGBAttenuateRow = ARGBAttenuateRow_NEON;
12301d160cb99f2b05df80c4555bd769825ad1175dc9fbarchard@google.com    }
1231f2c86d01cc46b0851e0bf88429dd064b8c8b0dbafbarchard@google.com  }
1232f2c86d01cc46b0851e0bf88429dd064b8c8b0dbafbarchard@google.com#endif
1233829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com
123470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
12358ed54222e723037322579f15c36d4faddb924e91fbarchard@google.com    ARGBAttenuateRow(src_argb, dst_argb, width);
1236829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    src_argb += src_stride_argb;
1237829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    dst_argb += dst_stride_argb;
1238829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com  }
1239829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com  return 0;
1240829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com}
1241829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com
1242da5cc4274b69efe633293a489e7c9550733daf5cfbarchard@google.com// Convert preattentuated ARGB to unattenuated ARGB.
1243fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1244829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.comint ARGBUnattenuate(const uint8* src_argb, int src_stride_argb,
1245829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com                    uint8* dst_argb, int dst_stride_argb,
1246829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com                    int width, int height) {
124770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
124870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBUnattenuateRow)(const uint8* src_argb, uint8* dst_argb,
124970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                             int width) = ARGBUnattenuateRow_C;
1250c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (!src_argb || !dst_argb || width <= 0 || height == 0) {
1251c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    return -1;
1252c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  }
1253829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com  if (height < 0) {
1254829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    height = -height;
1255829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    src_argb = src_argb + (height - 1) * src_stride_argb;
1256829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    src_stride_argb = -src_stride_argb;
1257829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com  }
1258095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
125911a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (src_stride_argb == width * 4 &&
126011a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_argb == width * 4) {
1261095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1262095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1263095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb = dst_stride_argb = 0;
126411a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
1265eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com#if defined(HAS_ARGBUNATTENUATEROW_SSE2)
126638157bdc719c403a620218bc2a35af0f9b4adc85fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
1267c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com    ARGBUnattenuateRow = ARGBUnattenuateRow_Any_SSE2;
1268c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com    if (IS_ALIGNED(width, 4)) {
1269c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com      ARGBUnattenuateRow = ARGBUnattenuateRow_SSE2;
1270c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com    }
12718ed54222e723037322579f15c36d4faddb924e91fbarchard@google.com  }
12728ed54222e723037322579f15c36d4faddb924e91fbarchard@google.com#endif
12733c7bb050bd54264f360ced29c1cd2777483bd6f0fbarchard@google.com#if defined(HAS_ARGBUNATTENUATEROW_AVX2)
1274c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
1275c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com    ARGBUnattenuateRow = ARGBUnattenuateRow_Any_AVX2;
1276c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
1277c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com      ARGBUnattenuateRow = ARGBUnattenuateRow_AVX2;
1278c0d9c3469062e20430685565a3e4bb1d7042d147fbarchard@google.com    }
12793c7bb050bd54264f360ced29c1cd2777483bd6f0fbarchard@google.com  }
12803c7bb050bd54264f360ced29c1cd2777483bd6f0fbarchard@google.com#endif
12813c7bb050bd54264f360ced29c1cd2777483bd6f0fbarchard@google.com// TODO(fbarchard): Neon version.
1282829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com
128370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
12848ed54222e723037322579f15c36d4faddb924e91fbarchard@google.com    ARGBUnattenuateRow(src_argb, dst_argb, width);
1285829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    src_argb += src_stride_argb;
1286829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com    dst_argb += dst_stride_argb;
1287829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com  }
1288829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com  return 0;
1289829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com}
1290829e7ea402a06fa616e4c70ee91675318e00e134fbarchard@google.com
1291eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com// Convert ARGB to Grayed ARGB.
1292fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1293eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.comint ARGBGrayTo(const uint8* src_argb, int src_stride_argb,
1294eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com               uint8* dst_argb, int dst_stride_argb,
1295eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com               int width, int height) {
129670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
129770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb,
129870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                      int width) = ARGBGrayRow_C;
1299eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com  if (!src_argb || !dst_argb || width <= 0 || height == 0) {
1300eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com    return -1;
1301eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com  }
1302eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com  if (height < 0) {
1303eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com    height = -height;
1304eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com    src_argb = src_argb + (height - 1) * src_stride_argb;
1305eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com    src_stride_argb = -src_stride_argb;
1306eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com  }
1307095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
130811a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (src_stride_argb == width * 4 &&
130911a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_argb == width * 4) {
1310095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1311095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1312095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb = dst_stride_argb = 0;
131311a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
1314eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com#if defined(HAS_ARGBGRAYROW_SSSE3)
1315eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
1316eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com      IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
1317eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
1318eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com    ARGBGrayRow = ARGBGrayRow_SSSE3;
1319eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com  }
132082375d6de22e6fdc09f9b74dfe036ec172c3af73fbarchard@google.com#elif defined(HAS_ARGBGRAYROW_NEON)
132182375d6de22e6fdc09f9b74dfe036ec172c3af73fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
132282375d6de22e6fdc09f9b74dfe036ec172c3af73fbarchard@google.com    ARGBGrayRow = ARGBGrayRow_NEON;
132382375d6de22e6fdc09f9b74dfe036ec172c3af73fbarchard@google.com  }
1324eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com#endif
1325eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com
132670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
1327eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com    ARGBGrayRow(src_argb, dst_argb, width);
1328eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com    src_argb += src_stride_argb;
1329eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com    dst_argb += dst_stride_argb;
1330eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com  }
1331eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com  return 0;
1332eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com}
1333eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com
1334ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com// Make a rectangle of ARGB gray scale.
1335fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1336ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.comint ARGBGray(uint8* dst_argb, int dst_stride_argb,
1337ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com             int dst_x, int dst_y,
1338ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com             int width, int height) {
133970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
134070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb,
134170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                      int width) = ARGBGrayRow_C;
134270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
1343ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com  if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
1344ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com    return -1;
1345ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com  }
1346095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
134711a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (dst_stride_argb == width * 4) {
1348095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1349095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1350095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    dst_stride_argb = 0;
135111a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
1352ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com#if defined(HAS_ARGBGRAYROW_SSSE3)
1353ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
1354ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
1355ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com    ARGBGrayRow = ARGBGrayRow_SSSE3;
1356ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com  }
135782375d6de22e6fdc09f9b74dfe036ec172c3af73fbarchard@google.com#elif defined(HAS_ARGBGRAYROW_NEON)
135882375d6de22e6fdc09f9b74dfe036ec172c3af73fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
135982375d6de22e6fdc09f9b74dfe036ec172c3af73fbarchard@google.com    ARGBGrayRow = ARGBGrayRow_NEON;
136082375d6de22e6fdc09f9b74dfe036ec172c3af73fbarchard@google.com  }
1361ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com#endif
136270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
1363eeac2903ef22110d475c50ef9bfd7826d3183a5efbarchard@google.com    ARGBGrayRow(dst, dst, width);
1364ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com    dst += dst_stride_argb;
1365ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com  }
1366ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com  return 0;
1367ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com}
1368ffaea7eee38e593a3e63553ffa90e554ba81fe30fbarchard@google.com
1369221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com// Make a rectangle of ARGB Sepia tone.
1370fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1371221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.comint ARGBSepia(uint8* dst_argb, int dst_stride_argb,
137281b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com              int dst_x, int dst_y, int width, int height) {
137370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
137470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBSepiaRow)(uint8* dst_argb, int width) = ARGBSepiaRow_C;
137570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
1376221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com  if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
1377221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com    return -1;
1378221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com  }
1379095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
138011a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (dst_stride_argb == width * 4) {
1381095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1382095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1383095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    dst_stride_argb = 0;
138411a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
1385221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com#if defined(HAS_ARGBSEPIAROW_SSSE3)
1386221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
1387221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
1388221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com    ARGBSepiaRow = ARGBSepiaRow_SSSE3;
1389221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com  }
1390c247625d7fabfa6217111c0b6a2f0f30b99da204fbarchard@google.com#elif defined(HAS_ARGBSEPIAROW_NEON)
1391c247625d7fabfa6217111c0b6a2f0f30b99da204fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
1392c247625d7fabfa6217111c0b6a2f0f30b99da204fbarchard@google.com    ARGBSepiaRow = ARGBSepiaRow_NEON;
1393c247625d7fabfa6217111c0b6a2f0f30b99da204fbarchard@google.com  }
1394221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com#endif
139570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
1396221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com    ARGBSepiaRow(dst, width);
1397221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com    dst += dst_stride_argb;
1398221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com  }
1399221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com  return 0;
1400221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com}
1401221e602f8a726f7457a0d521b5bcca05d89215bbfbarchard@google.com
1402c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com// Apply a 4x4 matrix to each ARGB pixel.
1403c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com// Note: Normally for shading, but can be used to swizzle or invert.
1404fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1405c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.comint ARGBColorMatrix(const uint8* src_argb, int src_stride_argb,
1406c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com                    uint8* dst_argb, int dst_stride_argb,
1407e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com                    const int8* matrix_argb,
1408c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com                    int width, int height) {
140970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
141070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBColorMatrixRow)(const uint8* src_argb, uint8* dst_argb,
141170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      const int8* matrix_argb, int width) = ARGBColorMatrixRow_C;
1412c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  if (!src_argb || !dst_argb || !matrix_argb || width <= 0 || height == 0) {
1413e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com    return -1;
1414e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  }
1415c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  if (height < 0) {
1416c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com    height = -height;
1417c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com    src_argb = src_argb + (height - 1) * src_stride_argb;
1418c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com    src_stride_argb = -src_stride_argb;
1419c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  }
1420095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
1421c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  if (src_stride_argb == width * 4 &&
1422c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com      dst_stride_argb == width * 4) {
1423095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1424095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1425095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb = dst_stride_argb = 0;
142611a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
1427e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com#if defined(HAS_ARGBCOLORMATRIXROW_SSSE3)
1428e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
1429e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
1430e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com    ARGBColorMatrixRow = ARGBColorMatrixRow_SSSE3;
1431e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  }
143262154e53a2820136f6a8cab8cc029622e3b100c1fbarchard@google.com#elif defined(HAS_ARGBCOLORMATRIXROW_NEON)
143362154e53a2820136f6a8cab8cc029622e3b100c1fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
143462154e53a2820136f6a8cab8cc029622e3b100c1fbarchard@google.com    ARGBColorMatrixRow = ARGBColorMatrixRow_NEON;
143562154e53a2820136f6a8cab8cc029622e3b100c1fbarchard@google.com  }
1436e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com#endif
143770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
1438c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com    ARGBColorMatrixRow(src_argb, dst_argb, matrix_argb, width);
1439c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com    src_argb += src_stride_argb;
1440c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com    dst_argb += dst_stride_argb;
1441e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  }
1442e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  return 0;
1443e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com}
14447c8e16f82ae94e09c9657276a0ceedafbf036315fbarchard@google.com
1445c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com// Apply a 4x3 matrix to each ARGB pixel.
1446c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com// Deprecated.
1447d9c9f37ac482ac958519e02db8b7c5b47bf1816afbarchard@google.comLIBYUV_API
1448c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.comint RGBColorMatrix(uint8* dst_argb, int dst_stride_argb,
1449c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com                   const int8* matrix_rgb,
1450c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com                   int dst_x, int dst_y, int width, int height) {
145170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  SIMD_ALIGNED(int8 matrix_argb[16]);
145270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
1453c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  if (!dst_argb || !matrix_rgb || width <= 0 || height <= 0 ||
1454c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com      dst_x < 0 || dst_y < 0) {
1455c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com    return -1;
1456c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  }
1457c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com
1458c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  // Convert 4x3 7 bit matrix to 4x4 6 bit matrix.
1459c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[0] = matrix_rgb[0] / 2;
1460c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[1] = matrix_rgb[1] / 2;
1461c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[2] = matrix_rgb[2] / 2;
1462c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[3] = matrix_rgb[3] / 2;
1463c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[4] = matrix_rgb[4] / 2;
1464c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[5] = matrix_rgb[5] / 2;
1465c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[6] = matrix_rgb[6] / 2;
1466c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[7] = matrix_rgb[7] / 2;
1467c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[8] = matrix_rgb[8] / 2;
1468c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[9] = matrix_rgb[9] / 2;
1469c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[10] = matrix_rgb[10] / 2;
1470c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[11] = matrix_rgb[11] / 2;
1471c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[14] = matrix_argb[13] = matrix_argb[12] = 0;
1472c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com  matrix_argb[15] = 64;  // 1.0
1473c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com
1474a1f5254a955c5c32484b56822596a4e3368e8eb7fbarchard@google.com  return ARGBColorMatrix((const uint8*)(dst), dst_stride_argb,
1475c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com                         dst, dst_stride_argb,
1476c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com                         &matrix_argb[0], width, height);
1477c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com}
1478c99db063e24d6180740d4adc29e84159096eef2dfbarchard@google.com
1479e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com// Apply a color table each ARGB pixel.
1480e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com// Table contains 256 ARGB values.
1481fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1482e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.comint ARGBColorTable(uint8* dst_argb, int dst_stride_argb,
1483e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com                   const uint8* table_argb,
1484e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com                   int dst_x, int dst_y, int width, int height) {
148570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
148670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBColorTableRow)(uint8* dst_argb, const uint8* table_argb,
148770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                            int width) = ARGBColorTableRow_C;
148870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
1489c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (!dst_argb || !table_argb || width <= 0 || height <= 0 ||
1490c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com      dst_x < 0 || dst_y < 0) {
1491e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com    return -1;
1492e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  }
1493095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
149411a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (dst_stride_argb == width * 4) {
1495095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1496095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1497095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    dst_stride_argb = 0;
149811a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
1499e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com#if defined(HAS_ARGBCOLORTABLEROW_X86)
1500e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  if (TestCpuFlag(kCpuHasX86)) {
1501e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com    ARGBColorTableRow = ARGBColorTableRow_X86;
1502e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  }
1503e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com#endif
150470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
1505e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com    ARGBColorTableRow(dst, table_argb, width);
1506e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com    dst += dst_stride_argb;
1507e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  }
1508e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com  return 0;
1509e442dc4c2a896e85419628e3b7d97c4dfbe71c9dfbarchard@google.com}
151081b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com
15115520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com// Apply a color table each ARGB pixel but preserve destination alpha.
15125520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com// Table contains 256 ARGB values.
15135520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.comLIBYUV_API
15145520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.comint RGBColorTable(uint8* dst_argb, int dst_stride_argb,
15155520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com                  const uint8* table_argb,
15165520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com                  int dst_x, int dst_y, int width, int height) {
151770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
151870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*RGBColorTableRow)(uint8* dst_argb, const uint8* table_argb,
151970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                           int width) = RGBColorTableRow_C;
152070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
15215520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com  if (!dst_argb || !table_argb || width <= 0 || height <= 0 ||
15225520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com      dst_x < 0 || dst_y < 0) {
15235520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com    return -1;
15245520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com  }
1525095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
15265520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com  if (dst_stride_argb == width * 4) {
1527095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1528095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1529095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    dst_stride_argb = 0;
15305520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com  }
15315520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com#if defined(HAS_RGBCOLORTABLEROW_X86)
15325520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com  if (TestCpuFlag(kCpuHasX86)) {
15335520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com    RGBColorTableRow = RGBColorTableRow_X86;
15345520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com  }
15355520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com#endif
153670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
15375520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com    RGBColorTableRow(dst, table_argb, width);
15385520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com    dst += dst_stride_argb;
15395520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com  }
15405520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com  return 0;
15415520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com}
15425520710ef7ce306357ab35c501f776b1fb0266e8fbarchard@google.com
154381b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com// ARGBQuantize is used to posterize art.
154481b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com// e.g. rgb / qvalue * qvalue + qvalue / 2
154581b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com// But the low levels implement efficiently with 3 parameters, and could be
154681b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com// used for other high level operations.
1547442b0ad0ac44825b9abbeacfa3940c32d0a5ca71fbarchard@google.com// dst_argb[0] = (b * scale >> 16) * interval_size + interval_offset;
1548442b0ad0ac44825b9abbeacfa3940c32d0a5ca71fbarchard@google.com// where scale is 1 / interval_size as a fixed point value.
154981b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com// The divide is replaces with a multiply by reciprocal fixed point multiply.
155081b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com// Caveat - although SSE2 saturates, the C function does not and should be used
155181b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com// with care if doing anything but quantization.
1552fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
155381b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.comint ARGBQuantize(uint8* dst_argb, int dst_stride_argb,
155481b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com                 int scale, int interval_size, int interval_offset,
155581b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com                 int dst_x, int dst_y, int width, int height) {
155670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
155770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBQuantizeRow)(uint8* dst_argb, int scale, int interval_size,
155870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                          int interval_offset, int width) = ARGBQuantizeRow_C;
155970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
156081b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com  if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0 ||
156181b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com      interval_size < 1 || interval_size > 255) {
156281b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com    return -1;
156381b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com  }
1564095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
156511a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (dst_stride_argb == width * 4) {
1566095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1567095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1568095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    dst_stride_argb = 0;
156911a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
157081b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com#if defined(HAS_ARGBQUANTIZEROW_SSE2)
157181b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4) &&
157281b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
157381b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com    ARGBQuantizeRow = ARGBQuantizeRow_SSE2;
157481b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com  }
1575ef60ab0db435c8e0bd1f63dc9aedb5ad880424a9fbarchard@google.com#elif defined(HAS_ARGBQUANTIZEROW_NEON)
1576ef60ab0db435c8e0bd1f63dc9aedb5ad880424a9fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
1577ef60ab0db435c8e0bd1f63dc9aedb5ad880424a9fbarchard@google.com    ARGBQuantizeRow = ARGBQuantizeRow_NEON;
1578ef60ab0db435c8e0bd1f63dc9aedb5ad880424a9fbarchard@google.com  }
157981b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com#endif
158070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
158181b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com    ARGBQuantizeRow(dst, scale, interval_size, interval_offset, width);
158281b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com    dst += dst_stride_argb;
158381b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com  }
158481b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com  return 0;
158581b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com}
158681b804e35c0346ee2fc5f8d11945eab9a88fdb10fbarchard@google.com
1587f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com// Computes table of cumulative sum for image where the value is the sum
158864ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com// of all values above and to the left of the entry. Used by ARGBBlur.
1589fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1590f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.comint ARGBComputeCumulativeSum(const uint8* src_argb, int src_stride_argb,
1591f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com                             int32* dst_cumsum, int dst_stride32_cumsum,
1592f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com                             int width, int height) {
159370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
159470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ComputeCumulativeSumRow)(const uint8* row, int32* cumsum,
159570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      const int32* previous_cumsum, int width) = ComputeCumulativeSumRow_C;
159670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int32* previous_cumsum = dst_cumsum;
1597f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  if (!dst_cumsum || !src_argb || width <= 0 || height <= 0) {
1598f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    return -1;
1599f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  }
1600f08ac6bb095348565b5259f2fab95f259ef47edefbarchard@google.com#if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
1601f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2)) {
1602f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
1603f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  }
1604f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com#endif
1605bac5f2c3ee12535817448e606c7a7704bbae8321fbarchard@google.com  memset(dst_cumsum, 0, width * sizeof(dst_cumsum[0]) * 4);  // 4 int per pixel.
160670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
1607f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    ComputeCumulativeSumRow(src_argb, dst_cumsum, previous_cumsum, width);
1608f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    previous_cumsum = dst_cumsum;
1609f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    dst_cumsum += dst_stride32_cumsum;
1610f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    src_argb += src_stride_argb;
1611f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  }
1612f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  return 0;
1613f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com}
1614f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com
1615f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com// Blur ARGB image.
1616133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com// Caller should allocate CumulativeSum table of width * height * 16 bytes
161764ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com// aligned to 16 byte boundary. height can be radius * 2 + 2 to save memory
1618133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com// as the buffer is treated as circular.
1619fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1620f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.comint ARGBBlur(const uint8* src_argb, int src_stride_argb,
1621f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com             uint8* dst_argb, int dst_stride_argb,
1622f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com             int32* dst_cumsum, int dst_stride32_cumsum,
1623f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com             int width, int height, int radius) {
162470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
162570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ComputeCumulativeSumRow)(const uint8 *row, int32 *cumsum,
162670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      const int32* previous_cumsum, int width) = ComputeCumulativeSumRow_C;
162770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*CumulativeSumToAverageRow)(const int32* topleft, const int32* botleft,
162870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      int width, int area, uint8* dst, int count) = CumulativeSumToAverageRow_C;
162970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int32* cumsum_bot_row;
163070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int32* max_cumsum_bot_row;
163170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int32* cumsum_top_row;
163270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com
1633c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (!src_argb || !dst_argb || width <= 0 || height == 0) {
1634c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    return -1;
1635c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  }
1636c4a70492c0f2f5b8da259046b951ae0a141bc60efbarchard@google.com  if (height < 0) {
1637c4a70492c0f2f5b8da259046b951ae0a141bc60efbarchard@google.com    height = -height;
1638c4a70492c0f2f5b8da259046b951ae0a141bc60efbarchard@google.com    src_argb = src_argb + (height - 1) * src_stride_argb;
1639c4a70492c0f2f5b8da259046b951ae0a141bc60efbarchard@google.com    src_stride_argb = -src_stride_argb;
1640c4a70492c0f2f5b8da259046b951ae0a141bc60efbarchard@google.com  }
16412732591d461755bcacda0b93074839acb239cc03fbarchard@google.com  if (radius > height) {
1642ba0eab9366a394d28fd3dce81fa9598af0f058d8fbarchard@google.com    radius = height;
16432732591d461755bcacda0b93074839acb239cc03fbarchard@google.com  }
1644ba0eab9366a394d28fd3dce81fa9598af0f058d8fbarchard@google.com  if (radius > (width / 2 - 1)) {
1645ba0eab9366a394d28fd3dce81fa9598af0f058d8fbarchard@google.com    radius = width / 2 - 1;
1646ba0eab9366a394d28fd3dce81fa9598af0f058d8fbarchard@google.com  }
1647ba0eab9366a394d28fd3dce81fa9598af0f058d8fbarchard@google.com  if (radius <= 0) {
1648ba0eab9366a394d28fd3dce81fa9598af0f058d8fbarchard@google.com    return -1;
16492732591d461755bcacda0b93074839acb239cc03fbarchard@google.com  }
1650f08ac6bb095348565b5259f2fab95f259ef47edefbarchard@google.com#if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
1651f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2)) {
1652f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com    ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
1653c4a70492c0f2f5b8da259046b951ae0a141bc60efbarchard@google.com    CumulativeSumToAverageRow = CumulativeSumToAverageRow_SSE2;
1654f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  }
1655f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com#endif
165664ce0ab544591b1e26ae6d276932cacdb8137071fbarchard@google.com  // Compute enough CumulativeSum for first row to be blurred. After this
1657133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com  // one row of CumulativeSum is updated at a time.
1658f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  ARGBComputeCumulativeSum(src_argb, src_stride_argb,
1659f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com                           dst_cumsum, dst_stride32_cumsum,
1660f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com                           width, radius);
1661f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com
1662f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com  src_argb = src_argb + radius * src_stride_argb;
166370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  cumsum_bot_row = &dst_cumsum[(radius - 1) * dst_stride32_cumsum];
1664f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com
166570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  max_cumsum_bot_row = &dst_cumsum[(radius * 2 + 2) * dst_stride32_cumsum];
166670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  cumsum_top_row = &dst_cumsum[0];
1667f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com
166870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
1669f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    int top_y = ((y - radius - 1) >= 0) ? (y - radius - 1) : 0;
1670f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    int bot_y = ((y + radius) < height) ? (y + radius) : (height - 1);
1671f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com    int area = radius * (bot_y - top_y);
167270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    int boxwidth = radius * 4;
167370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    int x;
167470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    int n;
1675f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com
1676133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com    // Increment cumsum_top_row pointer with circular buffer wrap around.
1677f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com    if (top_y) {
1678f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com      cumsum_top_row += dst_stride32_cumsum;
1679f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com      if (cumsum_top_row >= max_cumsum_bot_row) {
1680f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com        cumsum_top_row = dst_cumsum;
1681f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com      }
1682f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com    }
1683133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com    // Increment cumsum_bot_row pointer with circular buffer wrap around and
1684133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com    // then fill in a row of CumulativeSum.
1685f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com    if ((y + radius) < height) {
1686133adc46470722b24fdac30d7537d5009e61ef0cfbarchard@google.com      const int32* prev_cumsum_bot_row = cumsum_bot_row;
1687f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com      cumsum_bot_row += dst_stride32_cumsum;
1688f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com      if (cumsum_bot_row >= max_cumsum_bot_row) {
1689f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com        cumsum_bot_row = dst_cumsum;
1690f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com      }
1691f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com      ComputeCumulativeSumRow(src_argb, cumsum_bot_row, prev_cumsum_bot_row,
1692f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com                              width);
1693f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com      src_argb += src_stride_argb;
1694f38aefef4b66dc8ebe77ff37234be332731d47f6fbarchard@google.com    }
1695f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com
1696f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    // Left clipped.
1697f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    for (x = 0; x < radius + 1; ++x) {
1698c4a70492c0f2f5b8da259046b951ae0a141bc60efbarchard@google.com      CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row,
1699b99bcab7f77ebc724ed451c04e72b589a3d4acbbfbarchard@google.com                                boxwidth, area, &dst_argb[x * 4], 1);
1700f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com      area += (bot_y - top_y);
1701f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com      boxwidth += 4;
1702f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    }
1703f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com
1704f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    // Middle unclipped.
170570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    n = (width - 1) - radius - x + 1;
1706c4a70492c0f2f5b8da259046b951ae0a141bc60efbarchard@google.com    CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row,
1707b99bcab7f77ebc724ed451c04e72b589a3d4acbbfbarchard@google.com                              boxwidth, area, &dst_argb[x * 4], n);
1708f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com
1709f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    // Right clipped.
1710f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    for (x += n; x <= width - 1; ++x) {
1711f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com      area -= (bot_y - top_y);
1712f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com      boxwidth -= 4;
1713c4a70492c0f2f5b8da259046b951ae0a141bc60efbarchard@google.com      CumulativeSumToAverageRow(cumsum_top_row + (x - radius - 1) * 4,
1714b99bcab7f77ebc724ed451c04e72b589a3d4acbbfbarchard@google.com                                cumsum_bot_row + (x - radius - 1) * 4,
1715b99bcab7f77ebc724ed451c04e72b589a3d4acbbfbarchard@google.com                                boxwidth, area, &dst_argb[x * 4], 1);
1716f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    }
1717f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com    dst_argb += dst_stride_argb;
1718f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  }
1719f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com  return 0;
1720f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com}
1721f51e87912eebc959ac6b9d1ab44978e0e056ca74fbarchard@google.com
17220d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com// Multiply ARGB image by a specified ARGB value.
1723fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
1724c4500c9f7957f24021250a056f099300aa6f0476fbarchard@google.comint ARGBShade(const uint8* src_argb, int src_stride_argb,
1725c4500c9f7957f24021250a056f099300aa6f0476fbarchard@google.com              uint8* dst_argb, int dst_stride_argb,
1726c4500c9f7957f24021250a056f099300aa6f0476fbarchard@google.com              int width, int height, uint32 value) {
172770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
172870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBShadeRow)(const uint8* src_argb, uint8* dst_argb,
172970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                       int width, uint32 value) = ARGBShadeRow_C;
1730c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (!src_argb || !dst_argb || width <= 0 || height == 0 || value == 0u) {
1731c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    return -1;
1732c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  }
1733c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (height < 0) {
1734c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    height = -height;
1735c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    src_argb = src_argb + (height - 1) * src_stride_argb;
1736c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    src_stride_argb = -src_stride_argb;
1737c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  }
1738095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
173911a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (src_stride_argb == width * 4 &&
174011a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_argb == width * 4) {
1741095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1742095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1743095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb = dst_stride_argb = 0;
174411a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
1745f08ac6bb095348565b5259f2fab95f259ef47edefbarchard@google.com#if defined(HAS_ARGBSHADEROW_SSE2)
1746c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4) &&
1747c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com      IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
1748c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
1749c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    ARGBShadeRow = ARGBShadeRow_SSE2;
1750c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  }
1751b94b139e86635d40ed0d054bb66e30e6086ae7a3fbarchard@google.com#elif defined(HAS_ARGBSHADEROW_NEON)
1752b94b139e86635d40ed0d054bb66e30e6086ae7a3fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
1753b94b139e86635d40ed0d054bb66e30e6086ae7a3fbarchard@google.com    ARGBShadeRow = ARGBShadeRow_NEON;
1754b94b139e86635d40ed0d054bb66e30e6086ae7a3fbarchard@google.com  }
1755c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com#endif
1756c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com
175770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
1758c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    ARGBShadeRow(src_argb, dst_argb, width, value);
1759c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    src_argb += src_stride_argb;
1760c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com    dst_argb += dst_stride_argb;
1761c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  }
1762c4c578e327a9dbc9dafe113634612e9a349a8c1ffbarchard@google.com  return 0;
1763c4500c9f7957f24021250a056f099300aa6f0476fbarchard@google.com}
1764c4500c9f7957f24021250a056f099300aa6f0476fbarchard@google.com
17650d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com// Interpolate 2 ARGB images by specified amount (0 to 255).
1766fc7314e86bc7a1a88b38b815e881183521801ea9fbarchard@google.comLIBYUV_API
17670d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.comint ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
17680d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com                    const uint8* src_argb1, int src_stride_argb1,
17690d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com                    uint8* dst_argb, int dst_stride_argb,
17700d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com                    int width, int height, int interpolation) {
177170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
177270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
177370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                         ptrdiff_t src_stride, int dst_width,
177470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                         int source_y_fraction) = InterpolateRow_C;
17750d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com  if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
17760d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com    return -1;
17770d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com  }
17780d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com  // Negative height means invert the image.
17790d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com  if (height < 0) {
17800d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com    height = -height;
17810d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
17820d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com    dst_stride_argb = -dst_stride_argb;
17830d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com  }
1784095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
178511a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (src_stride_argb0 == width * 4 &&
178611a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      src_stride_argb1 == width * 4 &&
178711a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_argb == width * 4) {
1788095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1789095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1790095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
179111a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  }
1792b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com#if defined(HAS_INTERPOLATEROW_SSE2)
1793cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
1794b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com    InterpolateRow = InterpolateRow_Any_SSE2;
1795cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com    if (IS_ALIGNED(width, 4)) {
1796b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com      InterpolateRow = InterpolateRow_Unaligned_SSE2;
1797cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com      if (IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
1798cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com          IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
1799cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com          IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
1800b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com        InterpolateRow = InterpolateRow_SSE2;
1801cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com      }
1802cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com    }
18038811289be7ad257f16a6532aeec2cb5db331fa54fbarchard@google.com  }
18048811289be7ad257f16a6532aeec2cb5db331fa54fbarchard@google.com#endif
1805b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com#if defined(HAS_INTERPOLATEROW_SSSE3)
1806cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && width >= 4) {
1807b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com    InterpolateRow = InterpolateRow_Any_SSSE3;
1808cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com    if (IS_ALIGNED(width, 4)) {
1809b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com      InterpolateRow = InterpolateRow_Unaligned_SSSE3;
1810cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com      if (IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
1811cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com          IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
1812cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com          IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
1813b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com        InterpolateRow = InterpolateRow_SSSE3;
1814cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com      }
1815cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com    }
18160d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com  }
1817cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com#endif
18182154de414c1ac41fb434348964c728ccc077ffd3fbarchard@google.com#if defined(HAS_INTERPOLATEROW_AVX2)
18192154de414c1ac41fb434348964c728ccc077ffd3fbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
18202154de414c1ac41fb434348964c728ccc077ffd3fbarchard@google.com    InterpolateRow = InterpolateRow_Any_AVX2;
18212154de414c1ac41fb434348964c728ccc077ffd3fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
18222154de414c1ac41fb434348964c728ccc077ffd3fbarchard@google.com      InterpolateRow = InterpolateRow_AVX2;
18232154de414c1ac41fb434348964c728ccc077ffd3fbarchard@google.com    }
18242154de414c1ac41fb434348964c728ccc077ffd3fbarchard@google.com  }
18252154de414c1ac41fb434348964c728ccc077ffd3fbarchard@google.com#endif
1826b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com#if defined(HAS_INTERPOLATEROW_NEON)
1827cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 4) {
1828b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com    InterpolateRow = InterpolateRow_Any_NEON;
1829cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com    if (IS_ALIGNED(width, 4)) {
1830b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com      InterpolateRow = InterpolateRow_NEON;
1831cd6056c01cec8de0431390933537c9b8458bd472fbarchard@google.com    }
1832b5491759b45de37df781d4408a0c46abf6d4ae08fbarchard@google.com  }
18330d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com#endif
1834b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com#if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2)
1835b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com  if (TestCpuFlag(kCpuHasMIPS_DSPR2) && width >= 1 &&
1836b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com      IS_ALIGNED(src_argb0, 4) && IS_ALIGNED(src_stride_argb0, 4) &&
1837b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com      IS_ALIGNED(src_argb1, 4) && IS_ALIGNED(src_stride_argb1, 4) &&
1838b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com      IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
1839b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com    ScaleARGBFilterRows = InterpolateRow_MIPS_DSPR2;
1840b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com  }
1841b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com#endif
1842b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com
184370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
1844b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com    InterpolateRow(dst_argb, src_argb0, src_argb1 - src_argb0,
1845b911428afd3994f47e5780a80c876d05d1d4c590fbarchard@google.com                   width * 4, interpolation);
18460d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com    src_argb0 += src_stride_argb0;
18470d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com    src_argb1 += src_stride_argb1;
18480d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com    dst_argb += dst_stride_argb;
18490d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com  }
18500d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com  return 0;
18510d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com}
18520d95d4775792c26117d803adbab0bef1cee18052fbarchard@google.com
18531096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com// Shuffle ARGB channel order.  e.g. BGRA to ARGB.
18541096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.comLIBYUV_API
18551096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.comint ARGBShuffle(const uint8* src_bgra, int src_stride_bgra,
18561096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com                uint8* dst_argb, int dst_stride_argb,
18571096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com                const uint8* shuffler, int width, int height) {
185870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
185970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBShuffleRow)(const uint8* src_bgra, uint8* dst_argb,
186070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                         const uint8* shuffler, int pix) = ARGBShuffleRow_C;
18611096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  if (!src_bgra || !dst_argb ||
18621096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com      width <= 0 || height == 0) {
18631096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    return -1;
18641096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  }
18651096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  // Negative height means invert the image.
18661096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  if (height < 0) {
18671096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    height = -height;
18681096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    src_bgra = src_bgra + (height - 1) * src_stride_bgra;
18691096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    src_stride_bgra = -src_stride_bgra;
18701096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  }
1871095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
187211a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com  if (src_stride_bgra == width * 4 &&
187311a524362d9ee48fb30c1a2e6098a566199550f9fbarchard@google.com      dst_stride_argb == width * 4) {
1874095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
1875095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
1876095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_bgra = dst_stride_argb = 0;
18771096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  }
1878212a1a5000dbdd6bcff7ec355fa2bfa6a00183f8fbarchard@google.com#if defined(HAS_ARGBSHUFFLEROW_SSE2)
1879212a1a5000dbdd6bcff7ec355fa2bfa6a00183f8fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
1880212a1a5000dbdd6bcff7ec355fa2bfa6a00183f8fbarchard@google.com    ARGBShuffleRow = ARGBShuffleRow_Any_SSE2;
1881212a1a5000dbdd6bcff7ec355fa2bfa6a00183f8fbarchard@google.com    if (IS_ALIGNED(width, 4)) {
1882212a1a5000dbdd6bcff7ec355fa2bfa6a00183f8fbarchard@google.com      ARGBShuffleRow = ARGBShuffleRow_SSE2;
1883212a1a5000dbdd6bcff7ec355fa2bfa6a00183f8fbarchard@google.com    }
1884212a1a5000dbdd6bcff7ec355fa2bfa6a00183f8fbarchard@google.com  }
1885212a1a5000dbdd6bcff7ec355fa2bfa6a00183f8fbarchard@google.com#endif
18861096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com#if defined(HAS_ARGBSHUFFLEROW_SSSE3)
18871096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
18881096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    ARGBShuffleRow = ARGBShuffleRow_Any_SSSE3;
18891096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    if (IS_ALIGNED(width, 8)) {
18901096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com      ARGBShuffleRow = ARGBShuffleRow_Unaligned_SSSE3;
18911096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com      if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16) &&
18921096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com          IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
18931096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com        ARGBShuffleRow = ARGBShuffleRow_SSSE3;
18941096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com      }
18951096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    }
18961096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  }
18971096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com#endif
18981096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com#if defined(HAS_ARGBSHUFFLEROW_AVX2)
18991096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
19001096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    ARGBShuffleRow = ARGBShuffleRow_Any_AVX2;
19011096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    if (IS_ALIGNED(width, 16)) {
19021096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com      ARGBShuffleRow = ARGBShuffleRow_AVX2;
19031096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    }
19041096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  }
19051096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com#endif
19061096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com#if defined(HAS_ARGBSHUFFLEROW_NEON)
19071096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 4) {
19081096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    ARGBShuffleRow = ARGBShuffleRow_Any_NEON;
19091096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    if (IS_ALIGNED(width, 4)) {
19101096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com      ARGBShuffleRow = ARGBShuffleRow_NEON;
19111096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    }
19121096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  }
19131096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com#endif
19141096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com
191570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
19161096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    ARGBShuffleRow(src_bgra, dst_argb, shuffler, width);
19171096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    src_bgra += src_stride_bgra;
19181096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com    dst_argb += dst_stride_argb;
19191096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  }
19201096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com  return 0;
19211096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com}
19221096543eaa1e596a93ba5d3863e637dc489e32ccfbarchard@google.com
19231e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com// Sobel ARGB effect.
1924d9c9f37ac482ac958519e02db8b7c5b47bf1816afbarchard@google.comstatic int ARGBSobelize(const uint8* src_argb, int src_stride_argb,
1925d9c9f37ac482ac958519e02db8b7c5b47bf1816afbarchard@google.com                        uint8* dst_argb, int dst_stride_argb,
1926d9c9f37ac482ac958519e02db8b7c5b47bf1816afbarchard@google.com                        int width, int height,
1927d9c9f37ac482ac958519e02db8b7c5b47bf1816afbarchard@google.com                        void (*SobelRow)(const uint8* src_sobelx,
1928d9c9f37ac482ac958519e02db8b7c5b47bf1816afbarchard@google.com                                         const uint8* src_sobely,
1929d9c9f37ac482ac958519e02db8b7c5b47bf1816afbarchard@google.com                                         uint8* dst, int width)) {
193070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
193170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBToBayerRow)(const uint8* src_argb, uint8* dst_bayer,
193270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                         uint32 selector, int pix) = ARGBToBayerGGRow_C;
193370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*SobelYRow)(const uint8* src_y0, const uint8* src_y1,
193470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                    uint8* dst_sobely, int width) = SobelYRow_C;
193570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*SobelXRow)(const uint8* src_y0, const uint8* src_y1,
193670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                    const uint8* src_y2, uint8* dst_sobely, int width) =
193770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      SobelXRow_C;
19382732591d461755bcacda0b93074839acb239cc03fbarchard@google.com  const int kEdge = 16;  // Extra pixels at start of row for extrude/align.
1939b2a51d042d9ccc49de6180880e5fed3d07067d95fbarchard@google.com  if (!src_argb  || !dst_argb || width <= 0 || height == 0) {
19401e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com    return -1;
19411e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  }
19421e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  // Negative height means invert the image.
19431e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  if (height < 0) {
19441e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com    height = -height;
19451e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com    src_argb  = src_argb  + (height - 1) * src_stride_argb;
19461e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com    src_stride_argb = -src_stride_argb;
19471e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  }
1948e8df16bd7c44e58ea925c51ea82a34144ada3956fbarchard@google.com  // ARGBToBayer used to select G channel from ARGB.
194908b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com#if defined(HAS_ARGBTOBAYERGGROW_SSE2)
195008b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
195108b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com      IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
195208b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com    ARGBToBayerRow = ARGBToBayerGGRow_Any_SSE2;
195308b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
195408b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com      ARGBToBayerRow = ARGBToBayerGGRow_SSE2;
195508b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com    }
195608b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com  }
195708b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com#endif
1958e8df16bd7c44e58ea925c51ea82a34144ada3956fbarchard@google.com#if defined(HAS_ARGBTOBAYERROW_SSSE3)
1959e8df16bd7c44e58ea925c51ea82a34144ada3956fbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8 &&
1960e8df16bd7c44e58ea925c51ea82a34144ada3956fbarchard@google.com      IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
1961e8df16bd7c44e58ea925c51ea82a34144ada3956fbarchard@google.com    ARGBToBayerRow = ARGBToBayerRow_Any_SSSE3;
1962e8df16bd7c44e58ea925c51ea82a34144ada3956fbarchard@google.com    if (IS_ALIGNED(width, 8)) {
1963e8df16bd7c44e58ea925c51ea82a34144ada3956fbarchard@google.com      ARGBToBayerRow = ARGBToBayerRow_SSSE3;
19641e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com    }
19651e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  }
196608b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com#endif
196708b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com#if defined(HAS_ARGBTOBAYERGGROW_NEON)
1968c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
196908b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com    ARGBToBayerRow = ARGBToBayerGGRow_Any_NEON;
1970c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com    if (IS_ALIGNED(width, 8)) {
197108b24a4232600b2f9f21584f34f6868d8c15c215fbarchard@google.com      ARGBToBayerRow = ARGBToBayerGGRow_NEON;
19721e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com    }
19731e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  }
19741e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com#endif
1975092099507e44e9f429ec52956a20b28db634b910fbarchard@google.com#if defined(HAS_SOBELYROW_SSE2)
1976092099507e44e9f429ec52956a20b28db634b910fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2)) {
1977092099507e44e9f429ec52956a20b28db634b910fbarchard@google.com    SobelYRow = SobelYRow_SSE2;
19781e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  }
19791e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com#endif
1980c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com#if defined(HAS_SOBELYROW_NEON)
1981c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com  if (TestCpuFlag(kCpuHasNEON)) {
1982c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com    SobelYRow = SobelYRow_NEON;
1983c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com  }
1984c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com#endif
1985092099507e44e9f429ec52956a20b28db634b910fbarchard@google.com#if defined(HAS_SOBELXROW_SSE2)
1986092099507e44e9f429ec52956a20b28db634b910fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2)) {
1987092099507e44e9f429ec52956a20b28db634b910fbarchard@google.com    SobelXRow = SobelXRow_SSE2;
19881e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  }
19891e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com#endif
1990c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com#if defined(HAS_SOBELXROW_NEON)
1991c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com  if (TestCpuFlag(kCpuHasNEON)) {
1992c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com    SobelXRow = SobelXRow_NEON;
1993c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com  }
1994c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com#endif
199570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  {
199670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    // 3 rows with edges before/after.
199770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    const int kRowSize = (width + kEdge + 15) & ~15;
199870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    align_buffer_64(rows, kRowSize * 2 + (kEdge + kRowSize * 3 + kEdge));
199970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    uint8* row_sobelx = rows;
200070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    uint8* row_sobely = rows + kRowSize;
200170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    uint8* row_y = rows + kRowSize * 2;
200270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com
200370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    // Convert first row.
200470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    uint8* row_y0 = row_y + kEdge;
200570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    uint8* row_y1 = row_y0 + kRowSize;
200670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    uint8* row_y2 = row_y1 + kRowSize;
200770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    ARGBToBayerRow(src_argb, row_y0, 0x0d090501, width);
200870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    row_y0[-1] = row_y0[0];
200970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    memset(row_y0 + width, row_y0[width - 1], 16);  // Extrude 16 for valgrind.
201070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    ARGBToBayerRow(src_argb, row_y1, 0x0d090501, width);
201170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    row_y1[-1] = row_y1[0];
201270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    memset(row_y1 + width, row_y1[width - 1], 16);
201370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    memset(row_y2 + width, 0, 16);
201470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com
201570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    for (y = 0; y < height; ++y) {
201670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      // Convert next row of ARGB to Y.
201770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      if (y < (height - 1)) {
201870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com        src_argb += src_stride_argb;
201970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      }
202070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      ARGBToBayerRow(src_argb, row_y2, 0x0d090501, width);
202170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      row_y2[-1] = row_y2[0];
202270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      row_y2[width] = row_y2[width - 1];
202370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com
202470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      SobelXRow(row_y0 - 1, row_y1 - 1, row_y2 - 1, row_sobelx, width);
202570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      SobelYRow(row_y0 - 1, row_y2 - 1, row_sobely, width);
202670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      SobelRow(row_sobelx, row_sobely, dst_argb, width);
202770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com
202870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      // Cycle thru circular queue of 3 row_y buffers.
202970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      {
203070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com        uint8* row_yt = row_y0;
203170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com        row_y0 = row_y1;
203270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com        row_y1 = row_y2;
203370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com        row_y2 = row_yt;
203470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      }
20351e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com
203670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      dst_argb += dst_stride_argb;
203770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    }
203870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com    free_aligned_buffer_64(rows);
20391e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  }
20401e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com  return 0;
20411e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com}
20421e985bbc1607d52c6295c167de29cb2b736e9244fbarchard@google.com
20438be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com// Sobel ARGB effect.
2044610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.comLIBYUV_API
20458be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.comint ARGBSobel(const uint8* src_argb, int src_stride_argb,
20468be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com              uint8* dst_argb, int dst_stride_argb,
20478be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com              int width, int height) {
20488be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com  void (*SobelRow)(const uint8* src_sobelx, const uint8* src_sobely,
20498be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com                   uint8* dst_argb, int width) = SobelRow_C;
20508be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com#if defined(HAS_SOBELROW_SSE2)
20518be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
20528be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
20538be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com    SobelRow = SobelRow_SSE2;
2054610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com  }
2055610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com#endif
20568be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com#if defined(HAS_SOBELROW_NEON)
20578be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
20588be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com    SobelRow = SobelRow_NEON;
2059c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com  }
2060c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com#endif
20618be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com  return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
20628be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com                      width, height, SobelRow);
20638be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com}
20648be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com
20658be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com// Sobel ARGB effect with planar output.
20668be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.comLIBYUV_API
20678be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.comint ARGBSobelToPlane(const uint8* src_argb, int src_stride_argb,
20688be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com                     uint8* dst_y, int dst_stride_y,
20698be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com                     int width, int height) {
20708be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com  void (*SobelToPlaneRow)(const uint8* src_sobelx, const uint8* src_sobely,
20718be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com                          uint8* dst_, int width) = SobelToPlaneRow_C;
20728be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com#if defined(HAS_SOBELTOPLANEROW_SSE2)
20738be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
20748be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com      IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
20758be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com    SobelToPlaneRow = SobelToPlaneRow_SSE2;
2076610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com  }
2077610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com#endif
20788be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com#if defined(HAS_SOBELTOPLANEROW_NEON)
20798be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
20808be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com    SobelToPlaneRow = SobelToPlaneRow_NEON;
2081c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com  }
2082c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com#endif
20838be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com  return ARGBSobelize(src_argb, src_stride_argb, dst_y, dst_stride_y,
20848be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com                      width, height, SobelToPlaneRow);
20858be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com}
20868be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com
20878be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com// SobelXY ARGB effect.
20888be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com// Similar to Sobel, but also stores Sobel X in R and Sobel Y in B.  G = Sobel.
20898be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.comLIBYUV_API
20908be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.comint ARGBSobelXY(const uint8* src_argb, int src_stride_argb,
20918be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com                uint8* dst_argb, int dst_stride_argb,
20928be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com                int width, int height) {
2093610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com  void (*SobelXYRow)(const uint8* src_sobelx, const uint8* src_sobely,
2094c93a137671e2e281dfb8d32561fed95caacf608bfbarchard@google.com                     uint8* dst_argb, int width) = SobelXYRow_C;
2095610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com#if defined(HAS_SOBELXYROW_SSE2)
2096610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
2097610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
2098610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com    SobelXYRow = SobelXYRow_SSE2;
2099610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com  }
2100610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com#endif
2101c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com#if defined(HAS_SOBELXYROW_NEON)
2102c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
2103c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com    SobelXYRow = SobelXYRow_NEON;
2104c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com  }
2105c56a55fc7206a257eecc21969f94ab066dd80f2ffbarchard@google.com#endif
21068be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com  return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
21078be4b289c799356d84c68c4eb4b5403285096693fbarchard@google.com                      width, height, SobelXYRow);
2108610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com}
2109610e012d56b1cce420369b82335bd178f7e39397fbarchard@google.com
2110ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com// Apply a 4x4 polynomial to each ARGB pixel.
2111ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.comLIBYUV_API
2112ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.comint ARGBPolynomial(const uint8* src_argb, int src_stride_argb,
2113ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com                   uint8* dst_argb, int dst_stride_argb,
2114ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com                   const float* poly,
2115ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com                   int width, int height) {
211670bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
211770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBPolynomialRow)(const uint8* src_argb,
211870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                            uint8* dst_argb, const float* poly,
211970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com                            int width) = ARGBPolynomialRow_C;
21206f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com  if (!src_argb || !dst_argb || !poly || width <= 0 || height == 0) {
2121ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com    return -1;
2122ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com  }
21236f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com  // Negative height means invert the image.
21246f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com  if (height < 0) {
21256f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com    height = -height;
21266f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com    src_argb  = src_argb  + (height - 1) * src_stride_argb;
21276f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com    src_stride_argb = -src_stride_argb;
21286f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com  }
2129095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
2130095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  if (src_stride_argb == width * 4 &&
2131095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com      dst_stride_argb == width * 4) {
2132095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
2133095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
2134095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb = dst_stride_argb = 0;
2135ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com  }
2136ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com#if defined(HAS_ARGBPOLYNOMIALROW_SSE2)
2137c3c06ec328b5ea6c57012d3ca3ca442f22aad681fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 2)) {
2138ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com    ARGBPolynomialRow = ARGBPolynomialRow_SSE2;
2139ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com  }
2140ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com#endif
21416da76f3b34e80da2ffebff92d57fd08a93964942fbarchard@google.com#if defined(HAS_ARGBPOLYNOMIALROW_AVX2)
21422bbb64df2c997725ab1a024a0a21f1c63f895797fbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && TestCpuFlag(kCpuHasFMA3) &&
21432bbb64df2c997725ab1a024a0a21f1c63f895797fbarchard@google.com      IS_ALIGNED(width, 2)) {
21446da76f3b34e80da2ffebff92d57fd08a93964942fbarchard@google.com    ARGBPolynomialRow = ARGBPolynomialRow_AVX2;
21456da76f3b34e80da2ffebff92d57fd08a93964942fbarchard@google.com  }
21466da76f3b34e80da2ffebff92d57fd08a93964942fbarchard@google.com#endif
214770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com
214870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
2149ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com    ARGBPolynomialRow(src_argb, dst_argb, poly, width);
2150ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com    src_argb += src_stride_argb;
2151ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com    dst_argb += dst_stride_argb;
2152ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com  }
2153ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com  return 0;
2154ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com}
2155ae0091e3a74603b23c91f417c8ea023cd43e7e9cfbarchard@google.com
2156b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com// Apply a lumacolortable to each ARGB pixel.
2157b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.comLIBYUV_API
2158b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.comint ARGBLumaColorTable(const uint8* src_argb, int src_stride_argb,
2159b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com                       uint8* dst_argb, int dst_stride_argb,
2160b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com                       const uint8* luma,
2161b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com                       int width, int height) {
216270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
216370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBLumaColorTableRow)(const uint8* src_argb, uint8* dst_argb,
216470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      int width, const uint8* luma, const uint32 lumacoeff) =
216570bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      ARGBLumaColorTableRow_C;
21666f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com  if (!src_argb || !dst_argb || !luma || width <= 0 || height == 0) {
2167b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com    return -1;
2168b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com  }
21696f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com  // Negative height means invert the image.
21706f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com  if (height < 0) {
21716f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com    height = -height;
21726f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com    src_argb  = src_argb  + (height - 1) * src_stride_argb;
21736f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com    src_stride_argb = -src_stride_argb;
21746f7e514caa3e1c57ab1fd765151c52b9156113befbarchard@google.com  }
2175095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
2176095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  if (src_stride_argb == width * 4 &&
2177095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com      dst_stride_argb == width * 4) {
2178095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    width *= height;
2179095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    height = 1;
2180095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com    src_stride_argb = dst_stride_argb = 0;
2181b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com  }
2182b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com#if defined(HAS_ARGBLUMACOLORTABLEROW_SSSE3)
2183afd1d6b4ec467aef31f4605bc7c6be2b130036fcfbarchard@google.com  if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4)) {
2184b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com    ARGBLumaColorTableRow = ARGBLumaColorTableRow_SSSE3;
2185b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com  }
2186b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com#endif
218770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com
218870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
218911a0d48e45a7acd5aaf6b914caeee06432f06b6bfbarchard@google.com    ARGBLumaColorTableRow(src_argb, dst_argb, width, luma, 0x00264b0f);
2190b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com    src_argb += src_stride_argb;
2191b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com    dst_argb += dst_stride_argb;
2192b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com  }
2193b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com  return 0;
2194b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com}
2195b38b73d88cb63f41d943062aa579fc8c27544689fbarchard@google.com
2196adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com// Copy Alpha from one ARGB image to another.
21977f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.comLIBYUV_API
21987f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.comint ARGBCopyAlpha(const uint8* src_argb, int src_stride_argb,
21997f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com                  uint8* dst_argb, int dst_stride_argb,
22007f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com                  int width, int height) {
220170bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
220270bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBCopyAlphaRow)(const uint8* src_argb, uint8* dst_argb, int width) =
220370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      ARGBCopyAlphaRow_C;
2204adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  if (!src_argb || !dst_argb || width <= 0 || height == 0) {
22057f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com    return -1;
22067f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com  }
22077f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com  // Negative height means invert the image.
22087f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com  if (height < 0) {
22097f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com    height = -height;
22107f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com    src_argb = src_argb + (height - 1) * src_stride_argb;
22117f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com    src_stride_argb = -src_stride_argb;
22127f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com  }
2213095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
2214095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  if (src_stride_argb == width * 4 &&
2215095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com      dst_stride_argb == width * 4) {
2216adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    width *= height;
2217adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    height = 1;
2218adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    src_stride_argb = dst_stride_argb = 0;
22197f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com  }
22207f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com#if defined(HAS_ARGBCOPYALPHAROW_SSE2)
2221f6631bb814600f841f74a9d8a626b528be2fd8bbfbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) &&
2222f6631bb814600f841f74a9d8a626b528be2fd8bbfbarchard@google.com      IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
2223f6631bb814600f841f74a9d8a626b528be2fd8bbfbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16) &&
2224f6631bb814600f841f74a9d8a626b528be2fd8bbfbarchard@google.com      IS_ALIGNED(width, 8)) {
22257f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com    ARGBCopyAlphaRow = ARGBCopyAlphaRow_SSE2;
22267f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com  }
22277f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com#endif
2228f6631bb814600f841f74a9d8a626b528be2fd8bbfbarchard@google.com#if defined(HAS_ARGBCOPYALPHAROW_AVX2)
2229f6631bb814600f841f74a9d8a626b528be2fd8bbfbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 16)) {
2230f6631bb814600f841f74a9d8a626b528be2fd8bbfbarchard@google.com    ARGBCopyAlphaRow = ARGBCopyAlphaRow_AVX2;
2231f6631bb814600f841f74a9d8a626b528be2fd8bbfbarchard@google.com  }
2232f6631bb814600f841f74a9d8a626b528be2fd8bbfbarchard@google.com#endif
223370bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com
223470bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
22357f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com    ARGBCopyAlphaRow(src_argb, dst_argb, width);
22367f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com    src_argb += src_stride_argb;
22377f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com    dst_argb += dst_stride_argb;
22387f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com  }
22397f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com  return 0;
22407f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com}
22417f67961ec53f0ad12f827905fc4a4cc880f00931fbarchard@google.com
2242adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com// Copy a planar Y channel to the alpha channel of a destination ARGB image.
2243adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.comLIBYUV_API
2244adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.comint ARGBCopyYToAlpha(const uint8* src_y, int src_stride_y,
2245adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com                     uint8* dst_argb, int dst_stride_argb,
2246adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com                     int width, int height) {
224770bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  int y;
224870bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  void (*ARGBCopyYToAlphaRow)(const uint8* src_y, uint8* dst_argb, int width) =
224970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com      ARGBCopyYToAlphaRow_C;
2250adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  if (!src_y || !dst_argb || width <= 0 || height == 0) {
2251adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    return -1;
2252adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  }
2253adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  // Negative height means invert the image.
2254adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  if (height < 0) {
2255adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    height = -height;
2256adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    src_y = src_y + (height - 1) * src_stride_y;
2257adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    src_stride_y = -src_stride_y;
2258adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  }
2259095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  // Coalesce rows.
2260095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com  if (src_stride_y == width &&
2261095f33d870bdc68773db05e75484cc2ed1fe7550fbarchard@google.com      dst_stride_argb == width * 4) {
2262adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    width *= height;
2263adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    height = 1;
2264adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    src_stride_y = dst_stride_argb = 0;
2265adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  }
2266adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com#if defined(HAS_ARGBCOPYYTOALPHAROW_SSE2)
2267adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  if (TestCpuFlag(kCpuHasSSE2) &&
2268adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com      IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
2269adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com      IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16) &&
2270adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com      IS_ALIGNED(width, 8)) {
2271adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_SSE2;
2272adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  }
2273adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com#endif
2274adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com#if defined(HAS_ARGBCOPYYTOALPHAROW_AVX2)
2275adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 16)) {
2276adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_AVX2;
2277adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  }
2278adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com#endif
227970bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com
228070bc4995a08336ec0328226512e9395cba6c36eafbarchard@google.com  for (y = 0; y < height; ++y) {
2281adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    ARGBCopyYToAlphaRow(src_y, dst_argb, width);
2282adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    src_y += src_stride_y;
2283adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com    dst_argb += dst_stride_argb;
2284adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  }
2285adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com  return 0;
2286adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com}
2287adef267edfb3539cd773692d6fa4050ffd092f55fbarchard@google.com
2288fe5ff7ed5451496281697bda9cb85084c532926cfbarchard@google.com#ifdef __cplusplus
2289fe5ff7ed5451496281697bda9cb85084c532926cfbarchard@google.com}  // extern "C"
22903faa0f15cb5a585e20c93f816d326df9452dbd65fbarchard@google.com}  // namespace libyuv
2291fe5ff7ed5451496281697bda9cb85084c532926cfbarchard@google.com#endif
2292