Bug Summary

File:root/firefox-clang/media/libyuv/libyuv/source/convert.cc
Warning:line 1636, column 19
Addition of a null pointer (from variable 'src_y') and a probably nonzero integer value may result in undefined behavior

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name convert.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libyuv/libyuv/libyuv_libyuv -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libyuv/libyuv/libyuv_libyuv -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D _FILE_OFFSET_BITS=64 -D CHROMIUM_BUILD -D USE_LIBJPEG_TURBO=1 -D USE_NSS=1 -D ENABLE_ONE_CLICK_SIGNIN -D GTK_DISABLE_SINGLE_INCLUDES=1 -D _ISOC99_SOURCE=1 -D ENABLE_REMOTING=1 -D ENABLE_WEBRTC=1 -D ENABLE_CONFIGURATION_POLICY -D ENABLE_INPUT_SPEECH -D ENABLE_NOTIFICATIONS -D ENABLE_GPU=1 -D ENABLE_EGLIMAGE=1 -D USE_SKIA=1 -D ENABLE_TASK_MANAGER=1 -D ENABLE_WEB_INTENTS=1 -D ENABLE_EXTENSIONS=1 -D ENABLE_PLUGIN_INSTALLATION=1 -D ENABLE_PROTECTOR_SERVICE=1 -D ENABLE_SESSION_SERVICE=1 -D ENABLE_THEMES=1 -D ENABLE_BACKGROUND=1 -D ENABLE_AUTOMATION=1 -D ENABLE_PRINTING=1 -D ENABLE_CAPTIVE_PORTAL_DETECTION=1 -D LIBYUV_DISABLE_SME -D HAVE_JPEG -D __STDC_FORMAT_MACROS -D DYNAMIC_ANNOTATIONS_ENABLED=1 -D WTF_USE_DYNAMIC_ANNOTATIONS=1 -D _DEBUG -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/media/libyuv/libyuv -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/media/libyuv/libyuv/libyuv_libyuv -I /root/firefox-clang/media/libyuv/libyuv/include -I /root/firefox-clang/media/libyuv/libyuv -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c++ /root/firefox-clang/media/libyuv/libyuv/source/convert.cc
1/*
2 * Copyright 2011 The LibYuv Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "libyuv/convert.h"
12
13#include <limits.h>
14
15#include "libyuv/convert_from_argb.h"
16#include "libyuv/cpu_id.h"
17#include "libyuv/planar_functions.h"
18#include "libyuv/rotate.h"
19#include "libyuv/row.h"
20#include "libyuv/scale.h" // For ScalePlane()
21#include "libyuv/scale_row.h" // For FixedDiv
22#include "libyuv/scale_uv.h" // For UVScale()
23
24#ifdef __cplusplus202002L
25namespace libyuv {
26
27extern const struct ArgbConstants kArgbI601Constants;
28extern const struct ArgbConstants kArgbJPEGConstants;
29extern "C" {
30#endif
31
32// Subsample amount uses a shift.
33// v is value
34// a is amount to add to round up
35// s is shift to subsample down
36#define SUBSAMPLE(v, a, s)(v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
37static __inline int Abs(int v) {
38 return v >= 0 ? v : -v;
39}
40
41// Any I4xx To I420 format
42static int I4xxToI420(const uint8_t* src_y,
43 int src_stride_y,
44 const uint8_t* src_u,
45 int src_stride_u,
46 const uint8_t* src_v,
47 int src_stride_v,
48 uint8_t* dst_y,
49 int dst_stride_y,
50 uint8_t* dst_u,
51 int dst_stride_u,
52 uint8_t* dst_v,
53 int dst_stride_v,
54 int src_y_width,
55 int src_y_height,
56 int src_uv_width,
57 int src_uv_height) {
58 int r;
59 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v ||
60 src_y_width <= 0 || src_y_height == 0 || src_y_height == INT_MIN(-2147483647 -1) ||
61 src_uv_width <= 0 || src_uv_height == 0) {
62 return -1;
63 }
64 const int dst_y_width = src_y_width;
65 const int dst_y_height = Abs(src_y_height);
66 const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1)(dst_y_width < 0) ? (-((-dst_y_width + 1) >> 1)) : (
(dst_y_width + 1) >> 1)
;
67 const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1)(dst_y_height < 0) ? (-((-dst_y_height + 1) >> 1)) :
((dst_y_height + 1) >> 1)
;
68 if (dst_y) {
69 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, src_y_width,
70 src_y_height);
71 }
72 r = ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
73 dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
74 if (r != 0) {
75 return r;
76 }
77 r = ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
78 dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
79 return r;
80}
81
82// Copy I420 with optional vertical flipping using negative height.
83LIBYUV_API
84int I420Copy(const uint8_t* src_y,
85 int src_stride_y,
86 const uint8_t* src_u,
87 int src_stride_u,
88 const uint8_t* src_v,
89 int src_stride_v,
90 uint8_t* dst_y,
91 int dst_stride_y,
92 uint8_t* dst_u,
93 int dst_stride_u,
94 uint8_t* dst_v,
95 int dst_stride_v,
96 int width,
97 int height) {
98 int halfwidth = (width + 1) >> 1;
99 int halfheight = (height + 1) >> 1;
100 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
101 height == 0 || height == INT_MIN(-2147483647 -1)) {
102 return -1;
103 }
104 // Negative height means invert the image.
105 if (height < 0) {
106 height = -height;
107 halfheight = (height + 1) >> 1;
108 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
109 src_u = src_u + (ptrdiff_t)(halfheight - 1) * src_stride_u;
110 src_v = src_v + (ptrdiff_t)(halfheight - 1) * src_stride_v;
111 src_stride_y = -src_stride_y;
112 src_stride_u = -src_stride_u;
113 src_stride_v = -src_stride_v;
114 }
115
116 if (dst_y) {
117 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
118 }
119 // Copy UV planes.
120 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
121 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
122 return 0;
123}
124
125// Copy I010 with optional flipping.
126LIBYUV_API
127int I010Copy(const uint16_t* src_y,
128 int src_stride_y,
129 const uint16_t* src_u,
130 int src_stride_u,
131 const uint16_t* src_v,
132 int src_stride_v,
133 uint16_t* dst_y,
134 int dst_stride_y,
135 uint16_t* dst_u,
136 int dst_stride_u,
137 uint16_t* dst_v,
138 int dst_stride_v,
139 int width,
140 int height) {
141 int halfwidth = (width + 1) >> 1;
142 int halfheight = (height + 1) >> 1;
143 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
144 height == 0 || height == INT_MIN(-2147483647 -1)) {
145 return -1;
146 }
147 // Negative height means invert the image.
148 if (height < 0) {
149 height = -height;
150 halfheight = (height + 1) >> 1;
151 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
152 src_u = src_u + (ptrdiff_t)(halfheight - 1) * src_stride_u;
153 src_v = src_v + (ptrdiff_t)(halfheight - 1) * src_stride_v;
154 src_stride_y = -src_stride_y;
155 src_stride_u = -src_stride_u;
156 src_stride_v = -src_stride_v;
157 }
158
159 if (dst_y) {
160 CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
161 }
162 // Copy UV planes.
163 CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
164 CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
165 return 0;
166}
167
168static int Planar16bitTo8bit(const uint16_t* src_y,
169 int src_stride_y,
170 const uint16_t* src_u,
171 int src_stride_u,
172 const uint16_t* src_v,
173 int src_stride_v,
174 uint8_t* dst_y,
175 int dst_stride_y,
176 uint8_t* dst_u,
177 int dst_stride_u,
178 uint8_t* dst_v,
179 int dst_stride_v,
180 int width,
181 int height,
182 int subsample_x,
183 int subsample_y,
184 int depth) {
185 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
186 height == 0 || height == INT_MIN(-2147483647 -1)) {
187 return -1;
188 }
189 int uv_width = SUBSAMPLE(width, subsample_x, subsample_x)(width < 0) ? (-((-width + subsample_x) >> subsample_x
)) : ((width + subsample_x) >> subsample_x)
;
190 int uv_height = SUBSAMPLE(height, subsample_y, subsample_y)(height < 0) ? (-((-height + subsample_y) >> subsample_y
)) : ((height + subsample_y) >> subsample_y)
;
191 int scale = 1 << (24 - depth);
192 // Negative height means invert the image.
193 if (height < 0) {
194 height = -height;
195 uv_height = -uv_height;
196 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
197 src_u = src_u + (ptrdiff_t)(uv_height - 1) * src_stride_u;
198 src_v = src_v + (ptrdiff_t)(uv_height - 1) * src_stride_v;
199 src_stride_y = -src_stride_y;
200 src_stride_u = -src_stride_u;
201 src_stride_v = -src_stride_v;
202 }
203
204 // Convert Y plane.
205 if (dst_y) {
206 Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
207 height);
208 }
209 // Convert UV planes.
210 Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale, uv_width,
211 uv_height);
212 Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, scale, uv_width,
213 uv_height);
214 return 0;
215}
216
217static int I41xToI420(const uint16_t* src_y,
218 int src_stride_y,
219 const uint16_t* src_u,
220 int src_stride_u,
221 const uint16_t* src_v,
222 int src_stride_v,
223 uint8_t* dst_y,
224 int dst_stride_y,
225 uint8_t* dst_u,
226 int dst_stride_u,
227 uint8_t* dst_v,
228 int dst_stride_v,
229 int width,
230 int height,
231 int depth) {
232 int y;
233 const int scale = 1 << (24 - depth);
234 const int uv_width = SUBSAMPLE(width, 1, 1)(width < 0) ? (-((-width + 1) >> 1)) : ((width + 1) >>
1)
;
235 void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
236 int width) = Convert16To8Row_C;
237 void (*HalfWidthRow_16To8)(const uint16_t* src_uv, ptrdiff_t src_uv_stride,
238 uint8_t* dst_uv, int scale, int width) =
239 (width & 1) ? HalfWidthRow_16To8_Odd_C : HalfWidthRow_16To8_C;
240
241 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
242 height == 0 || height == INT_MIN(-2147483647 -1)) {
243 return -1;
244 }
245 // Negative height means invert the image.
246 if (height < 0) {
247 height = -height;
248 if (src_y) {
249 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
250 src_stride_y = -src_stride_y;
251 }
252 src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
253 src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
254 src_stride_u = -src_stride_u;
255 src_stride_v = -src_stride_v;
256 }
257
258#if defined(HAS_CONVERT16TO8ROW_NEON)
259 if (TestCpuFlag(kCpuHasNEON)) {
260 Convert16To8Row = Convert16To8Row_Any_NEON;
261 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
262 Convert16To8Row = Convert16To8Row_NEON;
263 }
264 }
265#endif
266#if defined(HAS_CONVERT16TO8ROW_SVE2)
267 if (TestCpuFlag(kCpuHasSVE2)) {
268 Convert16To8Row = Convert16To8Row_SVE2;
269 }
270#endif
271#if defined(HAS_CONVERT16TO8ROW_SME)
272 if (TestCpuFlag(kCpuHasSME)) {
273 Convert16To8Row = Convert16To8Row_SME;
274 }
275#endif
276#if defined(HAS_CONVERT16TO8ROW_SSSE3)
277 if (TestCpuFlag(kCpuHasSSSE3)) {
278 Convert16To8Row = Convert16To8Row_Any_SSSE3;
279 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
280 Convert16To8Row = Convert16To8Row_SSSE3;
281 }
282 }
283#endif
284#if defined(HAS_CONVERT16TO8ROW_AVX2)
285 if (TestCpuFlag(kCpuHasAVX2)) {
286 Convert16To8Row = Convert16To8Row_Any_AVX2;
287 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
288 Convert16To8Row = Convert16To8Row_AVX2;
289 }
290 }
291#endif
292#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
293 if (TestCpuFlag(kCpuHasAVX512BW)) {
294 Convert16To8Row = Convert16To8Row_Any_AVX512BW;
295 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
296 Convert16To8Row = Convert16To8Row_AVX512BW;
297 }
298 }
299#endif
300#if defined(HAS_CONVERT16TO8ROW_RVV)
301 if (TestCpuFlag(kCpuHasRVV)) {
302 Convert16To8Row = Convert16To8Row_RVV;
303 }
304#endif
305
306 if (IS_ALIGNED(width, 2)(!((uintptr_t)(width) & ((2) - 1)))) {
307#if defined(HAS_HALFWIDTHROW_16TO8_NEON)
308 if (TestCpuFlag(kCpuHasNEON)) {
309 HalfWidthRow_16To8 = HalfWidthRow_16To8_Any_NEON;
310 if (IS_ALIGNED(uv_width, 8)(!((uintptr_t)(uv_width) & ((8) - 1)))) {
311 HalfWidthRow_16To8 = HalfWidthRow_16To8_NEON;
312 }
313 }
314#endif
315#if defined(HAS_HALFWIDTHROW_16TO8_SVE2)
316 if (TestCpuFlag(kCpuHasSVE2)) {
317 HalfWidthRow_16To8 = HalfWidthRow_16To8_SVE2;
318 }
319#endif
320#if defined(HAS_HALFWIDTHROW_16TO8_SME)
321 if (TestCpuFlag(kCpuHasSME)) {
322 HalfWidthRow_16To8 = HalfWidthRow_16To8_SME;
323 }
324#endif
325#if defined(HAS_HALFWIDTHROW_16TO8_SSSE3)
326 if (TestCpuFlag(kCpuHasSSSE3)) {
327 HalfWidthRow_16To8 = HalfWidthRow_16To8_Any_SSSE3;
328 if (IS_ALIGNED(uv_width, 8)(!((uintptr_t)(uv_width) & ((8) - 1)))) {
329 HalfWidthRow_16To8 = HalfWidthRow_16To8_SSSE3;
330 }
331 }
332#endif
333#if defined(HAS_HALFWIDTHROW_16TO8_AVX2)
334 if (TestCpuFlag(kCpuHasAVX2)) {
335 HalfWidthRow_16To8 = HalfWidthRow_16To8_Any_AVX2;
336 if (IS_ALIGNED(uv_width, 16)(!((uintptr_t)(uv_width) & ((16) - 1)))) {
337 HalfWidthRow_16To8 = HalfWidthRow_16To8_AVX2;
338 }
339 }
340#endif
341#if defined(HAS_HALFWIDTHROW_16TO8_AVX512BW)
342 if (TestCpuFlag(kCpuHasAVX512BW)) {
343 HalfWidthRow_16To8 = HalfWidthRow_16To8_Any_AVX512BW;
344 if (IS_ALIGNED(uv_width, 32)(!((uintptr_t)(uv_width) & ((32) - 1)))) {
345 HalfWidthRow_16To8 = HalfWidthRow_16To8_AVX512BW;
346 }
347 }
348#endif
349#if defined(HAS_HALFWIDTHROW_16TO8_RVV)
350 if (TestCpuFlag(kCpuHasRVV)) {
351 HalfWidthRow_16To8 = HalfWidthRow_16To8_RVV;
352 }
353#endif
354 }
355
356 for (y = 0; y < height - 1; y += 2) {
357 HalfWidthRow_16To8(src_u, src_stride_u, dst_u, scale, uv_width);
358 HalfWidthRow_16To8(src_v, src_stride_v, dst_v, scale, uv_width);
359 if (dst_y) {
360 Convert16To8Row(src_y, dst_y, scale, width);
361 Convert16To8Row(src_y + src_stride_y, dst_y + dst_stride_y, scale, width);
362 src_y += src_stride_y * 2;
363 dst_y += dst_stride_y * 2;
364 }
365 src_u += src_stride_u * 2;
366 src_v += src_stride_v * 2;
367 dst_u += dst_stride_u;
368 dst_v += dst_stride_v;
369 }
370 if (height & 1) {
371 HalfWidthRow_16To8(src_u, 0, dst_u, scale, uv_width);
372 HalfWidthRow_16To8(src_v, 0, dst_v, scale, uv_width);
373 if (dst_y) {
374 Convert16To8Row(src_y, dst_y, scale, width);
375 }
376 }
377 return 0;
378}
379
380static int I21xToI420(const uint16_t* src_y,
381 int src_stride_y,
382 const uint16_t* src_u,
383 int src_stride_u,
384 const uint16_t* src_v,
385 int src_stride_v,
386 uint8_t* dst_y,
387 int dst_stride_y,
388 uint8_t* dst_u,
389 int dst_stride_u,
390 uint8_t* dst_v,
391 int dst_stride_v,
392 int width,
393 int height,
394 int depth) {
395 int y;
396 const int scale = 1 << (24 - depth);
397 const int uv_width = SUBSAMPLE(width, 1, 1)(width < 0) ? (-((-width + 1) >> 1)) : ((width + 1) >>
1)
;
398 void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
399 int width) = Convert16To8Row_C;
400 void (*HalfRow_16To8)(const uint16_t* src_uv, ptrdiff_t src_uv_stride,
401 uint8_t* dst_uv, int scale, int width) =
402 HalfRow_16To8_C;
403
404 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
405 height == 0 || height == INT_MIN(-2147483647 -1)) {
406 return -1;
407 }
408 // Negative height means invert the image.
409 if (height < 0) {
410 height = -height;
411 if (src_y) {
412 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
413 src_stride_y = -src_stride_y;
414 }
415 src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
416 src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
417 src_stride_u = -src_stride_u;
418 src_stride_v = -src_stride_v;
419 }
420
421#if defined(HAS_CONVERT16TO8ROW_NEON)
422 if (TestCpuFlag(kCpuHasNEON)) {
423 Convert16To8Row = Convert16To8Row_Any_NEON;
424 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
425 Convert16To8Row = Convert16To8Row_NEON;
426 }
427 }
428#endif
429#if defined(HAS_CONVERT16TO8ROW_SVE2)
430 if (TestCpuFlag(kCpuHasSVE2)) {
431 Convert16To8Row = Convert16To8Row_SVE2;
432 }
433#endif
434#if defined(HAS_CONVERT16TO8ROW_SME)
435 if (TestCpuFlag(kCpuHasSME)) {
436 Convert16To8Row = Convert16To8Row_SME;
437 }
438#endif
439#if defined(HAS_CONVERT16TO8ROW_SSSE3)
440 if (TestCpuFlag(kCpuHasSSSE3)) {
441 Convert16To8Row = Convert16To8Row_Any_SSSE3;
442 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
443 Convert16To8Row = Convert16To8Row_SSSE3;
444 }
445 }
446#endif
447#if defined(HAS_CONVERT16TO8ROW_AVX2)
448 if (TestCpuFlag(kCpuHasAVX2)) {
449 Convert16To8Row = Convert16To8Row_Any_AVX2;
450 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
451 Convert16To8Row = Convert16To8Row_AVX2;
452 }
453 }
454#endif
455#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
456 if (TestCpuFlag(kCpuHasAVX512BW)) {
457 Convert16To8Row = Convert16To8Row_Any_AVX512BW;
458 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
459 Convert16To8Row = Convert16To8Row_AVX512BW;
460 }
461 }
462#endif
463#if defined(HAS_CONVERT16TO8ROW_RVV)
464 if (TestCpuFlag(kCpuHasRVV)) {
465 Convert16To8Row = Convert16To8Row_RVV;
466 }
467#endif
468
469#if defined(HAS_HALFROW_16TO8_NEON)
470 if (TestCpuFlag(kCpuHasNEON)) {
471 HalfRow_16To8 = HalfRow_16To8_Any_NEON;
472 if (IS_ALIGNED(uv_width, 16)(!((uintptr_t)(uv_width) & ((16) - 1)))) {
473 HalfRow_16To8 = HalfRow_16To8_NEON;
474 }
475 }
476#endif
477#if defined(HAS_HALFROW_16TO8_SVE2)
478 if (TestCpuFlag(kCpuHasSVE2)) {
479 HalfRow_16To8 = HalfRow_16To8_SVE2;
480 }
481#endif
482#if defined(HAS_HALFROW_16TO8_SME)
483 if (TestCpuFlag(kCpuHasSME)) {
484 HalfRow_16To8 = HalfRow_16To8_SME;
485 }
486#endif
487#if defined(HAS_HALFROW_16TO8_SSSE3)
488 if (TestCpuFlag(kCpuHasSSSE3)) {
489 HalfRow_16To8 = HalfRow_16To8_Any_SSSE3;
490 if (IS_ALIGNED(uv_width, 16)(!((uintptr_t)(uv_width) & ((16) - 1)))) {
491 HalfRow_16To8 = HalfRow_16To8_SSSE3;
492 }
493 }
494#endif
495#if defined(HAS_HALFROW_16TO8_AVX2)
496 if (TestCpuFlag(kCpuHasAVX2)) {
497 HalfRow_16To8 = HalfRow_16To8_Any_AVX2;
498 if (IS_ALIGNED(uv_width, 32)(!((uintptr_t)(uv_width) & ((32) - 1)))) {
499 HalfRow_16To8 = HalfRow_16To8_AVX2;
500 }
501 }
502#endif
503#if defined(HAS_HALFROW_16TO8_AVX512BW)
504 if (TestCpuFlag(kCpuHasAVX512BW)) {
505 HalfRow_16To8 = HalfRow_16To8_Any_AVX512BW;
506 if (IS_ALIGNED(uv_width, 64)(!((uintptr_t)(uv_width) & ((64) - 1)))) {
507 HalfRow_16To8 = HalfRow_16To8_AVX512BW;
508 }
509 }
510#endif
511#if defined(HAS_HALFROW_16TO8_RVV)
512 if (TestCpuFlag(kCpuHasRVV)) {
513 HalfRow_16To8 = HalfRow_16To8_RVV;
514 }
515#endif
516
517 for (y = 0; y < height - 1; y += 2) {
518 HalfRow_16To8(src_u, src_stride_u, dst_u, scale, uv_width);
519 HalfRow_16To8(src_v, src_stride_v, dst_v, scale, uv_width);
520 if (dst_y) {
521 Convert16To8Row(src_y, dst_y, scale, width);
522 Convert16To8Row(src_y + src_stride_y, dst_y + dst_stride_y, scale, width);
523 src_y += src_stride_y * 2;
524 dst_y += dst_stride_y * 2;
525 }
526 src_u += src_stride_u * 2;
527 src_v += src_stride_v * 2;
528 dst_u += dst_stride_u;
529 dst_v += dst_stride_v;
530 }
531 if (height & 1) {
532 HalfRow_16To8(src_u, 0, dst_u, scale, uv_width);
533 HalfRow_16To8(src_v, 0, dst_v, scale, uv_width);
534 if (dst_y) {
535 Convert16To8Row(src_y, dst_y, scale, width);
536 }
537 }
538 return 0;
539}
540
541// Convert 10 bit YUV to 8 bit.
542LIBYUV_API
543int I010ToI420(const uint16_t* src_y,
544 int src_stride_y,
545 const uint16_t* src_u,
546 int src_stride_u,
547 const uint16_t* src_v,
548 int src_stride_v,
549 uint8_t* dst_y,
550 int dst_stride_y,
551 uint8_t* dst_u,
552 int dst_stride_u,
553 uint8_t* dst_v,
554 int dst_stride_v,
555 int width,
556 int height) {
557 return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
558 src_stride_v, dst_y, dst_stride_y, dst_u,
559 dst_stride_u, dst_v, dst_stride_v, width, height, 1,
560 1, 10);
561}
562
563LIBYUV_API
564int I210ToI420(const uint16_t* src_y,
565 int src_stride_y,
566 const uint16_t* src_u,
567 int src_stride_u,
568 const uint16_t* src_v,
569 int src_stride_v,
570 uint8_t* dst_y,
571 int dst_stride_y,
572 uint8_t* dst_u,
573 int dst_stride_u,
574 uint8_t* dst_v,
575 int dst_stride_v,
576 int width,
577 int height) {
578 return I21xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
579 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
580 dst_v, dst_stride_v, width, height, 10);
581}
582
583LIBYUV_API
584int I210ToI422(const uint16_t* src_y,
585 int src_stride_y,
586 const uint16_t* src_u,
587 int src_stride_u,
588 const uint16_t* src_v,
589 int src_stride_v,
590 uint8_t* dst_y,
591 int dst_stride_y,
592 uint8_t* dst_u,
593 int dst_stride_u,
594 uint8_t* dst_v,
595 int dst_stride_v,
596 int width,
597 int height) {
598 return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
599 src_stride_v, dst_y, dst_stride_y, dst_u,
600 dst_stride_u, dst_v, dst_stride_v, width, height, 1,
601 0, 10);
602}
603
604LIBYUV_API
605int I410ToI420(const uint16_t* src_y,
606 int src_stride_y,
607 const uint16_t* src_u,
608 int src_stride_u,
609 const uint16_t* src_v,
610 int src_stride_v,
611 uint8_t* dst_y,
612 int dst_stride_y,
613 uint8_t* dst_u,
614 int dst_stride_u,
615 uint8_t* dst_v,
616 int dst_stride_v,
617 int width,
618 int height) {
619 return I41xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
620 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
621 dst_v, dst_stride_v, width, height, 10);
622}
623
624LIBYUV_API
625int I410ToI444(const uint16_t* src_y,
626 int src_stride_y,
627 const uint16_t* src_u,
628 int src_stride_u,
629 const uint16_t* src_v,
630 int src_stride_v,
631 uint8_t* dst_y,
632 int dst_stride_y,
633 uint8_t* dst_u,
634 int dst_stride_u,
635 uint8_t* dst_v,
636 int dst_stride_v,
637 int width,
638 int height) {
639 return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
640 src_stride_v, dst_y, dst_stride_y, dst_u,
641 dst_stride_u, dst_v, dst_stride_v, width, height, 0,
642 0, 10);
643}
644
645LIBYUV_API
646int I012ToI420(const uint16_t* src_y,
647 int src_stride_y,
648 const uint16_t* src_u,
649 int src_stride_u,
650 const uint16_t* src_v,
651 int src_stride_v,
652 uint8_t* dst_y,
653 int dst_stride_y,
654 uint8_t* dst_u,
655 int dst_stride_u,
656 uint8_t* dst_v,
657 int dst_stride_v,
658 int width,
659 int height) {
660 return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
661 src_stride_v, dst_y, dst_stride_y, dst_u,
662 dst_stride_u, dst_v, dst_stride_v, width, height, 1,
663 1, 12);
664}
665
666LIBYUV_API
667int I212ToI422(const uint16_t* src_y,
668 int src_stride_y,
669 const uint16_t* src_u,
670 int src_stride_u,
671 const uint16_t* src_v,
672 int src_stride_v,
673 uint8_t* dst_y,
674 int dst_stride_y,
675 uint8_t* dst_u,
676 int dst_stride_u,
677 uint8_t* dst_v,
678 int dst_stride_v,
679 int width,
680 int height) {
681 return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
682 src_stride_v, dst_y, dst_stride_y, dst_u,
683 dst_stride_u, dst_v, dst_stride_v, width, height, 1,
684 0, 12);
685}
686
687LIBYUV_API
688int I212ToI420(const uint16_t* src_y,
689 int src_stride_y,
690 const uint16_t* src_u,
691 int src_stride_u,
692 const uint16_t* src_v,
693 int src_stride_v,
694 uint8_t* dst_y,
695 int dst_stride_y,
696 uint8_t* dst_u,
697 int dst_stride_u,
698 uint8_t* dst_v,
699 int dst_stride_v,
700 int width,
701 int height) {
702 return I21xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
703 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
704 dst_v, dst_stride_v, width, height, 12);
705}
706
707LIBYUV_API
708int I412ToI444(const uint16_t* src_y,
709 int src_stride_y,
710 const uint16_t* src_u,
711 int src_stride_u,
712 const uint16_t* src_v,
713 int src_stride_v,
714 uint8_t* dst_y,
715 int dst_stride_y,
716 uint8_t* dst_u,
717 int dst_stride_u,
718 uint8_t* dst_v,
719 int dst_stride_v,
720 int width,
721 int height) {
722 return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
723 src_stride_v, dst_y, dst_stride_y, dst_u,
724 dst_stride_u, dst_v, dst_stride_v, width, height, 0,
725 0, 12);
726}
727
728LIBYUV_API
729int I412ToI420(const uint16_t* src_y,
730 int src_stride_y,
731 const uint16_t* src_u,
732 int src_stride_u,
733 const uint16_t* src_v,
734 int src_stride_v,
735 uint8_t* dst_y,
736 int dst_stride_y,
737 uint8_t* dst_u,
738 int dst_stride_u,
739 uint8_t* dst_v,
740 int dst_stride_v,
741 int width,
742 int height) {
743 return I41xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
744 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
745 dst_v, dst_stride_v, width, height, 12);
746}
747
748// Any Ix10 To I010 format
749static int Ix10ToI010(const uint16_t* src_y,
750 int src_stride_y,
751 const uint16_t* src_u,
752 int src_stride_u,
753 const uint16_t* src_v,
754 int src_stride_v,
755 uint16_t* dst_y,
756 int dst_stride_y,
757 uint16_t* dst_u,
758 int dst_stride_u,
759 uint16_t* dst_v,
760 int dst_stride_v,
761 int width,
762 int height,
763 int subsample_x,
764 int subsample_y) {
765 int r;
766 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
767 height == 0 || height == INT_MIN(-2147483647 -1)) {
768 return -1;
769 }
770 const int dst_y_width = width;
771 const int dst_y_height = Abs(height);
772 const int src_uv_width = SUBSAMPLE(width, subsample_x, subsample_x)(width < 0) ? (-((-width + subsample_x) >> subsample_x
)) : ((width + subsample_x) >> subsample_x)
;
773 const int src_uv_height = SUBSAMPLE(height, subsample_y, subsample_y)(height < 0) ? (-((-height + subsample_y) >> subsample_y
)) : ((height + subsample_y) >> subsample_y)
;
774 const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1)(dst_y_width < 0) ? (-((-dst_y_width + 1) >> 1)) : (
(dst_y_width + 1) >> 1)
;
775 const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1)(dst_y_height < 0) ? (-((-dst_y_height + 1) >> 1)) :
((dst_y_height + 1) >> 1)
;
776 if (dst_y) {
777 CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
778 }
779 r = ScalePlane_12(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
780 dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
781 if (r != 0) {
782 return r;
783 }
784 r = ScalePlane_12(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
785 dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
786 return r;
787}
788
789LIBYUV_API
790int I410ToI010(const uint16_t* src_y,
791 int src_stride_y,
792 const uint16_t* src_u,
793 int src_stride_u,
794 const uint16_t* src_v,
795 int src_stride_v,
796 uint16_t* dst_y,
797 int dst_stride_y,
798 uint16_t* dst_u,
799 int dst_stride_u,
800 uint16_t* dst_v,
801 int dst_stride_v,
802 int width,
803 int height) {
804 return Ix10ToI010(src_y, src_stride_y, src_u, src_stride_u, src_v,
805 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
806 dst_v, dst_stride_v, width, height, 0, 0);
807}
808
809LIBYUV_API
810int I210ToI010(const uint16_t* src_y,
811 int src_stride_y,
812 const uint16_t* src_u,
813 int src_stride_u,
814 const uint16_t* src_v,
815 int src_stride_v,
816 uint16_t* dst_y,
817 int dst_stride_y,
818 uint16_t* dst_u,
819 int dst_stride_u,
820 uint16_t* dst_v,
821 int dst_stride_v,
822 int width,
823 int height) {
824 return Ix10ToI010(src_y, src_stride_y, src_u, src_stride_u, src_v,
825 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
826 dst_v, dst_stride_v, width, height, 1, 0);
827}
828
829// Any I[420]1[02] to P[420]1[02] format
830static int IxxxToPxxx(const uint16_t* src_y,
831 int src_stride_y,
832 const uint16_t* src_u,
833 int src_stride_u,
834 const uint16_t* src_v,
835 int src_stride_v,
836 uint16_t* dst_y,
837 int dst_stride_y,
838 uint16_t* dst_uv,
839 int dst_stride_uv,
840 int width,
841 int height,
842 int subsample_x,
843 int subsample_y,
844 int depth) {
845 if (width <= 0 || height == 0 || height == INT_MIN(-2147483647 -1)) {
846 return -1;
847 }
848 const int uv_width = SUBSAMPLE(width, subsample_x, subsample_x)(width < 0) ? (-((-width + subsample_x) >> subsample_x
)) : ((width + subsample_x) >> subsample_x)
;
849 const int uv_height = SUBSAMPLE(height, subsample_y, subsample_y)(height < 0) ? (-((-height + subsample_y) >> subsample_y
)) : ((height + subsample_y) >> subsample_y)
;
850
851 ConvertToMSBPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
852 depth);
853 MergeUVPlane_16(src_u, src_stride_u, src_v, src_stride_v, dst_uv,
854 dst_stride_uv, uv_width, uv_height, depth);
855 return 0;
856}
857
858LIBYUV_API
859int I010ToP010(const uint16_t* src_y,
860 int src_stride_y,
861 const uint16_t* src_u,
862 int src_stride_u,
863 const uint16_t* src_v,
864 int src_stride_v,
865 uint16_t* dst_y,
866 int dst_stride_y,
867 uint16_t* dst_uv,
868 int dst_stride_uv,
869 int width,
870 int height) {
871 return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
872 src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
873 width, height, 1, 1, 10);
874}
875
876LIBYUV_API
877int I010ToNV12(const uint16_t* src_y,
878 int src_stride_y,
879 const uint16_t* src_u,
880 int src_stride_u,
881 const uint16_t* src_v,
882 int src_stride_v,
883 uint8_t* dst_y,
884 int dst_stride_y,
885 uint8_t* dst_uv,
886 int dst_stride_uv,
887 int width,
888 int height) {
889 int y;
890 int halfwidth = (width + 1) >> 1;
891 int halfheight = (height + 1) >> 1;
892 const int scale = 16385; // 16384 for 10 bits
893 void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
894 int width) = Convert16To8Row_C;
895 void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
896 uint8_t* dst_uv, int width) = MergeUVRow_C;
897 if ((!src_y && dst_y) || !src_u || !src_v || !dst_uv || width <= 0 ||
898 height == 0 || height == INT_MIN(-2147483647 -1)) {
899 return -1;
900 }
901 // Negative height means invert the image.
902 if (height < 0) {
903 height = -height;
904 halfheight = (height + 1) >> 1;
905 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
906 src_u = src_u + (ptrdiff_t)(halfheight - 1) * src_stride_u;
907 src_v = src_v + (ptrdiff_t)(halfheight - 1) * src_stride_v;
908 src_stride_y = -src_stride_y;
909 src_stride_u = -src_stride_u;
910 src_stride_v = -src_stride_v;
911 }
912#if defined(HAS_CONVERT16TO8ROW_NEON)
913 if (TestCpuFlag(kCpuHasNEON)) {
914 Convert16To8Row = Convert16To8Row_Any_NEON;
915 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
916 Convert16To8Row = Convert16To8Row_NEON;
917 }
918 }
919#endif
920#if defined(HAS_CONVERT16TO8ROW_SME)
921 if (TestCpuFlag(kCpuHasSME)) {
922 Convert16To8Row = Convert16To8Row_SME;
923 }
924#endif
925#if defined(HAS_CONVERT16TO8ROW_SSSE3)
926 if (TestCpuFlag(kCpuHasSSSE3)) {
927 Convert16To8Row = Convert16To8Row_Any_SSSE3;
928 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
929 Convert16To8Row = Convert16To8Row_SSSE3;
930 }
931 }
932#endif
933#if defined(HAS_CONVERT16TO8ROW_AVX2)
934 if (TestCpuFlag(kCpuHasAVX2)) {
935 Convert16To8Row = Convert16To8Row_Any_AVX2;
936 if (IS_ALIGNED(halfwidth, 32)(!((uintptr_t)(halfwidth) & ((32) - 1)))) {
937 Convert16To8Row = Convert16To8Row_AVX2;
938 }
939 }
940#endif
941#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
942 if (TestCpuFlag(kCpuHasAVX512BW)) {
943 Convert16To8Row = Convert16To8Row_Any_AVX512BW;
944 if (IS_ALIGNED(halfwidth, 64)(!((uintptr_t)(halfwidth) & ((64) - 1)))) {
945 Convert16To8Row = Convert16To8Row_AVX512BW;
946 }
947 }
948#endif
949
950#if defined(HAS_MERGEUVROW_SSE2)
951 if (TestCpuFlag(kCpuHasSSE2)) {
952 MergeUVRow = MergeUVRow_Any_SSE2;
953 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
954 MergeUVRow = MergeUVRow_SSE2;
955 }
956 }
957#endif
958#if defined(HAS_MERGEUVROW_AVX2)
959 if (TestCpuFlag(kCpuHasAVX2)) {
960 MergeUVRow = MergeUVRow_Any_AVX2;
961 if (IS_ALIGNED(halfwidth, 32)(!((uintptr_t)(halfwidth) & ((32) - 1)))) {
962 MergeUVRow = MergeUVRow_AVX2;
963 }
964 }
965#endif
966#if defined(HAS_MERGEUVROW_AVX512BW)
967 if (TestCpuFlag(kCpuHasAVX512BW)) {
968 MergeUVRow = MergeUVRow_Any_AVX512BW;
969 if (IS_ALIGNED(halfwidth, 32)(!((uintptr_t)(halfwidth) & ((32) - 1)))) {
970 MergeUVRow = MergeUVRow_AVX512BW;
971 }
972 }
973#endif
974#if defined(HAS_MERGEUVROW_NEON)
975 if (TestCpuFlag(kCpuHasNEON)) {
976 MergeUVRow = MergeUVRow_Any_NEON;
977 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
978 MergeUVRow = MergeUVRow_NEON;
979 }
980 }
981#endif
982#if defined(HAS_MERGEUVROW_SVE2)
983 if (TestCpuFlag(kCpuHasSVE2)) {
984 MergeUVRow = MergeUVRow_SVE2;
985 }
986#endif
987#if defined(HAS_MERGEUVROW_SME)
988 if (TestCpuFlag(kCpuHasSME)) {
989 MergeUVRow = MergeUVRow_SME;
990 }
991#endif
992#if defined(HAS_MERGEUVROW_LSX)
993 if (TestCpuFlag(kCpuHasLSX)) {
994 MergeUVRow = MergeUVRow_Any_LSX;
995 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
996 MergeUVRow = MergeUVRow_LSX;
997 }
998 }
999#endif
1000#if defined(HAS_MERGEUVROW_RVV)
1001 if (TestCpuFlag(kCpuHasRVV)) {
1002 MergeUVRow = MergeUVRow_RVV;
1003 }
1004#endif
1005#if defined(HAS_MERGEUVROW_WASMSIMD)
1006 if (TestCpuFlag(kCpuHasWASMSIMD)) {
1007 MergeUVRow = MergeUVRow_Any_WASMSIMD;
1008 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
1009 MergeUVRow = MergeUVRow_WASMSIMD;
1010 }
1011 }
1012#endif
1013
1014 // Convert Y plane.
1015 if (dst_y) {
1016 Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
1017 height);
1018 }
1019
1020 {
1021 // Allocate a row of uv.
1022 align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2)size_t row_u_mem_size = (((halfwidth + 31) & ~31) * 2); void
* row_u_mem = (row_u_mem_size > (18446744073709551615UL) -
63) ? __null : malloc(row_u_mem_size + 63); uint8_t* row_u =
(uint8_t*)(((intptr_t)row_u_mem + 63) & ~63)
;
1023 uint8_t* row_v = row_u + ((halfwidth + 31) & ~31);
1024 if (!row_u)
1025 return 1;
1026
1027 for (y = 0; y < halfheight; ++y) {
1028 Convert16To8Row(src_u, row_u, scale, halfwidth);
1029 Convert16To8Row(src_v, row_v, scale, halfwidth);
1030 MergeUVRow(row_u, row_v, dst_uv, halfwidth);
1031 src_u += src_stride_u;
1032 src_v += src_stride_v;
1033 dst_uv += dst_stride_uv;
1034 }
1035 free_aligned_buffer_64(row_u)free(row_u_mem); row_u = __null;
1036 }
1037 return 0;
1038}
1039
1040LIBYUV_API
1041int I210ToP210(const uint16_t* src_y,
1042 int src_stride_y,
1043 const uint16_t* src_u,
1044 int src_stride_u,
1045 const uint16_t* src_v,
1046 int src_stride_v,
1047 uint16_t* dst_y,
1048 int dst_stride_y,
1049 uint16_t* dst_uv,
1050 int dst_stride_uv,
1051 int width,
1052 int height) {
1053 return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
1054 src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
1055 width, height, 1, 0, 10);
1056}
1057
1058LIBYUV_API
1059int I410ToP410(const uint16_t* src_y,
1060 int src_stride_y,
1061 const uint16_t* src_u,
1062 int src_stride_u,
1063 const uint16_t* src_v,
1064 int src_stride_v,
1065 uint16_t* dst_y,
1066 int dst_stride_y,
1067 uint16_t* dst_uv,
1068 int dst_stride_uv,
1069 int width,
1070 int height) {
1071 return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
1072 src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
1073 width, height, 0, 0, 10);
1074}
1075
1076LIBYUV_API
1077int I012ToP012(const uint16_t* src_y,
1078 int src_stride_y,
1079 const uint16_t* src_u,
1080 int src_stride_u,
1081 const uint16_t* src_v,
1082 int src_stride_v,
1083 uint16_t* dst_y,
1084 int dst_stride_y,
1085 uint16_t* dst_uv,
1086 int dst_stride_uv,
1087 int width,
1088 int height) {
1089 return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
1090 src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
1091 width, height, 1, 1, 12);
1092}
1093
1094LIBYUV_API
1095int I212ToP212(const uint16_t* src_y,
1096 int src_stride_y,
1097 const uint16_t* src_u,
1098 int src_stride_u,
1099 const uint16_t* src_v,
1100 int src_stride_v,
1101 uint16_t* dst_y,
1102 int dst_stride_y,
1103 uint16_t* dst_uv,
1104 int dst_stride_uv,
1105 int width,
1106 int height) {
1107 return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
1108 src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
1109 width, height, 1, 0, 12);
1110}
1111
1112LIBYUV_API
1113int I412ToP412(const uint16_t* src_y,
1114 int src_stride_y,
1115 const uint16_t* src_u,
1116 int src_stride_u,
1117 const uint16_t* src_v,
1118 int src_stride_v,
1119 uint16_t* dst_y,
1120 int dst_stride_y,
1121 uint16_t* dst_uv,
1122 int dst_stride_uv,
1123 int width,
1124 int height) {
1125 return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
1126 src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
1127 width, height, 0, 0, 12);
1128}
1129
1130// 422 chroma is 1/2 width, 1x height
1131// 420 chroma is 1/2 width, 1/2 height
1132LIBYUV_API
1133int I422ToI420(const uint8_t* src_y,
1134 int src_stride_y,
1135 const uint8_t* src_u,
1136 int src_stride_u,
1137 const uint8_t* src_v,
1138 int src_stride_v,
1139 uint8_t* dst_y,
1140 int dst_stride_y,
1141 uint8_t* dst_u,
1142 int dst_stride_u,
1143 uint8_t* dst_v,
1144 int dst_stride_v,
1145 int width,
1146 int height) {
1147 const int src_uv_width = SUBSAMPLE(width, 1, 1)(width < 0) ? (-((-width + 1) >> 1)) : ((width + 1) >>
1)
;
1148 return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
1149 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
1150 dst_v, dst_stride_v, width, height, src_uv_width, height);
1151}
1152
1153LIBYUV_API
1154int I422ToI210(const uint8_t* src_y,
1155 int src_stride_y,
1156 const uint8_t* src_u,
1157 int src_stride_u,
1158 const uint8_t* src_v,
1159 int src_stride_v,
1160 uint16_t* dst_y,
1161 int dst_stride_y,
1162 uint16_t* dst_u,
1163 int dst_stride_u,
1164 uint16_t* dst_v,
1165 int dst_stride_v,
1166 int width,
1167 int height) {
1168 int halfwidth = (width + 1) >> 1;
1169 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
1170 height == 0 || height == INT_MIN(-2147483647 -1)) {
1171 return -1;
1172 }
1173 // Negative height means invert the image.
1174 if (height < 0) {
1175 height = -height;
1176 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1177 src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
1178 src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
1179 src_stride_y = -src_stride_y;
1180 src_stride_u = -src_stride_u;
1181 src_stride_v = -src_stride_v;
1182 }
1183
1184 // Convert Y plane.
1185 Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
1186 height);
1187 // Convert UV planes.
1188 Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
1189 height);
1190 Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
1191 height);
1192 return 0;
1193}
1194
1195// TODO(fbarchard): Implement row conversion.
1196LIBYUV_API
1197int I422ToNV21(const uint8_t* src_y,
1198 int src_stride_y,
1199 const uint8_t* src_u,
1200 int src_stride_u,
1201 const uint8_t* src_v,
1202 int src_stride_v,
1203 uint8_t* dst_y,
1204 int dst_stride_y,
1205 uint8_t* dst_vu,
1206 int dst_stride_vu,
1207 int width,
1208 int height) {
1209 int r;
1210 if (width <= 0 || height == 0 || height == INT_MIN(-2147483647 -1)) {
1211 return -1;
1212 }
1213 int halfwidth = (width + 1) >> 1;
1214 int halfheight = (height + 1) >> 1;
1215 // Negative height means invert the image.
1216 if (height < 0) {
1217 height = -height;
1218 halfheight = (height + 1) >> 1;
1219 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1220 src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
1221 src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
1222 src_stride_y = -src_stride_y;
1223 src_stride_u = -src_stride_u;
1224 src_stride_v = -src_stride_v;
1225 }
1226
1227 // Allocate u and v buffers
1228 const uint64_t plane_size = (uint64_t)halfwidth * halfheight;
1229 if (plane_size > SIZE_MAX(18446744073709551615UL) / 2)
1230 return 1;
1231 align_buffer_64(plane_u, (size_t)plane_size * 2)size_t plane_u_mem_size = ((size_t)plane_size * 2); void* plane_u_mem
= (plane_u_mem_size > (18446744073709551615UL) - 63) ? __null
: malloc(plane_u_mem_size + 63); uint8_t* plane_u = (uint8_t
*)(((intptr_t)plane_u_mem + 63) & ~63)
;
1232 if (!plane_u)
1233 return 1;
1234 uint8_t* plane_v = plane_u + (size_t)plane_size;
1235
1236 r = I422ToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
1237 dst_y, dst_stride_y, plane_u, halfwidth, plane_v, halfwidth,
1238 width, height);
1239 if (r != 0) {
1240 return r;
1241 }
1242 MergeUVPlane(plane_v, halfwidth, plane_u, halfwidth, dst_vu, dst_stride_vu,
1243 halfwidth, halfheight);
1244 free_aligned_buffer_64(plane_u)free(plane_u_mem); plane_u = __null;
1245 return 0;
1246}
1247
1248LIBYUV_API
1249int MM21ToNV12(const uint8_t* src_y,
1250 int src_stride_y,
1251 const uint8_t* src_uv,
1252 int src_stride_uv,
1253 uint8_t* dst_y,
1254 int dst_stride_y,
1255 uint8_t* dst_uv,
1256 int dst_stride_uv,
1257 int width,
1258 int height) {
1259 if (!src_uv || !dst_uv || width <= 0) {
1260 return -1;
1261 }
1262
1263 int sign = height < 0 ? -1 : 1;
1264
1265 if (dst_y) {
1266 DetilePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height, 32);
1267 }
1268 DetilePlane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, (width + 1) & ~1,
1269 (height + sign) / 2, 16);
1270
1271 return 0;
1272}
1273
1274LIBYUV_API
1275int MM21ToI420(const uint8_t* src_y,
1276 int src_stride_y,
1277 const uint8_t* src_uv,
1278 int src_stride_uv,
1279 uint8_t* dst_y,
1280 int dst_stride_y,
1281 uint8_t* dst_u,
1282 int dst_stride_u,
1283 uint8_t* dst_v,
1284 int dst_stride_v,
1285 int width,
1286 int height) {
1287 int sign = height < 0 ? -1 : 1;
1288
1289 if (!src_uv || !dst_u || !dst_v || width <= 0) {
1290 return -1;
1291 }
1292
1293 if (dst_y) {
1294 DetilePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height, 32);
1295 }
1296 DetileSplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
1297 dst_stride_v, (width + 1) & ~1, (height + sign) / 2, 16);
1298
1299 return 0;
1300}
1301
1302LIBYUV_API
1303int MM21ToYUY2(const uint8_t* src_y,
1304 int src_stride_y,
1305 const uint8_t* src_uv,
1306 int src_stride_uv,
1307 uint8_t* dst_yuy2,
1308 int dst_stride_yuy2,
1309 int width,
1310 int height) {
1311 if (!src_y || !src_uv || !dst_yuy2 || width <= 0) {
1312 return -1;
1313 }
1314
1315 DetileToYUY2(src_y, src_stride_y, src_uv, src_stride_uv, dst_yuy2,
1316 dst_stride_yuy2, width, height, 32);
1317
1318 return 0;
1319}
1320
1321// Convert MT2T into P010. See tinyurl.com/mtk-10bit-video-format for format
1322// documentation.
1323// TODO(greenjustin): Add an MT2T to I420 conversion.
1324LIBYUV_API
1325int MT2TToP010(const uint8_t* src_y,
1326 int src_stride_y,
1327 const uint8_t* src_uv,
1328 int src_stride_uv,
1329 uint16_t* dst_y,
1330 int dst_stride_y,
1331 uint16_t* dst_uv,
1332 int dst_stride_uv,
1333 int width,
1334 int height) {
1335 if (width <= 0 || height == 0 || height == INT_MIN(-2147483647 -1) || !src_uv || !dst_uv) {
1336 return -1;
1337 }
1338
1339 {
1340 int uv_width = (width + 1) & ~1;
1341 int uv_height = (height + 1) / 2;
1342 int y = 0;
1343 const int tile_width = 16;
1344 const int y_tile_height = 32;
1345 const int uv_tile_height = 16;
1346 int padded_width = (width + tile_width - 1) & ~(tile_width - 1);
1347 int y_tile_row_size = padded_width * y_tile_height * 10 / 8;
1348 int uv_tile_row_size = padded_width * uv_tile_height * 10 / 8;
1349 size_t row_buf_size = padded_width * y_tile_height * sizeof(uint16_t);
1350 void (*UnpackMT2T)(const uint8_t* src, uint16_t* dst, size_t size) =
1351 UnpackMT2T_C;
1352 align_buffer_64(row_buf, row_buf_size)size_t row_buf_mem_size = (row_buf_size); void* row_buf_mem =
(row_buf_mem_size > (18446744073709551615UL) - 63) ? __null
: malloc(row_buf_mem_size + 63); uint8_t* row_buf = (uint8_t
*)(((intptr_t)row_buf_mem + 63) & ~63)
;
1353 if (!row_buf)
1354 return 1;
1355
1356#if defined(HAS_UNPACKMT2T_NEON)
1357 if (TestCpuFlag(kCpuHasNEON)) {
1358 UnpackMT2T = UnpackMT2T_NEON;
1359 }
1360#endif
1361 // Negative height means invert the image.
1362 if (height < 0) {
1363 height = -height;
1364 uv_height = (height + 1) / 2;
1365 if (dst_y) {
1366 dst_y = dst_y + (ptrdiff_t)(height - 1) * dst_stride_y;
1367 dst_stride_y = -dst_stride_y;
1368 }
1369 dst_uv = dst_uv + (ptrdiff_t)(uv_height - 1) * dst_stride_uv;
1370 dst_stride_uv = -dst_stride_uv;
1371 }
1372
1373 // Unpack and detile Y in rows of tiles
1374 if (src_y && dst_y) {
1375 for (y = 0; y < (height & ~(y_tile_height - 1)); y += y_tile_height) {
1376 UnpackMT2T(src_y, (uint16_t*)row_buf, y_tile_row_size);
1377 DetilePlane_16((uint16_t*)row_buf, padded_width, dst_y, dst_stride_y,
1378 width, y_tile_height, y_tile_height);
1379 src_y += src_stride_y * y_tile_height;
1380 dst_y += dst_stride_y * y_tile_height;
1381 }
1382 if (height & (y_tile_height - 1)) {
1383 UnpackMT2T(src_y, (uint16_t*)row_buf, y_tile_row_size);
1384 DetilePlane_16((uint16_t*)row_buf, padded_width, dst_y, dst_stride_y,
1385 width, height & (y_tile_height - 1), y_tile_height);
1386 }
1387 }
1388
1389 // Unpack and detile UV plane
1390 for (y = 0; y < (uv_height & ~(uv_tile_height - 1)); y += uv_tile_height) {
1391 UnpackMT2T(src_uv, (uint16_t*)row_buf, uv_tile_row_size);
1392 DetilePlane_16((uint16_t*)row_buf, padded_width, dst_uv, dst_stride_uv,
1393 uv_width, uv_tile_height, uv_tile_height);
1394 src_uv += src_stride_uv * uv_tile_height;
1395 dst_uv += dst_stride_uv * uv_tile_height;
1396 }
1397 if (uv_height & (uv_tile_height - 1)) {
1398 UnpackMT2T(src_uv, (uint16_t*)row_buf, uv_tile_row_size);
1399 DetilePlane_16((uint16_t*)row_buf, padded_width, dst_uv, dst_stride_uv,
1400 uv_width, uv_height & (uv_tile_height - 1),
1401 uv_tile_height);
1402 }
1403 free_aligned_buffer_64(row_buf)free(row_buf_mem); row_buf = __null;
1404 }
1405 return 0;
1406}
1407
1408#ifdef I422TONV21_ROW_VERSION
1409// Unittest fails for this version.
1410// 422 chroma is 1/2 width, 1x height
1411// 420 chroma is 1/2 width, 1/2 height
1412// Swap src_u and src_v to implement I422ToNV12
1413LIBYUV_API
1414int I422ToNV21(const uint8_t* src_y,
1415 int src_stride_y,
1416 const uint8_t* src_u,
1417 int src_stride_u,
1418 const uint8_t* src_v,
1419 int src_stride_v,
1420 uint8_t* dst_y,
1421 int dst_stride_y,
1422 uint8_t* dst_vu,
1423 int dst_stride_vu,
1424 int width,
1425 int height) {
1426 int y;
1427 void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
1428 uint8_t* dst_uv, int width) = MergeUVRow_C;
1429 void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr,
1430 ptrdiff_t src_stride, int dst_width,
1431 int source_y_fraction) = InterpolateRow_C;
1432 int halfwidth = (width + 1) >> 1;
1433 int halfheight = (height + 1) >> 1;
1434 if ((!src_y && dst_y) || !src_u || !src_v || !dst_vu || width <= 0 ||
1435 height == 0 || height == INT_MIN(-2147483647 -1)) {
1436 return -1;
1437 }
1438 // Negative height means invert the image.
1439 if (height < 0) {
1440 height = -height;
1441 halfheight = (height + 1) >> 1;
1442 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1443 src_u = src_u + (ptrdiff_t)(halfheight - 1) * src_stride_u;
1444 src_v = src_v + (ptrdiff_t)(halfheight - 1) * src_stride_v;
1445 src_stride_y = -src_stride_y;
1446 src_stride_u = -src_stride_u;
1447 src_stride_v = -src_stride_v;
1448 }
1449#if defined(HAS_MERGEUVROW_SSE2)
1450 if (TestCpuFlag(kCpuHasSSE2)) {
1451 MergeUVRow = MergeUVRow_Any_SSE2;
1452 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
1453 MergeUVRow = MergeUVRow_SSE2;
1454 }
1455 }
1456#endif
1457#if defined(HAS_MERGEUVROW_AVX2)
1458 if (TestCpuFlag(kCpuHasAVX2)) {
1459 MergeUVRow = MergeUVRow_Any_AVX2;
1460 if (IS_ALIGNED(halfwidth, 32)(!((uintptr_t)(halfwidth) & ((32) - 1)))) {
1461 MergeUVRow = MergeUVRow_AVX2;
1462 }
1463 }
1464#endif
1465#if defined(HAS_MERGEUVROW_AVX512BW)
1466 if (TestCpuFlag(kCpuHasAVX512BW)) {
1467 MergeUVRow = MergeUVRow_Any_AVX512BW;
1468 if (IS_ALIGNED(halfwidth, 32)(!((uintptr_t)(halfwidth) & ((32) - 1)))) {
1469 MergeUVRow = MergeUVRow_AVX512BW;
1470 }
1471 }
1472#endif
1473#if defined(HAS_MERGEUVROW_NEON)
1474 if (TestCpuFlag(kCpuHasNEON)) {
1475 MergeUVRow = MergeUVRow_Any_NEON;
1476 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
1477 MergeUVRow = MergeUVRow_NEON;
1478 }
1479 }
1480#endif
1481#if defined(HAS_MERGEUVROW_SVE2)
1482 if (TestCpuFlag(kCpuHasSVE2)) {
1483 MergeUVRow = MergeUVRow_SVE2;
1484 }
1485#endif
1486#if defined(HAS_MERGEUVROW_SME)
1487 if (TestCpuFlag(kCpuHasSME)) {
1488 MergeUVRow = MergeUVRow_SME;
1489 }
1490#endif
1491#if defined(HAS_MERGEUVROW_LSX)
1492 if (TestCpuFlag(kCpuHasLSX)) {
1493 MergeUVRow = MergeUVRow_Any_LSX;
1494 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
1495 MergeUVRow = MergeUVRow_LSX;
1496 }
1497 }
1498#endif
1499#if defined(HAS_MERGEUVROW_RVV)
1500 if (TestCpuFlag(kCpuHasRVV)) {
1501 MergeUVRow = MergeUVRow_RVV;
1502 }
1503#endif
1504#if defined(HAS_MERGEUVROW_WASMSIMD)
1505 if (TestCpuFlag(kCpuHasWASMSIMD)) {
1506 MergeUVRow = MergeUVRow_Any_WASMSIMD;
1507 if (IS_ALIGNED(halfwidth, 16)(!((uintptr_t)(halfwidth) & ((16) - 1)))) {
1508 MergeUVRow = MergeUVRow_WASMSIMD;
1509 }
1510 }
1511#endif
1512#if defined(HAS_INTERPOLATEROW_AVX2)
1513 if (TestCpuFlag(kCpuHasAVX2)) {
1514 InterpolateRow = InterpolateRow_Any_AVX2;
1515 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
1516 InterpolateRow = InterpolateRow_AVX2;
1517 }
1518 }
1519#endif
1520#if defined(HAS_INTERPOLATEROW_AVX512BW)
1521 if (TestCpuFlag(kCpuHasAVX512BW)) {
1522 InterpolateRow = InterpolateRow_AVX512BW;
1523 }
1524#endif
1525#if defined(HAS_INTERPOLATEROW_NEON)
1526 if (TestCpuFlag(kCpuHasNEON)) {
1527 InterpolateRow = InterpolateRow_Any_NEON;
1528 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
1529 InterpolateRow = InterpolateRow_NEON;
1530 }
1531 }
1532#endif
1533#if defined(HAS_INTERPOLATEROW_SVE2)
1534 if (TestCpuFlag(kCpuHasSVE2)) {
1535 InterpolateRow = InterpolateRow_SVE2;
1536 }
1537#endif
1538#if defined(HAS_INTERPOLATEROW_SME)
1539 if (TestCpuFlag(kCpuHasSME)) {
1540 InterpolateRow = InterpolateRow_SME;
1541 }
1542#endif
1543#if defined(HAS_INTERPOLATEROW_LSX)
1544 if (TestCpuFlag(kCpuHasLSX)) {
1545 InterpolateRow = InterpolateRow_Any_LSX;
1546 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
1547 InterpolateRow = InterpolateRow_LSX;
1548 }
1549 }
1550#endif
1551#if defined(HAS_INTERPOLATEROW_RVV)
1552 if (TestCpuFlag(kCpuHasRVV)) {
1553 InterpolateRow = InterpolateRow_RVV;
1554 }
1555#endif
1556#if defined(HAS_INTERPOLATEROW_WASMSIMD)
1557 if (TestCpuFlag(kCpuHasWASMSIMD)) {
1558 InterpolateRow = InterpolateRow_Any_WASMSIMD;
1559 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
1560 InterpolateRow = InterpolateRow_WASMSIMD;
1561 }
1562 }
1563#endif
1564
1565 if (dst_y) {
1566 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, halfwidth, height);
1567 }
1568 {
1569 // Allocate 2 rows of vu.
1570 int awidth = halfwidth * 2;
1571 align_buffer_64(row_vu_0, awidth * 2)size_t row_vu_0_mem_size = (awidth * 2); void* row_vu_0_mem =
(row_vu_0_mem_size > (18446744073709551615UL) - 63) ? __null
: malloc(row_vu_0_mem_size + 63); uint8_t* row_vu_0 = (uint8_t
*)(((intptr_t)row_vu_0_mem + 63) & ~63)
;
1572 uint8_t* row_vu_1 = row_vu_0 + awidth;
1573 if (!row_vu_0)
1574 return 1;
1575
1576 for (y = 0; y < height - 1; y += 2) {
1577 MergeUVRow(src_v, src_u, row_vu_0, halfwidth);
1578 MergeUVRow(src_v + src_stride_v, src_u + src_stride_u, row_vu_1,
1579 halfwidth);
1580 InterpolateRow(dst_vu, row_vu_0, awidth, awidth, 128);
1581 src_u += src_stride_u * 2;
1582 src_v += src_stride_v * 2;
1583 dst_vu += dst_stride_vu;
1584 }
1585 if (height & 1) {
1586 MergeUVRow(src_v, src_u, dst_vu, halfwidth);
1587 }
1588 free_aligned_buffer_64(row_vu_0)free(row_vu_0_mem); row_vu_0 = __null;
1589 }
1590 return 0;
1591}
1592#endif // I422TONV21_ROW_VERSION
1593
1594// 444 chroma is 1x width, 1x height
1595// 420 chroma is 1/2 width, 1/2 height
1596LIBYUV_API
1597int I444ToI420(const uint8_t* src_y,
1598 int src_stride_y,
1599 const uint8_t* src_u,
1600 int src_stride_u,
1601 const uint8_t* src_v,
1602 int src_stride_v,
1603 uint8_t* dst_y,
1604 int dst_stride_y,
1605 uint8_t* dst_u,
1606 int dst_stride_u,
1607 uint8_t* dst_v,
1608 int dst_stride_v,
1609 int width,
1610 int height) {
1611 return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
1612 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
1613 dst_v, dst_stride_v, width, height, width, height);
1614}
1615
1616LIBYUV_API
1617int I444ToNV12(const uint8_t* src_y,
1618 int src_stride_y,
1619 const uint8_t* src_u,
1620 int src_stride_u,
1621 const uint8_t* src_v,
1622 int src_stride_v,
1623 uint8_t* dst_y,
1624 int dst_stride_y,
1625 uint8_t* dst_uv,
1626 int dst_stride_uv,
1627 int width,
1628 int height) {
1629 if ((!src_y && dst_y) || !src_u || !src_v || !dst_uv || width <= 0 ||
3
Assuming 'src_y' is null
4
Assuming 'dst_y' is null
5
Assuming 'src_u' is non-null
6
Assuming 'src_v' is non-null
7
Assuming 'dst_uv' is non-null
8
Assuming 'width' is > 0
11
Taking false branch
1630 height == 0 || height == INT_MIN(-2147483647 -1)) {
9
Assuming 'height' is not equal to 0
10
Assuming the condition is false
1631 return -1;
1632 }
1633 // Negative height means invert the image.
1634 if (height < 0) {
12
Assuming 'height' is < 0
13
Taking true branch
1635 height = -height;
1636 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
14
Addition of a null pointer (from variable 'src_y') and a probably nonzero integer value may result in undefined behavior
1637 src_u = src_u + (ptrdiff_t)(height - 1) * src_stride_u;
1638 src_v = src_v + (ptrdiff_t)(height - 1) * src_stride_v;
1639 src_stride_y = -src_stride_y;
1640 src_stride_u = -src_stride_u;
1641 src_stride_v = -src_stride_v;
1642 }
1643 if (dst_y) {
1644 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1645 }
1646 HalfMergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv,
1647 dst_stride_uv, width, height);
1648 return 0;
1649}
1650
1651LIBYUV_API
1652int I444ToNV21(const uint8_t* src_y,
1653 int src_stride_y,
1654 const uint8_t* src_u,
1655 int src_stride_u,
1656 const uint8_t* src_v,
1657 int src_stride_v,
1658 uint8_t* dst_y,
1659 int dst_stride_y,
1660 uint8_t* dst_vu,
1661 int dst_stride_vu,
1662 int width,
1663 int height) {
1664 return I444ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
1
Passing value via 1st parameter 'src_y'
2
Calling 'I444ToNV12'
1665 src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
1666 width, height);
1667}
1668
1669// I400 is greyscale typically used in MJPG
1670LIBYUV_API
1671int I400ToI420(const uint8_t* src_y,
1672 int src_stride_y,
1673 uint8_t* dst_y,
1674 int dst_stride_y,
1675 uint8_t* dst_u,
1676 int dst_stride_u,
1677 uint8_t* dst_v,
1678 int dst_stride_v,
1679 int width,
1680 int height) {
1681 int halfwidth = (width + 1) >> 1;
1682 int halfheight = (height + 1) >> 1;
1683 if ((!src_y && dst_y) || !dst_u || !dst_v || width <= 0 || height == 0 ||
1684 height == INT_MIN(-2147483647 -1)) {
1685 return -1;
1686 }
1687 // Negative height means invert the image.
1688 if (height < 0) {
1689 height = -height;
1690 halfheight = (height + 1) >> 1;
1691 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1692 src_stride_y = -src_stride_y;
1693 }
1694 if (dst_y) {
1695 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1696 }
1697 SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
1698 SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
1699 return 0;
1700}
1701
1702// I400 is greyscale typically used in MJPG
1703LIBYUV_API
1704int I400ToNV21(const uint8_t* src_y,
1705 int src_stride_y,
1706 uint8_t* dst_y,
1707 int dst_stride_y,
1708 uint8_t* dst_vu,
1709 int dst_stride_vu,
1710 int width,
1711 int height) {
1712 int halfwidth = (width + 1) >> 1;
1713 int halfheight = (height + 1) >> 1;
1714 if ((!src_y && dst_y) || !dst_vu || width <= 0 || height == 0 ||
1715 height == INT_MIN(-2147483647 -1)) {
1716 return -1;
1717 }
1718 // Negative height means invert the image.
1719 if (height < 0) {
1720 height = -height;
1721 halfheight = (height + 1) >> 1;
1722 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1723 src_stride_y = -src_stride_y;
1724 }
1725 if (dst_y) {
1726 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1727 }
1728 SetPlane(dst_vu, dst_stride_vu, halfwidth * 2, halfheight, 128);
1729 return 0;
1730}
1731
1732// Convert NV12 to I420.
1733// TODO(fbarchard): Consider inverting destination. Faster on ARM with prfm.
1734LIBYUV_API
1735int NV12ToI420(const uint8_t* src_y,
1736 int src_stride_y,
1737 const uint8_t* src_uv,
1738 int src_stride_uv,
1739 uint8_t* dst_y,
1740 int dst_stride_y,
1741 uint8_t* dst_u,
1742 int dst_stride_u,
1743 uint8_t* dst_v,
1744 int dst_stride_v,
1745 int width,
1746 int height) {
1747 int halfwidth = (width + 1) >> 1;
1748 int halfheight = (height + 1) >> 1;
1749 if ((!src_y && dst_y) || !src_uv || !dst_u || !dst_v || width <= 0 ||
1750 height == 0 || height == INT_MIN(-2147483647 -1)) {
1751 return -1;
1752 }
1753 // Negative height means invert the image.
1754 if (height < 0) {
1755 height = -height;
1756 halfheight = (height + 1) >> 1;
1757 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
1758 src_uv = src_uv + (ptrdiff_t)(halfheight - 1) * src_stride_uv;
1759 src_stride_y = -src_stride_y;
1760 src_stride_uv = -src_stride_uv;
1761 }
1762 // Coalesce rows.
1763 if (src_stride_y == width && dst_stride_y == width &&
1764 (ptrdiff_t)width * height <= INT_MAX2147483647) {
1765 width *= height;
1766 height = 1;
1767 src_stride_y = dst_stride_y = 0;
1768 }
1769 // Coalesce rows.
1770 if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
1771 dst_stride_v == halfwidth &&
1772 (ptrdiff_t)halfwidth * halfheight <= INT_MAX2147483647) {
1773 halfwidth *= halfheight;
1774 halfheight = 1;
1775 src_stride_uv = dst_stride_u = dst_stride_v = 0;
1776 }
1777
1778 if (dst_y) {
1779 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1780 }
1781
1782 // Split UV plane - NV12 / NV21
1783 SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
1784 halfwidth, halfheight);
1785
1786 return 0;
1787}
1788
1789// Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
1790LIBYUV_API
1791int NV21ToI420(const uint8_t* src_y,
1792 int src_stride_y,
1793 const uint8_t* src_vu,
1794 int src_stride_vu,
1795 uint8_t* dst_y,
1796 int dst_stride_y,
1797 uint8_t* dst_u,
1798 int dst_stride_u,
1799 uint8_t* dst_v,
1800 int dst_stride_v,
1801 int width,
1802 int height) {
1803 return NV12ToI420(src_y, src_stride_y, src_vu, src_stride_vu, dst_y,
1804 dst_stride_y, dst_v, dst_stride_v, dst_u, dst_stride_u,
1805 width, height);
1806}
1807
1808LIBYUV_API
1809int NV12ToNV24(const uint8_t* src_y,
1810 int src_stride_y,
1811 const uint8_t* src_uv,
1812 int src_stride_uv,
1813 uint8_t* dst_y,
1814 int dst_stride_y,
1815 uint8_t* dst_uv,
1816 int dst_stride_uv,
1817 int width,
1818 int height) {
1819 int r;
1820 if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
1821 height == INT_MIN(-2147483647 -1)) {
1822 return -1;
1823 }
1824
1825 if (dst_y) {
1826 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1827 }
1828 r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1)(width < 0) ? (-((-width + 1) >> 1)) : ((width + 1) >>
1)
,
1829 SUBSAMPLE(height, 1, 1)(height < 0) ? (-((-height + 1) >> 1)) : ((height + 1
) >> 1)
, dst_uv, dst_stride_uv, Abs(width),
1830 Abs(height), kFilterBilinear);
1831 return r;
1832}
1833
1834LIBYUV_API
1835int NV16ToNV24(const uint8_t* src_y,
1836 int src_stride_y,
1837 const uint8_t* src_uv,
1838 int src_stride_uv,
1839 uint8_t* dst_y,
1840 int dst_stride_y,
1841 uint8_t* dst_uv,
1842 int dst_stride_uv,
1843 int width,
1844 int height) {
1845 int r;
1846 if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
1847 height == INT_MIN(-2147483647 -1)) {
1848 return -1;
1849 }
1850
1851 if (dst_y) {
1852 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1853 }
1854 r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1)(width < 0) ? (-((-width + 1) >> 1)) : ((width + 1) >>
1)
, height, dst_uv,
1855 dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
1856 return r;
1857}
1858
1859// Any P[420]1[02] to I[420]1[02] format
1860static int PxxxToIxxx(const uint16_t* src_y,
1861 int src_stride_y,
1862 const uint16_t* src_uv,
1863 int src_stride_uv,
1864 uint16_t* dst_y,
1865 int dst_stride_y,
1866 uint16_t* dst_u,
1867 int dst_stride_u,
1868 uint16_t* dst_v,
1869 int dst_stride_v,
1870 int width,
1871 int height,
1872 int subsample_x,
1873 int subsample_y,
1874 int depth) {
1875 const int uv_width = SUBSAMPLE(width, subsample_x, subsample_x)(width < 0) ? (-((-width + subsample_x) >> subsample_x
)) : ((width + subsample_x) >> subsample_x)
;
1876 const int uv_height = SUBSAMPLE(height, subsample_y, subsample_y)(height < 0) ? (-((-height + subsample_y) >> subsample_y
)) : ((height + subsample_y) >> subsample_y)
;
1877 if (!src_y || !dst_y || !src_uv || !dst_u || !dst_v || width <= 0 ||
1878 height == 0 || height == INT_MIN(-2147483647 -1)) {
1879 return -1;
1880 }
1881 ConvertToLSBPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
1882 depth);
1883 SplitUVPlane_16(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
1884 dst_stride_v, uv_width, uv_height, depth);
1885 return 0;
1886}
1887
1888LIBYUV_API
1889int P010ToI010(const uint16_t* src_y,
1890 int src_stride_y,
1891 const uint16_t* src_uv,
1892 int src_stride_uv,
1893 uint16_t* dst_y,
1894 int dst_stride_y,
1895 uint16_t* dst_u,
1896 int dst_stride_u,
1897 uint16_t* dst_v,
1898 int dst_stride_v,
1899 int width,
1900 int height) {
1901 return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
1902 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
1903 width, height, 1, 1, 10);
1904}
1905
1906LIBYUV_API
1907int P210ToI210(const uint16_t* src_y,
1908 int src_stride_y,
1909 const uint16_t* src_uv,
1910 int src_stride_uv,
1911 uint16_t* dst_y,
1912 int dst_stride_y,
1913 uint16_t* dst_u,
1914 int dst_stride_u,
1915 uint16_t* dst_v,
1916 int dst_stride_v,
1917 int width,
1918 int height) {
1919 return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
1920 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
1921 width, height, 1, 0, 10);
1922}
1923
1924LIBYUV_API
1925int P410ToI410(const uint16_t* src_y,
1926 int src_stride_y,
1927 const uint16_t* src_uv,
1928 int src_stride_uv,
1929 uint16_t* dst_y,
1930 int dst_stride_y,
1931 uint16_t* dst_u,
1932 int dst_stride_u,
1933 uint16_t* dst_v,
1934 int dst_stride_v,
1935 int width,
1936 int height) {
1937 return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
1938 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
1939 width, height, 0, 0, 10);
1940}
1941
1942static void InvertPx10(const uint16_t** src_y,
1943 int* src_stride_y,
1944 const uint16_t** src_uv,
1945 int* src_stride_uv,
1946 int* height,
1947 int subsample_y) {
1948 const int abs_height = Abs(*height);
1949 const int src_uv_height = SUBSAMPLE(abs_height, subsample_y, subsample_y)(abs_height < 0) ? (-((-abs_height + subsample_y) >>
subsample_y)) : ((abs_height + subsample_y) >> subsample_y
)
;
1950 if (*src_y) {
1951 *src_y = *src_y + (ptrdiff_t)(abs_height - 1) * *src_stride_y;
1952 *src_stride_y = -*src_stride_y;
1953 }
1954 *src_uv = *src_uv + (ptrdiff_t)(src_uv_height - 1) * *src_stride_uv;
1955 *src_stride_uv = -*src_stride_uv;
1956 *height = abs_height;
1957}
1958
1959static int Px10ToI420(const uint16_t* src_y,
1960 int src_stride_y,
1961 const uint16_t* src_uv,
1962 int src_stride_uv,
1963 uint8_t* dst_y,
1964 int dst_stride_y,
1965 uint8_t* dst_u,
1966 int dst_stride_u,
1967 uint8_t* dst_v,
1968 int dst_stride_v,
1969 int width,
1970 int height,
1971 int subsample_x,
1972 int subsample_y) {
1973 const int scale16 = 256; // P*10 stores 10-bit in the MSBs.
1974 int src_uv_width;
1975 int dst_uv_width;
1976 if ((!src_y && dst_y) || !src_uv || !dst_u || !dst_v || width <= 0 ||
1977 height == 0 || height == INT_MIN(-2147483647 -1)) {
1978 return -1;
1979 }
1980 if (height < 0) {
1981 InvertPx10(&src_y, &src_stride_y, &src_uv, &src_stride_uv, &height,
1982 subsample_y);
1983 }
1984 src_uv_width = SUBSAMPLE(width, subsample_x, subsample_x)(width < 0) ? (-((-width + subsample_x) >> subsample_x
)) : ((width + subsample_x) >> subsample_x)
;
1985 dst_uv_width = SUBSAMPLE(width, 1, 1)(width < 0) ? (-((-width + 1) >> 1)) : ((width + 1) >>
1)
;
1986
1987 if (dst_y) {
1988 Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale16, width,
1989 height);
1990 }
1991
1992 if (subsample_x && subsample_y) {
1993 int y;
1994 const int uv_packed = src_uv_width * 2;
1995 const int uv_height = SUBSAMPLE(height, 1, 1)(height < 0) ? (-((-height + 1) >> 1)) : ((height + 1
) >> 1)
;
1996 void (*Convert16To8Row)(const uint16_t* src_y, uint8_t* dst_y, int scale,
1997 int width) = Convert16To8Row_C;
1998 void (*SplitUVRow)(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v,
1999 int width) = SplitUVRow_C;
2000
2001#if defined(HAS_CONVERT16TO8ROW_NEON)
2002 if (TestCpuFlag(kCpuHasNEON)) {
2003 Convert16To8Row = Convert16To8Row_Any_NEON;
2004 if (IS_ALIGNED(uv_packed, 16)(!((uintptr_t)(uv_packed) & ((16) - 1)))) {
2005 Convert16To8Row = Convert16To8Row_NEON;
2006 }
2007 }
2008#endif
2009#if defined(HAS_CONVERT16TO8ROW_SVE2)
2010 if (TestCpuFlag(kCpuHasSVE2)) {
2011 Convert16To8Row = Convert16To8Row_SVE2;
2012 }
2013#endif
2014#if defined(HAS_CONVERT16TO8ROW_SME)
2015 if (TestCpuFlag(kCpuHasSME)) {
2016 Convert16To8Row = Convert16To8Row_SME;
2017 }
2018#endif
2019#if defined(HAS_CONVERT16TO8ROW_SSSE3)
2020 if (TestCpuFlag(kCpuHasSSSE3)) {
2021 Convert16To8Row = Convert16To8Row_Any_SSSE3;
2022 if (IS_ALIGNED(uv_packed, 16)(!((uintptr_t)(uv_packed) & ((16) - 1)))) {
2023 Convert16To8Row = Convert16To8Row_SSSE3;
2024 }
2025 }
2026#endif
2027#if defined(HAS_CONVERT16TO8ROW_AVX2)
2028 if (TestCpuFlag(kCpuHasAVX2)) {
2029 Convert16To8Row = Convert16To8Row_Any_AVX2;
2030 if (IS_ALIGNED(uv_packed, 32)(!((uintptr_t)(uv_packed) & ((32) - 1)))) {
2031 Convert16To8Row = Convert16To8Row_AVX2;
2032 }
2033 }
2034#endif
2035#if defined(HAS_CONVERT16TO8ROW_AVX512BW)
2036 if (TestCpuFlag(kCpuHasAVX512BW)) {
2037 Convert16To8Row = Convert16To8Row_Any_AVX512BW;
2038 if (IS_ALIGNED(uv_packed, 64)(!((uintptr_t)(uv_packed) & ((64) - 1)))) {
2039 Convert16To8Row = Convert16To8Row_AVX512BW;
2040 }
2041 }
2042#endif
2043#if defined(HAS_CONVERT16TO8ROW_RVV)
2044 if (TestCpuFlag(kCpuHasRVV)) {
2045 Convert16To8Row = Convert16To8Row_RVV;
2046 }
2047#endif
2048#if defined(HAS_SPLITUVROW_SSE2)
2049 if (TestCpuFlag(kCpuHasSSE2)) {
2050 SplitUVRow = SplitUVRow_Any_SSE2;
2051 if (IS_ALIGNED(src_uv_width, 16)(!((uintptr_t)(src_uv_width) & ((16) - 1)))) {
2052 SplitUVRow = SplitUVRow_SSE2;
2053 }
2054 }
2055#endif
2056#if defined(HAS_SPLITUVROW_AVX2)
2057 if (TestCpuFlag(kCpuHasAVX2)) {
2058 SplitUVRow = SplitUVRow_Any_AVX2;
2059 if (IS_ALIGNED(src_uv_width, 32)(!((uintptr_t)(src_uv_width) & ((32) - 1)))) {
2060 SplitUVRow = SplitUVRow_AVX2;
2061 }
2062 }
2063#endif
2064#if defined(HAS_SPLITUVROW_AVX512BW)
2065 if (TestCpuFlag(kCpuHasAVX512BW)) {
2066 SplitUVRow = SplitUVRow_Any_AVX512BW;
2067 if (IS_ALIGNED(src_uv_width, 64)(!((uintptr_t)(src_uv_width) & ((64) - 1)))) {
2068 SplitUVRow = SplitUVRow_AVX512BW;
2069 }
2070 }
2071#endif
2072#if defined(HAS_SPLITUVROW_NEON)
2073 if (TestCpuFlag(kCpuHasNEON)) {
2074 SplitUVRow = SplitUVRow_Any_NEON;
2075 if (IS_ALIGNED(src_uv_width, 16)(!((uintptr_t)(src_uv_width) & ((16) - 1)))) {
2076 SplitUVRow = SplitUVRow_NEON;
2077 }
2078 }
2079#endif
2080#if defined(HAS_SPLITUVROW_SVE2)
2081 if (TestCpuFlag(kCpuHasSVE2)) {
2082 SplitUVRow = SplitUVRow_SVE2;
2083 }
2084#endif
2085#if defined(HAS_SPLITUVROW_LSX)
2086 if (TestCpuFlag(kCpuHasLSX)) {
2087 SplitUVRow = SplitUVRow_Any_LSX;
2088 if (IS_ALIGNED(src_uv_width, 32)(!((uintptr_t)(src_uv_width) & ((32) - 1)))) {
2089 SplitUVRow = SplitUVRow_LSX;
2090 }
2091 }
2092#endif
2093#if defined(HAS_SPLITUVROW_RVV)
2094 if (TestCpuFlag(kCpuHasRVV)) {
2095 SplitUVRow = SplitUVRow_RVV;
2096 }
2097#endif
2098
2099 align_buffer_64(row_uv, ((uv_packed + 63) & ~63))size_t row_uv_mem_size = (((uv_packed + 63) & ~63)); void
* row_uv_mem = (row_uv_mem_size > (18446744073709551615UL)
- 63) ? __null : malloc(row_uv_mem_size + 63); uint8_t* row_uv
= (uint8_t*)(((intptr_t)row_uv_mem + 63) & ~63)
;
2100 if (!row_uv) {
2101 return 1;
2102 }
2103 for (y = 0; y < uv_height; ++y) {
2104 Convert16To8Row(src_uv, row_uv, scale16, uv_packed);
2105 SplitUVRow(row_uv, dst_u, dst_v, src_uv_width);
2106 src_uv += src_stride_uv;
2107 dst_u += dst_stride_u;
2108 dst_v += dst_stride_v;
2109 }
2110 free_aligned_buffer_64(row_uv)free(row_uv_mem); row_uv = __null;
2111 return 0;
2112 }
2113
2114 {
2115 int y;
2116 const int scale = 16384; // 10-bit LSB after SplitUVRow_16.
2117 int row_stride;
2118 void (*SplitUVRow_16)(const uint16_t* src_uv, uint16_t* dst_u,
2119 uint16_t* dst_v, int depth, int width) =
2120 SplitUVRow_16_C;
2121 void (*Half16To8)(const uint16_t* src_uv, ptrdiff_t src_uv_stride,
2122 uint8_t* dst_uv, int scale, int width) =
2123 subsample_x
2124 ? HalfRow_16To8_C
2125 : ((width & 1) ? HalfWidthRow_16To8_Odd_C : HalfWidthRow_16To8_C);
2126
2127#if defined(HAS_SPLITUVROW_16_AVX2)
2128 if (TestCpuFlag(kCpuHasAVX2)) {
2129 SplitUVRow_16 = SplitUVRow_16_Any_AVX2;
2130 if (IS_ALIGNED(src_uv_width, 16)(!((uintptr_t)(src_uv_width) & ((16) - 1)))) {
2131 SplitUVRow_16 = SplitUVRow_16_AVX2;
2132 }
2133 }
2134#endif
2135#if defined(HAS_SPLITUVROW_16_NEON)
2136 if (TestCpuFlag(kCpuHasNEON)) {
2137 SplitUVRow_16 = SplitUVRow_16_Any_NEON;
2138 if (IS_ALIGNED(src_uv_width, 8)(!((uintptr_t)(src_uv_width) & ((8) - 1)))) {
2139 SplitUVRow_16 = SplitUVRow_16_NEON;
2140 }
2141 }
2142#endif
2143 if (subsample_x) {
2144#if defined(HAS_HALFROW_16TO8_NEON)
2145 if (TestCpuFlag(kCpuHasNEON)) {
2146 Half16To8 = HalfRow_16To8_Any_NEON;
2147 if (IS_ALIGNED(dst_uv_width, 16)(!((uintptr_t)(dst_uv_width) & ((16) - 1)))) {
2148 Half16To8 = HalfRow_16To8_NEON;
2149 }
2150 }
2151#endif
2152#if defined(HAS_HALFROW_16TO8_SVE2)
2153 if (TestCpuFlag(kCpuHasSVE2)) {
2154 Half16To8 = HalfRow_16To8_SVE2;
2155 }
2156#endif
2157#if defined(HAS_HALFROW_16TO8_SME)
2158 if (TestCpuFlag(kCpuHasSME)) {
2159 Half16To8 = HalfRow_16To8_SME;
2160 }
2161#endif
2162#if defined(HAS_HALFROW_16TO8_SSSE3)
2163 if (TestCpuFlag(kCpuHasSSSE3)) {
2164 Half16To8 = HalfRow_16To8_Any_SSSE3;
2165 if (IS_ALIGNED(dst_uv_width, 16)(!((uintptr_t)(dst_uv_width) & ((16) - 1)))) {
2166 Half16To8 = HalfRow_16To8_SSSE3;
2167 }
2168 }
2169#endif
2170#if defined(HAS_HALFROW_16TO8_AVX2)
2171 if (TestCpuFlag(kCpuHasAVX2)) {
2172 Half16To8 = HalfRow_16To8_Any_AVX2;
2173 if (IS_ALIGNED(dst_uv_width, 32)(!((uintptr_t)(dst_uv_width) & ((32) - 1)))) {
2174 Half16To8 = HalfRow_16To8_AVX2;
2175 }
2176 }
2177#endif
2178#if defined(HAS_HALFROW_16TO8_AVX512BW)
2179 if (TestCpuFlag(kCpuHasAVX512BW)) {
2180 Half16To8 = HalfRow_16To8_Any_AVX512BW;
2181 if (IS_ALIGNED(dst_uv_width, 64)(!((uintptr_t)(dst_uv_width) & ((64) - 1)))) {
2182 Half16To8 = HalfRow_16To8_AVX512BW;
2183 }
2184 }
2185#endif
2186#if defined(HAS_HALFROW_16TO8_RVV)
2187 if (TestCpuFlag(kCpuHasRVV)) {
2188 Half16To8 = HalfRow_16To8_RVV;
2189 }
2190#endif
2191 } else if (IS_ALIGNED(width, 2)(!((uintptr_t)(width) & ((2) - 1)))) {
2192#if defined(HAS_HALFWIDTHROW_16TO8_NEON)
2193 if (TestCpuFlag(kCpuHasNEON)) {
2194 Half16To8 = HalfWidthRow_16To8_Any_NEON;
2195 if (IS_ALIGNED(dst_uv_width, 8)(!((uintptr_t)(dst_uv_width) & ((8) - 1)))) {
2196 Half16To8 = HalfWidthRow_16To8_NEON;
2197 }
2198 }
2199#endif
2200#if defined(HAS_HALFWIDTHROW_16TO8_SVE2)
2201 if (TestCpuFlag(kCpuHasSVE2)) {
2202 Half16To8 = HalfWidthRow_16To8_SVE2;
2203 }
2204#endif
2205#if defined(HAS_HALFWIDTHROW_16TO8_SME)
2206 if (TestCpuFlag(kCpuHasSME)) {
2207 Half16To8 = HalfWidthRow_16To8_SME;
2208 }
2209#endif
2210#if defined(HAS_HALFWIDTHROW_16TO8_SSSE3)
2211 if (TestCpuFlag(kCpuHasSSSE3)) {
2212 Half16To8 = HalfWidthRow_16To8_Any_SSSE3;
2213 if (IS_ALIGNED(dst_uv_width, 8)(!((uintptr_t)(dst_uv_width) & ((8) - 1)))) {
2214 Half16To8 = HalfWidthRow_16To8_SSSE3;
2215 }
2216 }
2217#endif
2218#if defined(HAS_HALFWIDTHROW_16TO8_AVX2)
2219 if (TestCpuFlag(kCpuHasAVX2)) {
2220 Half16To8 = HalfWidthRow_16To8_Any_AVX2;
2221 if (IS_ALIGNED(dst_uv_width, 16)(!((uintptr_t)(dst_uv_width) & ((16) - 1)))) {
2222 Half16To8 = HalfWidthRow_16To8_AVX2;
2223 }
2224 }
2225#endif
2226#if defined(HAS_HALFWIDTHROW_16TO8_AVX512BW)
2227 if (TestCpuFlag(kCpuHasAVX512BW)) {
2228 Half16To8 = HalfWidthRow_16To8_Any_AVX512BW;
2229 if (IS_ALIGNED(dst_uv_width, 32)(!((uintptr_t)(dst_uv_width) & ((32) - 1)))) {
2230 Half16To8 = HalfWidthRow_16To8_AVX512BW;
2231 }
2232 }
2233#endif
2234#if defined(HAS_HALFWIDTHROW_16TO8_RVV)
2235 if (TestCpuFlag(kCpuHasRVV)) {
2236 Half16To8 = HalfWidthRow_16To8_RVV;
2237 }
2238#endif
2239 }
2240
2241 row_stride = (src_uv_width + 31) & ~31;
2242 align_buffer_64(row_u, (size_t)row_stride * sizeof(uint16_t) * 4u)size_t row_u_mem_size = ((size_t)row_stride * sizeof(uint16_t
) * 4u); void* row_u_mem = (row_u_mem_size > (18446744073709551615UL
) - 63) ? __null : malloc(row_u_mem_size + 63); uint8_t* row_u
= (uint8_t*)(((intptr_t)row_u_mem + 63) & ~63)
;
2243 if (!row_u) {
2244 return 1;
2245 }
2246 {
2247 uint16_t* row_u0 = (uint16_t*)row_u;
2248 uint16_t* row_u1 = row_u0 + row_stride;
2249 uint16_t* row_v0 = row_u1 + row_stride;
2250 uint16_t* row_v1 = row_v0 + row_stride;
2251 for (y = 0; y < height - 1; y += 2) {
2252 SplitUVRow_16(src_uv, row_u0, row_v0, 10, src_uv_width);
2253 SplitUVRow_16(src_uv + src_stride_uv, row_u1, row_v1, 10, src_uv_width);
2254 Half16To8(row_u0, row_stride, dst_u, scale, dst_uv_width);
2255 Half16To8(row_v0, row_stride, dst_v, scale, dst_uv_width);
2256 src_uv += src_stride_uv * 2;
2257 dst_u += dst_stride_u;
2258 dst_v += dst_stride_v;
2259 }
2260 if (height & 1) {
2261 SplitUVRow_16(src_uv, row_u0, row_v0, 10, src_uv_width);
2262 Half16To8(row_u0, 0, dst_u, scale, dst_uv_width);
2263 Half16To8(row_v0, 0, dst_v, scale, dst_uv_width);
2264 }
2265 }
2266 free_aligned_buffer_64(row_u)free(row_u_mem); row_u = __null;
2267 return 0;
2268 }
2269}
2270
2271LIBYUV_API
2272int P010ToI420(const uint16_t* src_y,
2273 int src_stride_y,
2274 const uint16_t* src_uv,
2275 int src_stride_uv,
2276 uint8_t* dst_y,
2277 int dst_stride_y,
2278 uint8_t* dst_u,
2279 int dst_stride_u,
2280 uint8_t* dst_v,
2281 int dst_stride_v,
2282 int width,
2283 int height) {
2284 return Px10ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
2285 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
2286 width, height, 1, 1);
2287}
2288
2289LIBYUV_API
2290int P210ToI420(const uint16_t* src_y,
2291 int src_stride_y,
2292 const uint16_t* src_uv,
2293 int src_stride_uv,
2294 uint8_t* dst_y,
2295 int dst_stride_y,
2296 uint8_t* dst_u,
2297 int dst_stride_u,
2298 uint8_t* dst_v,
2299 int dst_stride_v,
2300 int width,
2301 int height) {
2302 return Px10ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
2303 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
2304 width, height, 1, 0);
2305}
2306
2307LIBYUV_API
2308int P410ToI420(const uint16_t* src_y,
2309 int src_stride_y,
2310 const uint16_t* src_uv,
2311 int src_stride_uv,
2312 uint8_t* dst_y,
2313 int dst_stride_y,
2314 uint8_t* dst_u,
2315 int dst_stride_u,
2316 uint8_t* dst_v,
2317 int dst_stride_v,
2318 int width,
2319 int height) {
2320 return Px10ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
2321 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
2322 width, height, 0, 0);
2323}
2324
2325LIBYUV_API
2326int P012ToI012(const uint16_t* src_y,
2327 int src_stride_y,
2328 const uint16_t* src_uv,
2329 int src_stride_uv,
2330 uint16_t* dst_y,
2331 int dst_stride_y,
2332 uint16_t* dst_u,
2333 int dst_stride_u,
2334 uint16_t* dst_v,
2335 int dst_stride_v,
2336 int width,
2337 int height) {
2338 return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
2339 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
2340 width, height, 1, 1, 12);
2341}
2342
2343LIBYUV_API
2344int P010ToP410(const uint16_t* src_y,
2345 int src_stride_y,
2346 const uint16_t* src_uv,
2347 int src_stride_uv,
2348 uint16_t* dst_y,
2349 int dst_stride_y,
2350 uint16_t* dst_uv,
2351 int dst_stride_uv,
2352 int width,
2353 int height) {
2354 int r;
2355 if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
2356 height == INT_MIN(-2147483647 -1)) {
2357 return -1;
2358 }
2359
2360 if (dst_y) {
2361 CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
2362 }
2363 r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1)(width < 0) ? (-((-width + 1) >> 1)) : ((width + 1) >>
1)
,
2364 SUBSAMPLE(height, 1, 1)(height < 0) ? (-((-height + 1) >> 1)) : ((height + 1
) >> 1)
, dst_uv, dst_stride_uv, Abs(width),
2365 Abs(height), kFilterBilinear);
2366 return r;
2367}
2368
2369LIBYUV_API
2370int P210ToP410(const uint16_t* src_y,
2371 int src_stride_y,
2372 const uint16_t* src_uv,
2373 int src_stride_uv,
2374 uint16_t* dst_y,
2375 int dst_stride_y,
2376 uint16_t* dst_uv,
2377 int dst_stride_uv,
2378 int width,
2379 int height) {
2380 int r;
2381 if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
2382 height == INT_MIN(-2147483647 -1)) {
2383 return -1;
2384 }
2385
2386 if (dst_y) {
2387 CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
2388 }
2389 r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1)(width < 0) ? (-((-width + 1) >> 1)) : ((width + 1) >>
1)
, height, dst_uv,
2390 dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
2391 return r;
2392}
2393
2394// Convert YUY2 to I420.
2395LIBYUV_API
2396int YUY2ToI420(const uint8_t* src_yuy2,
2397 int src_stride_yuy2,
2398 uint8_t* dst_y,
2399 int dst_stride_y,
2400 uint8_t* dst_u,
2401 int dst_stride_u,
2402 uint8_t* dst_v,
2403 int dst_stride_v,
2404 int width,
2405 int height) {
2406 int y;
2407 void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2,
2408 uint8_t* dst_u, uint8_t* dst_v, int width) =
2409 YUY2ToUVRow_C;
2410 void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) =
2411 YUY2ToYRow_C;
2412 if (width <= 0 || height == 0 || height == INT_MIN(-2147483647 -1)) {
2413 return -1;
2414 }
2415 // Negative height means invert the image.
2416 if (height < 0) {
2417 height = -height;
2418 src_yuy2 = src_yuy2 + (ptrdiff_t)(height - 1) * src_stride_yuy2;
2419 src_stride_yuy2 = -src_stride_yuy2;
2420 }
2421#if defined(HAS_YUY2TOYROW_SSE2)
2422 if (TestCpuFlag(kCpuHasSSE2)) {
2423 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
2424 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
2425 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2426 YUY2ToUVRow = YUY2ToUVRow_SSE2;
2427 YUY2ToYRow = YUY2ToYRow_SSE2;
2428 }
2429 }
2430#endif
2431#if defined(HAS_YUY2TOYROW_AVX2)
2432 if (TestCpuFlag(kCpuHasAVX2)) {
2433 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
2434 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
2435 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
2436 YUY2ToUVRow = YUY2ToUVRow_AVX2;
2437 YUY2ToYRow = YUY2ToYRow_AVX2;
2438 }
2439 }
2440#endif
2441#if defined(HAS_YUY2TOYROW_NEON)
2442 if (TestCpuFlag(kCpuHasNEON)) {
2443 YUY2ToYRow = YUY2ToYRow_Any_NEON;
2444 YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
2445 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2446 YUY2ToYRow = YUY2ToYRow_NEON;
2447 YUY2ToUVRow = YUY2ToUVRow_NEON;
2448 }
2449 }
2450#endif
2451#if defined(HAS_YUY2TOYROW_SVE2) && defined(HAS_YUY2TOUVROW_SVE2)
2452 if (TestCpuFlag(kCpuHasSVE2)) {
2453 YUY2ToYRow = YUY2ToYRow_SVE2;
2454 YUY2ToUVRow = YUY2ToUVRow_SVE2;
2455 }
2456#endif
2457#if defined(HAS_YUY2TOYROW_LSX) && defined(HAS_YUY2TOUVROW_LSX)
2458 if (TestCpuFlag(kCpuHasLSX)) {
2459 YUY2ToYRow = YUY2ToYRow_Any_LSX;
2460 YUY2ToUVRow = YUY2ToUVRow_Any_LSX;
2461 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2462 YUY2ToYRow = YUY2ToYRow_LSX;
2463 YUY2ToUVRow = YUY2ToUVRow_LSX;
2464 }
2465 }
2466#endif
2467#if defined(HAS_YUY2TOYROW_LASX) && defined(HAS_YUY2TOUVROW_LASX)
2468 if (TestCpuFlag(kCpuHasLASX)) {
2469 YUY2ToYRow = YUY2ToYRow_Any_LASX;
2470 YUY2ToUVRow = YUY2ToUVRow_Any_LASX;
2471 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
2472 YUY2ToYRow = YUY2ToYRow_LASX;
2473 YUY2ToUVRow = YUY2ToUVRow_LASX;
2474 }
2475 }
2476#endif
2477
2478 for (y = 0; y < height - 1; y += 2) {
2479 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
2480 YUY2ToYRow(src_yuy2, dst_y, width);
2481 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
2482 src_yuy2 += src_stride_yuy2 * 2;
2483 dst_y += dst_stride_y * 2;
2484 dst_u += dst_stride_u;
2485 dst_v += dst_stride_v;
2486 }
2487 if (height & 1) {
2488 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
2489 YUY2ToYRow(src_yuy2, dst_y, width);
2490 }
2491 return 0;
2492}
2493
2494// Convert UYVY to I420.
2495LIBYUV_API
2496int UYVYToI420(const uint8_t* src_uyvy,
2497 int src_stride_uyvy,
2498 uint8_t* dst_y,
2499 int dst_stride_y,
2500 uint8_t* dst_u,
2501 int dst_stride_u,
2502 uint8_t* dst_v,
2503 int dst_stride_v,
2504 int width,
2505 int height) {
2506 int y;
2507 void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy,
2508 uint8_t* dst_u, uint8_t* dst_v, int width) =
2509 UYVYToUVRow_C;
2510 void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) =
2511 UYVYToYRow_C;
2512 if (width <= 0 || height == 0 || height == INT_MIN(-2147483647 -1)) {
2513 return -1;
2514 }
2515 // Negative height means invert the image.
2516 if (height < 0) {
2517 height = -height;
2518 src_uyvy = src_uyvy + (ptrdiff_t)(height - 1) * src_stride_uyvy;
2519 src_stride_uyvy = -src_stride_uyvy;
2520 }
2521#if defined(HAS_UYVYTOYROW_SSE2)
2522 if (TestCpuFlag(kCpuHasSSE2)) {
2523 UYVYToUVRow = UYVYToUVRow_Any_SSE2;
2524 UYVYToYRow = UYVYToYRow_Any_SSE2;
2525 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2526 UYVYToUVRow = UYVYToUVRow_SSE2;
2527 UYVYToYRow = UYVYToYRow_SSE2;
2528 }
2529 }
2530#endif
2531#if defined(HAS_UYVYTOYROW_AVX2)
2532 if (TestCpuFlag(kCpuHasAVX2)) {
2533 UYVYToUVRow = UYVYToUVRow_Any_AVX2;
2534 UYVYToYRow = UYVYToYRow_Any_AVX2;
2535 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
2536 UYVYToUVRow = UYVYToUVRow_AVX2;
2537 UYVYToYRow = UYVYToYRow_AVX2;
2538 }
2539 }
2540#endif
2541#if defined(HAS_UYVYTOYROW_NEON)
2542 if (TestCpuFlag(kCpuHasNEON)) {
2543 UYVYToYRow = UYVYToYRow_Any_NEON;
2544 UYVYToUVRow = UYVYToUVRow_Any_NEON;
2545 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2546 UYVYToYRow = UYVYToYRow_NEON;
2547 UYVYToUVRow = UYVYToUVRow_NEON;
2548 }
2549 }
2550#endif
2551#if defined(HAS_UYVYTOYROW_SVE2) && defined(HAS_UYVYTOUVROW_SVE2)
2552 if (TestCpuFlag(kCpuHasSVE2)) {
2553 UYVYToYRow = UYVYToYRow_SVE2;
2554 UYVYToUVRow = UYVYToUVRow_SVE2;
2555 }
2556#endif
2557#if defined(HAS_UYVYTOYROW_LSX)
2558 if (TestCpuFlag(kCpuHasLSX)) {
2559 UYVYToYRow = UYVYToYRow_Any_LSX;
2560 UYVYToUVRow = UYVYToUVRow_Any_LSX;
2561 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2562 UYVYToYRow = UYVYToYRow_LSX;
2563 UYVYToUVRow = UYVYToUVRow_LSX;
2564 }
2565 }
2566#endif
2567#if defined(HAS_UYVYTOYROW_LSX)
2568 if (TestCpuFlag(kCpuHasLSX)) {
2569 UYVYToYRow = UYVYToYRow_Any_LSX;
2570 UYVYToUVRow = UYVYToUVRow_Any_LSX;
2571 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2572 UYVYToYRow = UYVYToYRow_LSX;
2573 UYVYToUVRow = UYVYToUVRow_LSX;
2574 }
2575 }
2576#endif
2577#if defined(HAS_UYVYTOYROW_LASX)
2578 if (TestCpuFlag(kCpuHasLASX)) {
2579 UYVYToYRow = UYVYToYRow_Any_LASX;
2580 UYVYToUVRow = UYVYToUVRow_Any_LASX;
2581 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
2582 UYVYToYRow = UYVYToYRow_LASX;
2583 UYVYToUVRow = UYVYToUVRow_LASX;
2584 }
2585 }
2586#endif
2587
2588 for (y = 0; y < height - 1; y += 2) {
2589 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
2590 UYVYToYRow(src_uyvy, dst_y, width);
2591 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
2592 src_uyvy += src_stride_uyvy * 2;
2593 dst_y += dst_stride_y * 2;
2594 dst_u += dst_stride_u;
2595 dst_v += dst_stride_v;
2596 }
2597 if (height & 1) {
2598 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
2599 UYVYToYRow(src_uyvy, dst_y, width);
2600 }
2601 return 0;
2602}
2603
2604// Convert AYUV to NV12.
2605LIBYUV_API
2606int AYUVToNV12(const uint8_t* src_ayuv,
2607 int src_stride_ayuv,
2608 uint8_t* dst_y,
2609 int dst_stride_y,
2610 uint8_t* dst_uv,
2611 int dst_stride_uv,
2612 int width,
2613 int height) {
2614 int y;
2615 void (*AYUVToUVRow)(const uint8_t* src_ayuv, int src_stride_ayuv,
2616 uint8_t* dst_uv, int width) = AYUVToUVRow_C;
2617 void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
2618 AYUVToYRow_C;
2619 if (width <= 0 || height == 0 || height == INT_MIN(-2147483647 -1)) {
2620 return -1;
2621 }
2622 // Negative height means invert the image.
2623 if (height < 0) {
2624 height = -height;
2625 src_ayuv = src_ayuv + (ptrdiff_t)(height - 1) * src_stride_ayuv;
2626 src_stride_ayuv = -src_stride_ayuv;
2627 }
2628// place holders for future intel code
2629#if defined(HAS_AYUVTOYROW_SSE2)
2630 if (TestCpuFlag(kCpuHasSSE2)) {
2631 AYUVToUVRow = AYUVToUVRow_Any_SSE2;
2632 AYUVToYRow = AYUVToYRow_Any_SSE2;
2633 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2634 AYUVToUVRow = AYUVToUVRow_SSE2;
2635 AYUVToYRow = AYUVToYRow_SSE2;
2636 }
2637 }
2638#endif
2639#if defined(HAS_AYUVTOYROW_AVX2)
2640 if (TestCpuFlag(kCpuHasAVX2)) {
2641 AYUVToUVRow = AYUVToUVRow_Any_AVX2;
2642 AYUVToYRow = AYUVToYRow_Any_AVX2;
2643 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
2644 AYUVToUVRow = AYUVToUVRow_AVX2;
2645 AYUVToYRow = AYUVToYRow_AVX2;
2646 }
2647 }
2648#endif
2649
2650#if defined(HAS_AYUVTOYROW_NEON)
2651 if (TestCpuFlag(kCpuHasNEON)) {
2652 AYUVToYRow = AYUVToYRow_Any_NEON;
2653 AYUVToUVRow = AYUVToUVRow_Any_NEON;
2654 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2655 AYUVToYRow = AYUVToYRow_NEON;
2656 AYUVToUVRow = AYUVToUVRow_NEON;
2657 }
2658 }
2659#endif
2660#if defined(HAS_AYUVTOUVROW_SVE2)
2661 if (TestCpuFlag(kCpuHasSVE2)) {
2662 AYUVToUVRow = AYUVToUVRow_Any_SVE2;
2663 if (IS_ALIGNED(width, 2)(!((uintptr_t)(width) & ((2) - 1)))) {
2664 AYUVToUVRow = AYUVToUVRow_SVE2;
2665 }
2666 }
2667#endif
2668
2669 for (y = 0; y < height - 1; y += 2) {
2670 AYUVToUVRow(src_ayuv, src_stride_ayuv, dst_uv, width);
2671 AYUVToYRow(src_ayuv, dst_y, width);
2672 AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
2673 src_ayuv += src_stride_ayuv * 2;
2674 dst_y += dst_stride_y * 2;
2675 dst_uv += dst_stride_uv;
2676 }
2677 if (height & 1) {
2678 AYUVToUVRow(src_ayuv, 0, dst_uv, width);
2679 AYUVToYRow(src_ayuv, dst_y, width);
2680 }
2681 return 0;
2682}
2683
2684// Convert AYUV to NV21.
2685LIBYUV_API
2686int AYUVToNV21(const uint8_t* src_ayuv,
2687 int src_stride_ayuv,
2688 uint8_t* dst_y,
2689 int dst_stride_y,
2690 uint8_t* dst_vu,
2691 int dst_stride_vu,
2692 int width,
2693 int height) {
2694 int y;
2695 void (*AYUVToVURow)(const uint8_t* src_ayuv, int src_stride_ayuv,
2696 uint8_t* dst_vu, int width) = AYUVToVURow_C;
2697 void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
2698 AYUVToYRow_C;
2699 if (width <= 0 || height == 0 || height == INT_MIN(-2147483647 -1)) {
2700 return -1;
2701 }
2702 // Negative height means invert the image.
2703 if (height < 0) {
2704 height = -height;
2705 src_ayuv = src_ayuv + (ptrdiff_t)(height - 1) * src_stride_ayuv;
2706 src_stride_ayuv = -src_stride_ayuv;
2707 }
2708// place holders for future intel code
2709#if defined(HAS_AYUVTOYROW_SSE2)
2710 if (TestCpuFlag(kCpuHasSSE2)) {
2711 AYUVToVURow = AYUVToVURow_Any_SSE2;
2712 AYUVToYRow = AYUVToYRow_Any_SSE2;
2713 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2714 AYUVToVURow = AYUVToVURow_SSE2;
2715 AYUVToYRow = AYUVToYRow_SSE2;
2716 }
2717 }
2718#endif
2719#if defined(HAS_AYUVTOYROW_AVX2)
2720 if (TestCpuFlag(kCpuHasAVX2)) {
2721 AYUVToVURow = AYUVToVURow_Any_AVX2;
2722 AYUVToYRow = AYUVToYRow_Any_AVX2;
2723 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
2724 AYUVToVURow = AYUVToVURow_AVX2;
2725 AYUVToYRow = AYUVToYRow_AVX2;
2726 }
2727 }
2728#endif
2729
2730#if defined(HAS_AYUVTOYROW_NEON)
2731 if (TestCpuFlag(kCpuHasNEON)) {
2732 AYUVToYRow = AYUVToYRow_Any_NEON;
2733 AYUVToVURow = AYUVToVURow_Any_NEON;
2734 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2735 AYUVToYRow = AYUVToYRow_NEON;
2736 AYUVToVURow = AYUVToVURow_NEON;
2737 }
2738 }
2739#endif
2740#if defined(HAS_AYUVTOVUROW_SVE2)
2741 if (TestCpuFlag(kCpuHasSVE2)) {
2742 AYUVToVURow = AYUVToVURow_Any_SVE2;
2743 if (IS_ALIGNED(width, 2)(!((uintptr_t)(width) & ((2) - 1)))) {
2744 AYUVToVURow = AYUVToVURow_SVE2;
2745 }
2746 }
2747#endif
2748
2749 for (y = 0; y < height - 1; y += 2) {
2750 AYUVToVURow(src_ayuv, src_stride_ayuv, dst_vu, width);
2751 AYUVToYRow(src_ayuv, dst_y, width);
2752 AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
2753 src_ayuv += src_stride_ayuv * 2;
2754 dst_y += dst_stride_y * 2;
2755 dst_vu += dst_stride_vu;
2756 }
2757 if (height & 1) {
2758 AYUVToVURow(src_ayuv, 0, dst_vu, width);
2759 AYUVToYRow(src_ayuv, dst_y, width);
2760 }
2761 return 0;
2762}
2763
2764// Convert ARGB to I420.
2765LIBYUV_API
2766int ARGBToI420(const uint8_t* src_argb,
2767 int src_stride_argb,
2768 uint8_t* dst_y,
2769 int dst_stride_y,
2770 uint8_t* dst_u,
2771 int dst_stride_u,
2772 uint8_t* dst_v,
2773 int dst_stride_v,
2774 int width,
2775 int height) {
2776 return ARGBToI420Matrix(src_argb, src_stride_argb, dst_y, dst_stride_y, dst_u,
2777 dst_stride_u, dst_v, dst_stride_v,
2778 &kArgbI601Constants, width, height);
2779}
2780
2781LIBYUV_API
2782int ARGBToI420Matrix(const uint8_t* src_argb,
2783 int src_stride_argb,
2784 uint8_t* dst_y,
2785 int dst_stride_y,
2786 uint8_t* dst_u,
2787 int dst_stride_u,
2788 uint8_t* dst_v,
2789 int dst_stride_v,
2790 const struct ArgbConstants* argbconstants,
2791 int width,
2792 int height) {
2793 int y;
2794 void (*ARGBToYMatrixRow)(const uint8_t* src_argb, uint8_t* dst_y, int width,
2795 const struct ArgbConstants* c) = ARGBToYMatrixRow_C;
2796 void (*ARGBToUVMatrixRow)(const uint8_t* src_argb, int src_stride_argb,
2797 uint8_t* dst_u, uint8_t* dst_v, int width,
2798 const struct ArgbConstants* c) =
2799 ARGBToUVMatrixRow_C;
2800
2801#if defined(HAS_ARGBTOYMATRIXROW_SSSE3)
2802 if (TestCpuFlag(kCpuHasSSSE3)) {
2803 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_SSSE3;
2804 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2805 ARGBToYMatrixRow = ARGBToYMatrixRow_SSSE3;
2806 }
2807 }
2808#endif
2809#if defined(HAS_ARGBTOYMATRIXROW_AVX2)
2810 if (TestCpuFlag(kCpuHasAVX2)) {
2811 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX2;
2812 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
2813 ARGBToYMatrixRow = ARGBToYMatrixRow_AVX2;
2814 }
2815 }
2816#endif
2817#if defined(HAS_ARGBTOYMATRIXROW_AVX512BW)
2818 if (TestCpuFlag(kCpuHasAVX512BW)) {
2819 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX512BW;
2820 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
2821 ARGBToYMatrixRow = ARGBToYMatrixRow_AVX512BW;
2822 }
2823 }
2824#endif
2825#if defined(HAS_ARGBTOYMATRIXROW_NEON)
2826 if (TestCpuFlag(kCpuHasNEON)) {
2827 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON;
2828 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2829 ARGBToYMatrixRow = ARGBToYMatrixRow_NEON;
2830 }
2831 }
2832#endif
2833#if defined(HAS_ARGBTOYMATRIXROW_NEON_DOTPROD)
2834 if (TestCpuFlag(kCpuHasNeonDotProd)) {
2835 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON_DotProd;
2836 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2837 ARGBToYMatrixRow = ARGBToYMatrixRow_NEON_DotProd;
2838 }
2839 }
2840#endif
2841#if defined(HAS_ARGBTOYMATRIXROW_SVE2)
2842 if (TestCpuFlag(kCpuHasSVE2)) {
2843 ARGBToYMatrixRow = ARGBToYMatrixRow_SVE2;
2844 }
2845#endif
2846#if defined(HAS_ARGBTOYMATRIXROW_SME)
2847 if (TestCpuFlag(kCpuHasSME)) {
2848 ARGBToYMatrixRow = ARGBToYMatrixRow_SME;
2849 }
2850#endif
2851#if defined(HAS_ARGBTOYMATRIXROW_LSX)
2852 if (TestCpuFlag(kCpuHasLSX)) {
2853 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LSX;
2854 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2855 ARGBToYMatrixRow = ARGBToYMatrixRow_LSX;
2856 }
2857 }
2858#endif
2859#if defined(HAS_ARGBTOYMATRIXROW_LASX)
2860 if (TestCpuFlag(kCpuHasLASX)) {
2861 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LASX;
2862 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
2863 ARGBToYMatrixRow = ARGBToYMatrixRow_LASX;
2864 }
2865 }
2866#endif
2867#if defined(HAS_ARGBTOYMATRIXROW_RVV)
2868 if (TestCpuFlag(kCpuHasRVV)) {
2869 ARGBToYMatrixRow = ARGBToYMatrixRow_RVV;
2870 }
2871#endif
2872#if defined(HAS_ARGBTOYMATRIXROW_WASMSIMD)
2873 if (TestCpuFlag(kCpuHasWASMSIMD)) {
2874 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_WASMSIMD;
2875 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2876 ARGBToYMatrixRow = ARGBToYMatrixRow_WASMSIMD;
2877 }
2878 }
2879#endif
2880
2881#if defined(HAS_ARGBTOUVMATRIXROW_NEON)
2882 if (TestCpuFlag(kCpuHasNEON)) {
2883 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON;
2884 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2885 ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON;
2886 }
2887 }
2888#endif
2889#if defined(HAS_ARGBTOUVMATRIXROW_NEON_I8MM)
2890 if (TestCpuFlag(kCpuHasNeonI8MM)) {
2891 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON_I8MM;
2892 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2893 ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON_I8MM;
2894 }
2895 }
2896#endif
2897#if defined(HAS_ARGBTOUVMATRIXROW_SVE2)
2898 if (TestCpuFlag(kCpuHasSVE2)) {
2899 if (IS_ALIGNED(width, 2)(!((uintptr_t)(width) & ((2) - 1)))) {
2900 ARGBToUVMatrixRow = ARGBToUVMatrixRow_SVE2;
2901 }
2902 }
2903#endif
2904#if defined(HAS_ARGBTOUVMATRIXROW_SME)
2905 if (TestCpuFlag(kCpuHasSME)) {
2906 if (IS_ALIGNED(width, 2)(!((uintptr_t)(width) & ((2) - 1)))) {
2907 ARGBToUVMatrixRow = ARGBToUVMatrixRow_SME;
2908 }
2909 }
2910#endif
2911#if defined(HAS_ARGBTOUVMATRIXROW_SSSE3)
2912 if (TestCpuFlag(kCpuHasSSSE3)) {
2913 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_SSSE3;
2914 if (IS_ALIGNED(width, 8)(!((uintptr_t)(width) & ((8) - 1)))) {
2915 ARGBToUVMatrixRow = ARGBToUVMatrixRow_SSSE3;
2916 }
2917 }
2918#endif
2919#if defined(HAS_ARGBTOUVMATRIXROW_AVX2)
2920 if (TestCpuFlag(kCpuHasAVX2)) {
2921 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX2;
2922 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
2923 ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX2;
2924 }
2925 }
2926#endif
2927#if defined(HAS_ARGBTOUVMATRIXROW_AVX512BW)
2928 if (TestCpuFlag(kCpuHasAVX512BW)) {
2929 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX512BW;
2930 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
2931 ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX512BW;
2932 }
2933 }
2934#endif
2935#if defined(HAS_ARGBTOUVMATRIXROW_RVV)
2936 if (TestCpuFlag(kCpuHasRVV)) {
2937 ARGBToUVMatrixRow = ARGBToUVMatrixRow_RVV;
2938 }
2939#endif
2940#if defined(HAS_ARGBTOUVMATRIXROW_WASMSIMD)
2941 if (TestCpuFlag(kCpuHasWASMSIMD)) {
2942 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_WASMSIMD;
2943 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
2944 ARGBToUVMatrixRow = ARGBToUVMatrixRow_WASMSIMD;
2945 }
2946 }
2947#endif
2948 if (!src_argb || !dst_y || !dst_u || !dst_v || !argbconstants || width <= 0 ||
2949 height == 0 || height == INT_MIN(-2147483647 -1)) {
2950 return -1;
2951 }
2952 // Negative height means invert the image.
2953 if (height < 0) {
2954 height = -height;
2955 src_argb = src_argb + (ptrdiff_t)(height - 1) * src_stride_argb;
2956 src_stride_argb = -src_stride_argb;
2957 }
2958
2959 for (y = 0; y < height - 1; y += 2) {
2960 ARGBToUVMatrixRow(src_argb, src_stride_argb, dst_u, dst_v, width,
2961 argbconstants);
2962 ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants);
2963 ARGBToYMatrixRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width,
2964 argbconstants);
2965 src_argb += src_stride_argb * 2;
2966 dst_y += dst_stride_y * 2;
2967 dst_u += dst_stride_u;
2968 dst_v += dst_stride_v;
2969 }
2970 if (height & 1) {
2971 ARGBToUVMatrixRow(src_argb, 0, dst_u, dst_v, width, argbconstants);
2972 ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants);
2973 }
2974 return 0;
2975}
2976
2977#ifdef USE_EXTRACTALPHA
2978// Convert ARGB to I420 with Alpha
2979// The following version calls ARGBExtractAlpha on the full image.
2980LIBYUV_API
2981int ARGBToI420Alpha(const uint8_t* src_argb,
2982 int src_stride_argb,
2983 uint8_t* dst_y,
2984 int dst_stride_y,
2985 uint8_t* dst_u,
2986 int dst_stride_u,
2987 uint8_t* dst_v,
2988 int dst_stride_v,
2989 uint8_t* dst_a,
2990 int dst_stride_a,
2991 int width,
2992 int height) {
2993 int r = ARGBToI420(src_argb, src_stride_argb, dst_y, dst_stride_y, dst_u,
2994 dst_stride_u, dst_v, dst_stride_v, width, height);
2995 if (r == 0) {
2996 r = ARGBExtractAlpha(src_argb, src_stride_argb, dst_a, dst_stride_a, width,
2997 height);
2998 }
2999 return r;
3000}
3001#else // USE_EXTRACTALPHA
3002// Convert ARGB to I420 with Alpha
3003LIBYUV_API
3004int ARGBToI420Alpha(const uint8_t* src_argb,
3005 int src_stride_argb,
3006 uint8_t* dst_y,
3007 int dst_stride_y,
3008 uint8_t* dst_u,
3009 int dst_stride_u,
3010 uint8_t* dst_v,
3011 int dst_stride_v,
3012 uint8_t* dst_a,
3013 int dst_stride_a,
3014 int width,
3015 int height) {
3016 int y;
3017 void (*ARGBToYMatrixRow)(const uint8_t* src_argb, uint8_t* dst_y, int width,
3018 const struct ArgbConstants* c) = ARGBToYMatrixRow_C;
3019 void (*ARGBToUVMatrixRow)(const uint8_t* src_argb, int src_stride_argb,
3020 uint8_t* dst_u, uint8_t* dst_v, int width,
3021 const struct ArgbConstants* c) =
3022 ARGBToUVMatrixRow_C;
3023 void (*ARGBExtractAlphaRow)(const uint8_t* src_argb, uint8_t* dst_a,
3024 int width) = ARGBExtractAlphaRow_C;
3025 if (!src_argb || !dst_y || !dst_u || !dst_v || !dst_a || width <= 0 ||
3026 height == 0 || height == INT_MIN(-2147483647 -1)) {
3027 return -1;
3028 }
3029 // Negative height means invert the image.
3030 if (height < 0) {
3031 height = -height;
3032 src_argb = src_argb + (ptrdiff_t)(height - 1) * src_stride_argb;
3033 src_stride_argb = -src_stride_argb;
3034 }
3035
3036#if defined(HAS_ARGBTOYMATRIXROW_SSSE3)
3037 if (TestCpuFlag(kCpuHasSSSE3)) {
3038 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_SSSE3;
3039 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3040 ARGBToYMatrixRow = ARGBToYMatrixRow_SSSE3;
3041 }
3042 }
3043#endif
3044#if defined(HAS_ARGBTOYMATRIXROW_AVX2)
3045 if (TestCpuFlag(kCpuHasAVX2)) {
3046 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX2;
3047 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3048 ARGBToYMatrixRow = ARGBToYMatrixRow_AVX2;
3049 }
3050 }
3051#endif
3052#if defined(HAS_ARGBTOYMATRIXROW_AVX512BW)
3053 if (TestCpuFlag(kCpuHasAVX512BW)) {
3054 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX512BW;
3055 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3056 ARGBToYMatrixRow = ARGBToYMatrixRow_AVX512BW;
3057 }
3058 }
3059#endif
3060#if defined(HAS_ARGBTOYMATRIXROW_NEON)
3061 if (TestCpuFlag(kCpuHasNEON)) {
3062 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON;
3063 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3064 ARGBToYMatrixRow = ARGBToYMatrixRow_NEON;
3065 }
3066 }
3067#endif
3068#if defined(HAS_ARGBTOYMATRIXROW_NEON_DOTPROD)
3069 if (TestCpuFlag(kCpuHasNeonDotProd)) {
3070 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON_DotProd;
3071 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3072 ARGBToYMatrixRow = ARGBToYMatrixRow_NEON_DotProd;
3073 }
3074 }
3075#endif
3076#if defined(HAS_ARGBTOYMATRIXROW_SVE2)
3077 if (TestCpuFlag(kCpuHasSVE2)) {
3078 ARGBToYMatrixRow = ARGBToYMatrixRow_SVE2;
3079 }
3080#endif
3081#if defined(HAS_ARGBTOYMATRIXROW_SME)
3082 if (TestCpuFlag(kCpuHasSME)) {
3083 ARGBToYMatrixRow = ARGBToYMatrixRow_SME;
3084 }
3085#endif
3086#if defined(HAS_ARGBTOYMATRIXROW_LSX)
3087 if (TestCpuFlag(kCpuHasLSX)) {
3088 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LSX;
3089 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3090 ARGBToYMatrixRow = ARGBToYMatrixRow_LSX;
3091 }
3092 }
3093#endif
3094#if defined(HAS_ARGBTOYMATRIXROW_LASX)
3095 if (TestCpuFlag(kCpuHasLASX)) {
3096 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LASX;
3097 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3098 ARGBToYMatrixRow = ARGBToYMatrixRow_LASX;
3099 }
3100 }
3101#endif
3102#if defined(HAS_ARGBTOYMATRIXROW_RVV)
3103 if (TestCpuFlag(kCpuHasRVV)) {
3104 ARGBToYMatrixRow = ARGBToYMatrixRow_RVV;
3105 }
3106#endif
3107#if defined(HAS_ARGBTOYMATRIXROW_WASMSIMD)
3108 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3109 ARGBToYMatrixRow = ARGBToYMatrixRow_Any_WASMSIMD;
3110 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3111 ARGBToYMatrixRow = ARGBToYMatrixRow_WASMSIMD;
3112 }
3113 }
3114#endif
3115
3116#if defined(HAS_ARGBTOUVMATRIXROW_NEON)
3117 if (TestCpuFlag(kCpuHasNEON)) {
3118 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON;
3119 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3120 ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON;
3121 }
3122 }
3123#endif
3124#if defined(HAS_ARGBTOUVMATRIXROW_NEON_I8MM)
3125 if (TestCpuFlag(kCpuHasNeonI8MM)) {
3126 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON_I8MM;
3127 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3128 ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON_I8MM;
3129 }
3130 }
3131#endif
3132#if defined(HAS_ARGBTOUVMATRIXROW_SVE2)
3133 if (TestCpuFlag(kCpuHasSVE2)) {
3134 if (IS_ALIGNED(width, 2)(!((uintptr_t)(width) & ((2) - 1)))) {
3135 ARGBToUVMatrixRow = ARGBToUVMatrixRow_SVE2;
3136 }
3137 }
3138#endif
3139#if defined(HAS_ARGBTOUVMATRIXROW_SME)
3140 if (TestCpuFlag(kCpuHasSME)) {
3141 if (IS_ALIGNED(width, 2)(!((uintptr_t)(width) & ((2) - 1)))) {
3142 ARGBToUVMatrixRow = ARGBToUVMatrixRow_SME;
3143 }
3144 }
3145#endif
3146#if defined(HAS_ARGBTOUVMATRIXROW_SSSE3)
3147 if (TestCpuFlag(kCpuHasSSSE3)) {
3148 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_SSSE3;
3149 if (IS_ALIGNED(width, 8)(!((uintptr_t)(width) & ((8) - 1)))) {
3150 ARGBToUVMatrixRow = ARGBToUVMatrixRow_SSSE3;
3151 }
3152 }
3153#endif
3154#if defined(HAS_ARGBTOUVMATRIXROW_AVX2)
3155 if (TestCpuFlag(kCpuHasAVX2)) {
3156 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX2;
3157 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3158 ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX2;
3159 }
3160 }
3161#endif
3162#if defined(HAS_ARGBTOUVMATRIXROW_AVX512BW)
3163 if (TestCpuFlag(kCpuHasAVX512BW)) {
3164 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX512BW;
3165 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3166 ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX512BW;
3167 }
3168 }
3169#endif
3170#if defined(HAS_ARGBTOUVMATRIXROW_RVV)
3171 if (TestCpuFlag(kCpuHasRVV)) {
3172 ARGBToUVMatrixRow = ARGBToUVMatrixRow_RVV;
3173 }
3174#endif
3175#if defined(HAS_ARGBTOUVMATRIXROW_WASMSIMD)
3176 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3177 ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_WASMSIMD;
3178 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3179 ARGBToUVMatrixRow = ARGBToUVMatrixRow_WASMSIMD;
3180 }
3181 }
3182#endif
3183
3184#if defined(HAS_ARGBEXTRACTALPHAROW_SSE2)
3185 if (TestCpuFlag(kCpuHasSSE2)) {
3186 ARGBExtractAlphaRow = IS_ALIGNED(width, 8)(!((uintptr_t)(width) & ((8) - 1))) ? ARGBExtractAlphaRow_SSE2
3187 : ARGBExtractAlphaRow_Any_SSE2;
3188 }
3189#endif
3190#if defined(HAS_ARGBEXTRACTALPHAROW_AVX2)
3191 if (TestCpuFlag(kCpuHasAVX2)) {
3192 ARGBExtractAlphaRow = IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1))) ? ARGBExtractAlphaRow_AVX2
3193 : ARGBExtractAlphaRow_Any_AVX2;
3194 }
3195#endif
3196#if defined(HAS_ARGBEXTRACTALPHAROW_AVX512BW)
3197 if (TestCpuFlag(kCpuHasAVX512BW)) {
3198 ARGBExtractAlphaRow = ARGBExtractAlphaRow_AVX512BW;
3199 }
3200#endif
3201#if defined(HAS_ARGBEXTRACTALPHAROW_NEON)
3202 if (TestCpuFlag(kCpuHasNEON)) {
3203 ARGBExtractAlphaRow = IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1))) ? ARGBExtractAlphaRow_NEON
3204 : ARGBExtractAlphaRow_Any_NEON;
3205 }
3206#endif
3207#if defined(HAS_ARGBEXTRACTALPHAROW_LSX)
3208 if (TestCpuFlag(kCpuHasLSX)) {
3209 ARGBExtractAlphaRow = IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1))) ? ARGBExtractAlphaRow_LSX
3210 : ARGBExtractAlphaRow_Any_LSX;
3211 }
3212#endif
3213#if defined(HAS_ARGBEXTRACTALPHAROW_WASMSIMD)
3214 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3215 ARGBExtractAlphaRow = IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))
3216 ? ARGBExtractAlphaRow_WASMSIMD
3217 : ARGBExtractAlphaRow_Any_WASMSIMD;
3218 }
3219#endif
3220#if defined(HAS_ARGBEXTRACTALPHAROW_RVV)
3221 if (TestCpuFlag(kCpuHasRVV)) {
3222 ARGBExtractAlphaRow = ARGBExtractAlphaRow_RVV;
3223 }
3224#endif
3225
3226 for (y = 0; y < height - 1; y += 2) {
3227 ARGBToUVMatrixRow(src_argb, src_stride_argb, dst_u, dst_v, width,
3228 &kArgbI601Constants);
3229 ARGBToYMatrixRow(src_argb, dst_y, width, &kArgbI601Constants);
3230 ARGBToYMatrixRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width,
3231 &kArgbI601Constants);
3232 ARGBExtractAlphaRow(src_argb, dst_a, width);
3233 ARGBExtractAlphaRow(src_argb + src_stride_argb, dst_a + dst_stride_a,
3234 width);
3235 src_argb += src_stride_argb * 2;
3236 dst_y += dst_stride_y * 2;
3237 dst_u += dst_stride_u;
3238 dst_v += dst_stride_v;
3239 dst_a += dst_stride_a * 2;
3240 }
3241 if (height & 1) {
3242 ARGBToUVMatrixRow(src_argb, 0, dst_u, dst_v, width, &kArgbI601Constants);
3243 ARGBToYMatrixRow(src_argb, dst_y, width, &kArgbI601Constants);
3244 ARGBExtractAlphaRow(src_argb, dst_a, width);
3245 }
3246 return 0;
3247}
3248#endif // USE_EXTRACTALPHA
3249
3250// Convert BGRA to I420.
3251LIBYUV_API
3252int BGRAToI420(const uint8_t* src_bgra,
3253 int src_stride_bgra,
3254 uint8_t* dst_y,
3255 int dst_stride_y,
3256 uint8_t* dst_u,
3257 int dst_stride_u,
3258 uint8_t* dst_v,
3259 int dst_stride_v,
3260 int width,
3261 int height) {
3262 return ARGBToI420Matrix(src_bgra, src_stride_bgra, dst_y, dst_stride_y, dst_u,
3263 dst_stride_u, dst_v, dst_stride_v,
3264 &kBgraI601Constants, width, height);
3265}
3266
3267// Convert BGRA to I422.
3268LIBYUV_API
3269int BGRAToI422(const uint8_t* src_bgra,
3270 int src_stride_bgra,
3271 uint8_t* dst_y,
3272 int dst_stride_y,
3273 uint8_t* dst_u,
3274 int dst_stride_u,
3275 uint8_t* dst_v,
3276 int dst_stride_v,
3277 int width,
3278 int height) {
3279 return ARGBToI422Matrix(src_bgra, src_stride_bgra, dst_y, dst_stride_y, dst_u,
3280 dst_stride_u, dst_v, dst_stride_v,
3281 &kBgraI601Constants, width, height);
3282}
3283
3284// Convert ABGR to I422.
3285LIBYUV_API
3286int ABGRToI422(const uint8_t* src_abgr,
3287 int src_stride_abgr,
3288 uint8_t* dst_y,
3289 int dst_stride_y,
3290 uint8_t* dst_u,
3291 int dst_stride_u,
3292 uint8_t* dst_v,
3293 int dst_stride_v,
3294 int width,
3295 int height) {
3296 return ARGBToI422Matrix(src_abgr, src_stride_abgr, dst_y, dst_stride_y, dst_u,
3297 dst_stride_u, dst_v, dst_stride_v,
3298 &kAbgrI601Constants, width, height);
3299}
3300
3301// Convert RGBA to I422.
3302LIBYUV_API
3303int RGBAToI422(const uint8_t* src_rgba,
3304 int src_stride_rgba,
3305 uint8_t* dst_y,
3306 int dst_stride_y,
3307 uint8_t* dst_u,
3308 int dst_stride_u,
3309 uint8_t* dst_v,
3310 int dst_stride_v,
3311 int width,
3312 int height) {
3313 return ARGBToI422Matrix(src_rgba, src_stride_rgba, dst_y, dst_stride_y, dst_u,
3314 dst_stride_u, dst_v, dst_stride_v,
3315 &kRgbaI601Constants, width, height);
3316}
3317
3318// Convert ABGR to I420.
3319LIBYUV_API
3320int ABGRToI420(const uint8_t* src_abgr,
3321 int src_stride_abgr,
3322 uint8_t* dst_y,
3323 int dst_stride_y,
3324 uint8_t* dst_u,
3325 int dst_stride_u,
3326 uint8_t* dst_v,
3327 int dst_stride_v,
3328 int width,
3329 int height) {
3330 return ARGBToI420Matrix(src_abgr, src_stride_abgr, dst_y, dst_stride_y, dst_u,
3331 dst_stride_u, dst_v, dst_stride_v,
3332 &kAbgrI601Constants, width, height);
3333}
3334
3335// Convert RGBA to I420.
3336LIBYUV_API
3337int RGBAToI420(const uint8_t* src_rgba,
3338 int src_stride_rgba,
3339 uint8_t* dst_y,
3340 int dst_stride_y,
3341 uint8_t* dst_u,
3342 int dst_stride_u,
3343 uint8_t* dst_v,
3344 int dst_stride_v,
3345 int width,
3346 int height) {
3347 return ARGBToI420Matrix(src_rgba, src_stride_rgba, dst_y, dst_stride_y, dst_u,
3348 dst_stride_u, dst_v, dst_stride_v,
3349 &kRgbaI601Constants, width, height);
3350}
3351
3352// Enabled if 1 pass is available
3353#if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_LSX) || \
3354 defined(HAS_RGB24TOYROW_RVV))
3355#define HAS_RGB24TOYROW
3356#endif
3357
3358// Convert RGB24 to I420.
3359LIBYUV_API
3360int RGB24ToI420(const uint8_t* src_rgb24,
3361 int src_stride_rgb24,
3362 uint8_t* dst_y,
3363 int dst_stride_y,
3364 uint8_t* dst_u,
3365 int dst_stride_u,
3366 uint8_t* dst_v,
3367 int dst_stride_v,
3368 int width,
3369 int height) {
3370 int y;
3371 void (*RGBToUVMatrixRow)(const uint8_t* src_rgb, int src_stride_rgb,
3372 uint8_t* dst_u, uint8_t* dst_v, int width,
3373 const struct ArgbConstants* c) = RGBToUVMatrixRow_C;
3374 void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3375 const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3376
3377#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3378 if (TestCpuFlag(kCpuHasSSSE3)) {
3379 RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3380 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3381 RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3382 }
3383 }
3384#endif
3385#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3386 if (TestCpuFlag(kCpuHasAVX2)) {
3387 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3388 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3389 RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3390 }
3391 }
3392#endif
3393#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3394 if (TestCpuFlag(kCpuHasAVX512BW)) {
3395 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3396 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3397 RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3398 }
3399 }
3400#endif
3401#if defined(HAS_RGBTOUVMATRIXROW_SSSE3)
3402 if (TestCpuFlag(kCpuHasSSSE3)) {
3403 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_SSSE3;
3404 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3405 RGBToUVMatrixRow = RGBToUVMatrixRow_SSSE3;
3406 }
3407 }
3408#endif
3409#if defined(HAS_RGBTOUVMATRIXROW_AVX2)
3410 if (TestCpuFlag(kCpuHasAVX2)) {
3411 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX2;
3412 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3413 RGBToUVMatrixRow = RGBToUVMatrixRow_AVX2;
3414 }
3415 }
3416#endif
3417#if defined(HAS_RGBTOUVMATRIXROW_AVX512BW)
3418 if (TestCpuFlag(kCpuHasAVX512BW)) {
3419 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX512BW;
3420 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3421 RGBToUVMatrixRow = RGBToUVMatrixRow_AVX512BW;
3422 }
3423 }
3424#endif
3425#if defined(HAS_RGBTOUVMATRIXROW_NEON)
3426 if (TestCpuFlag(kCpuHasNEON)) {
3427 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_NEON;
3428 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3429 RGBToUVMatrixRow = RGBToUVMatrixRow_NEON;
3430 }
3431 }
3432#endif
3433#if defined(HAS_RGBTOYMATRIXROW_NEON)
3434 if (TestCpuFlag(kCpuHasNEON)) {
3435 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3436 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3437 RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3438 }
3439 }
3440#endif
3441#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3442 if (TestCpuFlag(kCpuHasNeonDotProd)) {
3443 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3444 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3445 RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3446 }
3447 }
3448#endif
3449#if defined(HAS_RGBTOUVMATRIXROW_RVV)
3450 if (TestCpuFlag(kCpuHasRVV)) {
3451 RGBToUVMatrixRow = RGBToUVMatrixRow_RVV;
3452 }
3453#endif
3454#if defined(HAS_RGBTOYMATRIXROW_RVV)
3455 if (TestCpuFlag(kCpuHasRVV)) {
3456 RGBToYMatrixRow = RGBToYMatrixRow_RVV;
3457 }
3458#endif
3459#if defined(HAS_RGBTOUVMATRIXROW_WASMSIMD)
3460 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3461 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_WASMSIMD;
3462 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3463 RGBToUVMatrixRow = RGBToUVMatrixRow_WASMSIMD;
3464 }
3465 }
3466#endif
3467#if defined(HAS_RGBTOYMATRIXROW_WASMSIMD)
3468 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3469 RGBToYMatrixRow = RGBToYMatrixRow_Any_WASMSIMD;
3470 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3471 RGBToYMatrixRow = RGBToYMatrixRow_WASMSIMD;
3472 }
3473 }
3474#endif
3475
3476 if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
3477 height == INT_MIN(-2147483647 -1)) {
3478 return -1;
3479 }
3480 // Negative height means invert the image.
3481 if (height < 0) {
3482 height = -height;
3483 src_rgb24 = src_rgb24 + (ptrdiff_t)(height - 1) * src_stride_rgb24;
3484 src_stride_rgb24 = -src_stride_rgb24;
3485 }
3486
3487 for (y = 0; y < height - 1; y += 2) {
3488 RGBToUVMatrixRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width,
3489 &kArgbI601Constants);
3490 RGBToYMatrixRow(src_rgb24, dst_y, width, &kArgbI601Constants);
3491 RGBToYMatrixRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width,
3492 &kArgbI601Constants);
3493 src_rgb24 += src_stride_rgb24 * 2;
3494 dst_y += dst_stride_y * 2;
3495 dst_u += dst_stride_u;
3496 dst_v += dst_stride_v;
3497 }
3498 if (height & 1) {
3499 RGBToYMatrixRow(src_rgb24, dst_y, width, &kArgbI601Constants);
3500 RGBToUVMatrixRow(src_rgb24, 0, dst_u, dst_v, width, &kArgbI601Constants);
3501 }
3502 return 0;
3503}
3504#undef HAS_RGB24TOYROW
3505
3506/// Convert RGB24 to J420.
3507LIBYUV_API
3508int RGB24ToJ420(const uint8_t* src_rgb24,
3509 int src_stride_rgb24,
3510 uint8_t* dst_y,
3511 int dst_stride_y,
3512 uint8_t* dst_u,
3513 int dst_stride_u,
3514 uint8_t* dst_v,
3515 int dst_stride_v,
3516 int width,
3517 int height) {
3518 int y;
3519 void (*RGBToUVMatrixRow)(const uint8_t* src_rgb, int src_stride_rgb,
3520 uint8_t* dst_u, uint8_t* dst_v, int width,
3521 const struct ArgbConstants* c) = RGBToUVMatrixRow_C;
3522 void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3523 const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3524
3525#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3526 if (TestCpuFlag(kCpuHasSSSE3)) {
3527 RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3528 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3529 RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3530 }
3531 }
3532#endif
3533#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3534 if (TestCpuFlag(kCpuHasAVX2)) {
3535 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3536 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3537 RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3538 }
3539 }
3540#endif
3541#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3542 if (TestCpuFlag(kCpuHasAVX512BW)) {
3543 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3544 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3545 RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3546 }
3547 }
3548#endif
3549#if defined(HAS_RGBTOUVMATRIXROW_SSSE3)
3550 if (TestCpuFlag(kCpuHasSSSE3)) {
3551 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_SSSE3;
3552 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3553 RGBToUVMatrixRow = RGBToUVMatrixRow_SSSE3;
3554 }
3555 }
3556#endif
3557#if defined(HAS_RGBTOUVMATRIXROW_AVX2)
3558 if (TestCpuFlag(kCpuHasAVX2)) {
3559 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX2;
3560 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3561 RGBToUVMatrixRow = RGBToUVMatrixRow_AVX2;
3562 }
3563 }
3564#endif
3565#if defined(HAS_RGBTOUVMATRIXROW_AVX512BW)
3566 if (TestCpuFlag(kCpuHasAVX512BW)) {
3567 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX512BW;
3568 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3569 RGBToUVMatrixRow = RGBToUVMatrixRow_AVX512BW;
3570 }
3571 }
3572#endif
3573#if defined(HAS_RGBTOUVMATRIXROW_NEON)
3574 if (TestCpuFlag(kCpuHasNEON)) {
3575 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_NEON;
3576 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3577 RGBToUVMatrixRow = RGBToUVMatrixRow_NEON;
3578 }
3579 }
3580#endif
3581#if defined(HAS_RGBTOYMATRIXROW_NEON)
3582 if (TestCpuFlag(kCpuHasNEON)) {
3583 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3584 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3585 RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3586 }
3587 }
3588#endif
3589#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3590 if (TestCpuFlag(kCpuHasNeonDotProd)) {
3591 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3592 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3593 RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3594 }
3595 }
3596#endif
3597#if defined(HAS_RGBTOUVMATRIXROW_RVV)
3598 if (TestCpuFlag(kCpuHasRVV)) {
3599 RGBToUVMatrixRow = RGBToUVMatrixRow_RVV;
3600 }
3601#endif
3602#if defined(HAS_RGBTOYMATRIXROW_RVV)
3603 if (TestCpuFlag(kCpuHasRVV)) {
3604 RGBToYMatrixRow = RGBToYMatrixRow_RVV;
3605 }
3606#endif
3607#if defined(HAS_RGBTOUVMATRIXROW_WASMSIMD)
3608 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3609 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_WASMSIMD;
3610 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3611 RGBToUVMatrixRow = RGBToUVMatrixRow_WASMSIMD;
3612 }
3613 }
3614#endif
3615#if defined(HAS_RGBTOYMATRIXROW_WASMSIMD)
3616 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3617 RGBToYMatrixRow = RGBToYMatrixRow_Any_WASMSIMD;
3618 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3619 RGBToYMatrixRow = RGBToYMatrixRow_WASMSIMD;
3620 }
3621 }
3622#endif
3623
3624 if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
3625 height == INT_MIN(-2147483647 -1)) {
3626 return -1;
3627 }
3628 // Negative height means invert the image.
3629 if (height < 0) {
3630 height = -height;
3631 src_rgb24 = src_rgb24 + (ptrdiff_t)(height - 1) * src_stride_rgb24;
3632 src_stride_rgb24 = -src_stride_rgb24;
3633 }
3634
3635 for (y = 0; y < height - 1; y += 2) {
3636 RGBToUVMatrixRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width,
3637 &kArgbJPEGConstants);
3638 RGBToYMatrixRow(src_rgb24, dst_y, width, &kArgbJPEGConstants);
3639 RGBToYMatrixRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width,
3640 &kArgbJPEGConstants);
3641 src_rgb24 += src_stride_rgb24 * 2;
3642 dst_y += dst_stride_y * 2;
3643 dst_u += dst_stride_u;
3644 dst_v += dst_stride_v;
3645 }
3646 if (height & 1) {
3647 RGBToYMatrixRow(src_rgb24, dst_y, width, &kArgbJPEGConstants);
3648 RGBToUVMatrixRow(src_rgb24, 0, dst_u, dst_v, width, &kArgbJPEGConstants);
3649 }
3650 return 0;
3651}
3652
3653// Enabled if 1 pass is available
3654#if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_LSX) || \
3655 defined(HAS_RAWTOYROW_RVV))
3656#define HAS_RAWTOYROW
3657#endif
3658
3659// Convert RAW to I420.
3660LIBYUV_API
3661int RAWToI420(const uint8_t* src_raw,
3662 int src_stride_raw,
3663 uint8_t* dst_y,
3664 int dst_stride_y,
3665 uint8_t* dst_u,
3666 int dst_stride_u,
3667 uint8_t* dst_v,
3668 int dst_stride_v,
3669 int width,
3670 int height) {
3671 int y;
3672 void (*RGBToUVMatrixRow)(const uint8_t* src_rgb, int src_stride_rgb,
3673 uint8_t* dst_u, uint8_t* dst_v, int width,
3674 const struct ArgbConstants* c) = RGBToUVMatrixRow_C;
3675 void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3676 const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3677
3678#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3679 if (TestCpuFlag(kCpuHasSSSE3)) {
3680 RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3681 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3682 RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3683 }
3684 }
3685#endif
3686#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3687 if (TestCpuFlag(kCpuHasAVX2)) {
3688 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3689 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3690 RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3691 }
3692 }
3693#endif
3694#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3695 if (TestCpuFlag(kCpuHasAVX512BW)) {
3696 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3697 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3698 RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3699 }
3700 }
3701#endif
3702#if defined(HAS_RGBTOUVMATRIXROW_SSSE3)
3703 if (TestCpuFlag(kCpuHasSSSE3)) {
3704 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_SSSE3;
3705 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3706 RGBToUVMatrixRow = RGBToUVMatrixRow_SSSE3;
3707 }
3708 }
3709#endif
3710#if defined(HAS_RGBTOUVMATRIXROW_AVX2)
3711 if (TestCpuFlag(kCpuHasAVX2)) {
3712 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX2;
3713 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3714 RGBToUVMatrixRow = RGBToUVMatrixRow_AVX2;
3715 }
3716 }
3717#endif
3718#if defined(HAS_RGBTOUVMATRIXROW_AVX512BW)
3719 if (TestCpuFlag(kCpuHasAVX512BW)) {
3720 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX512BW;
3721 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3722 RGBToUVMatrixRow = RGBToUVMatrixRow_AVX512BW;
3723 }
3724 }
3725#endif
3726#if defined(HAS_RGBTOUVMATRIXROW_NEON)
3727 if (TestCpuFlag(kCpuHasNEON)) {
3728 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_NEON;
3729 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3730 RGBToUVMatrixRow = RGBToUVMatrixRow_NEON;
3731 }
3732 }
3733#endif
3734#if defined(HAS_RGBTOYMATRIXROW_NEON)
3735 if (TestCpuFlag(kCpuHasNEON)) {
3736 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3737 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3738 RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3739 }
3740 }
3741#endif
3742#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3743 if (TestCpuFlag(kCpuHasNeonDotProd)) {
3744 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3745 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3746 RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3747 }
3748 }
3749#endif
3750#if defined(HAS_RGBTOUVMATRIXROW_WASMSIMD)
3751 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3752 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_WASMSIMD;
3753 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3754 RGBToUVMatrixRow = RGBToUVMatrixRow_WASMSIMD;
3755 }
3756 }
3757#endif
3758#if defined(HAS_RGBTOYMATRIXROW_WASMSIMD)
3759 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3760 RGBToYMatrixRow = RGBToYMatrixRow_Any_WASMSIMD;
3761 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3762 RGBToYMatrixRow = RGBToYMatrixRow_WASMSIMD;
3763 }
3764 }
3765#endif
3766
3767 if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
3768 height == INT_MIN(-2147483647 -1)) {
3769 return -1;
3770 }
3771 // Negative height means invert the image.
3772 if (height < 0) {
3773 height = -height;
3774 src_raw = src_raw + (ptrdiff_t)(height - 1) * src_stride_raw;
3775 src_stride_raw = -src_stride_raw;
3776 }
3777
3778 for (y = 0; y < height - 1; y += 2) {
3779 RGBToUVMatrixRow(src_raw, src_stride_raw, dst_u, dst_v, width,
3780 &kAbgrI601Constants);
3781 RGBToYMatrixRow(src_raw, dst_y, width, &kAbgrI601Constants);
3782 RGBToYMatrixRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width,
3783 &kAbgrI601Constants);
3784 src_raw += src_stride_raw * 2;
3785 dst_y += dst_stride_y * 2;
3786 dst_u += dst_stride_u;
3787 dst_v += dst_stride_v;
3788 }
3789 if (height & 1) {
3790 RGBToYMatrixRow(src_raw, dst_y, width, &kAbgrI601Constants);
3791 RGBToUVMatrixRow(src_raw, 0, dst_u, dst_v, width, &kAbgrI601Constants);
3792 }
3793 return 0;
3794}
3795#undef HAS_RAWTOYROW
3796
3797// Convert RAW to J420.
3798LIBYUV_API
3799int RAWToJ420(const uint8_t* src_raw,
3800 int src_stride_raw,
3801 uint8_t* dst_y,
3802 int dst_stride_y,
3803 uint8_t* dst_u,
3804 int dst_stride_u,
3805 uint8_t* dst_v,
3806 int dst_stride_v,
3807 int width,
3808 int height) {
3809 int y;
3810 void (*RGBToUVMatrixRow)(const uint8_t* src_rgb, int src_stride_rgb,
3811 uint8_t* dst_u, uint8_t* dst_v, int width,
3812 const struct ArgbConstants* c) = RGBToUVMatrixRow_C;
3813 void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3814 const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3815
3816#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3817 if (TestCpuFlag(kCpuHasSSSE3)) {
3818 RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3819 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3820 RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3821 }
3822 }
3823#endif
3824#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3825 if (TestCpuFlag(kCpuHasAVX2)) {
3826 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3827 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3828 RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3829 }
3830 }
3831#endif
3832#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3833 if (TestCpuFlag(kCpuHasAVX512BW)) {
3834 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3835 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3836 RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3837 }
3838 }
3839#endif
3840#if defined(HAS_RGBTOUVMATRIXROW_SSSE3)
3841 if (TestCpuFlag(kCpuHasSSSE3)) {
3842 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_SSSE3;
3843 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3844 RGBToUVMatrixRow = RGBToUVMatrixRow_SSSE3;
3845 }
3846 }
3847#endif
3848#if defined(HAS_RGBTOUVMATRIXROW_AVX2)
3849 if (TestCpuFlag(kCpuHasAVX2)) {
3850 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX2;
3851 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3852 RGBToUVMatrixRow = RGBToUVMatrixRow_AVX2;
3853 }
3854 }
3855#endif
3856#if defined(HAS_RGBTOUVMATRIXROW_AVX512BW)
3857 if (TestCpuFlag(kCpuHasAVX512BW)) {
3858 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_AVX512BW;
3859 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3860 RGBToUVMatrixRow = RGBToUVMatrixRow_AVX512BW;
3861 }
3862 }
3863#endif
3864#if defined(HAS_RGBTOUVMATRIXROW_NEON)
3865 if (TestCpuFlag(kCpuHasNEON)) {
3866 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_NEON;
3867 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3868 RGBToUVMatrixRow = RGBToUVMatrixRow_NEON;
3869 }
3870 }
3871#endif
3872#if defined(HAS_RGBTOYMATRIXROW_NEON)
3873 if (TestCpuFlag(kCpuHasNEON)) {
3874 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3875 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3876 RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3877 }
3878 }
3879#endif
3880#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3881 if (TestCpuFlag(kCpuHasNeonDotProd)) {
3882 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3883 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3884 RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3885 }
3886 }
3887#endif
3888#if defined(HAS_RGBTOUVMATRIXROW_WASMSIMD)
3889 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3890 RGBToUVMatrixRow = RGBToUVMatrixRow_Any_WASMSIMD;
3891 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3892 RGBToUVMatrixRow = RGBToUVMatrixRow_WASMSIMD;
3893 }
3894 }
3895#endif
3896#if defined(HAS_RGBTOYMATRIXROW_WASMSIMD)
3897 if (TestCpuFlag(kCpuHasWASMSIMD)) {
3898 RGBToYMatrixRow = RGBToYMatrixRow_Any_WASMSIMD;
3899 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3900 RGBToYMatrixRow = RGBToYMatrixRow_WASMSIMD;
3901 }
3902 }
3903#endif
3904
3905 if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
3906 height == INT_MIN(-2147483647 -1)) {
3907 return -1;
3908 }
3909 // Negative height means invert the image.
3910 if (height < 0) {
3911 height = -height;
3912 src_raw = src_raw + (ptrdiff_t)(height - 1) * src_stride_raw;
3913 src_stride_raw = -src_stride_raw;
3914 }
3915
3916 for (y = 0; y < height - 1; y += 2) {
3917 RGBToUVMatrixRow(src_raw, src_stride_raw, dst_u, dst_v, width,
3918 &kAbgrJPEGConstants);
3919 RGBToYMatrixRow(src_raw, dst_y, width, &kAbgrJPEGConstants);
3920 RGBToYMatrixRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width,
3921 &kAbgrJPEGConstants);
3922 src_raw += src_stride_raw * 2;
3923 dst_y += dst_stride_y * 2;
3924 dst_u += dst_stride_u;
3925 dst_v += dst_stride_v;
3926 }
3927 if (height & 1) {
3928 RGBToYMatrixRow(src_raw, dst_y, width, &kAbgrJPEGConstants);
3929 RGBToUVMatrixRow(src_raw, 0, dst_u, dst_v, width, &kAbgrJPEGConstants);
3930 }
3931 return 0;
3932}
3933
3934// Convert RAW to I444 with matrix.
3935static int RAWToI444Matrix(const uint8_t* src_raw,
3936 int src_stride_raw,
3937 uint8_t* dst_y,
3938 int dst_stride_y,
3939 uint8_t* dst_u,
3940 int dst_stride_u,
3941 uint8_t* dst_v,
3942 int dst_stride_v,
3943 const struct ArgbConstants* argbconstants,
3944 int width,
3945 int height) {
3946 int y;
3947 void (*RGBToUV444MatrixRow)(
3948 const uint8_t* src_rgb, uint8_t* dst_u, uint8_t* dst_v, int width,
3949 const struct ArgbConstants* c) = RGBToUV444MatrixRow_C;
3950 void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
3951 const struct ArgbConstants* c) = RGBToYMatrixRow_C;
3952
3953#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
3954 if (TestCpuFlag(kCpuHasSSSE3)) {
3955 RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
3956 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3957 RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
3958 }
3959 }
3960#endif
3961#if defined(HAS_RGBTOYMATRIXROW_AVX2)
3962 if (TestCpuFlag(kCpuHasAVX2)) {
3963 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
3964 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
3965 RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
3966 }
3967 }
3968#endif
3969#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
3970 if (TestCpuFlag(kCpuHasAVX512BW)) {
3971 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
3972 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
3973 RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
3974 }
3975 }
3976#endif
3977#if defined(HAS_RGBTOYMATRIXROW_NEON)
3978 if (TestCpuFlag(kCpuHasNEON)) {
3979 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
3980 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3981 RGBToYMatrixRow = RGBToYMatrixRow_NEON;
3982 }
3983 }
3984#endif
3985#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
3986 if (TestCpuFlag(kCpuHasNeonDotProd)) {
3987 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
3988 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3989 RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
3990 }
3991 }
3992#endif
3993#if defined(HAS_RGBTOYMATRIXROW_LSX)
3994 if (TestCpuFlag(kCpuHasLSX)) {
3995 RGBToYMatrixRow = RGBToYMatrixRow_Any_LSX;
3996 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
3997 RGBToYMatrixRow = RGBToYMatrixRow_LSX;
3998 }
3999 }
4000#endif
4001#if defined(HAS_RGBTOYMATRIXROW_LASX)
4002 if (TestCpuFlag(kCpuHasLASX)) {
4003 RGBToYMatrixRow = RGBToYMatrixRow_Any_LASX;
4004 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
4005 RGBToYMatrixRow = RGBToYMatrixRow_LASX;
4006 }
4007 }
4008#endif
4009#if defined(HAS_RGBTOYMATRIXROW_RVV)
4010 if (TestCpuFlag(kCpuHasRVV)) {
4011 RGBToYMatrixRow = RGBToYMatrixRow_RVV;
4012 }
4013#endif
4014#if defined(HAS_RGBTOYMATRIXROW_WASMSIMD)
4015 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4016 RGBToYMatrixRow = RGBToYMatrixRow_Any_WASMSIMD;
4017 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4018 RGBToYMatrixRow = RGBToYMatrixRow_WASMSIMD;
4019 }
4020 }
4021#endif
4022
4023#if defined(HAS_RGBTOUV444MATRIXROW_SSSE3)
4024 if (TestCpuFlag(kCpuHasSSSE3)) {
4025 RGBToUV444MatrixRow = RGBToUV444MatrixRow_Any_SSSE3;
4026 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4027 RGBToUV444MatrixRow = RGBToUV444MatrixRow_SSSE3;
4028 }
4029 }
4030#endif
4031#if defined(HAS_RGBTOUV444MATRIXROW_AVX2)
4032 if (TestCpuFlag(kCpuHasAVX2)) {
4033 RGBToUV444MatrixRow = RGBToUV444MatrixRow_Any_AVX2;
4034 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
4035 RGBToUV444MatrixRow = RGBToUV444MatrixRow_AVX2;
4036 }
4037 }
4038#endif
4039#if defined(HAS_RGBTOUV444MATRIXROW_AVX512BW)
4040 if (TestCpuFlag(kCpuHasAVX512BW)) {
4041 RGBToUV444MatrixRow = RGBToUV444MatrixRow_Any_AVX512BW;
4042 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
4043 RGBToUV444MatrixRow = RGBToUV444MatrixRow_AVX512BW;
4044 }
4045 }
4046#endif
4047#if defined(HAS_RGBTOUV444MATRIXROW_NEON)
4048 if (TestCpuFlag(kCpuHasNEON)) {
4049 RGBToUV444MatrixRow = RGBToUV444MatrixRow_Any_NEON;
4050 if (IS_ALIGNED(width, 8)(!((uintptr_t)(width) & ((8) - 1)))) {
4051 RGBToUV444MatrixRow = RGBToUV444MatrixRow_NEON;
4052 }
4053 }
4054#endif
4055#if defined(HAS_RGBTOUV444MATRIXROW_RVV)
4056 if (TestCpuFlag(kCpuHasRVV)) {
4057 RGBToUV444MatrixRow = RGBToUV444MatrixRow_RVV;
4058 }
4059#endif
4060#if defined(HAS_RGBTOUV444MATRIXROW_WASMSIMD)
4061 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4062 RGBToUV444MatrixRow = RGBToUV444MatrixRow_Any_WASMSIMD;
4063 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4064 RGBToUV444MatrixRow = RGBToUV444MatrixRow_WASMSIMD;
4065 }
4066 }
4067#endif
4068
4069 if (!src_raw || !dst_y || !dst_u || !dst_v || !argbconstants || width <= 0 ||
4070 height == 0 || height == INT_MIN(-2147483647 -1)) {
4071 return -1;
4072 }
4073 if (height < 0) {
4074 height = -height;
4075 src_raw = src_raw + (ptrdiff_t)(height - 1) * src_stride_raw;
4076 src_stride_raw = -src_stride_raw;
4077 }
4078
4079 for (y = 0; y < height; ++y) {
4080 RGBToYMatrixRow(src_raw, dst_y, width, argbconstants);
4081 RGBToUV444MatrixRow(src_raw, dst_u, dst_v, width, argbconstants);
4082 src_raw += src_stride_raw;
4083 dst_y += dst_stride_y;
4084 dst_u += dst_stride_u;
4085 dst_v += dst_stride_v;
4086 }
4087 return 0;
4088}
4089
4090// Convert RAW to I444.
4091LIBYUV_API
4092int RAWToI444(const uint8_t* src_raw,
4093 int src_stride_raw,
4094 uint8_t* dst_y,
4095 int dst_stride_y,
4096 uint8_t* dst_u,
4097 int dst_stride_u,
4098 uint8_t* dst_v,
4099 int dst_stride_v,
4100 int width,
4101 int height) {
4102 return RAWToI444Matrix(src_raw, src_stride_raw, dst_y, dst_stride_y, dst_u,
4103 dst_stride_u, dst_v, dst_stride_v, &kAbgrI601Constants,
4104 width, height);
4105}
4106
4107// Convert RAW to J444.
4108LIBYUV_API
4109int RAWToJ444(const uint8_t* src_raw,
4110 int src_stride_raw,
4111 uint8_t* dst_y,
4112 int dst_stride_y,
4113 uint8_t* dst_u,
4114 int dst_stride_u,
4115 uint8_t* dst_v,
4116 int dst_stride_v,
4117 int width,
4118 int height) {
4119 return RAWToI444Matrix(src_raw, src_stride_raw, dst_y, dst_stride_y, dst_u,
4120 dst_stride_u, dst_v, dst_stride_v, &kAbgrJPEGConstants,
4121 width, height);
4122}
4123
4124// Convert RGB565 to I420.
4125LIBYUV_API
4126int RGB565ToI420(const uint8_t* src_rgb565,
4127 int src_stride_rgb565,
4128 uint8_t* dst_y,
4129 int dst_stride_y,
4130 uint8_t* dst_u,
4131 int dst_stride_u,
4132 uint8_t* dst_v,
4133 int dst_stride_v,
4134 int width,
4135 int height) {
4136 int y;
4137 void (*RGB565ToUVMatrixRow)(const uint8_t* src_rgb565, int src_stride_rgb565,
4138 uint8_t* dst_u, uint8_t* dst_v, int width,
4139 const struct ArgbConstants* c) =
4140 RGB565ToUVMatrixRow_C;
4141 void (*RGB565ToYMatrixRow)(const uint8_t* src_rgb565, uint8_t* dst_y,
4142 int width, const struct ArgbConstants* c) =
4143 RGB565ToYMatrixRow_C;
4144
4145#if defined(HAS_RGB565TOYMATRIXROW_AVX2)
4146 if (TestCpuFlag(kCpuHasAVX2)) {
4147 RGB565ToYMatrixRow = RGB565ToYMatrixRow_Any_AVX2;
4148 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
4149 RGB565ToYMatrixRow = RGB565ToYMatrixRow_AVX2;
4150 }
4151 }
4152#endif
4153#if defined(HAS_RGB565TOUVMATRIXROW_AVX2)
4154 if (TestCpuFlag(kCpuHasAVX2)) {
4155 RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_Any_AVX2;
4156 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4157 RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_AVX2;
4158 }
4159 }
4160#endif
4161#if defined(HAS_RGB565TOUVMATRIXROW_NEON)
4162 if (TestCpuFlag(kCpuHasNEON)) {
4163 RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_Any_NEON;
4164 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4165 RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_NEON;
4166 }
4167 }
4168#endif
4169#if defined(HAS_RGB565TOYMATRIXROW_NEON)
4170 if (TestCpuFlag(kCpuHasNEON)) {
4171 RGB565ToYMatrixRow = RGB565ToYMatrixRow_Any_NEON;
4172 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4173 RGB565ToYMatrixRow = RGB565ToYMatrixRow_NEON;
4174 }
4175 }
4176#endif
4177#if defined(HAS_RGB565TOUVMATRIXROW_WASMSIMD)
4178 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4179 RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_Any_WASMSIMD;
4180 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4181 RGB565ToUVMatrixRow = RGB565ToUVMatrixRow_WASMSIMD;
4182 }
4183 }
4184#endif
4185#if defined(HAS_RGB565TOYMATRIXROW_WASMSIMD)
4186 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4187 RGB565ToYMatrixRow = RGB565ToYMatrixRow_Any_WASMSIMD;
4188 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4189 RGB565ToYMatrixRow = RGB565ToYMatrixRow_WASMSIMD;
4190 }
4191 }
4192#endif
4193
4194 if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0 ||
4195 height == INT_MIN(-2147483647 -1)) {
4196 return -1;
4197 }
4198 // Negative height means invert the image.
4199 if (height < 0) {
4200 height = -height;
4201 src_rgb565 = src_rgb565 + (ptrdiff_t)(height - 1) * src_stride_rgb565;
4202 src_stride_rgb565 = -src_stride_rgb565;
4203 }
4204
4205 for (y = 0; y < height - 1; y += 2) {
4206 RGB565ToUVMatrixRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width,
4207 &kArgbI601Constants);
4208 RGB565ToYMatrixRow(src_rgb565, dst_y, width, &kArgbI601Constants);
4209 RGB565ToYMatrixRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y,
4210 width, &kArgbI601Constants);
4211 src_rgb565 += src_stride_rgb565 * 2;
4212 dst_y += dst_stride_y * 2;
4213 dst_u += dst_stride_u;
4214 dst_v += dst_stride_v;
4215 }
4216 if (height & 1) {
4217 RGB565ToYMatrixRow(src_rgb565, dst_y, width, &kArgbI601Constants);
4218 RGB565ToUVMatrixRow(src_rgb565, 0, dst_u, dst_v, width,
4219 &kArgbI601Constants);
4220 }
4221 return 0;
4222}
4223// Convert ARGB1555 to I420.
4224LIBYUV_API
4225int ARGB1555ToI420(const uint8_t* src_argb1555,
4226 int src_stride_argb1555,
4227 uint8_t* dst_y,
4228 int dst_stride_y,
4229 uint8_t* dst_u,
4230 int dst_stride_u,
4231 uint8_t* dst_v,
4232 int dst_stride_v,
4233 int width,
4234 int height) {
4235 int y;
4236 void (*ARGB1555ToUVMatrixRow)(
4237 const uint8_t* src_argb1555, int src_stride_argb1555, uint8_t* dst_u,
4238 uint8_t* dst_v, int width, const struct ArgbConstants* c) =
4239 ARGB1555ToUVMatrixRow_C;
4240 void (*ARGB1555ToYMatrixRow)(const uint8_t* src_argb1555, uint8_t* dst_y,
4241 int width, const struct ArgbConstants* c) =
4242 ARGB1555ToYMatrixRow_C;
4243
4244#if defined(HAS_ARGB1555TOYMATRIXROW_AVX2)
4245 if (TestCpuFlag(kCpuHasAVX2)) {
4246 ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_Any_AVX2;
4247 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
4248 ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_AVX2;
4249 }
4250 }
4251#endif
4252#if defined(HAS_ARGB1555TOUVMATRIXROW_AVX2)
4253 if (TestCpuFlag(kCpuHasAVX2)) {
4254 ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_Any_AVX2;
4255 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4256 ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_AVX2;
4257 }
4258 }
4259#endif
4260#if defined(HAS_ARGB1555TOUVMATRIXROW_NEON)
4261 if (TestCpuFlag(kCpuHasNEON)) {
4262 ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_Any_NEON;
4263 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4264 ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_NEON;
4265 }
4266 }
4267#endif
4268#if defined(HAS_ARGB1555TOYMATRIXROW_NEON)
4269 if (TestCpuFlag(kCpuHasNEON)) {
4270 ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_Any_NEON;
4271 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4272 ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_NEON;
4273 }
4274 }
4275#endif
4276#if defined(HAS_ARGB1555TOUVMATRIXROW_WASMSIMD)
4277 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4278 ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_Any_WASMSIMD;
4279 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4280 ARGB1555ToUVMatrixRow = ARGB1555ToUVMatrixRow_WASMSIMD;
4281 }
4282 }
4283#endif
4284#if defined(HAS_ARGB1555TOYMATRIXROW_WASMSIMD)
4285 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4286 ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_Any_WASMSIMD;
4287 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4288 ARGB1555ToYMatrixRow = ARGB1555ToYMatrixRow_WASMSIMD;
4289 }
4290 }
4291#endif
4292
4293 if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
4294 height == 0 || height == INT_MIN(-2147483647 -1)) {
4295 return -1;
4296 }
4297 // Negative height means invert the image.
4298 if (height < 0) {
4299 height = -height;
4300 src_argb1555 = src_argb1555 + (ptrdiff_t)(height - 1) * src_stride_argb1555;
4301 src_stride_argb1555 = -src_stride_argb1555;
4302 }
4303
4304 for (y = 0; y < height - 1; y += 2) {
4305 ARGB1555ToUVMatrixRow(src_argb1555, src_stride_argb1555, dst_u, dst_v,
4306 width, &kArgbI601Constants);
4307 ARGB1555ToYMatrixRow(src_argb1555, dst_y, width, &kArgbI601Constants);
4308 ARGB1555ToYMatrixRow(src_argb1555 + src_stride_argb1555,
4309 dst_y + dst_stride_y, width, &kArgbI601Constants);
4310 src_argb1555 += src_stride_argb1555 * 2;
4311 dst_y += dst_stride_y * 2;
4312 dst_u += dst_stride_u;
4313 dst_v += dst_stride_v;
4314 }
4315 if (height & 1) {
4316 ARGB1555ToYMatrixRow(src_argb1555, dst_y, width, &kArgbI601Constants);
4317 ARGB1555ToUVMatrixRow(src_argb1555, 0, dst_u, dst_v, width,
4318 &kArgbI601Constants);
4319 }
4320 return 0;
4321}
4322// Convert ARGB4444 to I420.
4323LIBYUV_API
4324int ARGB4444ToI420(const uint8_t* src_argb4444,
4325 int src_stride_argb4444,
4326 uint8_t* dst_y,
4327 int dst_stride_y,
4328 uint8_t* dst_u,
4329 int dst_stride_u,
4330 uint8_t* dst_v,
4331 int dst_stride_v,
4332 int width,
4333 int height) {
4334 int y;
4335 void (*ARGB4444ToUVMatrixRow)(
4336 const uint8_t* src_argb4444, int src_stride_argb4444, uint8_t* dst_u,
4337 uint8_t* dst_v, int width, const struct ArgbConstants* c) =
4338 ARGB4444ToUVMatrixRow_C;
4339 void (*ARGB4444ToYMatrixRow)(const uint8_t* src_argb4444, uint8_t* dst_y,
4340 int width, const struct ArgbConstants* c) =
4341 ARGB4444ToYMatrixRow_C;
4342
4343#if defined(HAS_ARGB4444TOYMATRIXROW_AVX2)
4344 if (TestCpuFlag(kCpuHasAVX2)) {
4345 ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_Any_AVX2;
4346 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
4347 ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_AVX2;
4348 }
4349 }
4350#endif
4351#if defined(HAS_ARGB4444TOUVMATRIXROW_AVX2)
4352 if (TestCpuFlag(kCpuHasAVX2)) {
4353 ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_Any_AVX2;
4354 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4355 ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_AVX2;
4356 }
4357 }
4358#endif
4359#if defined(HAS_ARGB4444TOUVMATRIXROW_NEON)
4360 if (TestCpuFlag(kCpuHasNEON)) {
4361 ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_Any_NEON;
4362 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4363 ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_NEON;
4364 }
4365 }
4366#endif
4367#if defined(HAS_ARGB4444TOYMATRIXROW_NEON)
4368 if (TestCpuFlag(kCpuHasNEON)) {
4369 ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_Any_NEON;
4370 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4371 ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_NEON;
4372 }
4373 }
4374#endif
4375#if defined(HAS_ARGB4444TOUVMATRIXROW_WASMSIMD)
4376 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4377 ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_Any_WASMSIMD;
4378 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4379 ARGB4444ToUVMatrixRow = ARGB4444ToUVMatrixRow_WASMSIMD;
4380 }
4381 }
4382#endif
4383#if defined(HAS_ARGB4444TOYMATRIXROW_WASMSIMD)
4384 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4385 ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_Any_WASMSIMD;
4386 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4387 ARGB4444ToYMatrixRow = ARGB4444ToYMatrixRow_WASMSIMD;
4388 }
4389 }
4390#endif
4391
4392 if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
4393 height == 0 || height == INT_MIN(-2147483647 -1)) {
4394 return -1;
4395 }
4396 // Negative height means invert the image.
4397 if (height < 0) {
4398 height = -height;
4399 src_argb4444 = src_argb4444 + (ptrdiff_t)(height - 1) * src_stride_argb4444;
4400 src_stride_argb4444 = -src_stride_argb4444;
4401 }
4402
4403 for (y = 0; y < height - 1; y += 2) {
4404 ARGB4444ToUVMatrixRow(src_argb4444, src_stride_argb4444, dst_u, dst_v,
4405 width, &kArgbI601Constants);
4406 ARGB4444ToYMatrixRow(src_argb4444, dst_y, width, &kArgbI601Constants);
4407 ARGB4444ToYMatrixRow(src_argb4444 + src_stride_argb4444,
4408 dst_y + dst_stride_y, width, &kArgbI601Constants);
4409 src_argb4444 += src_stride_argb4444 * 2;
4410 dst_y += dst_stride_y * 2;
4411 dst_u += dst_stride_u;
4412 dst_v += dst_stride_v;
4413 }
4414 if (height & 1) {
4415 ARGB4444ToYMatrixRow(src_argb4444, dst_y, width, &kArgbI601Constants);
4416 ARGB4444ToUVMatrixRow(src_argb4444, 0, dst_u, dst_v, width,
4417 &kArgbI601Constants);
4418 }
4419 return 0;
4420}
4421// Convert RGB24 to J400.
4422LIBYUV_API
4423int RGB24ToJ400(const uint8_t* src_rgb24,
4424 int src_stride_rgb24,
4425 uint8_t* dst_yj,
4426 int dst_stride_yj,
4427 int width,
4428 int height) {
4429 int y;
4430 void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
4431 const struct ArgbConstants* c) = RGBToYMatrixRow_C;
4432 if (!src_rgb24 || !dst_yj || width <= 0 || height == 0 || height == INT_MIN(-2147483647 -1)) {
4433 return -1;
4434 }
4435 if (height < 0) {
4436 height = -height;
4437 src_rgb24 = src_rgb24 + (ptrdiff_t)(height - 1) * src_stride_rgb24;
4438 src_stride_rgb24 = -src_stride_rgb24;
4439 }
4440 // Coalesce rows.
4441 if (src_stride_rgb24 == width * 3 && dst_stride_yj == width &&
4442 (ptrdiff_t)width * height <= INT_MAX2147483647) {
4443 width *= height;
4444 height = 1;
4445 src_stride_rgb24 = dst_stride_yj = 0;
4446 }
4447
4448#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
4449 if (TestCpuFlag(kCpuHasSSSE3)) {
4450 RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
4451 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4452 RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
4453 }
4454 }
4455#endif
4456#if defined(HAS_RGBTOYMATRIXROW_AVX2)
4457 if (TestCpuFlag(kCpuHasAVX2)) {
4458 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
4459 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
4460 RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
4461 }
4462 }
4463#endif
4464#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
4465 if (TestCpuFlag(kCpuHasAVX512BW)) {
4466 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
4467 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
4468 RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
4469 }
4470 }
4471#endif
4472#if defined(HAS_RGBTOYMATRIXROW_NEON)
4473 if (TestCpuFlag(kCpuHasNEON)) {
4474 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
4475 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4476 RGBToYMatrixRow = RGBToYMatrixRow_NEON;
4477 }
4478 }
4479#endif
4480#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
4481 if (TestCpuFlag(kCpuHasNeonDotProd)) {
4482 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
4483 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4484 RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
4485 }
4486 }
4487#endif
4488#if defined(HAS_RGBTOYMATRIXROW_LSX)
4489 if (TestCpuFlag(kCpuHasLSX)) {
4490 RGBToYMatrixRow = RGBToYMatrixRow_Any_LSX;
4491 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4492 RGBToYMatrixRow = RGBToYMatrixRow_LSX;
4493 }
4494 }
4495#endif
4496#if defined(HAS_RGBTOYMATRIXROW_LASX)
4497 if (TestCpuFlag(kCpuHasLASX)) {
4498 RGBToYMatrixRow = RGBToYMatrixRow_Any_LASX;
4499 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
4500 RGBToYMatrixRow = RGBToYMatrixRow_LASX;
4501 }
4502 }
4503#endif
4504#if defined(HAS_RGBTOYMATRIXROW_RVV)
4505 if (TestCpuFlag(kCpuHasRVV)) {
4506 RGBToYMatrixRow = RGBToYMatrixRow_RVV;
4507 }
4508#endif
4509#if defined(HAS_RGBTOYMATRIXROW_WASMSIMD)
4510 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4511 RGBToYMatrixRow = RGBToYMatrixRow_Any_WASMSIMD;
4512 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4513 RGBToYMatrixRow = RGBToYMatrixRow_WASMSIMD;
4514 }
4515 }
4516#endif
4517
4518 for (y = 0; y < height; ++y) {
4519 RGBToYMatrixRow(src_rgb24, dst_yj, width, &kArgbJPEGConstants);
4520 src_rgb24 += src_stride_rgb24;
4521 dst_yj += dst_stride_yj;
4522 }
4523 return 0;
4524}
4525
4526// Convert RAW to J400.
4527LIBYUV_API
4528int RAWToJ400(const uint8_t* src_raw,
4529 int src_stride_raw,
4530 uint8_t* dst_yj,
4531 int dst_stride_yj,
4532 int width,
4533 int height) {
4534 int y;
4535 void (*RGBToYMatrixRow)(const uint8_t* src_rgb, uint8_t* dst_y, int width,
4536 const struct ArgbConstants* c) = RGBToYMatrixRow_C;
4537 if (!src_raw || !dst_yj || width <= 0 || height == 0 || height == INT_MIN(-2147483647 -1)) {
4538 return -1;
4539 }
4540 if (height < 0) {
4541 height = -height;
4542 src_raw = src_raw + (ptrdiff_t)(height - 1) * src_stride_raw;
4543 src_stride_raw = -src_stride_raw;
4544 }
4545 // Coalesce rows.
4546 if (src_stride_raw == width * 3 && dst_stride_yj == width &&
4547 (ptrdiff_t)width * height <= INT_MAX2147483647) {
4548 width *= height;
4549 height = 1;
4550 src_stride_raw = dst_stride_yj = 0;
4551 }
4552
4553#if defined(HAS_RGBTOYMATRIXROW_SSSE3)
4554 if (TestCpuFlag(kCpuHasSSSE3)) {
4555 RGBToYMatrixRow = RGBToYMatrixRow_Any_SSSE3;
4556 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4557 RGBToYMatrixRow = RGBToYMatrixRow_SSSE3;
4558 }
4559 }
4560#endif
4561#if defined(HAS_RGBTOYMATRIXROW_AVX2)
4562 if (TestCpuFlag(kCpuHasAVX2)) {
4563 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX2;
4564 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
4565 RGBToYMatrixRow = RGBToYMatrixRow_AVX2;
4566 }
4567 }
4568#endif
4569#if defined(HAS_RGBTOYMATRIXROW_AVX512BW)
4570 if (TestCpuFlag(kCpuHasAVX512BW)) {
4571 RGBToYMatrixRow = RGBToYMatrixRow_Any_AVX512BW;
4572 if (IS_ALIGNED(width, 64)(!((uintptr_t)(width) & ((64) - 1)))) {
4573 RGBToYMatrixRow = RGBToYMatrixRow_AVX512BW;
4574 }
4575 }
4576#endif
4577#if defined(HAS_RGBTOYMATRIXROW_NEON)
4578 if (TestCpuFlag(kCpuHasNEON)) {
4579 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON;
4580 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4581 RGBToYMatrixRow = RGBToYMatrixRow_NEON;
4582 }
4583 }
4584#endif
4585#if defined(HAS_RGBTOYMATRIXROW_NEON_DOTPROD)
4586 if (TestCpuFlag(kCpuHasNeonDotProd)) {
4587 RGBToYMatrixRow = RGBToYMatrixRow_Any_NEON_DotProd;
4588 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4589 RGBToYMatrixRow = RGBToYMatrixRow_NEON_DotProd;
4590 }
4591 }
4592#endif
4593#if defined(HAS_RGBTOYMATRIXROW_LSX)
4594 if (TestCpuFlag(kCpuHasLSX)) {
4595 RGBToYMatrixRow = RGBToYMatrixRow_Any_LSX;
4596 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4597 RGBToYMatrixRow = RGBToYMatrixRow_LSX;
4598 }
4599 }
4600#endif
4601#if defined(HAS_RGBTOYMATRIXROW_LASX)
4602 if (TestCpuFlag(kCpuHasLASX)) {
4603 RGBToYMatrixRow = RGBToYMatrixRow_Any_LASX;
4604 if (IS_ALIGNED(width, 32)(!((uintptr_t)(width) & ((32) - 1)))) {
4605 RGBToYMatrixRow = RGBToYMatrixRow_LASX;
4606 }
4607 }
4608#endif
4609#if defined(HAS_RGBTOYMATRIXROW_RVV)
4610 if (TestCpuFlag(kCpuHasRVV)) {
4611 RGBToYMatrixRow = RGBToYMatrixRow_RVV;
4612 }
4613#endif
4614#if defined(HAS_RGBTOYMATRIXROW_WASMSIMD)
4615 if (TestCpuFlag(kCpuHasWASMSIMD)) {
4616 RGBToYMatrixRow = RGBToYMatrixRow_Any_WASMSIMD;
4617 if (IS_ALIGNED(width, 16)(!((uintptr_t)(width) & ((16) - 1)))) {
4618 RGBToYMatrixRow = RGBToYMatrixRow_WASMSIMD;
4619 }
4620 }
4621#endif
4622
4623 for (y = 0; y < height; ++y) {
4624 RGBToYMatrixRow(src_raw, dst_yj, width, &kAbgrJPEGConstants);
4625 src_raw += src_stride_raw;
4626 dst_yj += dst_stride_yj;
4627 }
4628 return 0;
4629}
4630
4631// Convert Android420 to I420.
4632LIBYUV_API
4633int Android420ToI420(const uint8_t* src_y,
4634 int src_stride_y,
4635 const uint8_t* src_u,
4636 int src_stride_u,
4637 const uint8_t* src_v,
4638 int src_stride_v,
4639 int src_pixel_stride_uv,
4640 uint8_t* dst_y,
4641 int dst_stride_y,
4642 uint8_t* dst_u,
4643 int dst_stride_u,
4644 uint8_t* dst_v,
4645 int dst_stride_v,
4646 int width,
4647 int height) {
4648 return Android420ToI420Rotate(src_y, src_stride_y, src_u, src_stride_u, src_v,
4649 src_stride_v, src_pixel_stride_uv, dst_y,
4650 dst_stride_y, dst_u, dst_stride_u, dst_v,
4651 dst_stride_v, width, height, kRotate0);
4652}
4653
4654// depth is source bits measured from lsb; For msb use 16
4655static int Biplanar16bitTo8bit(const uint16_t* src_y,
4656 int src_stride_y,
4657 const uint16_t* src_uv,
4658 int src_stride_uv,
4659 uint8_t* dst_y,
4660 int dst_stride_y,
4661 uint8_t* dst_uv,
4662 int dst_stride_uv,
4663 int width,
4664 int height,
4665 int subsample_x,
4666 int subsample_y,
4667 int depth) {
4668 if ((!src_y && dst_y) || !src_uv || !dst_uv || width <= 0 || height == 0 ||
4669 height == INT_MIN(-2147483647 -1)) {
4670 return -1;
4671 }
4672 int uv_width = SUBSAMPLE(width, subsample_x, subsample_x)(width < 0) ? (-((-width + subsample_x) >> subsample_x
)) : ((width + subsample_x) >> subsample_x)
;
4673 int uv_height = SUBSAMPLE(height, subsample_y, subsample_y)(height < 0) ? (-((-height + subsample_y) >> subsample_y
)) : ((height + subsample_y) >> subsample_y)
;
4674 int scale = 1 << (24 - depth);
4675 // Negative height means invert the image.
4676 if (height < 0) {
4677 height = -height;
4678 uv_height = -uv_height;
4679 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
4680 src_uv = src_uv + (ptrdiff_t)(uv_height - 1) * src_stride_uv;
4681 src_stride_y = -src_stride_y;
4682 src_stride_uv = -src_stride_uv;
4683 }
4684
4685 // Convert Y plane.
4686 if (dst_y) {
4687 Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
4688 height);
4689 }
4690 // Convert UV planes.
4691 Convert16To8Plane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, scale,
4692 uv_width * 2, uv_height);
4693 return 0;
4694}
4695
4696// Convert 10 bit P010 to 8 bit NV12.
4697// Depth set to 16 because P010 uses 10 msb and this function keeps the upper 8
4698// bits of the specified number of bits.
4699LIBYUV_API
4700int P010ToNV12(const uint16_t* src_y,
4701 int src_stride_y,
4702 const uint16_t* src_uv,
4703 int src_stride_uv,
4704 uint8_t* dst_y,
4705 int dst_stride_y,
4706 uint8_t* dst_uv,
4707 int dst_stride_uv,
4708 int width,
4709 int height) {
4710 return Biplanar16bitTo8bit(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
4711 dst_stride_y, dst_uv, dst_stride_uv, width, height,
4712 1, 1, 16);
4713}
4714
4715static int Planar8bitTo8bit(const uint8_t* src_y,
4716 int src_stride_y,
4717 const uint8_t* src_u,
4718 int src_stride_u,
4719 const uint8_t* src_v,
4720 int src_stride_v,
4721 uint8_t* dst_y,
4722 int dst_stride_y,
4723 uint8_t* dst_u,
4724 int dst_stride_u,
4725 uint8_t* dst_v,
4726 int dst_stride_v,
4727 int width,
4728 int height,
4729 int subsample_x,
4730 int subsample_y,
4731 int scale_y,
4732 int bias_y,
4733 int scale_uv,
4734 int bias_uv) {
4735 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
4736 height == 0 || height == INT_MIN(-2147483647 -1)) {
4737 return -1;
4738 }
4739 int uv_width = SUBSAMPLE(width, subsample_x, subsample_x)(width < 0) ? (-((-width + subsample_x) >> subsample_x
)) : ((width + subsample_x) >> subsample_x)
;
4740 int uv_height = SUBSAMPLE(height, subsample_y, subsample_y)(height < 0) ? (-((-height + subsample_y) >> subsample_y
)) : ((height + subsample_y) >> subsample_y)
;
4741 // Negative height means invert the image.
4742 if (height < 0) {
4743 height = -height;
4744 uv_height = -uv_height;
4745 src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y;
4746 src_u = src_u + (ptrdiff_t)(uv_height - 1) * src_stride_u;
4747 src_v = src_v + (ptrdiff_t)(uv_height - 1) * src_stride_v;
4748 src_stride_y = -src_stride_y;
4749 src_stride_u = -src_stride_u;
4750 src_stride_v = -src_stride_v;
4751 }
4752
4753 // Convert Y plane.
4754 if (dst_y) {
4755 Convert8To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale_y, bias_y,
4756 width, height);
4757 }
4758 // Convert UV planes.
4759 Convert8To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale_uv, bias_uv,
4760 uv_width, uv_height);
4761 Convert8To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, scale_uv, bias_uv,
4762 uv_width, uv_height);
4763 return 0;
4764}
4765
4766LIBYUV_API
4767int J420ToI420(const uint8_t* src_y,
4768 int src_stride_y,
4769 const uint8_t* src_u,
4770 int src_stride_u,
4771 const uint8_t* src_v,
4772 int src_stride_v,
4773 uint8_t* dst_y,
4774 int dst_stride_y,
4775 uint8_t* dst_u,
4776 int dst_stride_u,
4777 uint8_t* dst_v,
4778 int dst_stride_v,
4779 int width,
4780 int height) {
4781 return Planar8bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
4782 src_stride_v, dst_y, dst_stride_y, dst_u,
4783 dst_stride_u, dst_v, dst_stride_v, width, height, 1,
4784 1, 220, 16, 225, 16);
4785}
4786
4787#ifdef __cplusplus202002L
4788} // extern "C"
4789} // namespace libyuv
4790#endif