media/libyuv/source/format_conversion.cc

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:3a3a7c431ae6
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/format_conversion.h"
12
13 #include "libyuv/basic_types.h"
14 #include "libyuv/cpu_id.h"
15 #include "libyuv/video_common.h"
16 #include "libyuv/row.h"
17
18 #ifdef __cplusplus
19 namespace libyuv {
20 extern "C" {
21 #endif
22
23 // generate a selector mask useful for pshufb
24 static uint32 GenerateSelector(int select0, int select1) {
25 return (uint32)(select0) |
26 (uint32)((select1 + 4) << 8) |
27 (uint32)((select0 + 8) << 16) |
28 (uint32)((select1 + 12) << 24);
29 }
30
31 static int MakeSelectors(const int blue_index,
32 const int green_index,
33 const int red_index,
34 uint32 dst_fourcc_bayer,
35 uint32* index_map) {
36 // Now build a lookup table containing the indices for the four pixels in each
37 // 2x2 Bayer grid.
38 switch (dst_fourcc_bayer) {
39 case FOURCC_BGGR:
40 index_map[0] = GenerateSelector(blue_index, green_index);
41 index_map[1] = GenerateSelector(green_index, red_index);
42 break;
43 case FOURCC_GBRG:
44 index_map[0] = GenerateSelector(green_index, blue_index);
45 index_map[1] = GenerateSelector(red_index, green_index);
46 break;
47 case FOURCC_RGGB:
48 index_map[0] = GenerateSelector(red_index, green_index);
49 index_map[1] = GenerateSelector(green_index, blue_index);
50 break;
51 case FOURCC_GRBG:
52 index_map[0] = GenerateSelector(green_index, red_index);
53 index_map[1] = GenerateSelector(blue_index, green_index);
54 break;
55 default:
56 return -1; // Bad FourCC
57 }
58 return 0;
59 }
60
61 // Converts 32 bit ARGB to Bayer RGB formats.
62 LIBYUV_API
63 int ARGBToBayer(const uint8* src_argb, int src_stride_argb,
64 uint8* dst_bayer, int dst_stride_bayer,
65 int width, int height,
66 uint32 dst_fourcc_bayer) {
67 if (height < 0) {
68 height = -height;
69 src_argb = src_argb + (height - 1) * src_stride_argb;
70 src_stride_argb = -src_stride_argb;
71 }
72 void (*ARGBToBayerRow)(const uint8* src_argb, uint8* dst_bayer,
73 uint32 selector, int pix) = ARGBToBayerRow_C;
74 #if defined(HAS_ARGBTOBAYERROW_SSSE3)
75 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8 &&
76 IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
77 ARGBToBayerRow = ARGBToBayerRow_Any_SSSE3;
78 if (IS_ALIGNED(width, 8)) {
79 ARGBToBayerRow = ARGBToBayerRow_SSSE3;
80 }
81 }
82 #elif defined(HAS_ARGBTOBAYERROW_NEON)
83 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
84 ARGBToBayerRow = ARGBToBayerRow_Any_NEON;
85 if (IS_ALIGNED(width, 8)) {
86 ARGBToBayerRow = ARGBToBayerRow_NEON;
87 }
88 }
89 #endif
90 const int blue_index = 0; // Offsets for ARGB format
91 const int green_index = 1;
92 const int red_index = 2;
93 uint32 index_map[2];
94 if (MakeSelectors(blue_index, green_index, red_index,
95 dst_fourcc_bayer, index_map)) {
96 return -1; // Bad FourCC
97 }
98
99 for (int y = 0; y < height; ++y) {
100 ARGBToBayerRow(src_argb, dst_bayer, index_map[y & 1], width);
101 src_argb += src_stride_argb;
102 dst_bayer += dst_stride_bayer;
103 }
104 return 0;
105 }
106
107 #define AVG(a, b) (((a) + (b)) >> 1)
108
109 static void BayerRowBG(const uint8* src_bayer0, int src_stride_bayer,
110 uint8* dst_argb, int pix) {
111 const uint8* src_bayer1 = src_bayer0 + src_stride_bayer;
112 uint8 g = src_bayer0[1];
113 uint8 r = src_bayer1[1];
114 for (int x = 0; x < pix - 2; x += 2) {
115 dst_argb[0] = src_bayer0[0];
116 dst_argb[1] = AVG(g, src_bayer0[1]);
117 dst_argb[2] = AVG(r, src_bayer1[1]);
118 dst_argb[3] = 255U;
119 dst_argb[4] = AVG(src_bayer0[0], src_bayer0[2]);
120 dst_argb[5] = src_bayer0[1];
121 dst_argb[6] = src_bayer1[1];
122 dst_argb[7] = 255U;
123 g = src_bayer0[1];
124 r = src_bayer1[1];
125 src_bayer0 += 2;
126 src_bayer1 += 2;
127 dst_argb += 8;
128 }
129 dst_argb[0] = src_bayer0[0];
130 dst_argb[1] = AVG(g, src_bayer0[1]);
131 dst_argb[2] = AVG(r, src_bayer1[1]);
132 dst_argb[3] = 255U;
133 if (!(pix & 1)) {
134 dst_argb[4] = src_bayer0[0];
135 dst_argb[5] = src_bayer0[1];
136 dst_argb[6] = src_bayer1[1];
137 dst_argb[7] = 255U;
138 }
139 }
140
141 static void BayerRowRG(const uint8* src_bayer0, int src_stride_bayer,
142 uint8* dst_argb, int pix) {
143 const uint8* src_bayer1 = src_bayer0 + src_stride_bayer;
144 uint8 g = src_bayer0[1];
145 uint8 b = src_bayer1[1];
146 for (int x = 0; x < pix - 2; x += 2) {
147 dst_argb[0] = AVG(b, src_bayer1[1]);
148 dst_argb[1] = AVG(g, src_bayer0[1]);
149 dst_argb[2] = src_bayer0[0];
150 dst_argb[3] = 255U;
151 dst_argb[4] = src_bayer1[1];
152 dst_argb[5] = src_bayer0[1];
153 dst_argb[6] = AVG(src_bayer0[0], src_bayer0[2]);
154 dst_argb[7] = 255U;
155 g = src_bayer0[1];
156 b = src_bayer1[1];
157 src_bayer0 += 2;
158 src_bayer1 += 2;
159 dst_argb += 8;
160 }
161 dst_argb[0] = AVG(b, src_bayer1[1]);
162 dst_argb[1] = AVG(g, src_bayer0[1]);
163 dst_argb[2] = src_bayer0[0];
164 dst_argb[3] = 255U;
165 if (!(pix & 1)) {
166 dst_argb[4] = src_bayer1[1];
167 dst_argb[5] = src_bayer0[1];
168 dst_argb[6] = src_bayer0[0];
169 dst_argb[7] = 255U;
170 }
171 }
172
173 static void BayerRowGB(const uint8* src_bayer0, int src_stride_bayer,
174 uint8* dst_argb, int pix) {
175 const uint8* src_bayer1 = src_bayer0 + src_stride_bayer;
176 uint8 b = src_bayer0[1];
177 for (int x = 0; x < pix - 2; x += 2) {
178 dst_argb[0] = AVG(b, src_bayer0[1]);
179 dst_argb[1] = src_bayer0[0];
180 dst_argb[2] = src_bayer1[0];
181 dst_argb[3] = 255U;
182 dst_argb[4] = src_bayer0[1];
183 dst_argb[5] = AVG(src_bayer0[0], src_bayer0[2]);
184 dst_argb[6] = AVG(src_bayer1[0], src_bayer1[2]);
185 dst_argb[7] = 255U;
186 b = src_bayer0[1];
187 src_bayer0 += 2;
188 src_bayer1 += 2;
189 dst_argb += 8;
190 }
191 dst_argb[0] = AVG(b, src_bayer0[1]);
192 dst_argb[1] = src_bayer0[0];
193 dst_argb[2] = src_bayer1[0];
194 dst_argb[3] = 255U;
195 if (!(pix & 1)) {
196 dst_argb[4] = src_bayer0[1];
197 dst_argb[5] = src_bayer0[0];
198 dst_argb[6] = src_bayer1[0];
199 dst_argb[7] = 255U;
200 }
201 }
202
203 static void BayerRowGR(const uint8* src_bayer0, int src_stride_bayer,
204 uint8* dst_argb, int pix) {
205 const uint8* src_bayer1 = src_bayer0 + src_stride_bayer;
206 uint8 r = src_bayer0[1];
207 for (int x = 0; x < pix - 2; x += 2) {
208 dst_argb[0] = src_bayer1[0];
209 dst_argb[1] = src_bayer0[0];
210 dst_argb[2] = AVG(r, src_bayer0[1]);
211 dst_argb[3] = 255U;
212 dst_argb[4] = AVG(src_bayer1[0], src_bayer1[2]);
213 dst_argb[5] = AVG(src_bayer0[0], src_bayer0[2]);
214 dst_argb[6] = src_bayer0[1];
215 dst_argb[7] = 255U;
216 r = src_bayer0[1];
217 src_bayer0 += 2;
218 src_bayer1 += 2;
219 dst_argb += 8;
220 }
221 dst_argb[0] = src_bayer1[0];
222 dst_argb[1] = src_bayer0[0];
223 dst_argb[2] = AVG(r, src_bayer0[1]);
224 dst_argb[3] = 255U;
225 if (!(pix & 1)) {
226 dst_argb[4] = src_bayer1[0];
227 dst_argb[5] = src_bayer0[0];
228 dst_argb[6] = src_bayer0[1];
229 dst_argb[7] = 255U;
230 }
231 }
232
233 // Converts any Bayer RGB format to ARGB.
234 LIBYUV_API
235 int BayerToARGB(const uint8* src_bayer, int src_stride_bayer,
236 uint8* dst_argb, int dst_stride_argb,
237 int width, int height,
238 uint32 src_fourcc_bayer) {
239 if (height < 0) {
240 height = -height;
241 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
242 dst_stride_argb = -dst_stride_argb;
243 }
244 void (*BayerRow0)(const uint8* src_bayer, int src_stride_bayer,
245 uint8* dst_argb, int pix);
246 void (*BayerRow1)(const uint8* src_bayer, int src_stride_bayer,
247 uint8* dst_argb, int pix);
248 switch (src_fourcc_bayer) {
249 case FOURCC_BGGR:
250 BayerRow0 = BayerRowBG;
251 BayerRow1 = BayerRowGR;
252 break;
253 case FOURCC_GBRG:
254 BayerRow0 = BayerRowGB;
255 BayerRow1 = BayerRowRG;
256 break;
257 case FOURCC_GRBG:
258 BayerRow0 = BayerRowGR;
259 BayerRow1 = BayerRowBG;
260 break;
261 case FOURCC_RGGB:
262 BayerRow0 = BayerRowRG;
263 BayerRow1 = BayerRowGB;
264 break;
265 default:
266 return -1; // Bad FourCC
267 }
268
269 for (int y = 0; y < height - 1; y += 2) {
270 BayerRow0(src_bayer, src_stride_bayer, dst_argb, width);
271 BayerRow1(src_bayer + src_stride_bayer, -src_stride_bayer,
272 dst_argb + dst_stride_argb, width);
273 src_bayer += src_stride_bayer * 2;
274 dst_argb += dst_stride_argb * 2;
275 }
276 if (height & 1) {
277 BayerRow0(src_bayer, src_stride_bayer, dst_argb, width);
278 }
279 return 0;
280 }
281
282 // Converts any Bayer RGB format to ARGB.
283 LIBYUV_API
284 int BayerToI420(const uint8* src_bayer, int src_stride_bayer,
285 uint8* dst_y, int dst_stride_y,
286 uint8* dst_u, int dst_stride_u,
287 uint8* dst_v, int dst_stride_v,
288 int width, int height,
289 uint32 src_fourcc_bayer) {
290 // Negative height means invert the image.
291 if (height < 0) {
292 height = -height;
293 int halfheight = (height + 1) >> 1;
294 dst_y = dst_y + (height - 1) * dst_stride_y;
295 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
296 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
297 dst_stride_y = -dst_stride_y;
298 dst_stride_u = -dst_stride_u;
299 dst_stride_v = -dst_stride_v;
300 }
301 void (*BayerRow0)(const uint8* src_bayer, int src_stride_bayer,
302 uint8* dst_argb, int pix);
303 void (*BayerRow1)(const uint8* src_bayer, int src_stride_bayer,
304 uint8* dst_argb, int pix);
305
306 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
307 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
308 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
309 ARGBToYRow_C;
310 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
311 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
312 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
313 ARGBToYRow = ARGBToYRow_Any_SSSE3;
314 if (IS_ALIGNED(width, 16)) {
315 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
316 ARGBToUVRow = ARGBToUVRow_SSSE3;
317 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
318 ARGBToYRow = ARGBToYRow_SSSE3;
319 }
320 }
321 }
322 #elif defined(HAS_ARGBTOYROW_NEON)
323 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
324 ARGBToYRow = ARGBToYRow_Any_NEON;
325 if (IS_ALIGNED(width, 8)) {
326 ARGBToYRow = ARGBToYRow_NEON;
327 }
328 if (width >= 16) {
329 ARGBToUVRow = ARGBToUVRow_Any_NEON;
330 if (IS_ALIGNED(width, 16)) {
331 ARGBToUVRow = ARGBToUVRow_NEON;
332 }
333 }
334 }
335 #endif
336
337 switch (src_fourcc_bayer) {
338 case FOURCC_BGGR:
339 BayerRow0 = BayerRowBG;
340 BayerRow1 = BayerRowGR;
341 break;
342 case FOURCC_GBRG:
343 BayerRow0 = BayerRowGB;
344 BayerRow1 = BayerRowRG;
345 break;
346 case FOURCC_GRBG:
347 BayerRow0 = BayerRowGR;
348 BayerRow1 = BayerRowBG;
349 break;
350 case FOURCC_RGGB:
351 BayerRow0 = BayerRowRG;
352 BayerRow1 = BayerRowGB;
353 break;
354 default:
355 return -1; // Bad FourCC
356 }
357
358 // Allocate 2 rows of ARGB.
359 const int kRowSize = (width * 4 + 15) & ~15;
360 align_buffer_64(row, kRowSize * 2);
361 for (int y = 0; y < height - 1; y += 2) {
362 BayerRow0(src_bayer, src_stride_bayer, row, width);
363 BayerRow1(src_bayer + src_stride_bayer, -src_stride_bayer,
364 row + kRowSize, width);
365 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
366 ARGBToYRow(row, dst_y, width);
367 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
368 src_bayer += src_stride_bayer * 2;
369 dst_y += dst_stride_y * 2;
370 dst_u += dst_stride_u;
371 dst_v += dst_stride_v;
372 }
373 if (height & 1) {
374 BayerRow0(src_bayer, src_stride_bayer, row, width);
375 ARGBToUVRow(row, 0, dst_u, dst_v, width);
376 ARGBToYRow(row, dst_y, width);
377 }
378 free_aligned_buffer_64(row);
379 return 0;
380 }
381
382 // Convert I420 to Bayer.
383 LIBYUV_API
384 int I420ToBayer(const uint8* src_y, int src_stride_y,
385 const uint8* src_u, int src_stride_u,
386 const uint8* src_v, int src_stride_v,
387 uint8* dst_bayer, int dst_stride_bayer,
388 int width, int height,
389 uint32 dst_fourcc_bayer) {
390 // Negative height means invert the image.
391 if (height < 0) {
392 height = -height;
393 int halfheight = (height + 1) >> 1;
394 src_y = src_y + (height - 1) * src_stride_y;
395 src_u = src_u + (halfheight - 1) * src_stride_u;
396 src_v = src_v + (halfheight - 1) * src_stride_v;
397 src_stride_y = -src_stride_y;
398 src_stride_u = -src_stride_u;
399 src_stride_v = -src_stride_v;
400 }
401 void (*I422ToARGBRow)(const uint8* y_buf,
402 const uint8* u_buf,
403 const uint8* v_buf,
404 uint8* rgb_buf,
405 int width) = I422ToARGBRow_C;
406 #if defined(HAS_I422TOARGBROW_SSSE3)
407 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
408 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
409 if (IS_ALIGNED(width, 8)) {
410 I422ToARGBRow = I422ToARGBRow_SSSE3;
411 }
412 }
413 #endif
414 #if defined(HAS_I422TOARGBROW_AVX2)
415 if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
416 I422ToARGBRow = I422ToARGBRow_Any_AVX2;
417 if (IS_ALIGNED(width, 16)) {
418 I422ToARGBRow = I422ToARGBRow_AVX2;
419 }
420 }
421 #endif
422 #if defined(HAS_I422TOARGBROW_NEON)
423 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
424 I422ToARGBRow = I422ToARGBRow_Any_NEON;
425 if (IS_ALIGNED(width, 8)) {
426 I422ToARGBRow = I422ToARGBRow_NEON;
427 }
428 }
429 #endif
430 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
431 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
432 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
433 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
434 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) {
435 I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
436 }
437 #endif
438
439 void (*ARGBToBayerRow)(const uint8* src_argb, uint8* dst_bayer,
440 uint32 selector, int pix) = ARGBToBayerRow_C;
441 #if defined(HAS_ARGBTOBAYERROW_SSSE3)
442 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
443 ARGBToBayerRow = ARGBToBayerRow_Any_SSSE3;
444 if (IS_ALIGNED(width, 8)) {
445 ARGBToBayerRow = ARGBToBayerRow_SSSE3;
446 }
447 }
448 #elif defined(HAS_ARGBTOBAYERROW_NEON)
449 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
450 ARGBToBayerRow = ARGBToBayerRow_Any_NEON;
451 if (IS_ALIGNED(width, 8)) {
452 ARGBToBayerRow = ARGBToBayerRow_NEON;
453 }
454 }
455 #endif
456
457 const int blue_index = 0; // Offsets for ARGB format
458 const int green_index = 1;
459 const int red_index = 2;
460 uint32 index_map[2];
461 if (MakeSelectors(blue_index, green_index, red_index,
462 dst_fourcc_bayer, index_map)) {
463 return -1; // Bad FourCC
464 }
465 // Allocate a row of ARGB.
466 align_buffer_64(row, width * 4);
467 for (int y = 0; y < height; ++y) {
468 I422ToARGBRow(src_y, src_u, src_v, row, width);
469 ARGBToBayerRow(row, dst_bayer, index_map[y & 1], width);
470 dst_bayer += dst_stride_bayer;
471 src_y += src_stride_y;
472 if (y & 1) {
473 src_u += src_stride_u;
474 src_v += src_stride_v;
475 }
476 }
477 free_aligned_buffer_64(row);
478 return 0;
479 }
480
481 #define MAKEBAYERFOURCC(BAYER) \
482 LIBYUV_API \
483 int Bayer##BAYER##ToI420(const uint8* src_bayer, int src_stride_bayer, \
484 uint8* dst_y, int dst_stride_y, \
485 uint8* dst_u, int dst_stride_u, \
486 uint8* dst_v, int dst_stride_v, \
487 int width, int height) { \
488 return BayerToI420(src_bayer, src_stride_bayer, \
489 dst_y, dst_stride_y, \
490 dst_u, dst_stride_u, \
491 dst_v, dst_stride_v, \
492 width, height, \
493 FOURCC_##BAYER); \
494 } \
495 \
496 LIBYUV_API \
497 int I420ToBayer##BAYER(const uint8* src_y, int src_stride_y, \
498 const uint8* src_u, int src_stride_u, \
499 const uint8* src_v, int src_stride_v, \
500 uint8* dst_bayer, int dst_stride_bayer, \
501 int width, int height) { \
502 return I420ToBayer(src_y, src_stride_y, \
503 src_u, src_stride_u, \
504 src_v, src_stride_v, \
505 dst_bayer, dst_stride_bayer, \
506 width, height, \
507 FOURCC_##BAYER); \
508 } \
509 \
510 LIBYUV_API \
511 int ARGBToBayer##BAYER(const uint8* src_argb, int src_stride_argb, \
512 uint8* dst_bayer, int dst_stride_bayer, \
513 int width, int height) { \
514 return ARGBToBayer(src_argb, src_stride_argb, \
515 dst_bayer, dst_stride_bayer, \
516 width, height, \
517 FOURCC_##BAYER); \
518 } \
519 \
520 LIBYUV_API \
521 int Bayer##BAYER##ToARGB(const uint8* src_bayer, int src_stride_bayer, \
522 uint8* dst_argb, int dst_stride_argb, \
523 int width, int height) { \
524 return BayerToARGB(src_bayer, src_stride_bayer, \
525 dst_argb, dst_stride_argb, \
526 width, height, \
527 FOURCC_##BAYER); \
528 }
529
530 MAKEBAYERFOURCC(BGGR)
531 MAKEBAYERFOURCC(GBRG)
532 MAKEBAYERFOURCC(GRBG)
533 MAKEBAYERFOURCC(RGGB)
534
535 #ifdef __cplusplus
536 } // extern "C"
537 } // namespace libyuv
538 #endif

mercurial