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