1 // SPDX-License-Identifier: LGPL-2.1-only
2 /*
3  * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
4  */
5 
6 #include <unistd.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <inttypes.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <ctype.h>
15 #include <errno.h>
16 #include <sys/ioctl.h>
17 #include <sys/time.h>
18 #include <sys/types.h>
19 #include <dirent.h>
20 
21 #include <v4l2-info.h>
22 
23 #include <fstream>
24 
num2s(unsigned num,bool is_hex=true)25 static std::string num2s(unsigned num, bool is_hex = true)
26 {
27 	char buf[16];
28 
29 	if (is_hex)
30 		sprintf(buf, "0x%08x", num);
31 	else
32 		sprintf(buf, "%u", num);
33 	return buf;
34 }
35 
36 typedef struct {
37 	unsigned flag;
38 	const char *str;
39 } flag_def;
40 
flags2s(unsigned val,const flag_def * def)41 static std::string flags2s(unsigned val, const flag_def *def)
42 {
43 	std::string s;
44 
45 	while (def->flag) {
46 		if (val & def->flag) {
47 			if (s.length()) s += ", ";
48 			s += def->str;
49 			val &= ~def->flag;
50 		}
51 		def++;
52 	}
53 	if (val) {
54 		if (s.length()) s += ", ";
55 		s += num2s(val);
56 	}
57 	return s;
58 }
59 
cap2s(unsigned cap)60 static std::string cap2s(unsigned cap)
61 {
62 	std::string s;
63 
64 	if (cap & V4L2_CAP_VIDEO_CAPTURE)
65 		s += "\t\tVideo Capture\n";
66 	if (cap & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
67 		s += "\t\tVideo Capture Multiplanar\n";
68 	if (cap & V4L2_CAP_VIDEO_OUTPUT)
69 		s += "\t\tVideo Output\n";
70 	if (cap & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
71 		s += "\t\tVideo Output Multiplanar\n";
72 	if (cap & V4L2_CAP_VIDEO_M2M)
73 		s += "\t\tVideo Memory-to-Memory\n";
74 	if (cap & V4L2_CAP_VIDEO_M2M_MPLANE)
75 		s += "\t\tVideo Memory-to-Memory Multiplanar\n";
76 	if (cap & V4L2_CAP_VIDEO_OVERLAY)
77 		s += "\t\tVideo Overlay\n";
78 	if (cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
79 		s += "\t\tVideo Output Overlay\n";
80 	if (cap & V4L2_CAP_VBI_CAPTURE)
81 		s += "\t\tVBI Capture\n";
82 	if (cap & V4L2_CAP_VBI_OUTPUT)
83 		s += "\t\tVBI Output\n";
84 	if (cap & V4L2_CAP_SLICED_VBI_CAPTURE)
85 		s += "\t\tSliced VBI Capture\n";
86 	if (cap & V4L2_CAP_SLICED_VBI_OUTPUT)
87 		s += "\t\tSliced VBI Output\n";
88 	if (cap & V4L2_CAP_RDS_CAPTURE)
89 		s += "\t\tRDS Capture\n";
90 	if (cap & V4L2_CAP_RDS_OUTPUT)
91 		s += "\t\tRDS Output\n";
92 	if (cap & V4L2_CAP_SDR_CAPTURE)
93 		s += "\t\tSDR Capture\n";
94 	if (cap & V4L2_CAP_SDR_OUTPUT)
95 		s += "\t\tSDR Output\n";
96 	if (cap & V4L2_CAP_META_CAPTURE)
97 		s += "\t\tMetadata Capture\n";
98 	if (cap & V4L2_CAP_META_OUTPUT)
99 		s += "\t\tMetadata Output\n";
100 	if (cap & V4L2_CAP_TUNER)
101 		s += "\t\tTuner\n";
102 	if (cap & V4L2_CAP_TOUCH)
103 		s += "\t\tTouch Device\n";
104 	if (cap & V4L2_CAP_HW_FREQ_SEEK)
105 		s += "\t\tHW Frequency Seek\n";
106 	if (cap & V4L2_CAP_MODULATOR)
107 		s += "\t\tModulator\n";
108 	if (cap & V4L2_CAP_AUDIO)
109 		s += "\t\tAudio\n";
110 	if (cap & V4L2_CAP_RADIO)
111 		s += "\t\tRadio\n";
112 	if (cap & V4L2_CAP_READWRITE)
113 		s += "\t\tRead/Write\n";
114 	if (cap & V4L2_CAP_ASYNCIO)
115 		s += "\t\tAsync I/O\n";
116 	if (cap & V4L2_CAP_STREAMING)
117 		s += "\t\tStreaming\n";
118 	if (cap & V4L2_CAP_EXT_PIX_FORMAT)
119 		s += "\t\tExtended Pix Format\n";
120 	if (cap & V4L2_CAP_DEVICE_CAPS)
121 		s += "\t\tDevice Capabilities\n";
122 	return s;
123 }
124 
v4l2_info_capability(const v4l2_capability & vcap)125 void v4l2_info_capability(const v4l2_capability &vcap)
126 {
127 	printf("\tDriver name      : %s\n", vcap.driver);
128 	printf("\tCard type        : %s\n", vcap.card);
129 	printf("\tBus info         : %s\n", vcap.bus_info);
130 	printf("\tDriver version   : %d.%d.%d\n",
131 	       vcap.version >> 16,
132 	       (vcap.version >> 8) & 0xff,
133 	       vcap.version & 0xff);
134 	printf("\tCapabilities     : 0x%08x\n", vcap.capabilities);
135 	printf("%s", cap2s(vcap.capabilities).c_str());
136 	if (vcap.capabilities & V4L2_CAP_DEVICE_CAPS) {
137 		printf("\tDevice Caps      : 0x%08x\n", vcap.device_caps);
138 		printf("%s", cap2s(vcap.device_caps).c_str());
139 	}
140 }
141 
fcc2s(uint32_t val)142 std::string fcc2s(uint32_t val)
143 {
144 	std::string s;
145 
146 	s += val & 0x7f;
147 	s += (val >> 8) & 0x7f;
148 	s += (val >> 16) & 0x7f;
149 	s += (val >> 24) & 0x7f;
150 	if (val & (1U << 31))
151 		s += "-BE";
152 	return s;
153 }
154 
pixfmt2s(uint32_t format)155 std::string pixfmt2s(uint32_t format)
156 {
157 	switch (format) {
158 #include "v4l2-pix-formats.h"
159 	default:
160 		return std::string("Unknown (") + num2s(format) + ")";
161 	}
162 }
163 
buftype2s(int type)164 std::string buftype2s(int type)
165 {
166 	switch (type) {
167 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
168 		return "Video Capture";
169 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
170 		return "Video Capture Multiplanar";
171 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
172 		return "Video Output";
173 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
174 		return "Video Output Multiplanar";
175 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
176 		return "Video Overlay";
177 	case V4L2_BUF_TYPE_VBI_CAPTURE:
178 		return "VBI Capture";
179 	case V4L2_BUF_TYPE_VBI_OUTPUT:
180 		return "VBI Output";
181 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
182 		return "Sliced VBI Capture";
183 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
184 		return "Sliced VBI Output";
185 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
186 		return "Video Output Overlay";
187 	case V4L2_BUF_TYPE_SDR_CAPTURE:
188 		return "SDR Capture";
189 	case V4L2_BUF_TYPE_SDR_OUTPUT:
190 		return "SDR Output";
191 	case V4L2_BUF_TYPE_META_CAPTURE:
192 		return "Metadata Capture";
193 	case V4L2_BUF_TYPE_META_OUTPUT:
194 		return "Metadata Output";
195 	case V4L2_BUF_TYPE_PRIVATE:
196 		return "Private";
197 	default:
198 		return std::string("Unknown (") + num2s(type) + ")";
199 	}
200 }
201 
202 static const flag_def bufcap_def[] = {
203 	{ V4L2_BUF_CAP_SUPPORTS_MMAP, "mmap" },
204 	{ V4L2_BUF_CAP_SUPPORTS_USERPTR, "userptr" },
205 	{ V4L2_BUF_CAP_SUPPORTS_DMABUF, "dmabuf" },
206 	{ V4L2_BUF_CAP_SUPPORTS_REQUESTS, "requests" },
207 	{ V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS, "orphaned-bufs" },
208 	{ V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF, "m2m-hold-capture-buf" },
209 	{ 0, NULL }
210 };
211 
bufcap2s(uint32_t caps)212 std::string bufcap2s(uint32_t caps)
213 {
214 	return flags2s(caps, bufcap_def);
215 }
216 
field2s(int val)217 std::string field2s(int val)
218 {
219 	switch (val) {
220 	case V4L2_FIELD_ANY:
221 		return "Any";
222 	case V4L2_FIELD_NONE:
223 		return "None";
224 	case V4L2_FIELD_TOP:
225 		return "Top";
226 	case V4L2_FIELD_BOTTOM:
227 		return "Bottom";
228 	case V4L2_FIELD_INTERLACED:
229 		return "Interlaced";
230 	case V4L2_FIELD_SEQ_TB:
231 		return "Sequential Top-Bottom";
232 	case V4L2_FIELD_SEQ_BT:
233 		return "Sequential Bottom-Top";
234 	case V4L2_FIELD_ALTERNATE:
235 		return "Alternating";
236 	case V4L2_FIELD_INTERLACED_TB:
237 		return "Interlaced Top-Bottom";
238 	case V4L2_FIELD_INTERLACED_BT:
239 		return "Interlaced Bottom-Top";
240 	default:
241 		return "Unknown (" + num2s(val) + ")";
242 	}
243 }
244 
colorspace2s(int val)245 std::string colorspace2s(int val)
246 {
247 	switch (val) {
248 	case V4L2_COLORSPACE_DEFAULT:
249 		return "Default";
250 	case V4L2_COLORSPACE_SMPTE170M:
251 		return "SMPTE 170M";
252 	case V4L2_COLORSPACE_SMPTE240M:
253 		return "SMPTE 240M";
254 	case V4L2_COLORSPACE_REC709:
255 		return "Rec. 709";
256 	case V4L2_COLORSPACE_BT878:
257 		return "Broken Bt878";
258 	case V4L2_COLORSPACE_470_SYSTEM_M:
259 		return "470 System M";
260 	case V4L2_COLORSPACE_470_SYSTEM_BG:
261 		return "470 System BG";
262 	case V4L2_COLORSPACE_JPEG:
263 		return "JPEG";
264 	case V4L2_COLORSPACE_SRGB:
265 		return "sRGB";
266 	case V4L2_COLORSPACE_OPRGB:
267 		return "opRGB";
268 	case V4L2_COLORSPACE_DCI_P3:
269 		return "DCI-P3";
270 	case V4L2_COLORSPACE_BT2020:
271 		return "BT.2020";
272 	case V4L2_COLORSPACE_RAW:
273 		return "Raw";
274 	default:
275 		return "Unknown (" + num2s(val) + ")";
276 	}
277 }
278 
xfer_func2s(int val)279 std::string xfer_func2s(int val)
280 {
281 	switch (val) {
282 	case V4L2_XFER_FUNC_DEFAULT:
283 		return "Default";
284 	case V4L2_XFER_FUNC_709:
285 		return "Rec. 709";
286 	case V4L2_XFER_FUNC_SRGB:
287 		return "sRGB";
288 	case V4L2_XFER_FUNC_OPRGB:
289 		return "opRGB";
290 	case V4L2_XFER_FUNC_DCI_P3:
291 		return "DCI-P3";
292 	case V4L2_XFER_FUNC_SMPTE2084:
293 		return "SMPTE 2084";
294 	case V4L2_XFER_FUNC_SMPTE240M:
295 		return "SMPTE 240M";
296 	case V4L2_XFER_FUNC_NONE:
297 		return "None";
298 	default:
299 		return "Unknown (" + num2s(val) + ")";
300 	}
301 }
302 
ycbcr_enc2s(int val)303 std::string ycbcr_enc2s(int val)
304 {
305 	switch (val) {
306 	case V4L2_YCBCR_ENC_DEFAULT:
307 		return "Default";
308 	case V4L2_YCBCR_ENC_601:
309 		return "ITU-R 601";
310 	case V4L2_YCBCR_ENC_709:
311 		return "Rec. 709";
312 	case V4L2_YCBCR_ENC_XV601:
313 		return "xvYCC 601";
314 	case V4L2_YCBCR_ENC_XV709:
315 		return "xvYCC 709";
316 	case V4L2_YCBCR_ENC_BT2020:
317 		return "BT.2020";
318 	case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
319 		return "BT.2020 Constant Luminance";
320 	case V4L2_YCBCR_ENC_SMPTE240M:
321 		return "SMPTE 240M";
322 	case V4L2_HSV_ENC_180:
323 		return "HSV with Hue 0-179";
324 	case V4L2_HSV_ENC_256:
325 		return "HSV with Hue 0-255";
326 	default:
327 		return "Unknown (" + num2s(val) + ")";
328 	}
329 }
330 
quantization2s(int val)331 std::string quantization2s(int val)
332 {
333 	switch (val) {
334 	case V4L2_QUANTIZATION_DEFAULT:
335 		return "Default";
336 	case V4L2_QUANTIZATION_FULL_RANGE:
337 		return "Full Range";
338 	case V4L2_QUANTIZATION_LIM_RANGE:
339 		return "Limited Range";
340 	default:
341 		return "Unknown (" + num2s(val) + ")";
342 	}
343 }
344 
345 static const flag_def pixflags_def[] = {
346 	{ V4L2_PIX_FMT_FLAG_PREMUL_ALPHA,  "premultiplied-alpha" },
347 	{ 0, NULL }
348 };
349 
pixflags2s(unsigned flags)350 std::string pixflags2s(unsigned flags)
351 {
352 	return flags2s(flags, pixflags_def);
353 }
354 
355 static const flag_def service_def[] = {
356 	{ V4L2_SLICED_TELETEXT_B,  "teletext" },
357 	{ V4L2_SLICED_VPS,         "vps" },
358 	{ V4L2_SLICED_CAPTION_525, "cc" },
359 	{ V4L2_SLICED_WSS_625,     "wss" },
360 	{ 0, NULL }
361 };
362 
service2s(unsigned service)363 std::string service2s(unsigned service)
364 {
365 	return flags2s(service, service_def);
366 }
367 
368 static const flag_def fmtdesc_def[] = {
369 	{ V4L2_FMT_FLAG_COMPRESSED, "compressed" },
370 	{ V4L2_FMT_FLAG_EMULATED, "emulated" },
371 	{ V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, "continuous-bytestream" },
372 	{ V4L2_FMT_FLAG_DYN_RESOLUTION, "dyn-resolution" },
373 	{ 0, NULL }
374 };
375 
fmtdesc2s(unsigned flags)376 std::string fmtdesc2s(unsigned flags)
377 {
378 	return flags2s(flags, fmtdesc_def);
379 }
380 
381 static const flag_def selection_targets_def[] = {
382 	{ V4L2_SEL_TGT_CROP_ACTIVE, "crop" },
383 	{ V4L2_SEL_TGT_CROP_DEFAULT, "crop_default" },
384 	{ V4L2_SEL_TGT_CROP_BOUNDS, "crop_bounds" },
385 	{ V4L2_SEL_TGT_COMPOSE_ACTIVE, "compose" },
386 	{ V4L2_SEL_TGT_COMPOSE_DEFAULT, "compose_default" },
387 	{ V4L2_SEL_TGT_COMPOSE_BOUNDS, "compose_bounds" },
388 	{ V4L2_SEL_TGT_COMPOSE_PADDED, "compose_padded" },
389 	{ V4L2_SEL_TGT_NATIVE_SIZE, "native_size" },
390 	{ 0, NULL }
391 };
392 
valid_seltarget_at_idx(unsigned i)393 bool valid_seltarget_at_idx(unsigned i)
394 {
395 	return i < sizeof(selection_targets_def) / sizeof(selection_targets_def[0]) - 1;
396 }
397 
seltarget_at_idx(unsigned i)398 unsigned seltarget_at_idx(unsigned i)
399 {
400 	if (valid_seltarget_at_idx(i))
401 		return selection_targets_def[i].flag;
402 	return 0;
403 }
404 
seltarget2s(uint32_t target)405 std::string seltarget2s(uint32_t target)
406 {
407 	int i = 0;
408 
409 	while (selection_targets_def[i].str != NULL) {
410 		if (selection_targets_def[i].flag == target)
411 			return selection_targets_def[i].str;
412 		i++;
413 	}
414 	return std::string("Unknown (") + num2s(target) + ")";
415 }
416 
417 const flag_def selection_flags_def[] = {
418 	{ V4L2_SEL_FLAG_GE, "ge" },
419 	{ V4L2_SEL_FLAG_LE, "le" },
420 	{ V4L2_SEL_FLAG_KEEP_CONFIG, "keep-config" },
421 	{ 0, NULL }
422 };
423 
selflags2s(uint32_t flags)424 std::string selflags2s(uint32_t flags)
425 {
426 	return flags2s(flags, selection_flags_def);
427 }
428 
429 static const char *std_pal[] = {
430 	"B", "B1", "G", "H", "I", "D", "D1", "K",
431 	"M", "N", "Nc", "60",
432 	NULL
433 };
434 static const char *std_ntsc[] = {
435 	"M", "M-JP", "443", "M-KR",
436 	NULL
437 };
438 static const char *std_secam[] = {
439 	"B", "D", "G", "H", "K", "K1", "L", "Lc",
440 	NULL
441 };
442 static const char *std_atsc[] = {
443 	"8-VSB", "16-VSB",
444 	NULL
445 };
446 
partstd2s(const char * prefix,const char * stds[],unsigned long long std)447 static std::string partstd2s(const char *prefix, const char *stds[], unsigned long long std)
448 {
449 	std::string s = std::string(prefix) + "-";
450 	int first = 1;
451 
452 	while (*stds) {
453 		if (std & 1) {
454 			if (!first)
455 				s += "/";
456 			first = 0;
457 			s += *stds;
458 		}
459 		stds++;
460 		std >>= 1;
461 	}
462 	return s;
463 }
464 
std2s(v4l2_std_id std,const char * sep)465 std::string std2s(v4l2_std_id std, const char *sep)
466 {
467 	std::string s;
468 
469 	if (std & 0xfff) {
470 		s += partstd2s("PAL", std_pal, std);
471 	}
472 	if (std & 0xf000) {
473 		if (s.length()) s += sep;
474 		s += partstd2s("NTSC", std_ntsc, std >> 12);
475 	}
476 	if (std & 0xff0000) {
477 		if (s.length()) s += sep;
478 		s += partstd2s("SECAM", std_secam, std >> 16);
479 	}
480 	if (std & 0xf000000) {
481 		if (s.length()) s += sep;
482 		s += partstd2s("ATSC", std_atsc, std >> 24);
483 	}
484 	return s;
485 }
486 
ctrlflags2s(uint32_t flags)487 std::string ctrlflags2s(uint32_t flags)
488 {
489 	static const flag_def def[] = {
490 		{ V4L2_CTRL_FLAG_GRABBED,    "grabbed" },
491 		{ V4L2_CTRL_FLAG_DISABLED,   "disabled" },
492 		{ V4L2_CTRL_FLAG_READ_ONLY,  "read-only" },
493 		{ V4L2_CTRL_FLAG_UPDATE,     "update" },
494 		{ V4L2_CTRL_FLAG_INACTIVE,   "inactive" },
495 		{ V4L2_CTRL_FLAG_SLIDER,     "slider" },
496 		{ V4L2_CTRL_FLAG_WRITE_ONLY, "write-only" },
497 		{ V4L2_CTRL_FLAG_VOLATILE,   "volatile" },
498 		{ V4L2_CTRL_FLAG_HAS_PAYLOAD,"has-payload" },
499 		{ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, "execute-on-write" },
500 		{ V4L2_CTRL_FLAG_MODIFY_LAYOUT, "modify-layout" },
501 		{ 0, NULL }
502 	};
503 	return flags2s(flags, def);
504 }
505 
506 static const flag_def in_status_def[] = {
507 	{ V4L2_IN_ST_NO_POWER,    "no power" },
508 	{ V4L2_IN_ST_NO_SIGNAL,   "no signal" },
509 	{ V4L2_IN_ST_NO_COLOR,    "no color" },
510 	{ V4L2_IN_ST_HFLIP,       "hflip" },
511 	{ V4L2_IN_ST_VFLIP,       "vflip" },
512 	{ V4L2_IN_ST_NO_H_LOCK,   "no hsync lock" },
513 	{ V4L2_IN_ST_NO_V_LOCK,   "no vsync lock" },
514 	{ V4L2_IN_ST_NO_STD_LOCK, "no standard format lock" },
515 	{ V4L2_IN_ST_COLOR_KILL,  "color kill" },
516 	{ V4L2_IN_ST_NO_SYNC,     "no sync lock" },
517 	{ V4L2_IN_ST_NO_EQU,      "no equalizer lock" },
518 	{ V4L2_IN_ST_NO_CARRIER,  "no carrier" },
519 	{ V4L2_IN_ST_MACROVISION, "macrovision" },
520 	{ V4L2_IN_ST_NO_ACCESS,   "no conditional access" },
521 	{ V4L2_IN_ST_VTR,         "VTR time constant" },
522 	{ 0, NULL }
523 };
524 
in_status2s(uint32_t status)525 std::string in_status2s(uint32_t status)
526 {
527 	return status ? flags2s(status, in_status_def) : "ok";
528 }
529 
530 static const flag_def input_cap_def[] = {
531 	{ V4L2_IN_CAP_DV_TIMINGS, "DV timings" },
532 	{ V4L2_IN_CAP_STD, "SDTV standards" },
533 	{ V4L2_IN_CAP_NATIVE_SIZE, "Native Size" },
534 	{ 0, NULL }
535 };
536 
input_cap2s(uint32_t capabilities)537 std::string input_cap2s(uint32_t capabilities)
538 {
539 	return capabilities ? flags2s(capabilities, input_cap_def) : "not defined";
540 }
541 
542 static const flag_def output_cap_def[] = {
543 	{ V4L2_OUT_CAP_DV_TIMINGS, "DV timings" },
544 	{ V4L2_OUT_CAP_STD, "SDTV standards" },
545 	{ V4L2_OUT_CAP_NATIVE_SIZE, "Native Size" },
546 	{ 0, NULL }
547 };
548 
output_cap2s(uint32_t capabilities)549 std::string output_cap2s(uint32_t capabilities)
550 {
551 	return capabilities ? flags2s(capabilities, output_cap_def) : "not defined";
552 }
553 
fbufcap2s(unsigned cap)554 std::string fbufcap2s(unsigned cap)
555 {
556 	std::string s;
557 
558 	if (cap & V4L2_FBUF_CAP_EXTERNOVERLAY)
559 		s += "\t\t\tExtern Overlay\n";
560 	if (cap & V4L2_FBUF_CAP_CHROMAKEY)
561 		s += "\t\t\tChromakey\n";
562 	if (cap & V4L2_FBUF_CAP_SRC_CHROMAKEY)
563 		s += "\t\t\tSource Chromakey\n";
564 	if (cap & V4L2_FBUF_CAP_GLOBAL_ALPHA)
565 		s += "\t\t\tGlobal Alpha\n";
566 	if (cap & V4L2_FBUF_CAP_LOCAL_ALPHA)
567 		s += "\t\t\tLocal Alpha\n";
568 	if (cap & V4L2_FBUF_CAP_LOCAL_INV_ALPHA)
569 		s += "\t\t\tLocal Inverted Alpha\n";
570 	if (cap & V4L2_FBUF_CAP_LIST_CLIPPING)
571 		s += "\t\t\tClipping List\n";
572 	if (cap & V4L2_FBUF_CAP_BITMAP_CLIPPING)
573 		s += "\t\t\tClipping Bitmap\n";
574 	if (s.empty()) s += "\t\t\t\n";
575 	return s;
576 }
577 
fbufflags2s(unsigned fl)578 std::string fbufflags2s(unsigned fl)
579 {
580 	std::string s;
581 
582 	if (fl & V4L2_FBUF_FLAG_PRIMARY)
583 		s += "\t\t\tPrimary Graphics Surface\n";
584 	if (fl & V4L2_FBUF_FLAG_OVERLAY)
585 		s += "\t\t\tOverlay Matches Capture/Output Size\n";
586 	if (fl & V4L2_FBUF_FLAG_CHROMAKEY)
587 		s += "\t\t\tChromakey\n";
588 	if (fl & V4L2_FBUF_FLAG_SRC_CHROMAKEY)
589 		s += "\t\t\tSource Chromakey\n";
590 	if (fl & V4L2_FBUF_FLAG_GLOBAL_ALPHA)
591 		s += "\t\t\tGlobal Alpha\n";
592 	if (fl & V4L2_FBUF_FLAG_LOCAL_ALPHA)
593 		s += "\t\t\tLocal Alpha\n";
594 	if (fl & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)
595 		s += "\t\t\tLocal Inverted Alpha\n";
596 	if (s.empty()) s += "\t\t\t\n";
597 	return s;
598 }
599 
600 static const flag_def dv_standards_def[] = {
601 	{ V4L2_DV_BT_STD_CEA861, "CTA-861" },
602 	{ V4L2_DV_BT_STD_DMT, "DMT" },
603 	{ V4L2_DV_BT_STD_CVT, "CVT" },
604 	{ V4L2_DV_BT_STD_GTF, "GTF" },
605 	{ V4L2_DV_BT_STD_SDI, "SDI" },
606 	{ 0, NULL }
607 };
608 
dv_standards2s(uint32_t flags)609 std::string dv_standards2s(uint32_t flags)
610 {
611 	return flags2s(flags, dv_standards_def);
612 }
613 
dvflags2s(unsigned vsync,int val)614 std::string dvflags2s(unsigned vsync, int val)
615 {
616 	std::string s;
617 
618 	if (val & V4L2_DV_FL_REDUCED_BLANKING)
619 		s += vsync == 8 ?
620 			"reduced blanking v2, " :
621 			"reduced blanking, ";
622 	if (val & V4L2_DV_FL_CAN_REDUCE_FPS)
623 		s += "framerate can be reduced by 1/1.001, ";
624 	if (val & V4L2_DV_FL_REDUCED_FPS)
625 		s += "framerate is reduced by 1/1.001, ";
626 	if (val & V4L2_DV_FL_CAN_DETECT_REDUCED_FPS)
627 		s += "can detect reduced framerates, ";
628 	if (val & V4L2_DV_FL_HALF_LINE)
629 		s += "half-line, ";
630 	if (val & V4L2_DV_FL_IS_CE_VIDEO)
631 		s += "CE-video, ";
632 	if (val & V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE)
633 		s += "first field has extra line, ";
634 	if (val & V4L2_DV_FL_HAS_PICTURE_ASPECT)
635 		s += "has picture aspect, ";
636 	if (val & V4L2_DV_FL_HAS_CEA861_VIC)
637 		s += "has CTA-861 VIC, ";
638 	if (val & V4L2_DV_FL_HAS_HDMI_VIC)
639 		s += "has HDMI VIC, ";
640 	if (s.length())
641 		return s.erase(s.length() - 2, 2);
642 	return s;
643 }
644 
645 static const flag_def dv_caps_def[] = {
646 	{ V4L2_DV_BT_CAP_INTERLACED, "Interlaced" },
647 	{ V4L2_DV_BT_CAP_PROGRESSIVE, "Progressive" },
648 	{ V4L2_DV_BT_CAP_REDUCED_BLANKING, "Reduced Blanking" },
649 	{ V4L2_DV_BT_CAP_CUSTOM, "Custom Formats" },
650 	{ 0, NULL }
651 };
652 
dv_caps2s(uint32_t flags)653 std::string dv_caps2s(uint32_t flags)
654 {
655 	return flags2s(flags, dv_caps_def);
656 }
657 
658 static const flag_def tc_flags_def[] = {
659 	{ V4L2_TC_FLAG_DROPFRAME, "dropframe" },
660 	{ V4L2_TC_FLAG_COLORFRAME, "colorframe" },
661 	{ V4L2_TC_USERBITS_field, "userbits-field" },
662 	{ V4L2_TC_USERBITS_USERDEFINED, "userbits-userdefined" },
663 	{ V4L2_TC_USERBITS_8BITCHARS, "userbits-8bitchars" },
664 	{ 0, NULL }
665 };
666 
tc_flags2s(uint32_t flags)667 std::string tc_flags2s(uint32_t flags)
668 {
669 	return flags2s(flags, tc_flags_def);
670 }
671 
672 static const flag_def buffer_flags_def[] = {
673 	{ V4L2_BUF_FLAG_MAPPED, "mapped" },
674 	{ V4L2_BUF_FLAG_QUEUED, "queued" },
675 	{ V4L2_BUF_FLAG_DONE, "done" },
676 	{ V4L2_BUF_FLAG_KEYFRAME, "keyframe" },
677 	{ V4L2_BUF_FLAG_PFRAME, "P-frame" },
678 	{ V4L2_BUF_FLAG_BFRAME, "B-frame" },
679 	{ V4L2_BUF_FLAG_ERROR, "error" },
680 	{ V4L2_BUF_FLAG_TIMECODE, "timecode" },
681 	{ V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF, "m2m-hold-capture-buf" },
682 	{ V4L2_BUF_FLAG_PREPARED, "prepared" },
683 	{ V4L2_BUF_FLAG_NO_CACHE_INVALIDATE, "no-cache-invalidate" },
684 	{ V4L2_BUF_FLAG_NO_CACHE_CLEAN, "no-cache-clean" },
685 	{ V4L2_BUF_FLAG_LAST, "last" },
686 	{ V4L2_BUF_FLAG_REQUEST_FD, "request-fd" },
687 	{ V4L2_BUF_FLAG_IN_REQUEST, "in-request" },
688 	{ 0, NULL }
689 };
690 
bufferflags2s(uint32_t flags)691 std::string bufferflags2s(uint32_t flags)
692 {
693 	const unsigned ts_mask = V4L2_BUF_FLAG_TIMESTAMP_MASK | V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
694 	std::string s = flags2s(flags & ~ts_mask, buffer_flags_def);
695 
696 	if (s.length())
697 		s += ", ";
698 
699 	switch (flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) {
700 	case V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN:
701 		s += "ts-unknown";
702 		break;
703 	case V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC:
704 		s += "ts-monotonic";
705 		break;
706 	case V4L2_BUF_FLAG_TIMESTAMP_COPY:
707 		s += "ts-copy";
708 		break;
709 	default:
710 		s += "ts-invalid";
711 		break;
712 	}
713 	switch (flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK) {
714 	case V4L2_BUF_FLAG_TSTAMP_SRC_EOF:
715 		s += ", ts-src-eof";
716 		break;
717 	case V4L2_BUF_FLAG_TSTAMP_SRC_SOE:
718 		s += ", ts-src-soe";
719 		break;
720 	default:
721 		s += ", ts-src-invalid";
722 		break;
723 	}
724 	return s;
725 }
726 
727 static const flag_def vbi_def[] = {
728 	{ V4L2_VBI_UNSYNC,     "unsynchronized" },
729 	{ V4L2_VBI_INTERLACED, "interlaced" },
730 	{ 0, NULL }
731 };
732 
vbiflags2s(uint32_t flags)733 std::string vbiflags2s(uint32_t flags)
734 {
735 	return flags2s(flags, vbi_def);
736 }
737