/src/mozilla-central/media/libyuv/libyuv/source/convert.cc
Line | Count | Source (jump to first uncovered line) |
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 "libyuv/basic_types.h" |
14 | | #include "libyuv/cpu_id.h" |
15 | | #include "libyuv/planar_functions.h" |
16 | | #include "libyuv/rotate.h" |
17 | | #include "libyuv/row.h" |
18 | | #include "libyuv/scale.h" // For ScalePlane() |
19 | | |
20 | | #ifdef __cplusplus |
21 | | namespace libyuv { |
22 | | extern "C" { |
23 | | #endif |
24 | | |
25 | 0 | #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s) |
26 | 0 | static __inline int Abs(int v) { |
27 | 0 | return v >= 0 ? v : -v; |
28 | 0 | } |
29 | | |
30 | | // Any I4xx To I420 format with mirroring. |
31 | | static int I4xxToI420(const uint8_t* src_y, |
32 | | int src_stride_y, |
33 | | const uint8_t* src_u, |
34 | | int src_stride_u, |
35 | | const uint8_t* src_v, |
36 | | int src_stride_v, |
37 | | uint8_t* dst_y, |
38 | | int dst_stride_y, |
39 | | uint8_t* dst_u, |
40 | | int dst_stride_u, |
41 | | uint8_t* dst_v, |
42 | | int dst_stride_v, |
43 | | int src_y_width, |
44 | | int src_y_height, |
45 | | int src_uv_width, |
46 | 0 | int src_uv_height) { |
47 | 0 | const int dst_y_width = Abs(src_y_width); |
48 | 0 | const int dst_y_height = Abs(src_y_height); |
49 | 0 | const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1); |
50 | 0 | const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1); |
51 | 0 | if (src_uv_width == 0 || src_uv_height == 0) { |
52 | 0 | return -1; |
53 | 0 | } |
54 | 0 | if (dst_y) { |
55 | 0 | ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y, |
56 | 0 | dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear); |
57 | 0 | } |
58 | 0 | ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u, |
59 | 0 | dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear); |
60 | 0 | ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v, |
61 | 0 | dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear); |
62 | 0 | return 0; |
63 | 0 | } |
64 | | |
65 | | // Copy I420 with optional flipping. |
66 | | // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure |
67 | | // is does row coalescing. |
68 | | LIBYUV_API |
69 | | int I420Copy(const uint8_t* src_y, |
70 | | int src_stride_y, |
71 | | const uint8_t* src_u, |
72 | | int src_stride_u, |
73 | | const uint8_t* src_v, |
74 | | int src_stride_v, |
75 | | uint8_t* dst_y, |
76 | | int dst_stride_y, |
77 | | uint8_t* dst_u, |
78 | | int dst_stride_u, |
79 | | uint8_t* dst_v, |
80 | | int dst_stride_v, |
81 | | int width, |
82 | 0 | int height) { |
83 | 0 | int halfwidth = (width + 1) >> 1; |
84 | 0 | int halfheight = (height + 1) >> 1; |
85 | 0 | if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { |
86 | 0 | return -1; |
87 | 0 | } |
88 | 0 | // Negative height means invert the image. |
89 | 0 | if (height < 0) { |
90 | 0 | height = -height; |
91 | 0 | halfheight = (height + 1) >> 1; |
92 | 0 | src_y = src_y + (height - 1) * src_stride_y; |
93 | 0 | src_u = src_u + (halfheight - 1) * src_stride_u; |
94 | 0 | src_v = src_v + (halfheight - 1) * src_stride_v; |
95 | 0 | src_stride_y = -src_stride_y; |
96 | 0 | src_stride_u = -src_stride_u; |
97 | 0 | src_stride_v = -src_stride_v; |
98 | 0 | } |
99 | 0 |
|
100 | 0 | if (dst_y) { |
101 | 0 | CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
102 | 0 | } |
103 | 0 | // Copy UV planes. |
104 | 0 | CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); |
105 | 0 | CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); |
106 | 0 | return 0; |
107 | 0 | } |
108 | | |
109 | | // Copy I010 with optional flipping. |
110 | | LIBYUV_API |
111 | | int I010Copy(const uint16_t* src_y, |
112 | | int src_stride_y, |
113 | | const uint16_t* src_u, |
114 | | int src_stride_u, |
115 | | const uint16_t* src_v, |
116 | | int src_stride_v, |
117 | | uint16_t* dst_y, |
118 | | int dst_stride_y, |
119 | | uint16_t* dst_u, |
120 | | int dst_stride_u, |
121 | | uint16_t* dst_v, |
122 | | int dst_stride_v, |
123 | | int width, |
124 | 0 | int height) { |
125 | 0 | int halfwidth = (width + 1) >> 1; |
126 | 0 | int halfheight = (height + 1) >> 1; |
127 | 0 | if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { |
128 | 0 | return -1; |
129 | 0 | } |
130 | 0 | // Negative height means invert the image. |
131 | 0 | if (height < 0) { |
132 | 0 | height = -height; |
133 | 0 | halfheight = (height + 1) >> 1; |
134 | 0 | src_y = src_y + (height - 1) * src_stride_y; |
135 | 0 | src_u = src_u + (halfheight - 1) * src_stride_u; |
136 | 0 | src_v = src_v + (halfheight - 1) * src_stride_v; |
137 | 0 | src_stride_y = -src_stride_y; |
138 | 0 | src_stride_u = -src_stride_u; |
139 | 0 | src_stride_v = -src_stride_v; |
140 | 0 | } |
141 | 0 |
|
142 | 0 | if (dst_y) { |
143 | 0 | CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
144 | 0 | } |
145 | 0 | // Copy UV planes. |
146 | 0 | CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); |
147 | 0 | CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); |
148 | 0 | return 0; |
149 | 0 | } |
150 | | |
151 | | // Convert 10 bit YUV to 8 bit. |
152 | | LIBYUV_API |
153 | | int I010ToI420(const uint16_t* src_y, |
154 | | int src_stride_y, |
155 | | const uint16_t* src_u, |
156 | | int src_stride_u, |
157 | | const uint16_t* src_v, |
158 | | int src_stride_v, |
159 | | uint8_t* dst_y, |
160 | | int dst_stride_y, |
161 | | uint8_t* dst_u, |
162 | | int dst_stride_u, |
163 | | uint8_t* dst_v, |
164 | | int dst_stride_v, |
165 | | int width, |
166 | 0 | int height) { |
167 | 0 | int halfwidth = (width + 1) >> 1; |
168 | 0 | int halfheight = (height + 1) >> 1; |
169 | 0 | if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { |
170 | 0 | return -1; |
171 | 0 | } |
172 | 0 | // Negative height means invert the image. |
173 | 0 | if (height < 0) { |
174 | 0 | height = -height; |
175 | 0 | halfheight = (height + 1) >> 1; |
176 | 0 | src_y = src_y + (height - 1) * src_stride_y; |
177 | 0 | src_u = src_u + (halfheight - 1) * src_stride_u; |
178 | 0 | src_v = src_v + (halfheight - 1) * src_stride_v; |
179 | 0 | src_stride_y = -src_stride_y; |
180 | 0 | src_stride_u = -src_stride_u; |
181 | 0 | src_stride_v = -src_stride_v; |
182 | 0 | } |
183 | 0 |
|
184 | 0 | // Convert Y plane. |
185 | 0 | Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, 16384, width, |
186 | 0 | height); |
187 | 0 | // Convert UV planes. |
188 | 0 | Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, 16384, halfwidth, |
189 | 0 | halfheight); |
190 | 0 | Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, 16384, halfwidth, |
191 | 0 | halfheight); |
192 | 0 | return 0; |
193 | 0 | } |
194 | | |
195 | | // 422 chroma is 1/2 width, 1x height |
196 | | // 420 chroma is 1/2 width, 1/2 height |
197 | | LIBYUV_API |
198 | | int I422ToI420(const uint8_t* src_y, |
199 | | int src_stride_y, |
200 | | const uint8_t* src_u, |
201 | | int src_stride_u, |
202 | | const uint8_t* src_v, |
203 | | int src_stride_v, |
204 | | uint8_t* dst_y, |
205 | | int dst_stride_y, |
206 | | uint8_t* dst_u, |
207 | | int dst_stride_u, |
208 | | uint8_t* dst_v, |
209 | | int dst_stride_v, |
210 | | int width, |
211 | 0 | int height) { |
212 | 0 | const int src_uv_width = SUBSAMPLE(width, 1, 1); |
213 | 0 | return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, |
214 | 0 | src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u, |
215 | 0 | dst_v, dst_stride_v, width, height, src_uv_width, height); |
216 | 0 | } |
217 | | |
218 | | // 444 chroma is 1x width, 1x height |
219 | | // 420 chroma is 1/2 width, 1/2 height |
220 | | LIBYUV_API |
221 | | int I444ToI420(const uint8_t* src_y, |
222 | | int src_stride_y, |
223 | | const uint8_t* src_u, |
224 | | int src_stride_u, |
225 | | const uint8_t* src_v, |
226 | | int src_stride_v, |
227 | | uint8_t* dst_y, |
228 | | int dst_stride_y, |
229 | | uint8_t* dst_u, |
230 | | int dst_stride_u, |
231 | | uint8_t* dst_v, |
232 | | int dst_stride_v, |
233 | | int width, |
234 | 0 | int height) { |
235 | 0 | return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, |
236 | 0 | src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u, |
237 | 0 | dst_v, dst_stride_v, width, height, width, height); |
238 | 0 | } |
239 | | |
240 | | // I400 is greyscale typically used in MJPG |
241 | | LIBYUV_API |
242 | | int I400ToI420(const uint8_t* src_y, |
243 | | int src_stride_y, |
244 | | uint8_t* dst_y, |
245 | | int dst_stride_y, |
246 | | uint8_t* dst_u, |
247 | | int dst_stride_u, |
248 | | uint8_t* dst_v, |
249 | | int dst_stride_v, |
250 | | int width, |
251 | 0 | int height) { |
252 | 0 | int halfwidth = (width + 1) >> 1; |
253 | 0 | int halfheight = (height + 1) >> 1; |
254 | 0 | if (!dst_u || !dst_v || width <= 0 || height == 0) { |
255 | 0 | return -1; |
256 | 0 | } |
257 | 0 | // Negative height means invert the image. |
258 | 0 | if (height < 0) { |
259 | 0 | height = -height; |
260 | 0 | halfheight = (height + 1) >> 1; |
261 | 0 | src_y = src_y + (height - 1) * src_stride_y; |
262 | 0 | src_stride_y = -src_stride_y; |
263 | 0 | } |
264 | 0 | if (dst_y) { |
265 | 0 | CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
266 | 0 | } |
267 | 0 | SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128); |
268 | 0 | SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128); |
269 | 0 | return 0; |
270 | 0 | } |
271 | | |
272 | | static void CopyPlane2(const uint8_t* src, |
273 | | int src_stride_0, |
274 | | int src_stride_1, |
275 | | uint8_t* dst, |
276 | | int dst_stride, |
277 | | int width, |
278 | 0 | int height) { |
279 | 0 | int y; |
280 | 0 | void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C; |
281 | 0 | #if defined(HAS_COPYROW_SSE2) |
282 | 0 | if (TestCpuFlag(kCpuHasSSE2)) { |
283 | 0 | CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2; |
284 | 0 | } |
285 | 0 | #endif |
286 | 0 | #if defined(HAS_COPYROW_AVX) |
287 | 0 | if (TestCpuFlag(kCpuHasAVX)) { |
288 | 0 | CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX; |
289 | 0 | } |
290 | 0 | #endif |
291 | 0 | #if defined(HAS_COPYROW_ERMS) |
292 | 0 | if (TestCpuFlag(kCpuHasERMS)) { |
293 | 0 | CopyRow = CopyRow_ERMS; |
294 | 0 | } |
295 | 0 | #endif |
296 | | #if defined(HAS_COPYROW_NEON) |
297 | | if (TestCpuFlag(kCpuHasNEON)) { |
298 | | CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON; |
299 | | } |
300 | | #endif |
301 | |
|
302 | 0 | // Copy plane |
303 | 0 | for (y = 0; y < height - 1; y += 2) { |
304 | 0 | CopyRow(src, dst, width); |
305 | 0 | CopyRow(src + src_stride_0, dst + dst_stride, width); |
306 | 0 | src += src_stride_0 + src_stride_1; |
307 | 0 | dst += dst_stride * 2; |
308 | 0 | } |
309 | 0 | if (height & 1) { |
310 | 0 | CopyRow(src, dst, width); |
311 | 0 | } |
312 | 0 | } |
313 | | |
314 | | // Support converting from FOURCC_M420 |
315 | | // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for |
316 | | // easy conversion to I420. |
317 | | // M420 format description: |
318 | | // M420 is row biplanar 420: 2 rows of Y and 1 row of UV. |
319 | | // Chroma is half width / half height. (420) |
320 | | // src_stride_m420 is row planar. Normally this will be the width in pixels. |
321 | | // The UV plane is half width, but 2 values, so src_stride_m420 applies to |
322 | | // this as well as the two Y planes. |
323 | | static int X420ToI420(const uint8_t* src_y, |
324 | | int src_stride_y0, |
325 | | int src_stride_y1, |
326 | | const uint8_t* src_uv, |
327 | | int src_stride_uv, |
328 | | uint8_t* dst_y, |
329 | | int dst_stride_y, |
330 | | uint8_t* dst_u, |
331 | | int dst_stride_u, |
332 | | uint8_t* dst_v, |
333 | | int dst_stride_v, |
334 | | int width, |
335 | 0 | int height) { |
336 | 0 | int halfwidth = (width + 1) >> 1; |
337 | 0 | int halfheight = (height + 1) >> 1; |
338 | 0 | if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) { |
339 | 0 | return -1; |
340 | 0 | } |
341 | 0 | // Negative height means invert the image. |
342 | 0 | if (height < 0) { |
343 | 0 | height = -height; |
344 | 0 | halfheight = (height + 1) >> 1; |
345 | 0 | if (dst_y) { |
346 | 0 | dst_y = dst_y + (height - 1) * dst_stride_y; |
347 | 0 | } |
348 | 0 | dst_u = dst_u + (halfheight - 1) * dst_stride_u; |
349 | 0 | dst_v = dst_v + (halfheight - 1) * dst_stride_v; |
350 | 0 | dst_stride_y = -dst_stride_y; |
351 | 0 | dst_stride_u = -dst_stride_u; |
352 | 0 | dst_stride_v = -dst_stride_v; |
353 | 0 | } |
354 | 0 | // Coalesce rows. |
355 | 0 | if (src_stride_y0 == width && src_stride_y1 == width && |
356 | 0 | dst_stride_y == width) { |
357 | 0 | width *= height; |
358 | 0 | height = 1; |
359 | 0 | src_stride_y0 = src_stride_y1 = dst_stride_y = 0; |
360 | 0 | } |
361 | 0 | // Coalesce rows. |
362 | 0 | if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth && |
363 | 0 | dst_stride_v == halfwidth) { |
364 | 0 | halfwidth *= halfheight; |
365 | 0 | halfheight = 1; |
366 | 0 | src_stride_uv = dst_stride_u = dst_stride_v = 0; |
367 | 0 | } |
368 | 0 |
|
369 | 0 | if (dst_y) { |
370 | 0 | if (src_stride_y0 == src_stride_y1) { |
371 | 0 | CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height); |
372 | 0 | } else { |
373 | 0 | CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y, |
374 | 0 | width, height); |
375 | 0 | } |
376 | 0 | } |
377 | 0 |
|
378 | 0 | // Split UV plane - NV12 / NV21 |
379 | 0 | SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v, |
380 | 0 | halfwidth, halfheight); |
381 | 0 |
|
382 | 0 | return 0; |
383 | 0 | } |
384 | | |
385 | | // Convert NV12 to I420. |
386 | | LIBYUV_API |
387 | | int NV12ToI420(const uint8_t* src_y, |
388 | | int src_stride_y, |
389 | | const uint8_t* src_uv, |
390 | | int src_stride_uv, |
391 | | uint8_t* dst_y, |
392 | | int dst_stride_y, |
393 | | uint8_t* dst_u, |
394 | | int dst_stride_u, |
395 | | uint8_t* dst_v, |
396 | | int dst_stride_v, |
397 | | int width, |
398 | 0 | int height) { |
399 | 0 | return X420ToI420(src_y, src_stride_y, src_stride_y, src_uv, src_stride_uv, |
400 | 0 | dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, |
401 | 0 | dst_stride_v, width, height); |
402 | 0 | } |
403 | | |
404 | | // Convert NV21 to I420. Same as NV12 but u and v pointers swapped. |
405 | | LIBYUV_API |
406 | | int NV21ToI420(const uint8_t* src_y, |
407 | | int src_stride_y, |
408 | | const uint8_t* src_vu, |
409 | | int src_stride_vu, |
410 | | uint8_t* dst_y, |
411 | | int dst_stride_y, |
412 | | uint8_t* dst_u, |
413 | | int dst_stride_u, |
414 | | uint8_t* dst_v, |
415 | | int dst_stride_v, |
416 | | int width, |
417 | 0 | int height) { |
418 | 0 | return X420ToI420(src_y, src_stride_y, src_stride_y, src_vu, src_stride_vu, |
419 | 0 | dst_y, dst_stride_y, dst_v, dst_stride_v, dst_u, |
420 | 0 | dst_stride_u, width, height); |
421 | 0 | } |
422 | | |
423 | | // Convert M420 to I420. |
424 | | LIBYUV_API |
425 | | int M420ToI420(const uint8_t* src_m420, |
426 | | int src_stride_m420, |
427 | | uint8_t* dst_y, |
428 | | int dst_stride_y, |
429 | | uint8_t* dst_u, |
430 | | int dst_stride_u, |
431 | | uint8_t* dst_v, |
432 | | int dst_stride_v, |
433 | | int width, |
434 | 0 | int height) { |
435 | 0 | return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2, |
436 | 0 | src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, dst_y, |
437 | 0 | dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, |
438 | 0 | width, height); |
439 | 0 | } |
440 | | |
441 | | // Convert YUY2 to I420. |
442 | | LIBYUV_API |
443 | | int YUY2ToI420(const uint8_t* src_yuy2, |
444 | | int src_stride_yuy2, |
445 | | uint8_t* dst_y, |
446 | | int dst_stride_y, |
447 | | uint8_t* dst_u, |
448 | | int dst_stride_u, |
449 | | uint8_t* dst_v, |
450 | | int dst_stride_v, |
451 | | int width, |
452 | 0 | int height) { |
453 | 0 | int y; |
454 | 0 | void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2, |
455 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
456 | 0 | YUY2ToUVRow_C; |
457 | 0 | void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) = |
458 | 0 | YUY2ToYRow_C; |
459 | 0 | // Negative height means invert the image. |
460 | 0 | if (height < 0) { |
461 | 0 | height = -height; |
462 | 0 | src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; |
463 | 0 | src_stride_yuy2 = -src_stride_yuy2; |
464 | 0 | } |
465 | 0 | #if defined(HAS_YUY2TOYROW_SSE2) |
466 | 0 | if (TestCpuFlag(kCpuHasSSE2)) { |
467 | 0 | YUY2ToUVRow = YUY2ToUVRow_Any_SSE2; |
468 | 0 | YUY2ToYRow = YUY2ToYRow_Any_SSE2; |
469 | 0 | if (IS_ALIGNED(width, 16)) { |
470 | 0 | YUY2ToUVRow = YUY2ToUVRow_SSE2; |
471 | 0 | YUY2ToYRow = YUY2ToYRow_SSE2; |
472 | 0 | } |
473 | 0 | } |
474 | 0 | #endif |
475 | 0 | #if defined(HAS_YUY2TOYROW_AVX2) |
476 | 0 | if (TestCpuFlag(kCpuHasAVX2)) { |
477 | 0 | YUY2ToUVRow = YUY2ToUVRow_Any_AVX2; |
478 | 0 | YUY2ToYRow = YUY2ToYRow_Any_AVX2; |
479 | 0 | if (IS_ALIGNED(width, 32)) { |
480 | 0 | YUY2ToUVRow = YUY2ToUVRow_AVX2; |
481 | 0 | YUY2ToYRow = YUY2ToYRow_AVX2; |
482 | 0 | } |
483 | 0 | } |
484 | 0 | #endif |
485 | | #if defined(HAS_YUY2TOYROW_NEON) |
486 | | if (TestCpuFlag(kCpuHasNEON)) { |
487 | | YUY2ToYRow = YUY2ToYRow_Any_NEON; |
488 | | YUY2ToUVRow = YUY2ToUVRow_Any_NEON; |
489 | | if (IS_ALIGNED(width, 16)) { |
490 | | YUY2ToYRow = YUY2ToYRow_NEON; |
491 | | YUY2ToUVRow = YUY2ToUVRow_NEON; |
492 | | } |
493 | | } |
494 | | #endif |
495 | | #if defined(HAS_YUY2TOYROW_MSA) |
496 | | if (TestCpuFlag(kCpuHasMSA)) { |
497 | | YUY2ToYRow = YUY2ToYRow_Any_MSA; |
498 | | YUY2ToUVRow = YUY2ToUVRow_Any_MSA; |
499 | | if (IS_ALIGNED(width, 32)) { |
500 | | YUY2ToYRow = YUY2ToYRow_MSA; |
501 | | YUY2ToUVRow = YUY2ToUVRow_MSA; |
502 | | } |
503 | | } |
504 | | #endif |
505 | |
|
506 | 0 | for (y = 0; y < height - 1; y += 2) { |
507 | 0 | YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width); |
508 | 0 | YUY2ToYRow(src_yuy2, dst_y, width); |
509 | 0 | YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width); |
510 | 0 | src_yuy2 += src_stride_yuy2 * 2; |
511 | 0 | dst_y += dst_stride_y * 2; |
512 | 0 | dst_u += dst_stride_u; |
513 | 0 | dst_v += dst_stride_v; |
514 | 0 | } |
515 | 0 | if (height & 1) { |
516 | 0 | YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width); |
517 | 0 | YUY2ToYRow(src_yuy2, dst_y, width); |
518 | 0 | } |
519 | 0 | return 0; |
520 | 0 | } |
521 | | |
522 | | // Convert UYVY to I420. |
523 | | LIBYUV_API |
524 | | int UYVYToI420(const uint8_t* src_uyvy, |
525 | | int src_stride_uyvy, |
526 | | uint8_t* dst_y, |
527 | | int dst_stride_y, |
528 | | uint8_t* dst_u, |
529 | | int dst_stride_u, |
530 | | uint8_t* dst_v, |
531 | | int dst_stride_v, |
532 | | int width, |
533 | 0 | int height) { |
534 | 0 | int y; |
535 | 0 | void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy, |
536 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
537 | 0 | UYVYToUVRow_C; |
538 | 0 | void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) = |
539 | 0 | UYVYToYRow_C; |
540 | 0 | // Negative height means invert the image. |
541 | 0 | if (height < 0) { |
542 | 0 | height = -height; |
543 | 0 | src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; |
544 | 0 | src_stride_uyvy = -src_stride_uyvy; |
545 | 0 | } |
546 | 0 | #if defined(HAS_UYVYTOYROW_SSE2) |
547 | 0 | if (TestCpuFlag(kCpuHasSSE2)) { |
548 | 0 | UYVYToUVRow = UYVYToUVRow_Any_SSE2; |
549 | 0 | UYVYToYRow = UYVYToYRow_Any_SSE2; |
550 | 0 | if (IS_ALIGNED(width, 16)) { |
551 | 0 | UYVYToUVRow = UYVYToUVRow_SSE2; |
552 | 0 | UYVYToYRow = UYVYToYRow_SSE2; |
553 | 0 | } |
554 | 0 | } |
555 | 0 | #endif |
556 | 0 | #if defined(HAS_UYVYTOYROW_AVX2) |
557 | 0 | if (TestCpuFlag(kCpuHasAVX2)) { |
558 | 0 | UYVYToUVRow = UYVYToUVRow_Any_AVX2; |
559 | 0 | UYVYToYRow = UYVYToYRow_Any_AVX2; |
560 | 0 | if (IS_ALIGNED(width, 32)) { |
561 | 0 | UYVYToUVRow = UYVYToUVRow_AVX2; |
562 | 0 | UYVYToYRow = UYVYToYRow_AVX2; |
563 | 0 | } |
564 | 0 | } |
565 | 0 | #endif |
566 | | #if defined(HAS_UYVYTOYROW_NEON) |
567 | | if (TestCpuFlag(kCpuHasNEON)) { |
568 | | UYVYToYRow = UYVYToYRow_Any_NEON; |
569 | | UYVYToUVRow = UYVYToUVRow_Any_NEON; |
570 | | if (IS_ALIGNED(width, 16)) { |
571 | | UYVYToYRow = UYVYToYRow_NEON; |
572 | | UYVYToUVRow = UYVYToUVRow_NEON; |
573 | | } |
574 | | } |
575 | | #endif |
576 | | #if defined(HAS_UYVYTOYROW_MSA) |
577 | | if (TestCpuFlag(kCpuHasMSA)) { |
578 | | UYVYToYRow = UYVYToYRow_Any_MSA; |
579 | | UYVYToUVRow = UYVYToUVRow_Any_MSA; |
580 | | if (IS_ALIGNED(width, 32)) { |
581 | | UYVYToYRow = UYVYToYRow_MSA; |
582 | | UYVYToUVRow = UYVYToUVRow_MSA; |
583 | | } |
584 | | } |
585 | | #endif |
586 | |
|
587 | 0 | for (y = 0; y < height - 1; y += 2) { |
588 | 0 | UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width); |
589 | 0 | UYVYToYRow(src_uyvy, dst_y, width); |
590 | 0 | UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width); |
591 | 0 | src_uyvy += src_stride_uyvy * 2; |
592 | 0 | dst_y += dst_stride_y * 2; |
593 | 0 | dst_u += dst_stride_u; |
594 | 0 | dst_v += dst_stride_v; |
595 | 0 | } |
596 | 0 | if (height & 1) { |
597 | 0 | UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width); |
598 | 0 | UYVYToYRow(src_uyvy, dst_y, width); |
599 | 0 | } |
600 | 0 | return 0; |
601 | 0 | } |
602 | | |
603 | | // Convert ARGB to I420. |
604 | | LIBYUV_API |
605 | | int ARGBToI420(const uint8_t* src_argb, |
606 | | int src_stride_argb, |
607 | | uint8_t* dst_y, |
608 | | int dst_stride_y, |
609 | | uint8_t* dst_u, |
610 | | int dst_stride_u, |
611 | | uint8_t* dst_v, |
612 | | int dst_stride_v, |
613 | | int width, |
614 | 0 | int height) { |
615 | 0 | int y; |
616 | 0 | void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, |
617 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
618 | 0 | ARGBToUVRow_C; |
619 | 0 | void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = |
620 | 0 | ARGBToYRow_C; |
621 | 0 | if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { |
622 | 0 | return -1; |
623 | 0 | } |
624 | 0 | // Negative height means invert the image. |
625 | 0 | if (height < 0) { |
626 | 0 | height = -height; |
627 | 0 | src_argb = src_argb + (height - 1) * src_stride_argb; |
628 | 0 | src_stride_argb = -src_stride_argb; |
629 | 0 | } |
630 | 0 | #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) |
631 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
632 | 0 | ARGBToUVRow = ARGBToUVRow_Any_SSSE3; |
633 | 0 | ARGBToYRow = ARGBToYRow_Any_SSSE3; |
634 | 0 | if (IS_ALIGNED(width, 16)) { |
635 | 0 | ARGBToUVRow = ARGBToUVRow_SSSE3; |
636 | 0 | ARGBToYRow = ARGBToYRow_SSSE3; |
637 | 0 | } |
638 | 0 | } |
639 | 0 | #endif |
640 | 0 | #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) |
641 | 0 | if (TestCpuFlag(kCpuHasAVX2)) { |
642 | 0 | ARGBToUVRow = ARGBToUVRow_Any_AVX2; |
643 | 0 | ARGBToYRow = ARGBToYRow_Any_AVX2; |
644 | 0 | if (IS_ALIGNED(width, 32)) { |
645 | 0 | ARGBToUVRow = ARGBToUVRow_AVX2; |
646 | 0 | ARGBToYRow = ARGBToYRow_AVX2; |
647 | 0 | } |
648 | 0 | } |
649 | 0 | #endif |
650 | | #if defined(HAS_ARGBTOYROW_NEON) |
651 | | if (TestCpuFlag(kCpuHasNEON)) { |
652 | | ARGBToYRow = ARGBToYRow_Any_NEON; |
653 | | if (IS_ALIGNED(width, 8)) { |
654 | | ARGBToYRow = ARGBToYRow_NEON; |
655 | | } |
656 | | } |
657 | | #endif |
658 | | #if defined(HAS_ARGBTOUVROW_NEON) |
659 | | if (TestCpuFlag(kCpuHasNEON)) { |
660 | | ARGBToUVRow = ARGBToUVRow_Any_NEON; |
661 | | if (IS_ALIGNED(width, 16)) { |
662 | | ARGBToUVRow = ARGBToUVRow_NEON; |
663 | | } |
664 | | } |
665 | | #endif |
666 | | #if defined(HAS_ARGBTOYROW_MSA) |
667 | | if (TestCpuFlag(kCpuHasMSA)) { |
668 | | ARGBToYRow = ARGBToYRow_Any_MSA; |
669 | | if (IS_ALIGNED(width, 16)) { |
670 | | ARGBToYRow = ARGBToYRow_MSA; |
671 | | } |
672 | | } |
673 | | #endif |
674 | | #if defined(HAS_ARGBTOUVROW_MSA) |
675 | | if (TestCpuFlag(kCpuHasMSA)) { |
676 | | ARGBToUVRow = ARGBToUVRow_Any_MSA; |
677 | | if (IS_ALIGNED(width, 32)) { |
678 | | ARGBToUVRow = ARGBToUVRow_MSA; |
679 | | } |
680 | | } |
681 | | #endif |
682 | |
|
683 | 0 | for (y = 0; y < height - 1; y += 2) { |
684 | 0 | ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width); |
685 | 0 | ARGBToYRow(src_argb, dst_y, width); |
686 | 0 | ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width); |
687 | 0 | src_argb += src_stride_argb * 2; |
688 | 0 | dst_y += dst_stride_y * 2; |
689 | 0 | dst_u += dst_stride_u; |
690 | 0 | dst_v += dst_stride_v; |
691 | 0 | } |
692 | 0 | if (height & 1) { |
693 | 0 | ARGBToUVRow(src_argb, 0, dst_u, dst_v, width); |
694 | 0 | ARGBToYRow(src_argb, dst_y, width); |
695 | 0 | } |
696 | 0 | return 0; |
697 | 0 | } |
698 | | |
699 | | // Convert BGRA to I420. |
700 | | LIBYUV_API |
701 | | int BGRAToI420(const uint8_t* src_bgra, |
702 | | int src_stride_bgra, |
703 | | uint8_t* dst_y, |
704 | | int dst_stride_y, |
705 | | uint8_t* dst_u, |
706 | | int dst_stride_u, |
707 | | uint8_t* dst_v, |
708 | | int dst_stride_v, |
709 | | int width, |
710 | 0 | int height) { |
711 | 0 | int y; |
712 | 0 | void (*BGRAToUVRow)(const uint8_t* src_bgra0, int src_stride_bgra, |
713 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
714 | 0 | BGRAToUVRow_C; |
715 | 0 | void (*BGRAToYRow)(const uint8_t* src_bgra, uint8_t* dst_y, int width) = |
716 | 0 | BGRAToYRow_C; |
717 | 0 | if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { |
718 | 0 | return -1; |
719 | 0 | } |
720 | 0 | // Negative height means invert the image. |
721 | 0 | if (height < 0) { |
722 | 0 | height = -height; |
723 | 0 | src_bgra = src_bgra + (height - 1) * src_stride_bgra; |
724 | 0 | src_stride_bgra = -src_stride_bgra; |
725 | 0 | } |
726 | 0 | #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3) |
727 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
728 | 0 | BGRAToUVRow = BGRAToUVRow_Any_SSSE3; |
729 | 0 | BGRAToYRow = BGRAToYRow_Any_SSSE3; |
730 | 0 | if (IS_ALIGNED(width, 16)) { |
731 | 0 | BGRAToUVRow = BGRAToUVRow_SSSE3; |
732 | 0 | BGRAToYRow = BGRAToYRow_SSSE3; |
733 | 0 | } |
734 | 0 | } |
735 | 0 | #endif |
736 | | #if defined(HAS_BGRATOYROW_NEON) |
737 | | if (TestCpuFlag(kCpuHasNEON)) { |
738 | | BGRAToYRow = BGRAToYRow_Any_NEON; |
739 | | if (IS_ALIGNED(width, 8)) { |
740 | | BGRAToYRow = BGRAToYRow_NEON; |
741 | | } |
742 | | } |
743 | | #endif |
744 | | #if defined(HAS_BGRATOUVROW_NEON) |
745 | | if (TestCpuFlag(kCpuHasNEON)) { |
746 | | BGRAToUVRow = BGRAToUVRow_Any_NEON; |
747 | | if (IS_ALIGNED(width, 16)) { |
748 | | BGRAToUVRow = BGRAToUVRow_NEON; |
749 | | } |
750 | | } |
751 | | #endif |
752 | | #if defined(HAS_BGRATOYROW_MSA) |
753 | | if (TestCpuFlag(kCpuHasMSA)) { |
754 | | BGRAToYRow = BGRAToYRow_Any_MSA; |
755 | | if (IS_ALIGNED(width, 16)) { |
756 | | BGRAToYRow = BGRAToYRow_MSA; |
757 | | } |
758 | | } |
759 | | #endif |
760 | | #if defined(HAS_BGRATOUVROW_MSA) |
761 | | if (TestCpuFlag(kCpuHasMSA)) { |
762 | | BGRAToUVRow = BGRAToUVRow_Any_MSA; |
763 | | if (IS_ALIGNED(width, 16)) { |
764 | | BGRAToUVRow = BGRAToUVRow_MSA; |
765 | | } |
766 | | } |
767 | | #endif |
768 | |
|
769 | 0 | for (y = 0; y < height - 1; y += 2) { |
770 | 0 | BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width); |
771 | 0 | BGRAToYRow(src_bgra, dst_y, width); |
772 | 0 | BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width); |
773 | 0 | src_bgra += src_stride_bgra * 2; |
774 | 0 | dst_y += dst_stride_y * 2; |
775 | 0 | dst_u += dst_stride_u; |
776 | 0 | dst_v += dst_stride_v; |
777 | 0 | } |
778 | 0 | if (height & 1) { |
779 | 0 | BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width); |
780 | 0 | BGRAToYRow(src_bgra, dst_y, width); |
781 | 0 | } |
782 | 0 | return 0; |
783 | 0 | } |
784 | | |
785 | | // Convert ABGR to I420. |
786 | | LIBYUV_API |
787 | | int ABGRToI420(const uint8_t* src_abgr, |
788 | | int src_stride_abgr, |
789 | | uint8_t* dst_y, |
790 | | int dst_stride_y, |
791 | | uint8_t* dst_u, |
792 | | int dst_stride_u, |
793 | | uint8_t* dst_v, |
794 | | int dst_stride_v, |
795 | | int width, |
796 | 0 | int height) { |
797 | 0 | int y; |
798 | 0 | void (*ABGRToUVRow)(const uint8_t* src_abgr0, int src_stride_abgr, |
799 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
800 | 0 | ABGRToUVRow_C; |
801 | 0 | void (*ABGRToYRow)(const uint8_t* src_abgr, uint8_t* dst_y, int width) = |
802 | 0 | ABGRToYRow_C; |
803 | 0 | if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { |
804 | 0 | return -1; |
805 | 0 | } |
806 | 0 | // Negative height means invert the image. |
807 | 0 | if (height < 0) { |
808 | 0 | height = -height; |
809 | 0 | src_abgr = src_abgr + (height - 1) * src_stride_abgr; |
810 | 0 | src_stride_abgr = -src_stride_abgr; |
811 | 0 | } |
812 | 0 | #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3) |
813 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
814 | 0 | ABGRToUVRow = ABGRToUVRow_Any_SSSE3; |
815 | 0 | ABGRToYRow = ABGRToYRow_Any_SSSE3; |
816 | 0 | if (IS_ALIGNED(width, 16)) { |
817 | 0 | ABGRToUVRow = ABGRToUVRow_SSSE3; |
818 | 0 | ABGRToYRow = ABGRToYRow_SSSE3; |
819 | 0 | } |
820 | 0 | } |
821 | 0 | #endif |
822 | | #if defined(HAS_ABGRTOYROW_NEON) |
823 | | if (TestCpuFlag(kCpuHasNEON)) { |
824 | | ABGRToYRow = ABGRToYRow_Any_NEON; |
825 | | if (IS_ALIGNED(width, 8)) { |
826 | | ABGRToYRow = ABGRToYRow_NEON; |
827 | | } |
828 | | } |
829 | | #endif |
830 | | #if defined(HAS_ABGRTOUVROW_NEON) |
831 | | if (TestCpuFlag(kCpuHasNEON)) { |
832 | | ABGRToUVRow = ABGRToUVRow_Any_NEON; |
833 | | if (IS_ALIGNED(width, 16)) { |
834 | | ABGRToUVRow = ABGRToUVRow_NEON; |
835 | | } |
836 | | } |
837 | | #endif |
838 | | #if defined(HAS_ABGRTOYROW_MSA) |
839 | | if (TestCpuFlag(kCpuHasMSA)) { |
840 | | ABGRToYRow = ABGRToYRow_Any_MSA; |
841 | | if (IS_ALIGNED(width, 16)) { |
842 | | ABGRToYRow = ABGRToYRow_MSA; |
843 | | } |
844 | | } |
845 | | #endif |
846 | | #if defined(HAS_ABGRTOUVROW_MSA) |
847 | | if (TestCpuFlag(kCpuHasMSA)) { |
848 | | ABGRToUVRow = ABGRToUVRow_Any_MSA; |
849 | | if (IS_ALIGNED(width, 16)) { |
850 | | ABGRToUVRow = ABGRToUVRow_MSA; |
851 | | } |
852 | | } |
853 | | #endif |
854 | |
|
855 | 0 | for (y = 0; y < height - 1; y += 2) { |
856 | 0 | ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width); |
857 | 0 | ABGRToYRow(src_abgr, dst_y, width); |
858 | 0 | ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width); |
859 | 0 | src_abgr += src_stride_abgr * 2; |
860 | 0 | dst_y += dst_stride_y * 2; |
861 | 0 | dst_u += dst_stride_u; |
862 | 0 | dst_v += dst_stride_v; |
863 | 0 | } |
864 | 0 | if (height & 1) { |
865 | 0 | ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width); |
866 | 0 | ABGRToYRow(src_abgr, dst_y, width); |
867 | 0 | } |
868 | 0 | return 0; |
869 | 0 | } |
870 | | |
871 | | // Convert RGBA to I420. |
872 | | LIBYUV_API |
873 | | int RGBAToI420(const uint8_t* src_rgba, |
874 | | int src_stride_rgba, |
875 | | uint8_t* dst_y, |
876 | | int dst_stride_y, |
877 | | uint8_t* dst_u, |
878 | | int dst_stride_u, |
879 | | uint8_t* dst_v, |
880 | | int dst_stride_v, |
881 | | int width, |
882 | 0 | int height) { |
883 | 0 | int y; |
884 | 0 | void (*RGBAToUVRow)(const uint8_t* src_rgba0, int src_stride_rgba, |
885 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
886 | 0 | RGBAToUVRow_C; |
887 | 0 | void (*RGBAToYRow)(const uint8_t* src_rgba, uint8_t* dst_y, int width) = |
888 | 0 | RGBAToYRow_C; |
889 | 0 | if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { |
890 | 0 | return -1; |
891 | 0 | } |
892 | 0 | // Negative height means invert the image. |
893 | 0 | if (height < 0) { |
894 | 0 | height = -height; |
895 | 0 | src_rgba = src_rgba + (height - 1) * src_stride_rgba; |
896 | 0 | src_stride_rgba = -src_stride_rgba; |
897 | 0 | } |
898 | 0 | #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3) |
899 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
900 | 0 | RGBAToUVRow = RGBAToUVRow_Any_SSSE3; |
901 | 0 | RGBAToYRow = RGBAToYRow_Any_SSSE3; |
902 | 0 | if (IS_ALIGNED(width, 16)) { |
903 | 0 | RGBAToUVRow = RGBAToUVRow_SSSE3; |
904 | 0 | RGBAToYRow = RGBAToYRow_SSSE3; |
905 | 0 | } |
906 | 0 | } |
907 | 0 | #endif |
908 | | #if defined(HAS_RGBATOYROW_NEON) |
909 | | if (TestCpuFlag(kCpuHasNEON)) { |
910 | | RGBAToYRow = RGBAToYRow_Any_NEON; |
911 | | if (IS_ALIGNED(width, 8)) { |
912 | | RGBAToYRow = RGBAToYRow_NEON; |
913 | | } |
914 | | } |
915 | | #endif |
916 | | #if defined(HAS_RGBATOUVROW_NEON) |
917 | | if (TestCpuFlag(kCpuHasNEON)) { |
918 | | RGBAToUVRow = RGBAToUVRow_Any_NEON; |
919 | | if (IS_ALIGNED(width, 16)) { |
920 | | RGBAToUVRow = RGBAToUVRow_NEON; |
921 | | } |
922 | | } |
923 | | #endif |
924 | | #if defined(HAS_RGBATOYROW_MSA) |
925 | | if (TestCpuFlag(kCpuHasMSA)) { |
926 | | RGBAToYRow = RGBAToYRow_Any_MSA; |
927 | | if (IS_ALIGNED(width, 16)) { |
928 | | RGBAToYRow = RGBAToYRow_MSA; |
929 | | } |
930 | | } |
931 | | #endif |
932 | | #if defined(HAS_RGBATOUVROW_MSA) |
933 | | if (TestCpuFlag(kCpuHasMSA)) { |
934 | | RGBAToUVRow = RGBAToUVRow_Any_MSA; |
935 | | if (IS_ALIGNED(width, 16)) { |
936 | | RGBAToUVRow = RGBAToUVRow_MSA; |
937 | | } |
938 | | } |
939 | | #endif |
940 | |
|
941 | 0 | for (y = 0; y < height - 1; y += 2) { |
942 | 0 | RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width); |
943 | 0 | RGBAToYRow(src_rgba, dst_y, width); |
944 | 0 | RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width); |
945 | 0 | src_rgba += src_stride_rgba * 2; |
946 | 0 | dst_y += dst_stride_y * 2; |
947 | 0 | dst_u += dst_stride_u; |
948 | 0 | dst_v += dst_stride_v; |
949 | 0 | } |
950 | 0 | if (height & 1) { |
951 | 0 | RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width); |
952 | 0 | RGBAToYRow(src_rgba, dst_y, width); |
953 | 0 | } |
954 | 0 | return 0; |
955 | 0 | } |
956 | | |
957 | | // Convert RGB24 to I420. |
958 | | LIBYUV_API |
959 | | int RGB24ToI420(const uint8_t* src_rgb24, |
960 | | int src_stride_rgb24, |
961 | | uint8_t* dst_y, |
962 | | int dst_stride_y, |
963 | | uint8_t* dst_u, |
964 | | int dst_stride_u, |
965 | | uint8_t* dst_v, |
966 | | int dst_stride_v, |
967 | | int width, |
968 | 0 | int height) { |
969 | 0 | int y; |
970 | | #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) |
971 | | void (*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24, |
972 | | uint8_t* dst_u, uint8_t* dst_v, int width) = |
973 | | RGB24ToUVRow_C; |
974 | | void (*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) = |
975 | | RGB24ToYRow_C; |
976 | | #else |
977 | | void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = |
978 | 0 | RGB24ToARGBRow_C; |
979 | 0 | void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, |
980 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
981 | 0 | ARGBToUVRow_C; |
982 | 0 | void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = |
983 | 0 | ARGBToYRow_C; |
984 | 0 | #endif |
985 | 0 | if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { |
986 | 0 | return -1; |
987 | 0 | } |
988 | 0 | // Negative height means invert the image. |
989 | 0 | if (height < 0) { |
990 | 0 | height = -height; |
991 | 0 | src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; |
992 | 0 | src_stride_rgb24 = -src_stride_rgb24; |
993 | 0 | } |
994 | 0 |
|
995 | 0 | // Neon version does direct RGB24 to YUV. |
996 | | #if defined(HAS_RGB24TOYROW_NEON) |
997 | | if (TestCpuFlag(kCpuHasNEON)) { |
998 | | RGB24ToUVRow = RGB24ToUVRow_Any_NEON; |
999 | | RGB24ToYRow = RGB24ToYRow_Any_NEON; |
1000 | | if (IS_ALIGNED(width, 8)) { |
1001 | | RGB24ToYRow = RGB24ToYRow_NEON; |
1002 | | if (IS_ALIGNED(width, 16)) { |
1003 | | RGB24ToUVRow = RGB24ToUVRow_NEON; |
1004 | | } |
1005 | | } |
1006 | | } |
1007 | | #elif defined(HAS_RGB24TOYROW_MSA) |
1008 | | if (TestCpuFlag(kCpuHasMSA)) { |
1009 | | RGB24ToUVRow = RGB24ToUVRow_Any_MSA; |
1010 | | RGB24ToYRow = RGB24ToYRow_Any_MSA; |
1011 | | if (IS_ALIGNED(width, 16)) { |
1012 | | RGB24ToYRow = RGB24ToYRow_MSA; |
1013 | | RGB24ToUVRow = RGB24ToUVRow_MSA; |
1014 | | } |
1015 | | } |
1016 | | // Other platforms do intermediate conversion from RGB24 to ARGB. |
1017 | | #else |
1018 | | #if defined(HAS_RGB24TOARGBROW_SSSE3) |
1019 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
1020 | 0 | RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; |
1021 | 0 | if (IS_ALIGNED(width, 16)) { |
1022 | 0 | RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; |
1023 | 0 | } |
1024 | 0 | } |
1025 | 0 | #endif |
1026 | 0 | #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) |
1027 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
1028 | 0 | ARGBToUVRow = ARGBToUVRow_Any_SSSE3; |
1029 | 0 | ARGBToYRow = ARGBToYRow_Any_SSSE3; |
1030 | 0 | if (IS_ALIGNED(width, 16)) { |
1031 | 0 | ARGBToUVRow = ARGBToUVRow_SSSE3; |
1032 | 0 | ARGBToYRow = ARGBToYRow_SSSE3; |
1033 | 0 | } |
1034 | 0 | } |
1035 | 0 | #endif |
1036 | 0 | #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) |
1037 | 0 | if (TestCpuFlag(kCpuHasAVX2)) { |
1038 | 0 | ARGBToUVRow = ARGBToUVRow_Any_AVX2; |
1039 | 0 | ARGBToYRow = ARGBToYRow_Any_AVX2; |
1040 | 0 | if (IS_ALIGNED(width, 32)) { |
1041 | 0 | ARGBToUVRow = ARGBToUVRow_AVX2; |
1042 | 0 | ARGBToYRow = ARGBToYRow_AVX2; |
1043 | 0 | } |
1044 | 0 | } |
1045 | 0 | #endif |
1046 | 0 | #endif |
1047 | 0 |
|
1048 | 0 | { |
1049 | 0 | #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) |
1050 | 0 | // Allocate 2 rows of ARGB. |
1051 | 0 | const int kRowSize = (width * 4 + 31) & ~31; |
1052 | 0 | align_buffer_64(row, kRowSize * 2); |
1053 | 0 | #endif |
1054 | 0 |
|
1055 | 0 | for (y = 0; y < height - 1; y += 2) { |
1056 | | #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) |
1057 | | RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width); |
1058 | | RGB24ToYRow(src_rgb24, dst_y, width); |
1059 | | RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width); |
1060 | | #else |
1061 | | RGB24ToARGBRow(src_rgb24, row, width); |
1062 | 0 | RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width); |
1063 | 0 | ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); |
1064 | 0 | ARGBToYRow(row, dst_y, width); |
1065 | 0 | ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); |
1066 | 0 | #endif |
1067 | 0 | src_rgb24 += src_stride_rgb24 * 2; |
1068 | 0 | dst_y += dst_stride_y * 2; |
1069 | 0 | dst_u += dst_stride_u; |
1070 | 0 | dst_v += dst_stride_v; |
1071 | 0 | } |
1072 | 0 | if (height & 1) { |
1073 | | #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) |
1074 | | RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width); |
1075 | | RGB24ToYRow(src_rgb24, dst_y, width); |
1076 | | #else |
1077 | | RGB24ToARGBRow(src_rgb24, row, width); |
1078 | 0 | ARGBToUVRow(row, 0, dst_u, dst_v, width); |
1079 | 0 | ARGBToYRow(row, dst_y, width); |
1080 | 0 | #endif |
1081 | 0 | } |
1082 | 0 | #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA)) |
1083 | 0 | free_aligned_buffer_64(row); |
1084 | 0 | #endif |
1085 | 0 | } |
1086 | 0 | return 0; |
1087 | 0 | } |
1088 | | |
1089 | | // Convert RAW to I420. |
1090 | | LIBYUV_API |
1091 | | int RAWToI420(const uint8_t* src_raw, |
1092 | | int src_stride_raw, |
1093 | | uint8_t* dst_y, |
1094 | | int dst_stride_y, |
1095 | | uint8_t* dst_u, |
1096 | | int dst_stride_u, |
1097 | | uint8_t* dst_v, |
1098 | | int dst_stride_v, |
1099 | | int width, |
1100 | 0 | int height) { |
1101 | 0 | int y; |
1102 | | #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) |
1103 | | void (*RAWToUVRow)(const uint8_t* src_raw, int src_stride_raw, uint8_t* dst_u, |
1104 | | uint8_t* dst_v, int width) = RAWToUVRow_C; |
1105 | | void (*RAWToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) = |
1106 | | RAWToYRow_C; |
1107 | | #else |
1108 | | void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = |
1109 | 0 | RAWToARGBRow_C; |
1110 | 0 | void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, |
1111 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
1112 | 0 | ARGBToUVRow_C; |
1113 | 0 | void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = |
1114 | 0 | ARGBToYRow_C; |
1115 | 0 | #endif |
1116 | 0 | if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { |
1117 | 0 | return -1; |
1118 | 0 | } |
1119 | 0 | // Negative height means invert the image. |
1120 | 0 | if (height < 0) { |
1121 | 0 | height = -height; |
1122 | 0 | src_raw = src_raw + (height - 1) * src_stride_raw; |
1123 | 0 | src_stride_raw = -src_stride_raw; |
1124 | 0 | } |
1125 | 0 |
|
1126 | 0 | // Neon version does direct RAW to YUV. |
1127 | | #if defined(HAS_RAWTOYROW_NEON) |
1128 | | if (TestCpuFlag(kCpuHasNEON)) { |
1129 | | RAWToUVRow = RAWToUVRow_Any_NEON; |
1130 | | RAWToYRow = RAWToYRow_Any_NEON; |
1131 | | if (IS_ALIGNED(width, 8)) { |
1132 | | RAWToYRow = RAWToYRow_NEON; |
1133 | | if (IS_ALIGNED(width, 16)) { |
1134 | | RAWToUVRow = RAWToUVRow_NEON; |
1135 | | } |
1136 | | } |
1137 | | } |
1138 | | #elif defined(HAS_RAWTOYROW_MSA) |
1139 | | if (TestCpuFlag(kCpuHasMSA)) { |
1140 | | RAWToUVRow = RAWToUVRow_Any_MSA; |
1141 | | RAWToYRow = RAWToYRow_Any_MSA; |
1142 | | if (IS_ALIGNED(width, 16)) { |
1143 | | RAWToYRow = RAWToYRow_MSA; |
1144 | | RAWToUVRow = RAWToUVRow_MSA; |
1145 | | } |
1146 | | } |
1147 | | // Other platforms do intermediate conversion from RAW to ARGB. |
1148 | | #else |
1149 | | #if defined(HAS_RAWTOARGBROW_SSSE3) |
1150 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
1151 | 0 | RAWToARGBRow = RAWToARGBRow_Any_SSSE3; |
1152 | 0 | if (IS_ALIGNED(width, 16)) { |
1153 | 0 | RAWToARGBRow = RAWToARGBRow_SSSE3; |
1154 | 0 | } |
1155 | 0 | } |
1156 | 0 | #endif |
1157 | 0 | #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) |
1158 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
1159 | 0 | ARGBToUVRow = ARGBToUVRow_Any_SSSE3; |
1160 | 0 | ARGBToYRow = ARGBToYRow_Any_SSSE3; |
1161 | 0 | if (IS_ALIGNED(width, 16)) { |
1162 | 0 | ARGBToUVRow = ARGBToUVRow_SSSE3; |
1163 | 0 | ARGBToYRow = ARGBToYRow_SSSE3; |
1164 | 0 | } |
1165 | 0 | } |
1166 | 0 | #endif |
1167 | 0 | #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) |
1168 | 0 | if (TestCpuFlag(kCpuHasAVX2)) { |
1169 | 0 | ARGBToUVRow = ARGBToUVRow_Any_AVX2; |
1170 | 0 | ARGBToYRow = ARGBToYRow_Any_AVX2; |
1171 | 0 | if (IS_ALIGNED(width, 32)) { |
1172 | 0 | ARGBToUVRow = ARGBToUVRow_AVX2; |
1173 | 0 | ARGBToYRow = ARGBToYRow_AVX2; |
1174 | 0 | } |
1175 | 0 | } |
1176 | 0 | #endif |
1177 | 0 | #endif |
1178 | 0 |
|
1179 | 0 | { |
1180 | 0 | #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) |
1181 | 0 | // Allocate 2 rows of ARGB. |
1182 | 0 | const int kRowSize = (width * 4 + 31) & ~31; |
1183 | 0 | align_buffer_64(row, kRowSize * 2); |
1184 | 0 | #endif |
1185 | 0 |
|
1186 | 0 | for (y = 0; y < height - 1; y += 2) { |
1187 | | #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) |
1188 | | RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width); |
1189 | | RAWToYRow(src_raw, dst_y, width); |
1190 | | RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width); |
1191 | | #else |
1192 | | RAWToARGBRow(src_raw, row, width); |
1193 | 0 | RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width); |
1194 | 0 | ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); |
1195 | 0 | ARGBToYRow(row, dst_y, width); |
1196 | 0 | ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); |
1197 | 0 | #endif |
1198 | 0 | src_raw += src_stride_raw * 2; |
1199 | 0 | dst_y += dst_stride_y * 2; |
1200 | 0 | dst_u += dst_stride_u; |
1201 | 0 | dst_v += dst_stride_v; |
1202 | 0 | } |
1203 | 0 | if (height & 1) { |
1204 | | #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) |
1205 | | RAWToUVRow(src_raw, 0, dst_u, dst_v, width); |
1206 | | RAWToYRow(src_raw, dst_y, width); |
1207 | | #else |
1208 | | RAWToARGBRow(src_raw, row, width); |
1209 | 0 | ARGBToUVRow(row, 0, dst_u, dst_v, width); |
1210 | 0 | ARGBToYRow(row, dst_y, width); |
1211 | 0 | #endif |
1212 | 0 | } |
1213 | 0 | #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA)) |
1214 | 0 | free_aligned_buffer_64(row); |
1215 | 0 | #endif |
1216 | 0 | } |
1217 | 0 | return 0; |
1218 | 0 | } |
1219 | | |
1220 | | // Convert RGB565 to I420. |
1221 | | LIBYUV_API |
1222 | | int RGB565ToI420(const uint8_t* src_rgb565, |
1223 | | int src_stride_rgb565, |
1224 | | uint8_t* dst_y, |
1225 | | int dst_stride_y, |
1226 | | uint8_t* dst_u, |
1227 | | int dst_stride_u, |
1228 | | uint8_t* dst_v, |
1229 | | int dst_stride_v, |
1230 | | int width, |
1231 | 0 | int height) { |
1232 | 0 | int y; |
1233 | | #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) |
1234 | | void (*RGB565ToUVRow)(const uint8_t* src_rgb565, int src_stride_rgb565, |
1235 | | uint8_t* dst_u, uint8_t* dst_v, int width) = |
1236 | | RGB565ToUVRow_C; |
1237 | | void (*RGB565ToYRow)(const uint8_t* src_rgb565, uint8_t* dst_y, int width) = |
1238 | | RGB565ToYRow_C; |
1239 | | #else |
1240 | | void (*RGB565ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, |
1241 | 0 | int width) = RGB565ToARGBRow_C; |
1242 | 0 | void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, |
1243 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
1244 | 0 | ARGBToUVRow_C; |
1245 | 0 | void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = |
1246 | 0 | ARGBToYRow_C; |
1247 | 0 | #endif |
1248 | 0 | if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) { |
1249 | 0 | return -1; |
1250 | 0 | } |
1251 | 0 | // Negative height means invert the image. |
1252 | 0 | if (height < 0) { |
1253 | 0 | height = -height; |
1254 | 0 | src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; |
1255 | 0 | src_stride_rgb565 = -src_stride_rgb565; |
1256 | 0 | } |
1257 | 0 |
|
1258 | 0 | // Neon version does direct RGB565 to YUV. |
1259 | | #if defined(HAS_RGB565TOYROW_NEON) |
1260 | | if (TestCpuFlag(kCpuHasNEON)) { |
1261 | | RGB565ToUVRow = RGB565ToUVRow_Any_NEON; |
1262 | | RGB565ToYRow = RGB565ToYRow_Any_NEON; |
1263 | | if (IS_ALIGNED(width, 8)) { |
1264 | | RGB565ToYRow = RGB565ToYRow_NEON; |
1265 | | if (IS_ALIGNED(width, 16)) { |
1266 | | RGB565ToUVRow = RGB565ToUVRow_NEON; |
1267 | | } |
1268 | | } |
1269 | | } |
1270 | | #elif defined(HAS_RGB565TOYROW_MSA) |
1271 | | if (TestCpuFlag(kCpuHasMSA)) { |
1272 | | RGB565ToUVRow = RGB565ToUVRow_Any_MSA; |
1273 | | RGB565ToYRow = RGB565ToYRow_Any_MSA; |
1274 | | if (IS_ALIGNED(width, 16)) { |
1275 | | RGB565ToYRow = RGB565ToYRow_MSA; |
1276 | | RGB565ToUVRow = RGB565ToUVRow_MSA; |
1277 | | } |
1278 | | } |
1279 | | // Other platforms do intermediate conversion from RGB565 to ARGB. |
1280 | | #else |
1281 | | #if defined(HAS_RGB565TOARGBROW_SSE2) |
1282 | 0 | if (TestCpuFlag(kCpuHasSSE2)) { |
1283 | 0 | RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; |
1284 | 0 | if (IS_ALIGNED(width, 8)) { |
1285 | 0 | RGB565ToARGBRow = RGB565ToARGBRow_SSE2; |
1286 | 0 | } |
1287 | 0 | } |
1288 | 0 | #endif |
1289 | | #if defined(HAS_RGB565TOARGBROW_AVX2) |
1290 | | if (TestCpuFlag(kCpuHasAVX2)) { |
1291 | | RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2; |
1292 | | if (IS_ALIGNED(width, 16)) { |
1293 | | RGB565ToARGBRow = RGB565ToARGBRow_AVX2; |
1294 | | } |
1295 | | } |
1296 | | #endif |
1297 | | #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) |
1298 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
1299 | 0 | ARGBToUVRow = ARGBToUVRow_Any_SSSE3; |
1300 | 0 | ARGBToYRow = ARGBToYRow_Any_SSSE3; |
1301 | 0 | if (IS_ALIGNED(width, 16)) { |
1302 | 0 | ARGBToUVRow = ARGBToUVRow_SSSE3; |
1303 | 0 | ARGBToYRow = ARGBToYRow_SSSE3; |
1304 | 0 | } |
1305 | 0 | } |
1306 | 0 | #endif |
1307 | 0 | #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) |
1308 | 0 | if (TestCpuFlag(kCpuHasAVX2)) { |
1309 | 0 | ARGBToUVRow = ARGBToUVRow_Any_AVX2; |
1310 | 0 | ARGBToYRow = ARGBToYRow_Any_AVX2; |
1311 | 0 | if (IS_ALIGNED(width, 32)) { |
1312 | 0 | ARGBToUVRow = ARGBToUVRow_AVX2; |
1313 | 0 | ARGBToYRow = ARGBToYRow_AVX2; |
1314 | 0 | } |
1315 | 0 | } |
1316 | 0 | #endif |
1317 | 0 | #endif |
1318 | 0 | { |
1319 | 0 | #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) |
1320 | 0 | // Allocate 2 rows of ARGB. |
1321 | 0 | const int kRowSize = (width * 4 + 31) & ~31; |
1322 | 0 | align_buffer_64(row, kRowSize * 2); |
1323 | 0 | #endif |
1324 | 0 | for (y = 0; y < height - 1; y += 2) { |
1325 | | #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) |
1326 | | RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width); |
1327 | | RGB565ToYRow(src_rgb565, dst_y, width); |
1328 | | RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width); |
1329 | | #else |
1330 | | RGB565ToARGBRow(src_rgb565, row, width); |
1331 | 0 | RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width); |
1332 | 0 | ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); |
1333 | 0 | ARGBToYRow(row, dst_y, width); |
1334 | 0 | ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); |
1335 | 0 | #endif |
1336 | 0 | src_rgb565 += src_stride_rgb565 * 2; |
1337 | 0 | dst_y += dst_stride_y * 2; |
1338 | 0 | dst_u += dst_stride_u; |
1339 | 0 | dst_v += dst_stride_v; |
1340 | 0 | } |
1341 | 0 | if (height & 1) { |
1342 | | #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) |
1343 | | RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width); |
1344 | | RGB565ToYRow(src_rgb565, dst_y, width); |
1345 | | #else |
1346 | | RGB565ToARGBRow(src_rgb565, row, width); |
1347 | 0 | ARGBToUVRow(row, 0, dst_u, dst_v, width); |
1348 | 0 | ARGBToYRow(row, dst_y, width); |
1349 | 0 | #endif |
1350 | 0 | } |
1351 | 0 | #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA)) |
1352 | 0 | free_aligned_buffer_64(row); |
1353 | 0 | #endif |
1354 | 0 | } |
1355 | 0 | return 0; |
1356 | 0 | } |
1357 | | |
1358 | | // Convert ARGB1555 to I420. |
1359 | | LIBYUV_API |
1360 | | int ARGB1555ToI420(const uint8_t* src_argb1555, |
1361 | | int src_stride_argb1555, |
1362 | | uint8_t* dst_y, |
1363 | | int dst_stride_y, |
1364 | | uint8_t* dst_u, |
1365 | | int dst_stride_u, |
1366 | | uint8_t* dst_v, |
1367 | | int dst_stride_v, |
1368 | | int width, |
1369 | 0 | int height) { |
1370 | 0 | int y; |
1371 | | #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) |
1372 | | void (*ARGB1555ToUVRow)(const uint8_t* src_argb1555, int src_stride_argb1555, |
1373 | | uint8_t* dst_u, uint8_t* dst_v, int width) = |
1374 | | ARGB1555ToUVRow_C; |
1375 | | void (*ARGB1555ToYRow)(const uint8_t* src_argb1555, uint8_t* dst_y, |
1376 | | int width) = ARGB1555ToYRow_C; |
1377 | | #else |
1378 | | void (*ARGB1555ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, |
1379 | 0 | int width) = ARGB1555ToARGBRow_C; |
1380 | 0 | void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, |
1381 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
1382 | 0 | ARGBToUVRow_C; |
1383 | 0 | void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = |
1384 | 0 | ARGBToYRow_C; |
1385 | 0 | #endif |
1386 | 0 | if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 || |
1387 | 0 | height == 0) { |
1388 | 0 | return -1; |
1389 | 0 | } |
1390 | 0 | // Negative height means invert the image. |
1391 | 0 | if (height < 0) { |
1392 | 0 | height = -height; |
1393 | 0 | src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; |
1394 | 0 | src_stride_argb1555 = -src_stride_argb1555; |
1395 | 0 | } |
1396 | 0 |
|
1397 | 0 | // Neon version does direct ARGB1555 to YUV. |
1398 | | #if defined(HAS_ARGB1555TOYROW_NEON) |
1399 | | if (TestCpuFlag(kCpuHasNEON)) { |
1400 | | ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON; |
1401 | | ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON; |
1402 | | if (IS_ALIGNED(width, 8)) { |
1403 | | ARGB1555ToYRow = ARGB1555ToYRow_NEON; |
1404 | | if (IS_ALIGNED(width, 16)) { |
1405 | | ARGB1555ToUVRow = ARGB1555ToUVRow_NEON; |
1406 | | } |
1407 | | } |
1408 | | } |
1409 | | #elif defined(HAS_ARGB1555TOYROW_MSA) |
1410 | | if (TestCpuFlag(kCpuHasMSA)) { |
1411 | | ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA; |
1412 | | ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA; |
1413 | | if (IS_ALIGNED(width, 16)) { |
1414 | | ARGB1555ToYRow = ARGB1555ToYRow_MSA; |
1415 | | ARGB1555ToUVRow = ARGB1555ToUVRow_MSA; |
1416 | | } |
1417 | | } |
1418 | | // Other platforms do intermediate conversion from ARGB1555 to ARGB. |
1419 | | #else |
1420 | | #if defined(HAS_ARGB1555TOARGBROW_SSE2) |
1421 | 0 | if (TestCpuFlag(kCpuHasSSE2)) { |
1422 | 0 | ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; |
1423 | 0 | if (IS_ALIGNED(width, 8)) { |
1424 | 0 | ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; |
1425 | 0 | } |
1426 | 0 | } |
1427 | 0 | #endif |
1428 | | #if defined(HAS_ARGB1555TOARGBROW_AVX2) |
1429 | | if (TestCpuFlag(kCpuHasAVX2)) { |
1430 | | ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2; |
1431 | | if (IS_ALIGNED(width, 16)) { |
1432 | | ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2; |
1433 | | } |
1434 | | } |
1435 | | #endif |
1436 | | #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) |
1437 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
1438 | 0 | ARGBToUVRow = ARGBToUVRow_Any_SSSE3; |
1439 | 0 | ARGBToYRow = ARGBToYRow_Any_SSSE3; |
1440 | 0 | if (IS_ALIGNED(width, 16)) { |
1441 | 0 | ARGBToUVRow = ARGBToUVRow_SSSE3; |
1442 | 0 | ARGBToYRow = ARGBToYRow_SSSE3; |
1443 | 0 | } |
1444 | 0 | } |
1445 | 0 | #endif |
1446 | 0 | #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) |
1447 | 0 | if (TestCpuFlag(kCpuHasAVX2)) { |
1448 | 0 | ARGBToUVRow = ARGBToUVRow_Any_AVX2; |
1449 | 0 | ARGBToYRow = ARGBToYRow_Any_AVX2; |
1450 | 0 | if (IS_ALIGNED(width, 32)) { |
1451 | 0 | ARGBToUVRow = ARGBToUVRow_AVX2; |
1452 | 0 | ARGBToYRow = ARGBToYRow_AVX2; |
1453 | 0 | } |
1454 | 0 | } |
1455 | 0 | #endif |
1456 | 0 | #endif |
1457 | 0 | { |
1458 | 0 | #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) |
1459 | 0 | // Allocate 2 rows of ARGB. |
1460 | 0 | const int kRowSize = (width * 4 + 31) & ~31; |
1461 | 0 | align_buffer_64(row, kRowSize * 2); |
1462 | 0 | #endif |
1463 | 0 |
|
1464 | 0 | for (y = 0; y < height - 1; y += 2) { |
1465 | | #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) |
1466 | | ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width); |
1467 | | ARGB1555ToYRow(src_argb1555, dst_y, width); |
1468 | | ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y, |
1469 | | width); |
1470 | | #else |
1471 | | ARGB1555ToARGBRow(src_argb1555, row, width); |
1472 | 0 | ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize, |
1473 | 0 | width); |
1474 | 0 | ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); |
1475 | 0 | ARGBToYRow(row, dst_y, width); |
1476 | 0 | ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); |
1477 | 0 | #endif |
1478 | 0 | src_argb1555 += src_stride_argb1555 * 2; |
1479 | 0 | dst_y += dst_stride_y * 2; |
1480 | 0 | dst_u += dst_stride_u; |
1481 | 0 | dst_v += dst_stride_v; |
1482 | 0 | } |
1483 | 0 | if (height & 1) { |
1484 | | #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) |
1485 | | ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width); |
1486 | | ARGB1555ToYRow(src_argb1555, dst_y, width); |
1487 | | #else |
1488 | | ARGB1555ToARGBRow(src_argb1555, row, width); |
1489 | 0 | ARGBToUVRow(row, 0, dst_u, dst_v, width); |
1490 | 0 | ARGBToYRow(row, dst_y, width); |
1491 | 0 | #endif |
1492 | 0 | } |
1493 | 0 | #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA)) |
1494 | 0 | free_aligned_buffer_64(row); |
1495 | 0 | #endif |
1496 | 0 | } |
1497 | 0 | return 0; |
1498 | 0 | } |
1499 | | |
1500 | | // Convert ARGB4444 to I420. |
1501 | | LIBYUV_API |
1502 | | int ARGB4444ToI420(const uint8_t* src_argb4444, |
1503 | | int src_stride_argb4444, |
1504 | | uint8_t* dst_y, |
1505 | | int dst_stride_y, |
1506 | | uint8_t* dst_u, |
1507 | | int dst_stride_u, |
1508 | | uint8_t* dst_v, |
1509 | | int dst_stride_v, |
1510 | | int width, |
1511 | 0 | int height) { |
1512 | 0 | int y; |
1513 | | #if defined(HAS_ARGB4444TOYROW_NEON) |
1514 | | void (*ARGB4444ToUVRow)(const uint8_t* src_argb4444, int src_stride_argb4444, |
1515 | | uint8_t* dst_u, uint8_t* dst_v, int width) = |
1516 | | ARGB4444ToUVRow_C; |
1517 | | void (*ARGB4444ToYRow)(const uint8_t* src_argb4444, uint8_t* dst_y, |
1518 | | int width) = ARGB4444ToYRow_C; |
1519 | | #else |
1520 | | void (*ARGB4444ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, |
1521 | 0 | int width) = ARGB4444ToARGBRow_C; |
1522 | 0 | void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb, |
1523 | 0 | uint8_t* dst_u, uint8_t* dst_v, int width) = |
1524 | 0 | ARGBToUVRow_C; |
1525 | 0 | void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) = |
1526 | 0 | ARGBToYRow_C; |
1527 | 0 | #endif |
1528 | 0 | if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 || |
1529 | 0 | height == 0) { |
1530 | 0 | return -1; |
1531 | 0 | } |
1532 | 0 | // Negative height means invert the image. |
1533 | 0 | if (height < 0) { |
1534 | 0 | height = -height; |
1535 | 0 | src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; |
1536 | 0 | src_stride_argb4444 = -src_stride_argb4444; |
1537 | 0 | } |
1538 | 0 |
|
1539 | 0 | // Neon version does direct ARGB4444 to YUV. |
1540 | | #if defined(HAS_ARGB4444TOYROW_NEON) |
1541 | | if (TestCpuFlag(kCpuHasNEON)) { |
1542 | | ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON; |
1543 | | ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON; |
1544 | | if (IS_ALIGNED(width, 8)) { |
1545 | | ARGB4444ToYRow = ARGB4444ToYRow_NEON; |
1546 | | if (IS_ALIGNED(width, 16)) { |
1547 | | ARGB4444ToUVRow = ARGB4444ToUVRow_NEON; |
1548 | | } |
1549 | | } |
1550 | | } |
1551 | | // Other platforms do intermediate conversion from ARGB4444 to ARGB. |
1552 | | #else |
1553 | | #if defined(HAS_ARGB4444TOARGBROW_SSE2) |
1554 | 0 | if (TestCpuFlag(kCpuHasSSE2)) { |
1555 | 0 | ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; |
1556 | 0 | if (IS_ALIGNED(width, 8)) { |
1557 | 0 | ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; |
1558 | 0 | } |
1559 | 0 | } |
1560 | 0 | #endif |
1561 | | #if defined(HAS_ARGB4444TOARGBROW_AVX2) |
1562 | | if (TestCpuFlag(kCpuHasAVX2)) { |
1563 | | ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2; |
1564 | | if (IS_ALIGNED(width, 16)) { |
1565 | | ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2; |
1566 | | } |
1567 | | } |
1568 | | #endif |
1569 | | #if defined(HAS_ARGB4444TOARGBROW_MSA) |
1570 | | if (TestCpuFlag(kCpuHasMSA)) { |
1571 | | ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA; |
1572 | | if (IS_ALIGNED(width, 16)) { |
1573 | | ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA; |
1574 | | } |
1575 | | } |
1576 | | #endif |
1577 | | #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3) |
1578 | 0 | if (TestCpuFlag(kCpuHasSSSE3)) { |
1579 | 0 | ARGBToUVRow = ARGBToUVRow_Any_SSSE3; |
1580 | 0 | ARGBToYRow = ARGBToYRow_Any_SSSE3; |
1581 | 0 | if (IS_ALIGNED(width, 16)) { |
1582 | 0 | ARGBToUVRow = ARGBToUVRow_SSSE3; |
1583 | 0 | ARGBToYRow = ARGBToYRow_SSSE3; |
1584 | 0 | } |
1585 | 0 | } |
1586 | 0 | #endif |
1587 | 0 | #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2) |
1588 | 0 | if (TestCpuFlag(kCpuHasAVX2)) { |
1589 | 0 | ARGBToUVRow = ARGBToUVRow_Any_AVX2; |
1590 | 0 | ARGBToYRow = ARGBToYRow_Any_AVX2; |
1591 | 0 | if (IS_ALIGNED(width, 32)) { |
1592 | 0 | ARGBToUVRow = ARGBToUVRow_AVX2; |
1593 | 0 | ARGBToYRow = ARGBToYRow_AVX2; |
1594 | 0 | } |
1595 | 0 | } |
1596 | 0 | #endif |
1597 | | #if defined(HAS_ARGBTOYROW_MSA) |
1598 | | if (TestCpuFlag(kCpuHasMSA)) { |
1599 | | ARGBToUVRow = ARGBToUVRow_Any_MSA; |
1600 | | ARGBToYRow = ARGBToYRow_Any_MSA; |
1601 | | if (IS_ALIGNED(width, 16)) { |
1602 | | ARGBToYRow = ARGBToYRow_MSA; |
1603 | | if (IS_ALIGNED(width, 32)) { |
1604 | | ARGBToUVRow = ARGBToUVRow_MSA; |
1605 | | } |
1606 | | } |
1607 | | } |
1608 | | #endif |
1609 | | #endif |
1610 | 0 |
|
1611 | 0 | { |
1612 | 0 | #if !defined(HAS_ARGB4444TOYROW_NEON) |
1613 | 0 | // Allocate 2 rows of ARGB. |
1614 | 0 | const int kRowSize = (width * 4 + 31) & ~31; |
1615 | 0 | align_buffer_64(row, kRowSize * 2); |
1616 | 0 | #endif |
1617 | 0 |
|
1618 | 0 | for (y = 0; y < height - 1; y += 2) { |
1619 | | #if defined(HAS_ARGB4444TOYROW_NEON) |
1620 | | ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width); |
1621 | | ARGB4444ToYRow(src_argb4444, dst_y, width); |
1622 | | ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y, |
1623 | | width); |
1624 | | #else |
1625 | | ARGB4444ToARGBRow(src_argb4444, row, width); |
1626 | 0 | ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize, |
1627 | 0 | width); |
1628 | 0 | ARGBToUVRow(row, kRowSize, dst_u, dst_v, width); |
1629 | 0 | ARGBToYRow(row, dst_y, width); |
1630 | 0 | ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width); |
1631 | 0 | #endif |
1632 | 0 | src_argb4444 += src_stride_argb4444 * 2; |
1633 | 0 | dst_y += dst_stride_y * 2; |
1634 | 0 | dst_u += dst_stride_u; |
1635 | 0 | dst_v += dst_stride_v; |
1636 | 0 | } |
1637 | 0 | if (height & 1) { |
1638 | | #if defined(HAS_ARGB4444TOYROW_NEON) |
1639 | | ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width); |
1640 | | ARGB4444ToYRow(src_argb4444, dst_y, width); |
1641 | | #else |
1642 | | ARGB4444ToARGBRow(src_argb4444, row, width); |
1643 | 0 | ARGBToUVRow(row, 0, dst_u, dst_v, width); |
1644 | 0 | ARGBToYRow(row, dst_y, width); |
1645 | 0 | #endif |
1646 | 0 | } |
1647 | 0 | #if !defined(HAS_ARGB4444TOYROW_NEON) |
1648 | 0 | free_aligned_buffer_64(row); |
1649 | 0 | #endif |
1650 | 0 | } |
1651 | 0 | return 0; |
1652 | 0 | } |
1653 | | |
1654 | | static void SplitPixels(const uint8_t* src_u, |
1655 | | int src_pixel_stride_uv, |
1656 | | uint8_t* dst_u, |
1657 | 0 | int width) { |
1658 | 0 | int i; |
1659 | 0 | for (i = 0; i < width; ++i) { |
1660 | 0 | *dst_u = *src_u; |
1661 | 0 | ++dst_u; |
1662 | 0 | src_u += src_pixel_stride_uv; |
1663 | 0 | } |
1664 | 0 | } |
1665 | | |
1666 | | // Convert Android420 to I420. |
1667 | | LIBYUV_API |
1668 | | int Android420ToI420(const uint8_t* src_y, |
1669 | | int src_stride_y, |
1670 | | const uint8_t* src_u, |
1671 | | int src_stride_u, |
1672 | | const uint8_t* src_v, |
1673 | | int src_stride_v, |
1674 | | int src_pixel_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 | 0 | int height) { |
1683 | 0 | int y; |
1684 | 0 | const ptrdiff_t vu_off = src_v - src_u; |
1685 | 0 | int halfwidth = (width + 1) >> 1; |
1686 | 0 | int halfheight = (height + 1) >> 1; |
1687 | 0 | if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) { |
1688 | 0 | return -1; |
1689 | 0 | } |
1690 | 0 | // Negative height means invert the image. |
1691 | 0 | if (height < 0) { |
1692 | 0 | height = -height; |
1693 | 0 | halfheight = (height + 1) >> 1; |
1694 | 0 | src_y = src_y + (height - 1) * src_stride_y; |
1695 | 0 | src_u = src_u + (halfheight - 1) * src_stride_u; |
1696 | 0 | src_v = src_v + (halfheight - 1) * src_stride_v; |
1697 | 0 | src_stride_y = -src_stride_y; |
1698 | 0 | src_stride_u = -src_stride_u; |
1699 | 0 | src_stride_v = -src_stride_v; |
1700 | 0 | } |
1701 | 0 |
|
1702 | 0 | if (dst_y) { |
1703 | 0 | CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); |
1704 | 0 | } |
1705 | 0 |
|
1706 | 0 | // Copy UV planes as is - I420 |
1707 | 0 | if (src_pixel_stride_uv == 1) { |
1708 | 0 | CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight); |
1709 | 0 | CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight); |
1710 | 0 | return 0; |
1711 | 0 | // Split UV planes - NV21 |
1712 | 0 | } |
1713 | 0 | if (src_pixel_stride_uv == 2 && vu_off == -1 && |
1714 | 0 | src_stride_u == src_stride_v) { |
1715 | 0 | SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u, |
1716 | 0 | halfwidth, halfheight); |
1717 | 0 | return 0; |
1718 | 0 | // Split UV planes - NV12 |
1719 | 0 | } |
1720 | 0 | if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) { |
1721 | 0 | SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v, |
1722 | 0 | halfwidth, halfheight); |
1723 | 0 | return 0; |
1724 | 0 | } |
1725 | 0 | |
1726 | 0 | for (y = 0; y < halfheight; ++y) { |
1727 | 0 | SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth); |
1728 | 0 | SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth); |
1729 | 0 | src_u += src_stride_u; |
1730 | 0 | src_v += src_stride_v; |
1731 | 0 | dst_u += dst_stride_u; |
1732 | 0 | dst_v += dst_stride_v; |
1733 | 0 | } |
1734 | 0 | return 0; |
1735 | 0 | } |
1736 | | |
1737 | | #ifdef __cplusplus |
1738 | | } // extern "C" |
1739 | | } // namespace libyuv |
1740 | | #endif |