1 /*
2 V4L2 API compliance color checking tests.
3
4 Copyright (C) 2015 Hans Verkuil <hverkuil@xs4all.nl>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 */
16
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <inttypes.h>
22 #include <getopt.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <ctype.h>
27 #include <errno.h>
28 #include <sys/ioctl.h>
29 #include <sys/time.h>
30 #include <math.h>
31
32 #include <sys/cdefs.h>
33 #include "v4l2-compliance.h"
34
setupPlanes(const cv4l_fmt & fmt,uint8_t * planes[3])35 static void setupPlanes(const cv4l_fmt &fmt, uint8_t *planes[3])
36 {
37 if (fmt.g_num_planes() > 1)
38 return;
39
40 unsigned bpl = fmt.g_bytesperline();
41 unsigned h = fmt.g_height();
42 unsigned size = bpl * h;
43
44 switch (fmt.g_pixelformat()) {
45 case V4L2_PIX_FMT_YUV420:
46 case V4L2_PIX_FMT_YVU420:
47 planes[1] = planes[0] + size;
48 planes[2] = planes[1] + size / 4;
49 break;
50 case V4L2_PIX_FMT_YUV422P:
51 planes[1] = planes[0] + size;
52 planes[2] = planes[1] + size / 2;
53 break;
54 case V4L2_PIX_FMT_NV16:
55 case V4L2_PIX_FMT_NV61:
56 case V4L2_PIX_FMT_NV12:
57 case V4L2_PIX_FMT_NV21:
58 case V4L2_PIX_FMT_NV24:
59 case V4L2_PIX_FMT_NV42:
60 planes[1] = planes[0] + size;
61 break;
62 default:
63 break;
64 }
65 }
66
67 struct color {
68 double r, g, b, a;
69 };
70
71 static const double bt601[3][3] = {
72 { 1, 0, 1.4020 },
73 { 1, -0.3441, -0.7141 },
74 { 1, 1.7720, 0 },
75 };
76 static const double rec709[3][3] = {
77 { 1, 0, 1.5748 },
78 { 1, -0.1873, -0.4681 },
79 { 1, 1.8556, 0 },
80 };
81 static const double smpte240m[3][3] = {
82 { 1, 0, 1.5756 },
83 { 1, -0.2253, -0.4767 },
84 { 1, 1.8270, 0 },
85 };
86 static const double bt2020[3][3] = {
87 { 1, 0, 1.4746 },
88 { 1, -0.1646, -0.5714 },
89 { 1, 1.8814, 0 },
90 };
91
ycbcr2rgb(const double m[3][3],double y,double cb,double cr,color & c)92 static void ycbcr2rgb(const double m[3][3], double y, double cb, double cr,
93 color &c)
94 {
95 c.r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
96 c.g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
97 c.b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
98 }
99
getColor(const cv4l_fmt & fmt,uint8_t * const planes[3],unsigned y,unsigned x,color & c)100 static void getColor(const cv4l_fmt &fmt, uint8_t * const planes[3],
101 unsigned y, unsigned x, color &c)
102 {
103 unsigned bpl = fmt.g_bytesperline();
104 unsigned yeven = y & ~1;
105 unsigned xeven = x & ~1;
106 unsigned offset = bpl * y;
107 unsigned hoffset = (bpl / 2) * y;
108 unsigned voffset = bpl * (y / 2);
109 unsigned hvoffset = (bpl / 2) * (y / 2);
110 const uint8_t *p8 = planes[0] + offset;
111 uint8_t v8 = 0;
112 uint16_t v16 = 0;
113 uint32_t v32 = 0;
114
115 /* component order: ARGB or AYUV */
116 switch (fmt.g_pixelformat()) {
117 case V4L2_PIX_FMT_RGB332:
118 v8 = p8[x];
119 break;
120 case V4L2_PIX_FMT_RGB565:
121 case V4L2_PIX_FMT_RGB444:
122 case V4L2_PIX_FMT_XRGB444:
123 case V4L2_PIX_FMT_ARGB444:
124 case V4L2_PIX_FMT_RGB555:
125 case V4L2_PIX_FMT_XRGB555:
126 case V4L2_PIX_FMT_ARGB555:
127 case V4L2_PIX_FMT_YUV444:
128 case V4L2_PIX_FMT_YUV555:
129 case V4L2_PIX_FMT_YUV565:
130 v16 = p8[2 * x] + (p8[2 * x + 1] << 8);
131 break;
132 case V4L2_PIX_FMT_RGB565X:
133 case V4L2_PIX_FMT_RGB555X:
134 case V4L2_PIX_FMT_XRGB555X:
135 case V4L2_PIX_FMT_ARGB555X:
136 v16 = p8[2 * x + 1] + (p8[2 * x] << 8);
137 break;
138 case V4L2_PIX_FMT_RGBX555:
139 case V4L2_PIX_FMT_RGBA555:
140 v16 = p8[2 * x] + (p8[2 * x + 1] << 8);
141 v16 = ((v16 & 1) << 15) | (v16 >> 1);
142 break;
143 case V4L2_PIX_FMT_XBGR555:
144 case V4L2_PIX_FMT_ABGR555:
145 v16 = p8[2 * x] + (p8[2 * x + 1] << 8);
146 v16 = (v16 & 0x8000) |
147 ((v16 & 0x001f) << 10) |
148 (v16 & 0x03e0) |
149 ((v16 & 0x7c00) >> 10);
150 break;
151 case V4L2_PIX_FMT_BGRX555:
152 case V4L2_PIX_FMT_BGRA555:
153 v16 = p8[2 * x] + (p8[2 * x + 1] << 8);
154 v16 = ((v16 & 1) << 15) |
155 ((v16 & 0x003e) << 9) |
156 (v16 & 0x07c0) |
157 ((v16 & 0xf800) >> 11);
158 break;
159 case V4L2_PIX_FMT_XBGR444:
160 case V4L2_PIX_FMT_ABGR444:
161 v16 = p8[2 * x] + (p8[2 * x + 1] << 8);
162 v16 = (v16 & 0xf000) |
163 ((v16 & 0x0f00) >> 8) |
164 (v16 & 0x00f0) |
165 ((v16 & 0x000f) << 8);
166 break;
167 case V4L2_PIX_FMT_RGBX444:
168 case V4L2_PIX_FMT_RGBA444:
169 v16 = p8[2 * x] + (p8[2 * x + 1] << 8);
170 v16 = ((v16 & 0xf) << 12) | ((v16 >> 4) & 0xfff);
171 break;
172 case V4L2_PIX_FMT_BGRX444:
173 case V4L2_PIX_FMT_BGRA444:
174 v16 = p8[2 * x] + (p8[2 * x + 1] << 8);
175 v16 = ((v16 & 0x000f) << 12) |
176 ((v16 & 0x00f0) << 4) |
177 ((v16 & 0x0f00) >> 4) |
178 ((v16 & 0xf000) >> 12);
179 break;
180 case V4L2_PIX_FMT_RGB24:
181 v32 = p8[3 * x + 2] + (p8[3 * x + 1] << 8) +
182 (p8[3 * x] << 16);
183 break;
184 case V4L2_PIX_FMT_BGR24:
185 v32 = p8[3 * x] + (p8[3 * x + 1] << 8) +
186 (p8[3 * x + 2] << 16);
187 break;
188 case V4L2_PIX_FMT_RGB32:
189 case V4L2_PIX_FMT_XRGB32:
190 case V4L2_PIX_FMT_ARGB32:
191 case V4L2_PIX_FMT_YUV32:
192 case V4L2_PIX_FMT_AYUV32:
193 case V4L2_PIX_FMT_XYUV32:
194 v32 = p8[4 * x + 3] + (p8[4 * x + 2] << 8) +
195 (p8[4 * x + 1] << 16) + (p8[4 * x] << 24);
196 break;
197 case V4L2_PIX_FMT_BGR666:
198 v32 = ((p8[4 * x + 2] & 0xc0) << 10) + ((p8[4 * x + 1] & 0xf) << 18) +
199 ((p8[4 * x + 1] & 0xf0) << 4) +
200 ((p8[4 * x] & 0x3) << 12) + ((p8[4 * x] & 0xfc) >> 2);
201 break;
202 case V4L2_PIX_FMT_BGR32:
203 case V4L2_PIX_FMT_XBGR32:
204 case V4L2_PIX_FMT_ABGR32:
205 case V4L2_PIX_FMT_VUYA32:
206 case V4L2_PIX_FMT_VUYX32:
207 v32 = p8[4 * x] + (p8[4 * x + 1] << 8) +
208 (p8[4 * x + 2] << 16) + (p8[4 * x + 3] << 24);
209 break;
210 case V4L2_PIX_FMT_RGBX32:
211 case V4L2_PIX_FMT_RGBA32:
212 v32 = p8[4 * x + 2] + (p8[4 * x + 1] << 8) +
213 (p8[4 * x] << 16) + (p8[4 * x + 3] << 24);
214 break;
215 case V4L2_PIX_FMT_BGRX32:
216 case V4L2_PIX_FMT_BGRA32:
217 v32 = p8[4 * x + 1] + (p8[4 * x + 2] << 8) +
218 (p8[4 * x + 3] << 16) + (p8[4 * x] << 24);
219 break;
220 case V4L2_PIX_FMT_SBGGR8:
221 p8 = planes[0] + bpl * yeven + xeven;
222 v32 = p8[0] + (p8[(y & 1) * bpl + 1 - (y & 1)] << 8) + (p8[bpl + 1] << 16);
223 break;
224 case V4L2_PIX_FMT_SGBRG8:
225 p8 = planes[0] + bpl * yeven + xeven;
226 v32 = (p8[bpl] << 16) + (p8[(y & 1) * bpl + (y & 1)] << 8) + p8[1];
227 break;
228 case V4L2_PIX_FMT_SGRBG8:
229 p8 = planes[0] + bpl * yeven + xeven;
230 v32 = p8[bpl] + (p8[(y & 1) * bpl + (y & 1)] << 8) + (p8[1] << 16);
231 break;
232 case V4L2_PIX_FMT_SRGGB8:
233 p8 = planes[0] + bpl * yeven + xeven;
234 v32 = (p8[0] << 16) + (p8[(y & 1) * bpl + 1 - (y & 1)] << 8) + p8[bpl + 1];
235 break;
236 case V4L2_PIX_FMT_YUYV:
237 v32 = (p8[2 * x] << 16) + (p8[2 * xeven + 1] << 8) + p8[2 * xeven + 3];
238 break;
239 case V4L2_PIX_FMT_UYVY:
240 v32 = (p8[2 * x + 1] << 16) + (p8[2 * xeven] << 8) + p8[2 * xeven + 2];
241 break;
242 case V4L2_PIX_FMT_YVYU:
243 v32 = (p8[2 * x] << 16) + (p8[2 * xeven + 3] << 8) + p8[2 * xeven + 1];
244 break;
245 case V4L2_PIX_FMT_VYUY:
246 v32 = (p8[2 * x + 1] << 16) + (p8[2 * xeven + 2] << 8) + p8[2 * xeven];
247 break;
248 case V4L2_PIX_FMT_NV12:
249 case V4L2_PIX_FMT_NV12M:
250 v32 = (p8[x] << 16) +
251 (planes[1][voffset + xeven] << 8) +
252 planes[1][voffset + xeven + 1];
253 break;
254 case V4L2_PIX_FMT_NV21:
255 case V4L2_PIX_FMT_NV21M:
256 v32 = (p8[x] << 16) +
257 (planes[1][voffset + xeven + 1] << 8) +
258 planes[1][voffset + xeven];
259 break;
260 case V4L2_PIX_FMT_NV16:
261 case V4L2_PIX_FMT_NV16M:
262 v32 = (p8[x] << 16) +
263 (planes[1][offset + xeven] << 8) +
264 planes[1][offset + xeven + 1];
265 break;
266 case V4L2_PIX_FMT_NV61:
267 case V4L2_PIX_FMT_NV61M:
268 v32 = (p8[x] << 16) +
269 (planes[1][offset + xeven + 1] << 8) +
270 planes[1][offset + xeven];
271 break;
272 case V4L2_PIX_FMT_YVU422M:
273 v32 = (p8[x] << 16) +
274 (planes[2][hoffset + x / 2] << 8) +
275 planes[1][hoffset + x / 2];
276 break;
277 case V4L2_PIX_FMT_YUV422M:
278 case V4L2_PIX_FMT_YUV422P:
279 v32 = (p8[x] << 16) +
280 (planes[1][hoffset + x / 2] << 8) +
281 planes[2][hoffset + x / 2];
282 break;
283 case V4L2_PIX_FMT_YUV444M:
284 v32 = (p8[x] << 16) + (planes[1][offset + x] << 8) +
285 planes[2][offset + x];
286 break;
287 case V4L2_PIX_FMT_YVU444M:
288 v32 = (p8[x] << 16) + (planes[2][offset + x] << 8) +
289 planes[1][offset + x];
290 break;
291 case V4L2_PIX_FMT_YUV420:
292 case V4L2_PIX_FMT_YUV420M:
293 v32 = (p8[x] << 16) +
294 (planes[1][hvoffset + x / 2] << 8) +
295 planes[2][hvoffset + x / 2];
296 break;
297 case V4L2_PIX_FMT_YVU420:
298 case V4L2_PIX_FMT_YVU420M:
299 v32 = (p8[x] << 16) +
300 (planes[2][hvoffset + x / 2] << 8) +
301 planes[1][hvoffset + x / 2];
302 break;
303 case V4L2_PIX_FMT_NV24:
304 v32 = (p8[x] << 16) +
305 (planes[1][bpl * 2 * y + 2 * x] << 8) +
306 planes[1][bpl * 2 * y + 2 * x + 1];
307 break;
308 case V4L2_PIX_FMT_NV42:
309 v32 = (p8[x] << 16) +
310 (planes[1][bpl * 2 * y + 2 * x + 1] << 8) +
311 planes[1][bpl * 2 * y + 2 * x];
312 break;
313 }
314
315 switch (fmt.g_pixelformat()) {
316 case V4L2_PIX_FMT_RGB332:
317 c.r = (v8 >> 5) / 7.0;
318 c.g = ((v8 >> 2) & 7) / 7.0;
319 c.b = (v8 & 3) / 3.0;
320 break;
321 case V4L2_PIX_FMT_RGB565:
322 case V4L2_PIX_FMT_RGB565X:
323 case V4L2_PIX_FMT_YUV565:
324 c.r = (v16 >> 11) / 31.0;
325 c.g = ((v16 >> 5) & 0x3f) / 63.0;
326 c.b = (v16 & 0x1f) / 31.0;
327 break;
328 case V4L2_PIX_FMT_ARGB444:
329 case V4L2_PIX_FMT_ABGR444:
330 case V4L2_PIX_FMT_RGBA444:
331 case V4L2_PIX_FMT_BGRA444:
332 c.a = (v16 >> 12) / 15.0;
333 ;
334 case V4L2_PIX_FMT_RGB444:
335 case V4L2_PIX_FMT_XRGB444:
336 case V4L2_PIX_FMT_XBGR444:
337 case V4L2_PIX_FMT_RGBX444:
338 case V4L2_PIX_FMT_BGRX444:
339 case V4L2_PIX_FMT_YUV444:
340 c.r = ((v16 >> 8) & 0xf) / 15.0;
341 c.g = ((v16 >> 4) & 0xf) / 15.0;
342 c.b = (v16 & 0xf) / 15.0;
343 break;
344 case V4L2_PIX_FMT_ARGB555:
345 case V4L2_PIX_FMT_ARGB555X:
346 case V4L2_PIX_FMT_RGBA555:
347 case V4L2_PIX_FMT_ABGR555:
348 case V4L2_PIX_FMT_BGRA555:
349 c.a = v16 >> 15;
350 ;
351 case V4L2_PIX_FMT_YUV555:
352 case V4L2_PIX_FMT_RGB555:
353 case V4L2_PIX_FMT_XRGB555:
354 case V4L2_PIX_FMT_RGB555X:
355 case V4L2_PIX_FMT_XRGB555X:
356 case V4L2_PIX_FMT_RGBX555:
357 case V4L2_PIX_FMT_XBGR555:
358 case V4L2_PIX_FMT_BGRX555:
359 c.r = ((v16 >> 10) & 0x1f) / 31.0;
360 c.g = ((v16 >> 5) & 0x1f) / 31.0;
361 c.b = (v16 & 0x1f) / 31.0;
362 break;
363 case V4L2_PIX_FMT_YUYV:
364 case V4L2_PIX_FMT_UYVY:
365 case V4L2_PIX_FMT_YVYU:
366 case V4L2_PIX_FMT_VYUY:
367 c.r = (v32 >> 16) / 255.0;
368 c.g = ((v32 >> 8) & 0xff) / 255.0;
369 c.b = (v32 & 0xff) / 255.0;
370 break;
371 case V4L2_PIX_FMT_BGR666:
372 c.r = ((v32 >> 16) & 0x3f) / 63.0;
373 c.g = ((v32 >> 8) & 0x3f) / 63.0;
374 c.b = (v32 & 0x3f) / 63.0;
375 break;
376 case V4L2_PIX_FMT_ARGB32:
377 case V4L2_PIX_FMT_ABGR32:
378 case V4L2_PIX_FMT_RGBA32:
379 case V4L2_PIX_FMT_BGRA32:
380 c.a = ((v32 >> 24) & 0xff) / 255.0;
381 ;
382 default:
383 c.r = ((v32 >> 16) & 0xff) / 255.0;
384 c.g = ((v32 >> 8) & 0xff) / 255.0;
385 c.b = (v32 & 0xff) / 255.0;
386 break;
387 }
388
389 switch (fmt.g_pixelformat()) {
390 case V4L2_PIX_FMT_YUV444:
391 case V4L2_PIX_FMT_YUV555:
392 case V4L2_PIX_FMT_YUV565:
393 case V4L2_PIX_FMT_YUV32:
394 case V4L2_PIX_FMT_AYUV32:
395 case V4L2_PIX_FMT_XYUV32:
396 case V4L2_PIX_FMT_VUYA32:
397 case V4L2_PIX_FMT_VUYX32:
398 case V4L2_PIX_FMT_YUYV:
399 case V4L2_PIX_FMT_UYVY:
400 case V4L2_PIX_FMT_YVYU:
401 case V4L2_PIX_FMT_VYUY:
402 case V4L2_PIX_FMT_NV12:
403 case V4L2_PIX_FMT_NV12M:
404 case V4L2_PIX_FMT_NV21:
405 case V4L2_PIX_FMT_NV21M:
406 case V4L2_PIX_FMT_NV16:
407 case V4L2_PIX_FMT_NV16M:
408 case V4L2_PIX_FMT_NV61:
409 case V4L2_PIX_FMT_NV61M:
410 case V4L2_PIX_FMT_YUV422M:
411 case V4L2_PIX_FMT_YVU422M:
412 case V4L2_PIX_FMT_YUV422P:
413 case V4L2_PIX_FMT_YUV420:
414 case V4L2_PIX_FMT_YUV420M:
415 case V4L2_PIX_FMT_YVU420:
416 case V4L2_PIX_FMT_YVU420M:
417 case V4L2_PIX_FMT_NV24:
418 case V4L2_PIX_FMT_NV42:
419 case V4L2_PIX_FMT_YUV444M:
420 case V4L2_PIX_FMT_YVU444M:
421 break;
422 default:
423 if (fmt.g_quantization() == V4L2_QUANTIZATION_LIM_RANGE ||
424 (fmt.g_colorspace() == V4L2_YCBCR_ENC_BT2020 &&
425 fmt.g_quantization() == V4L2_QUANTIZATION_DEFAULT)) {
426 c.r = (c.r - 16.0 / 255.0) * 255.0 / 219.0;
427 c.g = (c.g - 16.0 / 255.0) * 255.0 / 219.0;
428 c.b = (c.b - 16.0 / 255.0) * 255.0 / 219.0;
429 }
430
431 return;
432 }
433
434 double Y = c.r;
435 double cb = c.g - 0.5;
436 double cr = c.b - 0.5;
437
438 if (fmt.g_quantization() != V4L2_QUANTIZATION_FULL_RANGE) {
439 Y = (Y - 16.0 / 255.0) * 255.0 / 219.0;
440 cb *= 255.0 / 224.0;
441 cr *= 255.0 / 224.0;
442 }
443
444 switch (fmt.g_ycbcr_enc()) {
445 case V4L2_YCBCR_ENC_XV601:
446 Y = (Y - 16.0 / 255.0) * 255.0 / 219.0;
447 cb *= 255.0 / 224.0;
448 cr *= 255.0 / 224.0;
449 ;
450 case V4L2_YCBCR_ENC_601:
451 default:
452 ycbcr2rgb(bt601, Y, cb, cr, c);
453 break;
454 case V4L2_YCBCR_ENC_XV709:
455 Y = (Y - 16.0 / 255.0) * 255.0 / 219.0;
456 cb *= 255.0 / 224.0;
457 cr *= 255.0 / 224.0;
458 ;
459 case V4L2_YCBCR_ENC_709:
460 ycbcr2rgb(rec709, Y, cb, cr, c);
461 break;
462 case V4L2_YCBCR_ENC_SMPTE240M:
463 ycbcr2rgb(smpte240m, Y, cb, cr, c);
464 break;
465 /*
466 * For now just interpret BT2020_CONST_LUM as BT2020.
467 * It's pretty complex to handle this correctly, so
468 * for now approximate it with BT2020.
469 */
470 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
471 case V4L2_YCBCR_ENC_BT2020:
472 ycbcr2rgb(bt2020, Y, cb, cr, c);
473 break;
474 }
475 }
476
477 static const char * const colors[] = {
478 "red",
479 "green",
480 "blue"
481 };
482
testColorsFmt(struct node * node,unsigned component,unsigned skip,unsigned perc)483 static int testColorsFmt(struct node *node, unsigned component,
484 unsigned skip, unsigned perc)
485 {
486 cv4l_queue q;
487 cv4l_fmt fmt;
488 uint8_t *planes[3] = { 0, 0, 0 };
489 skip++;
490
491 node->g_fmt(fmt);
492
493 if (node->g_caps() & V4L2_CAP_STREAMING) {
494 cv4l_buffer buf;
495
496 q.init(node->g_type(), V4L2_MEMORY_MMAP);
497 buf.init(q);
498 fail_on_test(q.reqbufs(node, 3));
499 fail_on_test(q.obtain_bufs(node));
500 fail_on_test(q.queue_all(node));
501 fail_on_test(node->streamon());
502
503 while (node->dqbuf(buf) == 0) {
504 if (--skip == 0)
505 break;
506 fail_on_test(node->qbuf(buf));
507 }
508 fail_on_test(skip);
509 for (unsigned i = 0; i < fmt.g_num_planes(); i++)
510 planes[i] = static_cast<uint8_t *>(q.g_dataptr(buf.g_index(), i));
511
512 } else {
513 fail_on_test(!(node->g_caps() & V4L2_CAP_READWRITE));
514
515 int size = fmt.g_sizeimage();
516 void *tmp = malloc(size);
517
518 for (unsigned i = 0; i < skip; i++) {
519 int ret;
520
521 ret = node->read(tmp, size);
522 fail_on_test(ret != size);
523 }
524 planes[0] = static_cast<uint8_t *>(tmp);
525 }
526
527 setupPlanes(fmt, planes);
528
529 if (fmt.g_ycbcr_enc() == V4L2_YCBCR_ENC_DEFAULT) {
530 switch (fmt.g_colorspace()) {
531 case V4L2_COLORSPACE_REC709:
532 fmt.s_ycbcr_enc(V4L2_YCBCR_ENC_709);
533 break;
534 case V4L2_COLORSPACE_SMPTE240M:
535 fmt.s_ycbcr_enc(V4L2_YCBCR_ENC_SMPTE240M);
536 break;
537 case V4L2_COLORSPACE_BT2020:
538 fmt.s_ycbcr_enc(V4L2_YCBCR_ENC_BT2020);
539 break;
540 default:
541 fmt.s_ycbcr_enc(V4L2_YCBCR_ENC_601);
542 break;
543 }
544 }
545
546 unsigned h = fmt.g_height();
547 unsigned w = fmt.g_width();
548 unsigned color_cnt[3] = { 0, 0, 0 };
549 v4l2_std_id std;
550 bool is_50hz = false;
551 unsigned total;
552
553 if ((node->cur_io_caps & V4L2_IN_CAP_STD) &&
554 !node->g_std(std) && (std & V4L2_STD_625_50))
555 is_50hz = true;
556
557 total = w * h - (is_50hz ? w / 2 : 0);
558
559 for (unsigned y = 0; y < h; y++) {
560 /*
561 * 50 Hz (PAL/SECAM) formats have a garbage first half-line,
562 * so skip that.
563 */
564 for (unsigned x = (y == 0 && is_50hz) ? w / 2 : 0; x < w; x++) {
565 color c = { 0, 0, 0, 0 };
566
567 getColor(fmt, planes, y, x, c);
568 if (c.r > c.b && c.r > c.g)
569 color_cnt[0]++;
570 else if (c.g > c.r && c.g > c.b)
571 color_cnt[1]++;
572 else
573 color_cnt[2]++;
574 }
575 }
576 if (node->g_caps() & V4L2_CAP_STREAMING)
577 q.free(node);
578 else
579 free(planes[0]);
580
581 if (color_cnt[component] < total * perc / 100) {
582 return fail("red: %u%% green: %u%% blue: %u%% expected: %s >= %u%%\n",
583 color_cnt[0] * 100 / total,
584 color_cnt[1] * 100 / total,
585 color_cnt[2] * 100 / total,
586 colors[component], perc);
587 }
588 return 0;
589 }
590
testColorsAllFormats(struct node * node,unsigned component,unsigned skip,unsigned perc)591 int testColorsAllFormats(struct node *node, unsigned component,
592 unsigned skip, unsigned perc)
593 {
594 v4l2_fmtdesc fmtdesc;
595
596 if (node->enum_fmt(fmtdesc, true))
597 return 0;
598 do {
599 if (fmtdesc.flags & V4L2_FMT_FLAG_COMPRESSED)
600 continue;
601 switch (fmtdesc.pixelformat) {
602 case V4L2_PIX_FMT_GREY:
603 case V4L2_PIX_FMT_Y4:
604 case V4L2_PIX_FMT_Y6:
605 case V4L2_PIX_FMT_Y10:
606 case V4L2_PIX_FMT_Y12:
607 case V4L2_PIX_FMT_Y16:
608 case V4L2_PIX_FMT_Y16_BE:
609 case V4L2_PIX_FMT_Y10BPACK:
610 case V4L2_PIX_FMT_PAL8:
611 case V4L2_PIX_FMT_UV8:
612 continue;
613 }
614
615 restoreFormat(node);
616
617 cv4l_fmt fmt;
618 node->g_fmt(fmt);
619 fmt.s_pixelformat(fmtdesc.pixelformat);
620 node->s_fmt(fmt);
621 printf("\ttest %u%% %s for format %s: %s\n",
622 perc, colors[component],
623 fcc2s(fmt.g_pixelformat()).c_str(),
624 ok(testColorsFmt(node, component, skip, perc)));
625 } while (!node->enum_fmt(fmtdesc));
626 printf("\n");
627 return 0;
628 }
629