• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <v4l2-info.h>
7 
num2s(unsigned num,bool is_hex=true)8 static std::string num2s(unsigned num, bool is_hex = true)
9 {
10 	char buf[16];
11 
12 	if (is_hex)
13 		sprintf(buf, "0x%08x", num);
14 	else
15 		sprintf(buf, "%u", num);
16 	return buf;
17 }
18 
flags2s(unsigned val,const flag_def * def)19 std::string flags2s(unsigned val, const flag_def *def)
20 {
21 	std::string s;
22 
23 	while (def->flag) {
24 		if (val & def->flag) {
25 			if (s.length()) s += ", ";
26 			s += def->str;
27 			val &= ~def->flag;
28 		}
29 		def++;
30 	}
31 	if (val) {
32 		if (s.length()) s += ", ";
33 		s += num2s(val);
34 	}
35 	return s;
36 }
37 
cap2s(unsigned cap)38 static std::string cap2s(unsigned cap)
39 {
40 	std::string s;
41 
42 	if (cap & V4L2_CAP_VIDEO_CAPTURE)
43 		s += "\t\tVideo Capture\n";
44 	if (cap & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
45 		s += "\t\tVideo Capture Multiplanar\n";
46 	if (cap & V4L2_CAP_VIDEO_OUTPUT)
47 		s += "\t\tVideo Output\n";
48 	if (cap & V4L2_CAP_VIDEO_OUTPUT_MPLANE)
49 		s += "\t\tVideo Output Multiplanar\n";
50 	if (cap & V4L2_CAP_VIDEO_M2M)
51 		s += "\t\tVideo Memory-to-Memory\n";
52 	if (cap & V4L2_CAP_VIDEO_M2M_MPLANE)
53 		s += "\t\tVideo Memory-to-Memory Multiplanar\n";
54 	if (cap & V4L2_CAP_VIDEO_OVERLAY)
55 		s += "\t\tVideo Overlay\n";
56 	if (cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)
57 		s += "\t\tVideo Output Overlay\n";
58 	if (cap & V4L2_CAP_VBI_CAPTURE)
59 		s += "\t\tVBI Capture\n";
60 	if (cap & V4L2_CAP_VBI_OUTPUT)
61 		s += "\t\tVBI Output\n";
62 	if (cap & V4L2_CAP_SLICED_VBI_CAPTURE)
63 		s += "\t\tSliced VBI Capture\n";
64 	if (cap & V4L2_CAP_SLICED_VBI_OUTPUT)
65 		s += "\t\tSliced VBI Output\n";
66 	if (cap & V4L2_CAP_RDS_CAPTURE)
67 		s += "\t\tRDS Capture\n";
68 	if (cap & V4L2_CAP_RDS_OUTPUT)
69 		s += "\t\tRDS Output\n";
70 	if (cap & V4L2_CAP_SDR_CAPTURE)
71 		s += "\t\tSDR Capture\n";
72 	if (cap & V4L2_CAP_SDR_OUTPUT)
73 		s += "\t\tSDR Output\n";
74 	if (cap & V4L2_CAP_META_CAPTURE)
75 		s += "\t\tMetadata Capture\n";
76 	if (cap & V4L2_CAP_META_OUTPUT)
77 		s += "\t\tMetadata Output\n";
78 	if (cap & V4L2_CAP_TUNER)
79 		s += "\t\tTuner\n";
80 	if (cap & V4L2_CAP_TOUCH)
81 		s += "\t\tTouch Device\n";
82 	if (cap & V4L2_CAP_HW_FREQ_SEEK)
83 		s += "\t\tHW Frequency Seek\n";
84 	if (cap & V4L2_CAP_MODULATOR)
85 		s += "\t\tModulator\n";
86 	if (cap & V4L2_CAP_AUDIO)
87 		s += "\t\tAudio\n";
88 	if (cap & V4L2_CAP_RADIO)
89 		s += "\t\tRadio\n";
90 	if (cap & V4L2_CAP_IO_MC)
91 		s += "\t\tI/O MC\n";
92 	if (cap & V4L2_CAP_READWRITE)
93 		s += "\t\tRead/Write\n";
94 	if (cap & V4L2_CAP_STREAMING)
95 		s += "\t\tStreaming\n";
96 	if (cap & V4L2_CAP_EXT_PIX_FORMAT)
97 		s += "\t\tExtended Pix Format\n";
98 	if (cap & V4L2_CAP_DEVICE_CAPS)
99 		s += "\t\tDevice Capabilities\n";
100 	return s;
101 }
102 
subdevcap2s(unsigned cap)103 static std::string subdevcap2s(unsigned cap)
104 {
105 	std::string s;
106 
107 	if (cap & V4L2_SUBDEV_CAP_RO_SUBDEV)
108 		s += "\t\tRead-Only Sub-Device\n";
109 	if (cap & V4L2_SUBDEV_CAP_STREAMS)
110 		s += "\t\tStreams Support\n";
111 	return s;
112 }
113 
v4l2_info_capability(const v4l2_capability & vcap)114 void v4l2_info_capability(const v4l2_capability &vcap)
115 {
116 	printf("\tDriver name      : %s\n", vcap.driver);
117 	printf("\tCard type        : %s\n", vcap.card);
118 	printf("\tBus info         : %s\n", vcap.bus_info);
119 	printf("\tDriver version   : %d.%d.%d\n",
120 	       vcap.version >> 16,
121 	       (vcap.version >> 8) & 0xff,
122 	       vcap.version & 0xff);
123 	printf("\tCapabilities     : 0x%08x\n", vcap.capabilities);
124 	printf("%s", cap2s(vcap.capabilities).c_str());
125 	if (vcap.capabilities & V4L2_CAP_DEVICE_CAPS) {
126 		printf("\tDevice Caps      : 0x%08x\n", vcap.device_caps);
127 		printf("%s", cap2s(vcap.device_caps).c_str());
128 	}
129 }
130 
v4l2_info_subdev_capability(const v4l2_subdev_capability & subdevcap,const v4l2_subdev_client_capability & subdevclientcap)131 void v4l2_info_subdev_capability(const v4l2_subdev_capability &subdevcap,
132 				 const v4l2_subdev_client_capability &subdevclientcap)
133 {
134 	printf("\tDriver version   : %d.%d.%d\n",
135 	       subdevcap.version >> 16,
136 	       (subdevcap.version >> 8) & 0xff,
137 	       subdevcap.version & 0xff);
138 	printf("\tCapabilities     : 0x%08x\n", subdevcap.capabilities);
139 	printf("%s", subdevcap2s(subdevcap.capabilities).c_str());
140 	printf("\tClient Capabilities: 0x%016llx\n", subdevclientcap.capabilities);
141 	printf("%s", subdevclientcap2s(subdevclientcap.capabilities).c_str());
142 }
143 
fcc2s(__u32 val)144 std::string fcc2s(__u32 val)
145 {
146 	std::string s;
147 
148 	s += val & 0x7f;
149 	s += (val >> 8) & 0x7f;
150 	s += (val >> 16) & 0x7f;
151 	s += (val >> 24) & 0x7f;
152 	if (val & (1U << 31))
153 		s += "-BE";
154 	return s;
155 }
156 
pixfmt2s(__u32 format)157 std::string pixfmt2s(__u32 format)
158 {
159 	switch (format) {
160 #include "v4l2-pix-formats.h"
161 	default:
162 		return std::string("Unknown (") + num2s(format) + ")";
163 	}
164 }
165 
buftype2s(int type)166 std::string buftype2s(int type)
167 {
168 	switch (type) {
169 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
170 		return "Video Capture";
171 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
172 		return "Video Capture Multiplanar";
173 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
174 		return "Video Output";
175 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
176 		return "Video Output Multiplanar";
177 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
178 		return "Video Overlay";
179 	case V4L2_BUF_TYPE_VBI_CAPTURE:
180 		return "VBI Capture";
181 	case V4L2_BUF_TYPE_VBI_OUTPUT:
182 		return "VBI Output";
183 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
184 		return "Sliced VBI Capture";
185 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
186 		return "Sliced VBI Output";
187 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
188 		return "Video Output Overlay";
189 	case V4L2_BUF_TYPE_SDR_CAPTURE:
190 		return "SDR Capture";
191 	case V4L2_BUF_TYPE_SDR_OUTPUT:
192 		return "SDR Output";
193 	case V4L2_BUF_TYPE_META_CAPTURE:
194 		return "Metadata Capture";
195 	case V4L2_BUF_TYPE_META_OUTPUT:
196 		return "Metadata Output";
197 	case V4L2_BUF_TYPE_PRIVATE:
198 		return "Private";
199 	default:
200 		return std::string("Unknown (") + num2s(type) + ")";
201 	}
202 }
203 
204 static constexpr flag_def bufcap_def[] = {
205 	{ V4L2_BUF_CAP_SUPPORTS_MMAP, "mmap" },
206 	{ V4L2_BUF_CAP_SUPPORTS_USERPTR, "userptr" },
207 	{ V4L2_BUF_CAP_SUPPORTS_DMABUF, "dmabuf" },
208 	{ V4L2_BUF_CAP_SUPPORTS_REQUESTS, "requests" },
209 	{ V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS, "orphaned-bufs" },
210 	{ V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF, "m2m-hold-capture-buf" },
211 	{ V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS, "mmap-cache-hints" },
212 	{ V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS, "max-num-buffers" },
213 	{ V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS, "remove-bufs" },
214 	{ 0, nullptr }
215 };
216 
bufcap2s(__u32 caps)217 std::string bufcap2s(__u32 caps)
218 {
219 	return flags2s(caps, bufcap_def);
220 }
221 
field2s(int val)222 std::string field2s(int val)
223 {
224 	switch (val) {
225 	case V4L2_FIELD_ANY:
226 		return "Any";
227 	case V4L2_FIELD_NONE:
228 		return "None";
229 	case V4L2_FIELD_TOP:
230 		return "Top";
231 	case V4L2_FIELD_BOTTOM:
232 		return "Bottom";
233 	case V4L2_FIELD_INTERLACED:
234 		return "Interlaced";
235 	case V4L2_FIELD_SEQ_TB:
236 		return "Sequential Top-Bottom";
237 	case V4L2_FIELD_SEQ_BT:
238 		return "Sequential Bottom-Top";
239 	case V4L2_FIELD_ALTERNATE:
240 		return "Alternating";
241 	case V4L2_FIELD_INTERLACED_TB:
242 		return "Interlaced Top-Bottom";
243 	case V4L2_FIELD_INTERLACED_BT:
244 		return "Interlaced Bottom-Top";
245 	default:
246 		return "Unknown (" + num2s(val) + ")";
247 	}
248 }
249 
colorspace2s(int val)250 std::string colorspace2s(int val)
251 {
252 	switch (val) {
253 	case V4L2_COLORSPACE_DEFAULT:
254 		return "Default";
255 	case V4L2_COLORSPACE_SMPTE170M:
256 		return "SMPTE 170M";
257 	case V4L2_COLORSPACE_SMPTE240M:
258 		return "SMPTE 240M";
259 	case V4L2_COLORSPACE_REC709:
260 		return "Rec. 709";
261 	case V4L2_COLORSPACE_BT878:
262 		return "Broken Bt878";
263 	case V4L2_COLORSPACE_470_SYSTEM_M:
264 		return "470 System M";
265 	case V4L2_COLORSPACE_470_SYSTEM_BG:
266 		return "470 System BG";
267 	case V4L2_COLORSPACE_JPEG:
268 		return "JPEG";
269 	case V4L2_COLORSPACE_SRGB:
270 		return "sRGB";
271 	case V4L2_COLORSPACE_OPRGB:
272 		return "opRGB";
273 	case V4L2_COLORSPACE_DCI_P3:
274 		return "DCI-P3";
275 	case V4L2_COLORSPACE_BT2020:
276 		return "BT.2020";
277 	case V4L2_COLORSPACE_RAW:
278 		return "Raw";
279 	default:
280 		return "Unknown (" + num2s(val) + ")";
281 	}
282 }
283 
xfer_func2s(int val)284 std::string xfer_func2s(int val)
285 {
286 	switch (val) {
287 	case V4L2_XFER_FUNC_DEFAULT:
288 		return "Default";
289 	case V4L2_XFER_FUNC_709:
290 		return "Rec. 709";
291 	case V4L2_XFER_FUNC_SRGB:
292 		return "sRGB";
293 	case V4L2_XFER_FUNC_OPRGB:
294 		return "opRGB";
295 	case V4L2_XFER_FUNC_DCI_P3:
296 		return "DCI-P3";
297 	case V4L2_XFER_FUNC_SMPTE2084:
298 		return "SMPTE 2084";
299 	case V4L2_XFER_FUNC_SMPTE240M:
300 		return "SMPTE 240M";
301 	case V4L2_XFER_FUNC_NONE:
302 		return "None";
303 	default:
304 		return "Unknown (" + num2s(val) + ")";
305 	}
306 }
307 
ycbcr_enc2s(int val)308 std::string ycbcr_enc2s(int val)
309 {
310 	switch (val) {
311 	case V4L2_YCBCR_ENC_DEFAULT:
312 		return "Default";
313 	case V4L2_YCBCR_ENC_601:
314 		return "ITU-R 601";
315 	case V4L2_YCBCR_ENC_709:
316 		return "Rec. 709";
317 	case V4L2_YCBCR_ENC_XV601:
318 		return "xvYCC 601";
319 	case V4L2_YCBCR_ENC_XV709:
320 		return "xvYCC 709";
321 	case V4L2_YCBCR_ENC_BT2020:
322 		return "BT.2020";
323 	case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
324 		return "BT.2020 Constant Luminance";
325 	case V4L2_YCBCR_ENC_SMPTE240M:
326 		return "SMPTE 240M";
327 	case V4L2_HSV_ENC_180:
328 		return "HSV with Hue 0-179";
329 	case V4L2_HSV_ENC_256:
330 		return "HSV with Hue 0-255";
331 	default:
332 		return "Unknown (" + num2s(val) + ")";
333 	}
334 }
335 
quantization2s(int val)336 std::string quantization2s(int val)
337 {
338 	switch (val) {
339 	case V4L2_QUANTIZATION_DEFAULT:
340 		return "Default";
341 	case V4L2_QUANTIZATION_FULL_RANGE:
342 		return "Full Range";
343 	case V4L2_QUANTIZATION_LIM_RANGE:
344 		return "Limited Range";
345 	default:
346 		return "Unknown (" + num2s(val) + ")";
347 	}
348 }
349 
350 static constexpr flag_def pixflags_def[] = {
351 	{ V4L2_PIX_FMT_FLAG_PREMUL_ALPHA,  "premultiplied-alpha" },
352 	{ V4L2_PIX_FMT_FLAG_SET_CSC,  "set-csc" },
353 	{ 0, nullptr }
354 };
355 
pixflags2s(unsigned flags)356 std::string pixflags2s(unsigned flags)
357 {
358 	return flags2s(flags, pixflags_def);
359 }
360 
361 static constexpr flag_def service_def[] = {
362 	{ V4L2_SLICED_TELETEXT_B,  "teletext" },
363 	{ V4L2_SLICED_VPS,         "vps" },
364 	{ V4L2_SLICED_CAPTION_525, "cc" },
365 	{ V4L2_SLICED_WSS_625,     "wss" },
366 	{ 0, nullptr }
367 };
368 
service2s(unsigned service)369 std::string service2s(unsigned service)
370 {
371 	return flags2s(service, service_def);
372 }
373 
374 #define FMTDESC_DEF(enc_type)							\
375 static constexpr flag_def fmtdesc_ ## enc_type ## _def[] = { 			\
376 	{ V4L2_FMT_FLAG_COMPRESSED, "compressed" }, 				\
377 	{ V4L2_FMT_FLAG_EMULATED, "emulated" }, 				\
378 	{ V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, "continuous-bytestream" }, 	\
379 	{ V4L2_FMT_FLAG_DYN_RESOLUTION, "dyn-resolution" }, 			\
380 	{ V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL, "enc-cap-frame-interval" },	\
381 	{ V4L2_FMT_FLAG_CSC_COLORSPACE, "csc-colorspace" }, 			\
382 	{ V4L2_FMT_FLAG_CSC_YCBCR_ENC, "csc-"#enc_type }, 			\
383 	{ V4L2_FMT_FLAG_CSC_QUANTIZATION, "csc-quantization" }, 		\
384 	{ V4L2_FMT_FLAG_CSC_XFER_FUNC, "csc-xfer-func" }, 			\
385 	{ V4L2_FMT_FLAG_META_LINE_BASED, "meta-line-based" },			\
386 	{ 0, NULL } 								\
387 };
388 
389 FMTDESC_DEF(ycbcr)
FMTDESC_DEF(hsv)390 FMTDESC_DEF(hsv)
391 
392 std::string fmtdesc2s(unsigned flags, bool is_hsv)
393 {
394 	if (is_hsv)
395 		return flags2s(flags, fmtdesc_hsv_def);
396 	return flags2s(flags, fmtdesc_ycbcr_def);
397 }
398 
399 #define MBUS_DEF(enc_type)						\
400 static constexpr flag_def mbus_ ## enc_type ## _def[] = { 			\
401 	{ V4L2_SUBDEV_MBUS_CODE_CSC_COLORSPACE, "csc-colorspace" }, 	\
402 	{ V4L2_SUBDEV_MBUS_CODE_CSC_YCBCR_ENC, "csc-"#enc_type },	\
403 	{ V4L2_SUBDEV_MBUS_CODE_CSC_QUANTIZATION, "csc-quantization" }, \
404 	{ V4L2_SUBDEV_MBUS_CODE_CSC_XFER_FUNC, "csc-xfer-func" }, 	\
405 	{ 0, NULL }							\
406 };
407 
408 MBUS_DEF(ycbcr)
MBUS_DEF(hsv)409 MBUS_DEF(hsv)
410 
411 std::string mbus2s(unsigned flags, bool is_hsv)
412 {
413 	if (is_hsv)
414 		return flags2s(flags, mbus_hsv_def);
415 	return flags2s(flags, mbus_ycbcr_def);
416 }
417 
418 static constexpr flag_def selection_targets_def[] = {
419 	{ V4L2_SEL_TGT_CROP_ACTIVE, "crop" },
420 	{ V4L2_SEL_TGT_CROP_DEFAULT, "crop_default" },
421 	{ V4L2_SEL_TGT_CROP_BOUNDS, "crop_bounds" },
422 	{ V4L2_SEL_TGT_COMPOSE_ACTIVE, "compose" },
423 	{ V4L2_SEL_TGT_COMPOSE_DEFAULT, "compose_default" },
424 	{ V4L2_SEL_TGT_COMPOSE_BOUNDS, "compose_bounds" },
425 	{ V4L2_SEL_TGT_COMPOSE_PADDED, "compose_padded" },
426 	{ V4L2_SEL_TGT_NATIVE_SIZE, "native_size" },
427 	{ 0, nullptr }
428 };
429 
valid_seltarget_at_idx(unsigned i)430 bool valid_seltarget_at_idx(unsigned i)
431 {
432 	return i < sizeof(selection_targets_def) / sizeof(selection_targets_def[0]) - 1;
433 }
434 
seltarget_at_idx(unsigned i)435 unsigned seltarget_at_idx(unsigned i)
436 {
437 	if (valid_seltarget_at_idx(i))
438 		return selection_targets_def[i].flag;
439 	return 0;
440 }
441 
seltarget2s(__u32 target)442 std::string seltarget2s(__u32 target)
443 {
444 	int i = 0;
445 
446 	while (selection_targets_def[i].str != nullptr) {
447 		if (selection_targets_def[i].flag == target)
448 			return selection_targets_def[i].str;
449 		i++;
450 	}
451 	return std::string("Unknown (") + num2s(target) + ")";
452 }
453 
454 const flag_def selection_flags_def[] = {
455 	{ V4L2_SEL_FLAG_GE, "ge" },
456 	{ V4L2_SEL_FLAG_LE, "le" },
457 	{ V4L2_SEL_FLAG_KEEP_CONFIG, "keep-config" },
458 	{ 0, nullptr }
459 };
460 
selflags2s(__u32 flags)461 std::string selflags2s(__u32 flags)
462 {
463 	return flags2s(flags, selection_flags_def);
464 }
465 
466 static const char *std_pal[] = {
467 	"B", "B1", "G", "H", "I", "D", "D1", "K",
468 	"M", "N", "Nc", "60",
469 	nullptr
470 };
471 static const char *std_ntsc[] = {
472 	"M", "M-JP", "443", "M-KR",
473 	nullptr
474 };
475 static const char *std_secam[] = {
476 	"B", "D", "G", "H", "K", "K1", "L", "Lc",
477 	nullptr
478 };
479 static const char *std_atsc[] = {
480 	"8-VSB", "16-VSB",
481 	nullptr
482 };
483 
partstd2s(const char * prefix,const char * stds[],unsigned long long std)484 static std::string partstd2s(const char *prefix, const char *stds[], unsigned long long std)
485 {
486 	std::string s = std::string(prefix) + "-";
487 	int first = 1;
488 
489 	while (*stds) {
490 		if (std & 1) {
491 			if (!first)
492 				s += "/";
493 			first = 0;
494 			s += *stds;
495 		}
496 		stds++;
497 		std >>= 1;
498 	}
499 	return s;
500 }
501 
std2s(v4l2_std_id std,const char * sep)502 std::string std2s(v4l2_std_id std, const char *sep)
503 {
504 	std::string s;
505 
506 	if (std & 0xfff) {
507 		s += partstd2s("PAL", std_pal, std);
508 	}
509 	if (std & 0xf000) {
510 		if (s.length()) s += sep;
511 		s += partstd2s("NTSC", std_ntsc, std >> 12);
512 	}
513 	if (std & 0xff0000) {
514 		if (s.length()) s += sep;
515 		s += partstd2s("SECAM", std_secam, std >> 16);
516 	}
517 	if (std & 0xf000000) {
518 		if (s.length()) s += sep;
519 		s += partstd2s("ATSC", std_atsc, std >> 24);
520 	}
521 	return s;
522 }
523 
ctrlflags2s(__u32 flags)524 std::string ctrlflags2s(__u32 flags)
525 {
526 	static constexpr flag_def def[] = {
527 		{ V4L2_CTRL_FLAG_GRABBED,    "grabbed" },
528 		{ V4L2_CTRL_FLAG_DISABLED,   "disabled" },
529 		{ V4L2_CTRL_FLAG_READ_ONLY,  "read-only" },
530 		{ V4L2_CTRL_FLAG_UPDATE,     "update" },
531 		{ V4L2_CTRL_FLAG_INACTIVE,   "inactive" },
532 		{ V4L2_CTRL_FLAG_SLIDER,     "slider" },
533 		{ V4L2_CTRL_FLAG_WRITE_ONLY, "write-only" },
534 		{ V4L2_CTRL_FLAG_VOLATILE,   "volatile" },
535 		{ V4L2_CTRL_FLAG_HAS_PAYLOAD,"has-payload" },
536 		{ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, "execute-on-write" },
537 		{ V4L2_CTRL_FLAG_MODIFY_LAYOUT, "modify-layout" },
538 		{ V4L2_CTRL_FLAG_DYNAMIC_ARRAY, "dynamic-array" },
539 		{ 0, nullptr }
540 	};
541 	return flags2s(flags, def);
542 }
543 
544 static constexpr flag_def in_status_def[] = {
545 	{ V4L2_IN_ST_NO_POWER,    "no power" },
546 	{ V4L2_IN_ST_NO_SIGNAL,   "no signal" },
547 	{ V4L2_IN_ST_NO_COLOR,    "no color" },
548 	{ V4L2_IN_ST_HFLIP,       "hflip" },
549 	{ V4L2_IN_ST_VFLIP,       "vflip" },
550 	{ V4L2_IN_ST_NO_H_LOCK,   "no hsync lock" },
551 	{ V4L2_IN_ST_NO_V_LOCK,   "no vsync lock" },
552 	{ V4L2_IN_ST_NO_STD_LOCK, "no standard format lock" },
553 	{ V4L2_IN_ST_COLOR_KILL,  "color kill" },
554 	{ V4L2_IN_ST_NO_SYNC,     "no sync lock" },
555 	{ V4L2_IN_ST_NO_EQU,      "no equalizer lock" },
556 	{ V4L2_IN_ST_NO_CARRIER,  "no carrier" },
557 	{ V4L2_IN_ST_MACROVISION, "macrovision" },
558 	{ V4L2_IN_ST_NO_ACCESS,   "no conditional access" },
559 	{ V4L2_IN_ST_VTR,         "VTR time constant" },
560 	{ 0, nullptr }
561 };
562 
in_status2s(__u32 status)563 std::string in_status2s(__u32 status)
564 {
565 	return status ? flags2s(status, in_status_def) : "ok";
566 }
567 
568 static constexpr flag_def input_cap_def[] = {
569 	{ V4L2_IN_CAP_DV_TIMINGS, "DV timings" },
570 	{ V4L2_IN_CAP_STD, "SDTV standards" },
571 	{ V4L2_IN_CAP_NATIVE_SIZE, "Native Size" },
572 	{ 0, nullptr }
573 };
574 
input_cap2s(__u32 capabilities)575 std::string input_cap2s(__u32 capabilities)
576 {
577 	return capabilities ? flags2s(capabilities, input_cap_def) : "not defined";
578 }
579 
580 static constexpr flag_def output_cap_def[] = {
581 	{ V4L2_OUT_CAP_DV_TIMINGS, "DV timings" },
582 	{ V4L2_OUT_CAP_STD, "SDTV standards" },
583 	{ V4L2_OUT_CAP_NATIVE_SIZE, "Native Size" },
584 	{ 0, nullptr }
585 };
586 
output_cap2s(__u32 capabilities)587 std::string output_cap2s(__u32 capabilities)
588 {
589 	return capabilities ? flags2s(capabilities, output_cap_def) : "not defined";
590 }
591 
fbufcap2s(unsigned cap)592 std::string fbufcap2s(unsigned cap)
593 {
594 	std::string s;
595 
596 	if (cap & V4L2_FBUF_CAP_EXTERNOVERLAY)
597 		s += "\t\t\tExtern Overlay\n";
598 	if (cap & V4L2_FBUF_CAP_CHROMAKEY)
599 		s += "\t\t\tChromakey\n";
600 	if (cap & V4L2_FBUF_CAP_SRC_CHROMAKEY)
601 		s += "\t\t\tSource Chromakey\n";
602 	if (cap & V4L2_FBUF_CAP_GLOBAL_ALPHA)
603 		s += "\t\t\tGlobal Alpha\n";
604 	if (cap & V4L2_FBUF_CAP_LOCAL_ALPHA)
605 		s += "\t\t\tLocal Alpha\n";
606 	if (cap & V4L2_FBUF_CAP_LOCAL_INV_ALPHA)
607 		s += "\t\t\tLocal Inverted Alpha\n";
608 	if (cap & V4L2_FBUF_CAP_LIST_CLIPPING)
609 		s += "\t\t\tClipping List\n";
610 	if (cap & V4L2_FBUF_CAP_BITMAP_CLIPPING)
611 		s += "\t\t\tClipping Bitmap\n";
612 	if (s.empty()) s += "\t\t\t\n";
613 	return s;
614 }
615 
fbufflags2s(unsigned fl)616 std::string fbufflags2s(unsigned fl)
617 {
618 	std::string s;
619 
620 	if (fl & V4L2_FBUF_FLAG_PRIMARY)
621 		s += "\t\t\tPrimary Graphics Surface\n";
622 	if (fl & V4L2_FBUF_FLAG_OVERLAY)
623 		s += "\t\t\tOverlay Matches Capture/Output Size\n";
624 	if (fl & V4L2_FBUF_FLAG_CHROMAKEY)
625 		s += "\t\t\tChromakey\n";
626 	if (fl & V4L2_FBUF_FLAG_SRC_CHROMAKEY)
627 		s += "\t\t\tSource Chromakey\n";
628 	if (fl & V4L2_FBUF_FLAG_GLOBAL_ALPHA)
629 		s += "\t\t\tGlobal Alpha\n";
630 	if (fl & V4L2_FBUF_FLAG_LOCAL_ALPHA)
631 		s += "\t\t\tLocal Alpha\n";
632 	if (fl & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)
633 		s += "\t\t\tLocal Inverted Alpha\n";
634 	if (s.empty()) s += "\t\t\t\n";
635 	return s;
636 }
637 
638 static constexpr flag_def dv_standards_def[] = {
639 	{ V4L2_DV_BT_STD_CEA861, "CTA-861" },
640 	{ V4L2_DV_BT_STD_DMT, "DMT" },
641 	{ V4L2_DV_BT_STD_CVT, "CVT" },
642 	{ V4L2_DV_BT_STD_GTF, "GTF" },
643 	{ V4L2_DV_BT_STD_SDI, "SDI" },
644 	{ 0, nullptr }
645 };
646 
dv_standards2s(__u32 flags)647 std::string dv_standards2s(__u32 flags)
648 {
649 	return flags2s(flags, dv_standards_def);
650 }
651 
dvflags2s(unsigned vsync,int val)652 std::string dvflags2s(unsigned vsync, int val)
653 {
654 	std::string s;
655 
656 	if (val & V4L2_DV_FL_REDUCED_BLANKING)
657 		s += vsync == 8 ?
658 			"reduced blanking v2, " :
659 			"reduced blanking, ";
660 	if (val & V4L2_DV_FL_CAN_REDUCE_FPS)
661 		s += "framerate can be reduced by 1/1.001, ";
662 	if (val & V4L2_DV_FL_REDUCED_FPS)
663 		s += "framerate is reduced by 1/1.001, ";
664 	if (val & V4L2_DV_FL_CAN_DETECT_REDUCED_FPS)
665 		s += "can detect reduced framerates, ";
666 	if (val & V4L2_DV_FL_HALF_LINE)
667 		s += "half-line, ";
668 	if (val & V4L2_DV_FL_IS_CE_VIDEO)
669 		s += "CE-video, ";
670 	if (val & V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE)
671 		s += "first field has extra line, ";
672 	if (val & V4L2_DV_FL_HAS_PICTURE_ASPECT)
673 		s += "has picture aspect, ";
674 	if (val & V4L2_DV_FL_HAS_CEA861_VIC)
675 		s += "has CTA-861 VIC, ";
676 	if (val & V4L2_DV_FL_HAS_HDMI_VIC)
677 		s += "has HDMI VIC, ";
678 	if (s.length())
679 		return s.erase(s.length() - 2, 2);
680 	return s;
681 }
682 
683 static constexpr flag_def dv_caps_def[] = {
684 	{ V4L2_DV_BT_CAP_INTERLACED, "Interlaced" },
685 	{ V4L2_DV_BT_CAP_PROGRESSIVE, "Progressive" },
686 	{ V4L2_DV_BT_CAP_REDUCED_BLANKING, "Reduced Blanking" },
687 	{ V4L2_DV_BT_CAP_CUSTOM, "Custom Formats" },
688 	{ 0, nullptr }
689 };
690 
dv_caps2s(__u32 flags)691 std::string dv_caps2s(__u32 flags)
692 {
693 	return flags2s(flags, dv_caps_def);
694 }
695 
696 static constexpr flag_def tc_flags_def[] = {
697 	{ V4L2_TC_FLAG_DROPFRAME, "dropframe" },
698 	{ V4L2_TC_FLAG_COLORFRAME, "colorframe" },
699 	{ V4L2_TC_USERBITS_field, "userbits-field" },
700 	{ V4L2_TC_USERBITS_USERDEFINED, "userbits-userdefined" },
701 	{ V4L2_TC_USERBITS_8BITCHARS, "userbits-8bitchars" },
702 	{ 0, nullptr }
703 };
704 
tc_flags2s(__u32 flags)705 std::string tc_flags2s(__u32 flags)
706 {
707 	return flags2s(flags, tc_flags_def);
708 }
709 
710 static constexpr flag_def buffer_flags_def[] = {
711 	{ V4L2_BUF_FLAG_MAPPED, "mapped" },
712 	{ V4L2_BUF_FLAG_QUEUED, "queued" },
713 	{ V4L2_BUF_FLAG_DONE, "done" },
714 	{ V4L2_BUF_FLAG_KEYFRAME, "keyframe" },
715 	{ V4L2_BUF_FLAG_PFRAME, "P-frame" },
716 	{ V4L2_BUF_FLAG_BFRAME, "B-frame" },
717 	{ V4L2_BUF_FLAG_ERROR, "error" },
718 	{ V4L2_BUF_FLAG_TIMECODE, "timecode" },
719 	{ V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF, "m2m-hold-capture-buf" },
720 	{ V4L2_BUF_FLAG_PREPARED, "prepared" },
721 	{ V4L2_BUF_FLAG_NO_CACHE_INVALIDATE, "no-cache-invalidate" },
722 	{ V4L2_BUF_FLAG_NO_CACHE_CLEAN, "no-cache-clean" },
723 	{ V4L2_BUF_FLAG_LAST, "last" },
724 	{ V4L2_BUF_FLAG_REQUEST_FD, "request-fd" },
725 	{ V4L2_BUF_FLAG_IN_REQUEST, "in-request" },
726 	{ 0, nullptr }
727 };
728 
bufferflags2s(__u32 flags)729 std::string bufferflags2s(__u32 flags)
730 {
731 	const unsigned ts_mask = V4L2_BUF_FLAG_TIMESTAMP_MASK | V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
732 	std::string s = flags2s(flags & ~ts_mask, buffer_flags_def);
733 
734 	if (s.length())
735 		s += ", ";
736 
737 	switch (flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) {
738 	case V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN:
739 		s += "ts-unknown";
740 		break;
741 	case V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC:
742 		s += "ts-monotonic";
743 		break;
744 	case V4L2_BUF_FLAG_TIMESTAMP_COPY:
745 		s += "ts-copy";
746 		break;
747 	default:
748 		s += "ts-invalid";
749 		break;
750 	}
751 	switch (flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK) {
752 	case V4L2_BUF_FLAG_TSTAMP_SRC_EOF:
753 		s += ", ts-src-eof";
754 		break;
755 	case V4L2_BUF_FLAG_TSTAMP_SRC_SOE:
756 		s += ", ts-src-soe";
757 		break;
758 	default:
759 		s += ", ts-src-invalid";
760 		break;
761 	}
762 	return s;
763 }
764 
765 static const flag_def vbi_def[] = {
766 	{ V4L2_VBI_UNSYNC,     "unsynchronized" },
767 	{ V4L2_VBI_INTERLACED, "interlaced" },
768 	{ 0, nullptr }
769 };
770 
vbiflags2s(__u32 flags)771 std::string vbiflags2s(__u32 flags)
772 {
773 	return flags2s(flags, vbi_def);
774 }
775 
ttype2s(int type)776 std::string ttype2s(int type)
777 {
778 	switch (type) {
779 		case V4L2_TUNER_RADIO: return "radio";
780 		case V4L2_TUNER_ANALOG_TV: return "Analog TV";
781 		case V4L2_TUNER_DIGITAL_TV: return "Digital TV";
782 		case V4L2_TUNER_SDR: return "SDR";
783 		case V4L2_TUNER_RF: return "RF";
784 		default: return "unknown";
785 	}
786 }
787 
audmode2s(int audmode)788 std::string audmode2s(int audmode)
789 {
790 	switch (audmode) {
791 		case V4L2_TUNER_MODE_STEREO: return "stereo";
792 		case V4L2_TUNER_MODE_LANG1: return "lang1";
793 		case V4L2_TUNER_MODE_LANG2: return "lang2";
794 		case V4L2_TUNER_MODE_LANG1_LANG2: return "bilingual";
795 		case V4L2_TUNER_MODE_MONO: return "mono";
796 		default: return "unknown";
797 	}
798 }
799 
rxsubchans2s(int rxsubchans)800 std::string rxsubchans2s(int rxsubchans)
801 {
802 	std::string s;
803 
804 	if (rxsubchans & V4L2_TUNER_SUB_MONO)
805 		s += "mono ";
806 	if (rxsubchans & V4L2_TUNER_SUB_STEREO)
807 		s += "stereo ";
808 	if (rxsubchans & V4L2_TUNER_SUB_LANG1)
809 		s += "lang1 ";
810 	if (rxsubchans & V4L2_TUNER_SUB_LANG2)
811 		s += "lang2 ";
812 	if (rxsubchans & V4L2_TUNER_SUB_RDS)
813 		s += "rds ";
814 	return s;
815 }
816 
txsubchans2s(int txsubchans)817 std::string txsubchans2s(int txsubchans)
818 {
819 	std::string s;
820 
821 	if (txsubchans & V4L2_TUNER_SUB_MONO)
822 		s += "mono ";
823 	if (txsubchans & V4L2_TUNER_SUB_STEREO)
824 		s += "stereo ";
825 	if (txsubchans & V4L2_TUNER_SUB_LANG1)
826 		s += "bilingual ";
827 	if (txsubchans & V4L2_TUNER_SUB_SAP)
828 		s += "sap ";
829 	if (txsubchans & V4L2_TUNER_SUB_RDS)
830 		s += "rds ";
831 	return s;
832 }
833 
tcap2s(unsigned cap)834 std::string tcap2s(unsigned cap)
835 {
836 	std::string s;
837 
838 	if (cap & V4L2_TUNER_CAP_LOW)
839 		s += "62.5 Hz ";
840 	else if (cap & V4L2_TUNER_CAP_1HZ)
841 		s += "1 Hz ";
842 	else
843 		s += "62.5 kHz ";
844 	if (cap & V4L2_TUNER_CAP_NORM)
845 		s += "multi-standard ";
846 	if (cap & V4L2_TUNER_CAP_HWSEEK_BOUNDED)
847 		s += "hwseek-bounded ";
848 	if (cap & V4L2_TUNER_CAP_HWSEEK_WRAP)
849 		s += "hwseek-wrap ";
850 	if (cap & V4L2_TUNER_CAP_STEREO)
851 		s += "stereo ";
852 	if (cap & V4L2_TUNER_CAP_LANG1)
853 		s += "lang1 ";
854 	if (cap & V4L2_TUNER_CAP_LANG2)
855 		s += "lang2 ";
856 	if (cap & V4L2_TUNER_CAP_RDS)
857 		s += "rds ";
858 	if (cap & V4L2_TUNER_CAP_RDS_BLOCK_IO)
859 		s += "rds-block-I/O ";
860 	if (cap & V4L2_TUNER_CAP_RDS_CONTROLS)
861 		s += "rds-controls ";
862 	if (cap & V4L2_TUNER_CAP_FREQ_BANDS)
863 		s += "freq-bands ";
864 	if (cap & V4L2_TUNER_CAP_HWSEEK_PROG_LIM)
865 		s += "hwseek-prog-lim ";
866 	return s;
867 }
868 
modulation2s(unsigned modulation)869 std::string modulation2s(unsigned modulation)
870 {
871 	switch (modulation) {
872 	case V4L2_BAND_MODULATION_VSB:
873 		return "VSB";
874 	case V4L2_BAND_MODULATION_FM:
875 		return "FM";
876 	case V4L2_BAND_MODULATION_AM:
877 		return "AM";
878 	}
879 	return "Unknown";
880 }
881 
subdevclientcap2s(__u64 cap)882 std::string subdevclientcap2s(__u64 cap)
883 {
884 	std::string s;
885 
886 	if (cap & V4L2_SUBDEV_CLIENT_CAP_STREAMS)
887 		s += "streams ";
888 	if (cap & V4L2_SUBDEV_CLIENT_CAP_INTERVAL_USES_WHICH)
889 		s += "interval-uses-which ";
890 	return s;
891 }
892