Bug Summary

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