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