• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo dot com>
3 
4     Cleanup and VBI and audio in/out options, introduction in v4l-dvb,
5     support for most new APIs since 2006.
6     Copyright (C) 2004, 2006, 2007  Hans Verkuil <hverkuil@xs4all.nl>
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
21  */
22 
23 #include <cctype>
24 #include <vector>
25 
26 #include <dirent.h>
27 #include <getopt.h>
28 #include <sys/epoll.h>
29 
30 #include <linux/media.h>
31 
32 #include "v4l2-ctl.h"
33 
34 #include <media-info.h>
35 
36 #ifdef HAVE_SYS_KLOG_H
37 #include <sys/klog.h>
38 #endif
39 
40 char options[OptLast];
41 
42 static int app_result;
43 int verbose;
44 
45 unsigned capabilities;
46 unsigned out_capabilities;
47 unsigned priv_magic;
48 unsigned out_priv_magic;
49 bool is_multiplanar;
50 __u32 vidcap_buftype;
51 __u32 vidout_buftype;
52 
53 static struct option long_options[] = {
54 	{"list-audio-inputs", no_argument, nullptr, OptListAudioInputs},
55 	{"list-audio-outputs", no_argument, nullptr, OptListAudioOutputs},
56 	{"all", no_argument, nullptr, OptAll},
57 	{"device", required_argument, nullptr, OptSetDevice},
58 	{"out-device", required_argument, nullptr, OptSetOutDevice},
59 	{"export-device", required_argument, nullptr, OptSetExportDevice},
60 	{"media-bus-info", required_argument, nullptr, OptMediaBusInfo},
61 	{"get-fmt-video", no_argument, nullptr, OptGetVideoFormat},
62 	{"set-fmt-video", required_argument, nullptr, OptSetVideoFormat},
63 	{"try-fmt-video", required_argument, nullptr, OptTryVideoFormat},
64 	{"get-fmt-video-out", no_argument, nullptr, OptGetVideoOutFormat},
65 	{"set-fmt-video-out", required_argument, nullptr, OptSetVideoOutFormat},
66 	{"try-fmt-video-out", required_argument, nullptr, OptTryVideoOutFormat},
67 	{"get-routing", no_argument, 0, OptGetRouting},
68 	{"set-routing", required_argument, 0, OptSetRouting},
69 	{"try-routing", required_argument, 0, OptTryRouting},
70 	{"help", no_argument, nullptr, OptHelp},
71 	{"help-tuner", no_argument, nullptr, OptHelpTuner},
72 	{"help-io", no_argument, nullptr, OptHelpIO},
73 	{"help-stds", no_argument, nullptr, OptHelpStds},
74 	{"help-vidcap", no_argument, nullptr, OptHelpVidCap},
75 	{"help-vidout", no_argument, nullptr, OptHelpVidOut},
76 	{"help-overlay", no_argument, nullptr, OptHelpOverlay},
77 	{"help-vbi", no_argument, nullptr, OptHelpVbi},
78 	{"help-sdr", no_argument, nullptr, OptHelpSdr},
79 	{"help-meta", no_argument, nullptr, OptHelpMeta},
80 	{"help-subdev", no_argument, nullptr, OptHelpSubDev},
81 	{"help-selection", no_argument, nullptr, OptHelpSelection},
82 	{"help-misc", no_argument, nullptr, OptHelpMisc},
83 	{"help-streaming", no_argument, nullptr, OptHelpStreaming},
84 	{"help-edid", no_argument, nullptr, OptHelpEdid},
85 	{"help-all", no_argument, nullptr, OptHelpAll},
86 #ifndef NO_LIBV4L2
87 	{"wrapper", no_argument, nullptr, OptUseWrapper},
88 #endif
89 	{"concise", no_argument, nullptr, OptConcise},
90 	{"get-output", no_argument, nullptr, OptGetOutput},
91 	{"set-output", required_argument, nullptr, OptSetOutput},
92 	{"list-outputs", no_argument, nullptr, OptListOutputs},
93 	{"list-inputs", no_argument, nullptr, OptListInputs},
94 	{"get-input", no_argument, nullptr, OptGetInput},
95 	{"set-input", required_argument, nullptr, OptSetInput},
96 	{"get-audio-input", no_argument, nullptr, OptGetAudioInput},
97 	{"set-audio-input", required_argument, nullptr, OptSetAudioInput},
98 	{"get-audio-output", no_argument, nullptr, OptGetAudioOutput},
99 	{"set-audio-output", required_argument, nullptr, OptSetAudioOutput},
100 	{"get-freq", no_argument, nullptr, OptGetFreq},
101 	{"set-freq", required_argument, nullptr, OptSetFreq},
102 	{"list-standards", no_argument, nullptr, OptListStandards},
103 	{"list-formats", optional_argument, nullptr, OptListFormats},
104 	{"list-formats-ext", optional_argument, nullptr, OptListFormatsExt},
105 	{"list-fields", no_argument, nullptr, OptListFields},
106 	{"list-framesizes", required_argument, nullptr, OptListFrameSizes},
107 	{"list-frameintervals", required_argument, nullptr, OptListFrameIntervals},
108 	{"list-formats-overlay", no_argument, nullptr, OptListOverlayFormats},
109 	{"list-formats-sdr", no_argument, nullptr, OptListSdrFormats},
110 	{"list-formats-sdr-out", no_argument, nullptr, OptListSdrOutFormats},
111 	{"list-formats-out", optional_argument, nullptr, OptListOutFormats},
112 	{"list-formats-out-ext", optional_argument, nullptr, OptListOutFormatsExt},
113 	{"list-formats-meta", optional_argument, nullptr, OptListMetaFormats},
114 	{"list-formats-meta-out", optional_argument, nullptr, OptListMetaOutFormats},
115 	{"list-subdev-mbus-codes", optional_argument, nullptr, OptListSubDevMBusCodes},
116 	{"list-subdev-framesizes", required_argument, nullptr, OptListSubDevFrameSizes},
117 	{"list-subdev-frameintervals", required_argument, nullptr, OptListSubDevFrameIntervals},
118 	{"list-fields-out", no_argument, nullptr, OptListOutFields},
119 	{"clear-clips", no_argument, nullptr, OptClearClips},
120 	{"clear-bitmap", no_argument, nullptr, OptClearBitmap},
121 	{"add-clip", required_argument, nullptr, OptAddClip},
122 	{"add-bitmap", required_argument, nullptr, OptAddBitmap},
123 	{"find-fb", no_argument, nullptr, OptFindFb},
124 	{"subset", required_argument, nullptr, OptSubset},
125 	{"get-standard", no_argument, nullptr, OptGetStandard},
126 	{"set-standard", required_argument, nullptr, OptSetStandard},
127 	{"get-detected-standard", no_argument, nullptr, OptQueryStandard},
128 	{"get-parm", no_argument, nullptr, OptGetParm},
129 	{"set-parm", required_argument, nullptr, OptSetParm},
130 	{"get-output-parm", no_argument, nullptr, OptGetOutputParm},
131 	{"set-output-parm", required_argument, nullptr, OptSetOutputParm},
132 	{"info", no_argument, nullptr, OptGetDriverInfo},
133 	{"list-ctrls", no_argument, nullptr, OptListCtrls},
134 	{"list-ctrls-menus", no_argument, nullptr, OptListCtrlsMenus},
135 	{"set-ctrl", required_argument, nullptr, OptSetCtrl},
136 	{"get-ctrl", required_argument, nullptr, OptGetCtrl},
137 	{"get-tuner", no_argument, nullptr, OptGetTuner},
138 	{"set-tuner", required_argument, nullptr, OptSetTuner},
139 	{"list-freq-bands", no_argument, nullptr, OptListFreqBands},
140 	{"silent", no_argument, nullptr, OptSilent},
141 	{"verbose", no_argument, nullptr, OptVerbose},
142 	{"log-status", no_argument, nullptr, OptLogStatus},
143 	{"get-fmt-overlay", no_argument, nullptr, OptGetOverlayFormat},
144 	{"set-fmt-overlay", optional_argument, nullptr, OptSetOverlayFormat},
145 	{"try-fmt-overlay", optional_argument, nullptr, OptTryOverlayFormat},
146 	{"get-fmt-sliced-vbi", no_argument, nullptr, OptGetSlicedVbiFormat},
147 	{"set-fmt-sliced-vbi", required_argument, nullptr, OptSetSlicedVbiFormat},
148 	{"try-fmt-sliced-vbi", required_argument, nullptr, OptTrySlicedVbiFormat},
149 	{"get-fmt-sliced-vbi-out", no_argument, nullptr, OptGetSlicedVbiOutFormat},
150 	{"set-fmt-sliced-vbi-out", required_argument, nullptr, OptSetSlicedVbiOutFormat},
151 	{"try-fmt-sliced-vbi-out", required_argument, nullptr, OptTrySlicedVbiOutFormat},
152 	{"get-fmt-vbi", no_argument, nullptr, OptGetVbiFormat},
153 	{"set-fmt-vbi", required_argument, nullptr, OptSetVbiFormat},
154 	{"try-fmt-vbi", required_argument, nullptr, OptTryVbiFormat},
155 	{"get-fmt-vbi-out", no_argument, nullptr, OptGetVbiOutFormat},
156 	{"set-fmt-vbi-out", required_argument, nullptr, OptSetVbiOutFormat},
157 	{"try-fmt-vbi-out", required_argument, nullptr, OptTryVbiOutFormat},
158 	{"get-fmt-sdr", no_argument, nullptr, OptGetSdrFormat},
159 	{"set-fmt-sdr", required_argument, nullptr, OptSetSdrFormat},
160 	{"try-fmt-sdr", required_argument, nullptr, OptTrySdrFormat},
161 	{"get-fmt-sdr-out", no_argument, nullptr, OptGetSdrOutFormat},
162 	{"set-fmt-sdr-out", required_argument, nullptr, OptSetSdrOutFormat},
163 	{"try-fmt-sdr-out", required_argument, nullptr, OptTrySdrOutFormat},
164 	{"get-fmt-meta", no_argument, nullptr, OptGetMetaFormat},
165 	{"set-fmt-meta", required_argument, nullptr, OptSetMetaFormat},
166 	{"try-fmt-meta", required_argument, nullptr, OptTryMetaFormat},
167 	{"get-fmt-meta-out", no_argument, nullptr, OptGetMetaOutFormat},
168 	{"set-fmt-meta-out", required_argument, nullptr, OptSetMetaOutFormat},
169 	{"try-fmt-meta-out", required_argument, nullptr, OptTryMetaOutFormat},
170 	{"get-subdev-fmt", optional_argument, nullptr, OptGetSubDevFormat},
171 	{"set-subdev-fmt", required_argument, nullptr, OptSetSubDevFormat},
172 	{"try-subdev-fmt", required_argument, nullptr, OptTrySubDevFormat},
173 	{"get-sliced-vbi-cap", no_argument, nullptr, OptGetSlicedVbiCap},
174 	{"get-sliced-vbi-out-cap", no_argument, nullptr, OptGetSlicedVbiOutCap},
175 	{"get-fbuf", no_argument, nullptr, OptGetFBuf},
176 	{"set-fbuf", required_argument, nullptr, OptSetFBuf},
177 	{"get-cropcap", no_argument, nullptr, OptGetCropCap},
178 	{"get-crop", no_argument, nullptr, OptGetCrop},
179 	{"set-crop", required_argument, nullptr, OptSetCrop},
180 	{"get-cropcap-output", no_argument, nullptr, OptGetOutputCropCap},
181 	{"get-crop-output", no_argument, nullptr, OptGetOutputCrop},
182 	{"set-crop-output", required_argument, nullptr, OptSetOutputCrop},
183 	{"get-cropcap-overlay", no_argument, nullptr, OptGetOverlayCropCap},
184 	{"get-crop-overlay", no_argument, nullptr, OptGetOverlayCrop},
185 	{"set-crop-overlay", required_argument, nullptr, OptSetOverlayCrop},
186 	{"get-cropcap-output-overlay", no_argument, nullptr, OptGetOutputOverlayCropCap},
187 	{"get-crop-output-overlay", no_argument, nullptr, OptGetOutputOverlayCrop},
188 	{"set-crop-output-overlay", required_argument, nullptr, OptSetOutputOverlayCrop},
189 	{"get-selection", required_argument, nullptr, OptGetSelection},
190 	{"set-selection", required_argument, nullptr, OptSetSelection},
191 	{"get-selection-output", required_argument, nullptr, OptGetOutputSelection},
192 	{"set-selection-output", required_argument, nullptr, OptSetOutputSelection},
193 	{"get-subdev-selection", required_argument, nullptr, OptGetSubDevSelection},
194 	{"set-subdev-selection", required_argument, nullptr, OptSetSubDevSelection},
195 	{"try-subdev-selection", required_argument, nullptr, OptTrySubDevSelection},
196 	{"get-subdev-fps", optional_argument, nullptr, OptGetSubDevFPS},
197 	{"set-subdev-fps", required_argument, nullptr, OptSetSubDevFPS},
198 	{"get-jpeg-comp", no_argument, nullptr, OptGetJpegComp},
199 	{"set-jpeg-comp", required_argument, nullptr, OptSetJpegComp},
200 	{"get-modulator", no_argument, nullptr, OptGetModulator},
201 	{"set-modulator", required_argument, nullptr, OptSetModulator},
202 	{"get-priority", no_argument, nullptr, OptGetPriority},
203 	{"set-priority", required_argument, nullptr, OptSetPriority},
204 	{"wait-for-event", required_argument, nullptr, OptWaitForEvent},
205 	{"poll-for-event", required_argument, nullptr, OptPollForEvent},
206 	{"epoll-for-event", required_argument, nullptr, OptEPollForEvent},
207 	{"overlay", required_argument, nullptr, OptOverlay},
208 	{"sleep", required_argument, nullptr, OptSleep},
209 	{"list-devices", no_argument, nullptr, OptListDevices},
210 	{"list-dv-timings", optional_argument, nullptr, OptListDvTimings},
211 	{"query-dv-timings", no_argument, nullptr, OptQueryDvTimings},
212 	{"get-dv-timings", no_argument, nullptr, OptGetDvTimings},
213 	{"set-dv-bt-timings", required_argument, nullptr, OptSetDvBtTimings},
214 	{"get-dv-timings-cap", optional_argument, nullptr, OptGetDvTimingsCap},
215 	{"freq-seek", required_argument, nullptr, OptFreqSeek},
216 	{"encoder-cmd", required_argument, nullptr, OptEncoderCmd},
217 	{"try-encoder-cmd", required_argument, nullptr, OptTryEncoderCmd},
218 	{"decoder-cmd", required_argument, nullptr, OptDecoderCmd},
219 	{"try-decoder-cmd", required_argument, nullptr, OptTryDecoderCmd},
220 	{"set-edid", required_argument, nullptr, OptSetEdid},
221 	{"clear-edid", optional_argument, nullptr, OptClearEdid},
222 	{"get-edid", optional_argument, nullptr, OptGetEdid},
223 	{"info-edid", optional_argument, nullptr, OptInfoEdid},
224 	{"show-edid", required_argument, nullptr, OptShowEdid},
225 	{"keep-edid-checksums", no_argument, nullptr, OptKeepEdidChecksums},
226 	{"tuner-index", required_argument, nullptr, OptTunerIndex},
227 	{"list-buffers", no_argument, nullptr, OptListBuffers},
228 	{"list-buffers-out", no_argument, nullptr, OptListBuffersOut},
229 	{"list-buffers-vbi", no_argument, nullptr, OptListBuffersVbi},
230 	{"list-buffers-sliced-vbi", no_argument, nullptr, OptListBuffersSlicedVbi},
231 	{"list-buffers-vbi-out", no_argument, nullptr, OptListBuffersVbiOut},
232 	{"list-buffers-sliced-vbi-out", no_argument, nullptr, OptListBuffersSlicedVbiOut},
233 	{"list-buffers-sdr", no_argument, nullptr, OptListBuffersSdr},
234 	{"list-buffers-sdr-out", no_argument, nullptr, OptListBuffersSdrOut},
235 	{"list-buffers-meta", no_argument, nullptr, OptListBuffersMeta},
236 	{"list-buffers-meta-out", no_argument, nullptr, OptListBuffersMetaOut},
237 	{"stream-count", required_argument, nullptr, OptStreamCount},
238 	{"stream-skip", required_argument, nullptr, OptStreamSkip},
239 	{"stream-loop", no_argument, nullptr, OptStreamLoop},
240 	{"stream-sleep", required_argument, nullptr, OptStreamSleep},
241 	{"stream-poll", no_argument, nullptr, OptStreamPoll},
242 	{"stream-no-query", no_argument, nullptr, OptStreamNoQuery},
243 #ifndef NO_STREAM_TO
244 	{"stream-to", required_argument, nullptr, OptStreamTo},
245 	{"stream-to-hdr", required_argument, nullptr, OptStreamToHdr},
246 	{"stream-lossless", no_argument, nullptr, OptStreamLossless},
247 	{"stream-to-host", required_argument, nullptr, OptStreamToHost},
248 #endif
249 	{"stream-buf-caps", no_argument, nullptr, OptStreamBufCaps},
250 	{"stream-show-delta-now", no_argument, nullptr, OptStreamShowDeltaNow},
251 	{"stream-mmap", optional_argument, nullptr, OptStreamMmap},
252 	{"stream-user", optional_argument, nullptr, OptStreamUser},
253 	{"stream-dmabuf", no_argument, nullptr, OptStreamDmaBuf},
254 	{"stream-from", required_argument, nullptr, OptStreamFrom},
255 	{"stream-from-hdr", required_argument, nullptr, OptStreamFromHdr},
256 	{"stream-from-host", required_argument, nullptr, OptStreamFromHost},
257 	{"stream-out-pattern", required_argument, nullptr, OptStreamOutPattern},
258 	{"stream-out-square", no_argument, nullptr, OptStreamOutSquare},
259 	{"stream-out-border", no_argument, nullptr, OptStreamOutBorder},
260 	{"stream-out-sav", no_argument, nullptr, OptStreamOutInsertSAV},
261 	{"stream-out-eav", no_argument, nullptr, OptStreamOutInsertEAV},
262 	{"stream-out-pixel-aspect", required_argument, nullptr, OptStreamOutPixelAspect},
263 	{"stream-out-video-aspect", required_argument, nullptr, OptStreamOutVideoAspect},
264 	{"stream-out-alpha", required_argument, nullptr, OptStreamOutAlphaComponent},
265 	{"stream-out-alpha-red-only", no_argument, nullptr, OptStreamOutAlphaRedOnly},
266 	{"stream-out-rgb-lim-range", required_argument, nullptr, OptStreamOutRGBLimitedRange},
267 	{"stream-out-hor-speed", required_argument, nullptr, OptStreamOutHorSpeed},
268 	{"stream-out-vert-speed", required_argument, nullptr, OptStreamOutVertSpeed},
269 	{"stream-out-perc-fill", required_argument, nullptr, OptStreamOutPercFill},
270 	{"stream-out-buf-caps", no_argument, nullptr, OptStreamOutBufCaps},
271 	{"stream-out-mmap", optional_argument, nullptr, OptStreamOutMmap},
272 	{"stream-out-user", optional_argument, nullptr, OptStreamOutUser},
273 	{"stream-out-dmabuf", no_argument, nullptr, OptStreamOutDmaBuf},
274 	{"list-patterns", no_argument, nullptr, OptListPatterns},
275 	{"version", no_argument, nullptr, OptVersion},
276 	{nullptr, 0, nullptr, 0}
277 };
278 
usage_all()279 static void usage_all()
280 {
281        common_usage();
282        tuner_usage();
283        io_usage();
284        stds_usage();
285        vidcap_usage();
286        vidout_usage();
287        overlay_usage();
288        vbi_usage();
289        sdr_usage();
290        meta_usage();
291        subdev_usage();
292        selection_usage();
293        misc_usage();
294        streaming_usage();
295        edid_usage();
296 }
297 
print_version()298 static void print_version()
299 {
300 #define STR(x) #x
301 #define STRING(x) STR(x)
302 	printf("v4l2-ctl %s%s\n", PACKAGE_VERSION, STRING(GIT_COMMIT_CNT));
303 }
304 
test_ioctl(int fd,unsigned long cmd,void * arg)305 int test_ioctl(int fd, unsigned long cmd, void *arg)
306 {
307 	return options[OptUseWrapper] ? v4l2_ioctl(fd, cmd, arg) : ioctl(fd, cmd, arg);
308 }
309 
doioctl_name(int fd,unsigned long int request,void * parm,const char * name)310 int doioctl_name(int fd, unsigned long int request, void *parm, const char *name)
311 {
312 	int retval = test_ioctl(fd, request, parm);
313 
314 	if (retval < 0)
315 		app_result = -1;
316 	if (options[OptSilent]) return retval;
317 	if (retval < 0)
318 		printf("%s: failed: %s\n", name, strerror(errno));
319 	else if (verbose)
320 		printf("%s: ok\n", name);
321 
322 	return retval;
323 }
324 
325 /*
326  * Any pixelformat that is not a YUV format is assumed to be
327  * RGB or HSV.
328  */
is_rgb_or_hsv(__u32 pixelformat)329 static bool is_rgb_or_hsv(__u32 pixelformat)
330 {
331 	switch (pixelformat) {
332 	case V4L2_PIX_FMT_UV8:
333 	case V4L2_PIX_FMT_YVU410:
334 	case V4L2_PIX_FMT_YVU420:
335 	case V4L2_PIX_FMT_YUYV:
336 	case V4L2_PIX_FMT_YYUV:
337 	case V4L2_PIX_FMT_YVYU:
338 	case V4L2_PIX_FMT_UYVY:
339 	case V4L2_PIX_FMT_VYUY:
340 	case V4L2_PIX_FMT_YUV422P:
341 	case V4L2_PIX_FMT_YUV411P:
342 	case V4L2_PIX_FMT_Y41P:
343 	case V4L2_PIX_FMT_YUV444:
344 	case V4L2_PIX_FMT_YUV555:
345 	case V4L2_PIX_FMT_YUV565:
346 	case V4L2_PIX_FMT_YUV32:
347 	case V4L2_PIX_FMT_AYUV32:
348 	case V4L2_PIX_FMT_XYUV32:
349 	case V4L2_PIX_FMT_VUYA32:
350 	case V4L2_PIX_FMT_VUYX32:
351 	case V4L2_PIX_FMT_YUVA32:
352 	case V4L2_PIX_FMT_YUVX32:
353 	case V4L2_PIX_FMT_YUV410:
354 	case V4L2_PIX_FMT_YUV420:
355 	case V4L2_PIX_FMT_HI240:
356 	case V4L2_PIX_FMT_NV12_16L16:
357 	case V4L2_PIX_FMT_M420:
358 	case V4L2_PIX_FMT_NV12:
359 	case V4L2_PIX_FMT_NV21:
360 	case V4L2_PIX_FMT_NV16:
361 	case V4L2_PIX_FMT_NV61:
362 	case V4L2_PIX_FMT_NV24:
363 	case V4L2_PIX_FMT_NV42:
364 	case V4L2_PIX_FMT_NV12M:
365 	case V4L2_PIX_FMT_NV21M:
366 	case V4L2_PIX_FMT_NV16M:
367 	case V4L2_PIX_FMT_NV61M:
368 	case V4L2_PIX_FMT_NV12MT:
369 	case V4L2_PIX_FMT_NV12MT_16X16:
370 	case V4L2_PIX_FMT_YUV420M:
371 	case V4L2_PIX_FMT_YVU420M:
372 	case V4L2_PIX_FMT_YUV422M:
373 	case V4L2_PIX_FMT_YVU422M:
374 	case V4L2_PIX_FMT_YUV444M:
375 	case V4L2_PIX_FMT_YVU444M:
376 	case V4L2_PIX_FMT_SN9C20X_I420:
377 	case V4L2_PIX_FMT_SPCA501:
378 	case V4L2_PIX_FMT_SPCA505:
379 	case V4L2_PIX_FMT_SPCA508:
380 	case V4L2_PIX_FMT_CIT_YYVYUY:
381 	case V4L2_PIX_FMT_KONICA420:
382 		return false;
383 	default:
384 		return true;
385 	}
386 }
387 
printfmtname(int fd,__u32 type,__u32 pixfmt)388 static std::string printfmtname(int fd, __u32 type, __u32 pixfmt)
389 {
390 	struct v4l2_fmtdesc fmt = {};
391 	std::string s(" (");
392 
393 	fmt.index = 0;
394 	fmt.type = type;
395 	while (test_ioctl(fd, VIDIOC_ENUM_FMT, &fmt) >= 0) {
396 		if (fmt.pixelformat == pixfmt)
397 			return s + reinterpret_cast<const char *>(fmt.description) + ")";
398 		fmt.index++;
399 	}
400 	return "";
401 }
402 
printfmt(int fd,const struct v4l2_format & vfmt)403 void printfmt(int fd, const struct v4l2_format &vfmt)
404 {
405 	__u32 colsp = vfmt.fmt.pix.colorspace;
406 	__u32 ycbcr_enc = vfmt.fmt.pix.ycbcr_enc;
407 
408 	printf("Format %s:\n", buftype2s(vfmt.type).c_str());
409 
410 	switch (vfmt.type) {
411 	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
412 	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
413 		printf("\tWidth/Height      : %u/%u\n", vfmt.fmt.pix.width, vfmt.fmt.pix.height);
414 		printf("\tPixel Format      : '%s'%s\n", fcc2s(vfmt.fmt.pix.pixelformat).c_str(),
415 		       printfmtname(fd, vfmt.type, vfmt.fmt.pix.pixelformat).c_str());
416 		printf("\tField             : %s\n", field2s(vfmt.fmt.pix.field).c_str());
417 		printf("\tBytes per Line    : %u\n", vfmt.fmt.pix.bytesperline);
418 		printf("\tSize Image        : %u\n", vfmt.fmt.pix.sizeimage);
419 		printf("\tColorspace        : %s\n", colorspace2s(colsp).c_str());
420 		printf("\tTransfer Function : %s", xfer_func2s(vfmt.fmt.pix.xfer_func).c_str());
421 		if (vfmt.fmt.pix.xfer_func == V4L2_XFER_FUNC_DEFAULT)
422 			printf(" (maps to %s)",
423 			       xfer_func2s(V4L2_MAP_XFER_FUNC_DEFAULT(colsp)).c_str());
424 		printf("\n");
425 		printf("\tYCbCr/HSV Encoding: %s", ycbcr_enc2s(ycbcr_enc).c_str());
426 		if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
427 			ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colsp);
428 			printf(" (maps to %s)", ycbcr_enc2s(ycbcr_enc).c_str());
429 		}
430 		printf("\n");
431 		printf("\tQuantization      : %s", quantization2s(vfmt.fmt.pix.quantization).c_str());
432 		if (vfmt.fmt.pix.quantization == V4L2_QUANTIZATION_DEFAULT)
433 			printf(" (maps to %s)",
434 			       quantization2s(V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb_or_hsv(vfmt.fmt.pix.pixelformat),
435 									    colsp, ycbcr_enc)).c_str());
436 		printf("\n");
437 		if (vfmt.fmt.pix.priv == V4L2_PIX_FMT_PRIV_MAGIC)
438 			printf("\tFlags             : %s\n", pixflags2s(vfmt.fmt.pix.flags).c_str());
439 		break;
440 	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
441 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
442 		printf("\tWidth/Height      : %u/%u\n", vfmt.fmt.pix_mp.width, vfmt.fmt.pix_mp.height);
443 		printf("\tPixel Format      : '%s'%s\n", fcc2s(vfmt.fmt.pix_mp.pixelformat).c_str(),
444 		       printfmtname(fd, vfmt.type, vfmt.fmt.pix_mp.pixelformat).c_str());
445 		printf("\tField             : %s\n", field2s(vfmt.fmt.pix_mp.field).c_str());
446 		printf("\tNumber of planes  : %u\n", vfmt.fmt.pix_mp.num_planes);
447 		printf("\tFlags             : %s\n", pixflags2s(vfmt.fmt.pix_mp.flags).c_str());
448 		printf("\tColorspace        : %s\n", colorspace2s(vfmt.fmt.pix_mp.colorspace).c_str());
449 		printf("\tTransfer Function : %s\n", xfer_func2s(vfmt.fmt.pix_mp.xfer_func).c_str());
450 		printf("\tYCbCr/HSV Encoding: %s\n", ycbcr_enc2s(vfmt.fmt.pix_mp.ycbcr_enc).c_str());
451 		printf("\tQuantization      : %s\n", quantization2s(vfmt.fmt.pix_mp.quantization).c_str());
452 		for (int i = 0; i < vfmt.fmt.pix_mp.num_planes && i < VIDEO_MAX_PLANES; i++) {
453 			printf("\tPlane %d           :\n", i);
454 			printf("\t   Bytes per Line : %u\n", vfmt.fmt.pix_mp.plane_fmt[i].bytesperline);
455 			printf("\t   Size Image     : %u\n", vfmt.fmt.pix_mp.plane_fmt[i].sizeimage);
456 		}
457 		break;
458 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
459 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
460 		printf("\tLeft/Top    : %d/%d\n",
461 				vfmt.fmt.win.w.left, vfmt.fmt.win.w.top);
462 		printf("\tWidth/Height: %d/%d\n",
463 				vfmt.fmt.win.w.width, vfmt.fmt.win.w.height);
464 		printf("\tField       : %s\n", field2s(vfmt.fmt.win.field).c_str());
465 		printf("\tChroma Key  : 0x%08x\n", vfmt.fmt.win.chromakey);
466 		printf("\tGlobal Alpha: 0x%02x\n", vfmt.fmt.win.global_alpha);
467 		printf("\tClip Count  : %u\n", vfmt.fmt.win.clipcount);
468 		if (vfmt.fmt.win.clips)
469 			for (unsigned i = 0; i < vfmt.fmt.win.clipcount; i++) {
470 				struct v4l2_rect &r = vfmt.fmt.win.clips[i].c;
471 
472 				printf("\t\tClip %2d: %ux%u@%ux%u\n", i,
473 						r.width, r.height, r.left, r.top);
474 			}
475 		printf("\tClip Bitmap : %s", vfmt.fmt.win.bitmap ? "Yes, " : "No\n");
476 		if (vfmt.fmt.win.bitmap) {
477 			auto bitmap = static_cast<unsigned char *>(vfmt.fmt.win.bitmap);
478 			unsigned stride = (vfmt.fmt.win.w.width + 7) / 8;
479 			unsigned cnt = 0;
480 
481 			for (unsigned y = 0; y < vfmt.fmt.win.w.height; y++)
482 				for (unsigned x = 0; x < vfmt.fmt.win.w.width; x++)
483 					if (bitmap[y * stride + x / 8] & (1 << (x & 7)))
484 						cnt++;
485 			printf("%u bits of %u are set\n", cnt,
486 					vfmt.fmt.win.w.width * vfmt.fmt.win.w.height);
487 		}
488 		break;
489 	case V4L2_BUF_TYPE_VBI_CAPTURE:
490 	case V4L2_BUF_TYPE_VBI_OUTPUT:
491 		printf("\tSampling Rate   : %u Hz\n", vfmt.fmt.vbi.sampling_rate);
492 		printf("\tOffset          : %u samples (%g secs after leading edge)\n",
493 				vfmt.fmt.vbi.offset,
494 				static_cast<double>(vfmt.fmt.vbi.offset) / static_cast<double>(vfmt.fmt.vbi.sampling_rate));
495 		printf("\tSamples per Line: %u\n", vfmt.fmt.vbi.samples_per_line);
496 		printf("\tSample Format   : '%s'\n", fcc2s(vfmt.fmt.vbi.sample_format).c_str());
497 		printf("\tStart 1st Field : %u\n", vfmt.fmt.vbi.start[0]);
498 		printf("\tCount 1st Field : %u\n", vfmt.fmt.vbi.count[0]);
499 		printf("\tStart 2nd Field : %u\n", vfmt.fmt.vbi.start[1]);
500 		printf("\tCount 2nd Field : %u\n", vfmt.fmt.vbi.count[1]);
501 		if (vfmt.fmt.vbi.flags)
502 			printf("\tFlags           : %s\n", vbiflags2s(vfmt.fmt.vbi.flags).c_str());
503 		break;
504 	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
505 	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
506 		printf("\tService Set    : %s\n",
507 				service2s(vfmt.fmt.sliced.service_set).c_str());
508 		for (int i = 0; i < 24; i++) {
509 			printf("\tService Line %2d: %8s / %-8s\n", i,
510 			       service2s(vfmt.fmt.sliced.service_lines[0][i]).c_str(),
511 			       service2s(vfmt.fmt.sliced.service_lines[1][i]).c_str());
512 		}
513 		printf("\tI/O Size       : %u\n", vfmt.fmt.sliced.io_size);
514 		break;
515 	case V4L2_BUF_TYPE_SDR_CAPTURE:
516 	case V4L2_BUF_TYPE_SDR_OUTPUT:
517 		printf("\tSample Format   : '%s'%s\n", fcc2s(vfmt.fmt.sdr.pixelformat).c_str(),
518 		       printfmtname(fd, vfmt.type, vfmt.fmt.sdr.pixelformat).c_str());
519 		printf("\tBuffer Size     : %u\n", vfmt.fmt.sdr.buffersize);
520 		break;
521 	case V4L2_BUF_TYPE_META_CAPTURE:
522 	case V4L2_BUF_TYPE_META_OUTPUT:
523 		printf("\tSample Format   : '%s'%s\n", fcc2s(vfmt.fmt.meta.dataformat).c_str(),
524 		       printfmtname(fd, vfmt.type, vfmt.fmt.meta.dataformat).c_str());
525 		printf("\tBuffer Size     : %u\n", vfmt.fmt.meta.buffersize);
526 		break;
527 	}
528 }
529 
frmtype2s(unsigned type)530 static std::string frmtype2s(unsigned type)
531 {
532 	static constexpr const char *types[] = {
533 		"Unknown",
534 		"Discrete",
535 		"Continuous",
536 		"Stepwise"
537 	};
538 
539 	if (type > 3)
540 		type = 0;
541 	return types[type];
542 }
543 
fract2sec(const struct v4l2_fract & f)544 static std::string fract2sec(const struct v4l2_fract &f)
545 {
546 	char buf[100];
547 
548 	sprintf(buf, "%.3f", (1.0 * f.numerator) / f.denominator);
549 	return buf;
550 }
551 
fract2fps(const struct v4l2_fract & f)552 static std::string fract2fps(const struct v4l2_fract &f)
553 {
554 	char buf[100];
555 
556 	sprintf(buf, "%.3f", (1.0 * f.denominator) / f.numerator);
557 	return buf;
558 }
559 
print_frmsize(const struct v4l2_frmsizeenum & frmsize,const char * prefix)560 void print_frmsize(const struct v4l2_frmsizeenum &frmsize, const char *prefix)
561 {
562 	printf("%s\tSize: %s ", prefix, frmtype2s(frmsize.type).c_str());
563 	if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
564 		printf("%dx%d", frmsize.discrete.width, frmsize.discrete.height);
565 	} else if (frmsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
566 		printf("%dx%d - %dx%d",
567 				frmsize.stepwise.min_width,
568 				frmsize.stepwise.min_height,
569 				frmsize.stepwise.max_width,
570 				frmsize.stepwise.max_height);
571 	} else if (frmsize.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
572 		printf("%dx%d - %dx%d with step %d/%d",
573 				frmsize.stepwise.min_width,
574 				frmsize.stepwise.min_height,
575 				frmsize.stepwise.max_width,
576 				frmsize.stepwise.max_height,
577 				frmsize.stepwise.step_width,
578 				frmsize.stepwise.step_height);
579 	}
580 	printf("\n");
581 }
582 
print_frmival(const struct v4l2_frmivalenum & frmival,const char * prefix)583 void print_frmival(const struct v4l2_frmivalenum &frmival, const char *prefix)
584 {
585 	printf("%s\tInterval: %s ", prefix, frmtype2s(frmival.type).c_str());
586 	if (frmival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
587 		printf("%ss (%s fps)\n", fract2sec(frmival.discrete).c_str(),
588 				fract2fps(frmival.discrete).c_str());
589 	} else if (frmival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS) {
590 		printf("%ss - %ss (%s-%s fps)\n",
591 				fract2sec(frmival.stepwise.min).c_str(),
592 				fract2sec(frmival.stepwise.max).c_str(),
593 				fract2fps(frmival.stepwise.max).c_str(),
594 				fract2fps(frmival.stepwise.min).c_str());
595 	} else if (frmival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
596 		printf("%ss - %ss with step %ss (%s-%s fps)\n",
597 				fract2sec(frmival.stepwise.min).c_str(),
598 				fract2sec(frmival.stepwise.max).c_str(),
599 				fract2sec(frmival.stepwise.step).c_str(),
600 				fract2fps(frmival.stepwise.max).c_str(),
601 				fract2fps(frmival.stepwise.min).c_str());
602 	}
603 }
604 
print_video_formats(cv4l_fd & fd,__u32 type,unsigned int mbus_code)605 void print_video_formats(cv4l_fd &fd, __u32 type, unsigned int mbus_code)
606 {
607 	cv4l_disable_trace dt(fd);
608 	struct v4l2_fmtdesc fmt = {};
609 
610 	if (mbus_code && !(capabilities & V4L2_CAP_IO_MC))
611 		mbus_code = 0;
612 
613 	printf("\tType: %s\n\n", buftype2s(type).c_str());
614 	if (fd.enum_fmt(fmt, true, 0, type, mbus_code))
615 		return;
616 	do {
617 		printf("\t[%d]: '%s' (%s", fmt.index, fcc2s(fmt.pixelformat).c_str(),
618 		       fmt.description);
619 		if (fmt.flags) {
620 			bool is_hsv = fmt.pixelformat == V4L2_PIX_FMT_HSV24 ||
621 				      fmt.pixelformat == V4L2_PIX_FMT_HSV32;
622 
623 			printf(", %s", fmtdesc2s(fmt.flags, is_hsv).c_str());
624 		}
625 		printf(")\n");
626 	} while (!fd.enum_fmt(fmt));
627 }
628 
print_video_formats_ext(cv4l_fd & fd,__u32 type,unsigned int mbus_code)629 void print_video_formats_ext(cv4l_fd &fd, __u32 type, unsigned int mbus_code)
630 {
631 	cv4l_disable_trace dt(fd);
632 	struct v4l2_fmtdesc fmt = {};
633 	struct v4l2_frmsizeenum frmsize;
634 	struct v4l2_frmivalenum frmival;
635 
636 	if (mbus_code && !(capabilities & V4L2_CAP_IO_MC))
637 		mbus_code = 0;
638 
639 	printf("\tType: %s\n\n", buftype2s(type).c_str());
640 	if (fd.enum_fmt(fmt, true, 0, type, mbus_code))
641 		return;
642 	do {
643 		printf("\t[%d]: '%s' (%s", fmt.index, fcc2s(fmt.pixelformat).c_str(),
644 		       fmt.description);
645 		if (fmt.flags) {
646 			bool is_hsv = fmt.pixelformat == V4L2_PIX_FMT_HSV24 ||
647 				      fmt.pixelformat == V4L2_PIX_FMT_HSV32;
648 
649 			printf(", %s", fmtdesc2s(fmt.flags, is_hsv).c_str());
650 		}
651 		printf(")\n");
652 		if (fd.enum_framesizes(frmsize, fmt.pixelformat))
653 			continue;
654 		do {
655 			print_frmsize(frmsize, "\t");
656 			if (frmsize.type != V4L2_FRMSIZE_TYPE_DISCRETE)
657 				continue;
658 
659 			if (fd.enum_frameintervals(frmival, fmt.pixelformat,
660 						   frmsize.discrete.width,
661 						   frmsize.discrete.height))
662 				continue;
663 			do {
664 				print_frmival(frmival, "\t\t");
665 			} while (!fd.enum_frameintervals(frmival));
666 		} while (!fd.enum_framesizes(frmsize));
667 	} while (!fd.enum_fmt(fmt));
668 }
669 
parse_subopt(char ** subs,const char * const * subopts,char ** value)670 int parse_subopt(char **subs, const char * const *subopts, char **value)
671 {
672 	int opt = v4l_getsubopt(subs, const_cast<char * const *>(subopts), value);
673 
674 	if (opt == -1) {
675 		fprintf(stderr, "Invalid suboptions specified\n");
676 		return -1;
677 	}
678 	if (*value == nullptr) {
679 		fprintf(stderr, "No value given to suboption <%s>\n",
680 				subopts[opt]);
681 		return -1;
682 	}
683 	return opt;
684 }
685 
parse_field(const char * s)686 __u32 parse_field(const char *s)
687 {
688 	if (!strcmp(s, "any")) return V4L2_FIELD_ANY;
689 	if (!strcmp(s, "none")) return V4L2_FIELD_NONE;
690 	if (!strcmp(s, "top")) return V4L2_FIELD_TOP;
691 	if (!strcmp(s, "bottom")) return V4L2_FIELD_BOTTOM;
692 	if (!strcmp(s, "interlaced")) return V4L2_FIELD_INTERLACED;
693 	if (!strcmp(s, "seq_tb")) return V4L2_FIELD_SEQ_TB;
694 	if (!strcmp(s, "seq_bt")) return V4L2_FIELD_SEQ_BT;
695 	if (!strcmp(s, "alternate")) return V4L2_FIELD_ALTERNATE;
696 	if (!strcmp(s, "interlaced_tb")) return V4L2_FIELD_INTERLACED_TB;
697 	if (!strcmp(s, "interlaced_bt")) return V4L2_FIELD_INTERLACED_BT;
698 	return V4L2_FIELD_ANY;
699 }
700 
parse_colorspace(const char * s)701 __u32 parse_colorspace(const char *s)
702 {
703 	if (!strcmp(s, "smpte170m")) return V4L2_COLORSPACE_SMPTE170M;
704 	if (!strcmp(s, "smpte240m")) return V4L2_COLORSPACE_SMPTE240M;
705 	if (!strcmp(s, "rec709")) return V4L2_COLORSPACE_REC709;
706 	if (!strcmp(s, "470m")) return V4L2_COLORSPACE_470_SYSTEM_M;
707 	if (!strcmp(s, "470bg")) return V4L2_COLORSPACE_470_SYSTEM_BG;
708 	if (!strcmp(s, "jpeg")) return V4L2_COLORSPACE_JPEG;
709 	if (!strcmp(s, "srgb")) return V4L2_COLORSPACE_SRGB;
710 	if (!strcmp(s, "oprgb")) return V4L2_COLORSPACE_OPRGB;
711 	if (!strcmp(s, "bt2020")) return V4L2_COLORSPACE_BT2020;
712 	if (!strcmp(s, "dcip3")) return V4L2_COLORSPACE_DCI_P3;
713 	return 0;
714 }
715 
parse_xfer_func(const char * s)716 __u32 parse_xfer_func(const char *s)
717 {
718 	if (!strcmp(s, "default")) return V4L2_XFER_FUNC_DEFAULT;
719 	if (!strcmp(s, "smpte240m")) return V4L2_XFER_FUNC_SMPTE240M;
720 	if (!strcmp(s, "rec709")) return V4L2_XFER_FUNC_709;
721 	if (!strcmp(s, "srgb")) return V4L2_XFER_FUNC_SRGB;
722 	if (!strcmp(s, "oprgb")) return V4L2_XFER_FUNC_OPRGB;
723 	if (!strcmp(s, "dcip3")) return V4L2_XFER_FUNC_DCI_P3;
724 	if (!strcmp(s, "smpte2084")) return V4L2_XFER_FUNC_SMPTE2084;
725 	if (!strcmp(s, "none")) return V4L2_XFER_FUNC_NONE;
726 	return 0;
727 }
728 
parse_ycbcr(const char * s)729 __u32 parse_ycbcr(const char *s)
730 {
731 	if (!strcmp(s, "default")) return V4L2_YCBCR_ENC_DEFAULT;
732 	if (!strcmp(s, "601")) return V4L2_YCBCR_ENC_601;
733 	if (!strcmp(s, "709")) return V4L2_YCBCR_ENC_709;
734 	if (!strcmp(s, "xv601")) return V4L2_YCBCR_ENC_XV601;
735 	if (!strcmp(s, "xv709")) return V4L2_YCBCR_ENC_XV709;
736 	if (!strcmp(s, "bt2020")) return V4L2_YCBCR_ENC_BT2020;
737 	if (!strcmp(s, "bt2020c")) return V4L2_YCBCR_ENC_BT2020_CONST_LUM;
738 	if (!strcmp(s, "smpte240m")) return V4L2_YCBCR_ENC_SMPTE240M;
739 	return V4L2_YCBCR_ENC_DEFAULT;
740 }
741 
parse_hsv(const char * s)742 __u32 parse_hsv(const char *s)
743 {
744 	if (!strcmp(s, "default")) return V4L2_YCBCR_ENC_DEFAULT;
745 	if (!strcmp(s, "180")) return V4L2_HSV_ENC_180;
746 	if (!strcmp(s, "256")) return V4L2_HSV_ENC_256;
747 	return V4L2_YCBCR_ENC_DEFAULT;
748 }
749 
parse_quantization(const char * s)750 __u32 parse_quantization(const char *s)
751 {
752 	if (!strcmp(s, "default")) return V4L2_QUANTIZATION_DEFAULT;
753 	if (!strcmp(s, "full-range")) return V4L2_QUANTIZATION_FULL_RANGE;
754 	if (!strcmp(s, "lim-range")) return V4L2_QUANTIZATION_LIM_RANGE;
755 	return V4L2_QUANTIZATION_DEFAULT;
756 }
757 
parse_fmt(char * optarg,__u32 & width,__u32 & height,__u32 & pixelformat,__u32 & field,__u32 & colorspace,__u32 & xfer_func,__u32 & ycbcr,__u32 & quantization,__u32 & flags,__u32 * bytesperline,__u32 * sizeimage)758 int parse_fmt(char *optarg, __u32 &width, __u32 &height, __u32 &pixelformat,
759 	      __u32 &field, __u32 &colorspace, __u32 &xfer_func, __u32 &ycbcr,
760 	      __u32 &quantization, __u32 &flags, __u32 *bytesperline,
761 	      __u32 *sizeimage)
762 {
763 	char *value, *subs;
764 	int fmts = 0;
765 	unsigned bpl_index = 0;
766 	unsigned sizeimage_index = 0;
767 	bool be_pixfmt;
768 
769 	field = V4L2_FIELD_ANY;
770 	flags = 0;
771 	subs = optarg;
772 	while (*subs != '\0') {
773 		static constexpr const char *subopts[] = {
774 			"width",
775 			"height",
776 			"pixelformat",
777 			"field",
778 			"colorspace",
779 			"ycbcr",
780 			"hsv",
781 			"bytesperline",
782 			"premul-alpha",
783 			"quantization",
784 			"xfer",
785 			"sizeimage",
786 			nullptr
787 		};
788 
789 		switch (parse_subopt(&subs, subopts, &value)) {
790 		case 0:
791 			width = strtoul(value, nullptr, 0);
792 			fmts |= FmtWidth;
793 			break;
794 		case 1:
795 			height = strtoul(value, nullptr, 0);
796 			fmts |= FmtHeight;
797 			break;
798 		case 2:
799 			be_pixfmt = strlen(value) == 7 && !memcmp(value + 4, "-BE", 3);
800 			if (be_pixfmt || strlen(value) == 4) {
801 				pixelformat =
802 					v4l2_fourcc(value[0], value[1],
803 						    value[2], value[3]);
804 				if (be_pixfmt)
805 					pixelformat |= 1U << 31;
806 			} else if (isdigit(value[0])) {
807 				pixelformat = strtol(value, nullptr, 0);
808 			} else {
809 				fprintf(stderr, "The pixelformat '%s' is invalid\n", value);
810 				std::exit(EXIT_FAILURE);
811 			}
812 			fmts |= FmtPixelFormat;
813 			break;
814 		case 3:
815 			field = parse_field(value);
816 			fmts |= FmtField;
817 			break;
818 		case 4:
819 			colorspace = parse_colorspace(value);
820 			if (colorspace)
821 				fmts |= FmtColorspace;
822 			else
823 				fprintf(stderr, "unknown colorspace %s\n", value);
824 			break;
825 		case 5:
826 			ycbcr = parse_ycbcr(value);
827 			fmts |= FmtYCbCr;
828 			break;
829 		case 6:
830 			ycbcr = parse_hsv(value);
831 			fmts |= FmtYCbCr;
832 			break;
833 		case 7:
834 			bytesperline[bpl_index] = strtoul(value, nullptr, 0);
835 			if (bytesperline[bpl_index] > 0xffff) {
836 				fprintf(stderr, "bytesperline can't be more than 65535\n");
837 				bytesperline[bpl_index] = 0;
838 			}
839 			bpl_index++;
840 			fmts |= FmtBytesPerLine;
841 			break;
842 		case 8:
843 			if (strtoul(value, nullptr, 0))
844 				flags |= V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
845 			else
846 				flags &= ~V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
847 			fmts |= FmtFlags;
848 			break;
849 		case 9:
850 			quantization = parse_quantization(value);
851 			fmts |= FmtQuantization;
852 			break;
853 		case 10:
854 			xfer_func = parse_xfer_func(value);
855 			fmts |= FmtXferFunc;
856 			break;
857 		case 11:
858 			sizeimage[sizeimage_index] = strtoul(value, nullptr, 0);
859 			sizeimage_index++;
860 			fmts |= FmtSizeImage;
861 			break;
862 		default:
863 			return 0;
864 		}
865 	}
866 	return fmts;
867 }
868 
parse_selection_flags(const char * s)869 int parse_selection_flags(const char *s)
870 {
871 	if (!strcmp(s, "le")) return V4L2_SEL_FLAG_LE;
872 	if (!strcmp(s, "ge")) return V4L2_SEL_FLAG_GE;
873 	if (!strcmp(s, "keep-config")) return V4L2_SEL_FLAG_KEEP_CONFIG;
874 	return 0;
875 }
876 
print_selection(const struct v4l2_selection & sel)877 void print_selection(const struct v4l2_selection &sel)
878 {
879 	printf("Selection %s: %s, Left %d, Top %d, Width %d, Height %d, Flags: %s\n",
880 			buftype2s(sel.type).c_str(), seltarget2s(sel.target).c_str(),
881 			sel.r.left, sel.r.top, sel.r.width, sel.r.height,
882 			selflags2s(sel.flags).c_str());
883 }
884 
parse_selection_target(const char * s,unsigned int & target)885 int parse_selection_target(const char *s, unsigned int &target)
886 {
887 	if (!strcmp(s, "crop")) target = V4L2_SEL_TGT_CROP_ACTIVE;
888 	else if (!strcmp(s, "crop_default")) target = V4L2_SEL_TGT_CROP_DEFAULT;
889 	else if (!strcmp(s, "crop_bounds")) target = V4L2_SEL_TGT_CROP_BOUNDS;
890 	else if (!strcmp(s, "compose")) target = V4L2_SEL_TGT_COMPOSE_ACTIVE;
891 	else if (!strcmp(s, "compose_default")) target = V4L2_SEL_TGT_COMPOSE_DEFAULT;
892 	else if (!strcmp(s, "compose_bounds")) target = V4L2_SEL_TGT_COMPOSE_BOUNDS;
893 	else if (!strcmp(s, "compose_padded")) target = V4L2_SEL_TGT_COMPOSE_PADDED;
894 	else if (!strcmp(s, "native_size")) target = V4L2_SEL_TGT_NATIVE_SIZE;
895 	else return -EINVAL;
896 
897 	return 0;
898 }
899 
900 
print_event(int fd,const struct v4l2_event * ev)901 static void print_event(int fd, const struct v4l2_event *ev)
902 {
903 	printf("%lld.%06ld: event %u, pending %u: ",
904 			static_cast<__u64>(ev->timestamp.tv_sec), ev->timestamp.tv_nsec / 1000,
905 			ev->sequence, ev->pending);
906 	switch (ev->type) {
907 	case V4L2_EVENT_VSYNC:
908 		printf("vsync %s\n", field2s(ev->u.vsync.field).c_str());
909 		break;
910 	case V4L2_EVENT_EOS:
911 		printf("eos\n");
912 		break;
913 	case V4L2_EVENT_CTRL:
914 		common_control_event(fd, ev);
915 		break;
916 	case V4L2_EVENT_FRAME_SYNC:
917 		printf("frame_sync %d\n", ev->u.frame_sync.frame_sequence);
918 		break;
919 	case V4L2_EVENT_SOURCE_CHANGE:
920 		printf("source_change: pad/input=%d changes: %x\n", ev->id, ev->u.src_change.changes);
921 		break;
922 	case V4L2_EVENT_MOTION_DET:
923 		if (ev->u.motion_det.flags & V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ)
924 			printf("motion_det frame %d, regions 0x%x\n",
925 					ev->u.motion_det.frame_sequence,
926 					ev->u.motion_det.region_mask);
927 		else
928 			printf("motion_det regions 0x%x\n", ev->u.motion_det.region_mask);
929 		break;
930 	default:
931 		if (ev->type >= V4L2_EVENT_PRIVATE_START)
932 			printf("unknown private event (%08x)\n", ev->type);
933 		else
934 			printf("unknown event (%08x)\n", ev->type);
935 		break;
936 	}
937 }
938 
parse_event(const char * e,const char ** name)939 static __u32 parse_event(const char *e, const char **name)
940 {
941 	__u32 event = 0;
942 
943 	*name = "0";
944 	if (isdigit(e[0])) {
945 		event = strtoul(e, nullptr, 0);
946 		if (event == V4L2_EVENT_CTRL) {
947 			fprintf(stderr, "Missing control name for ctrl event, use ctrl=<name>\n");
948 			misc_usage();
949 			std::exit(EXIT_FAILURE);
950 		}
951 	} else if (!strcmp(e, "eos")) {
952 		event = V4L2_EVENT_EOS;
953 	} else if (!strcmp(e, "vsync")) {
954 		event = V4L2_EVENT_VSYNC;
955 	} else if (!strcmp(e, "frame_sync")) {
956 		event = V4L2_EVENT_FRAME_SYNC;
957 	} else if (!strcmp(e, "motion_det")) {
958 		event = V4L2_EVENT_MOTION_DET;
959 	} else if (!strncmp(e, "ctrl=", 5)) {
960 		event = V4L2_EVENT_CTRL;
961 		*name = e + 5;
962 	} else if (!strncmp(e, "source_change=", 14)) {
963 		event = V4L2_EVENT_SOURCE_CHANGE;
964 		*name = e + 14;
965 	} else if (!strcmp(e, "source_change")) {
966 		event = V4L2_EVENT_SOURCE_CHANGE;
967 	}
968 
969 	if (event == 0) {
970 		fprintf(stderr, "Unknown event\n");
971 		misc_usage();
972 		std::exit(EXIT_FAILURE);
973 	}
974 	return event;
975 }
976 
valid_pixel_format(int fd,__u32 pixelformat,bool output,bool mplane)977 bool valid_pixel_format(int fd, __u32 pixelformat, bool output, bool mplane)
978 {
979 	struct v4l2_fmtdesc fmt = {};
980 
981 	if (output)
982 		fmt.type = mplane ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
983 			V4L2_BUF_TYPE_VIDEO_OUTPUT;
984 	else
985 		fmt.type = mplane ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
986 			V4L2_BUF_TYPE_VIDEO_CAPTURE;
987 
988 	while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmt)) {
989 		if (fmt.pixelformat == pixelformat)
990 			return true;
991 		fmt.index++;
992 	}
993 	return false;
994 }
995 
find_pixel_format(int fd,unsigned index,bool output,bool mplane)996 __u32 find_pixel_format(int fd, unsigned index, bool output, bool mplane)
997 {
998 	struct v4l2_fmtdesc fmt = {};
999 
1000 	fmt.index = index;
1001 	if (output)
1002 		fmt.type = mplane ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1003 			V4L2_BUF_TYPE_VIDEO_OUTPUT;
1004 	else
1005 		fmt.type = mplane ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1006 			V4L2_BUF_TYPE_VIDEO_CAPTURE;
1007 
1008 	if (ioctl(fd, VIDIOC_ENUM_FMT, &fmt))
1009 		return 0;
1010 	return fmt.pixelformat;
1011 }
1012 
open_media_bus_info(const std::string & bus_info)1013 static int open_media_bus_info(const std::string &bus_info)
1014 {
1015 	DIR *dp;
1016 	struct dirent *ep;
1017 
1018 	dp = opendir("/dev");
1019 	if (dp == nullptr)
1020 		return -1;
1021 
1022 	while ((ep = readdir(dp))) {
1023 		const char *name = ep->d_name;
1024 
1025 		if (!memcmp(name, "media", 5) && isdigit(name[5])) {
1026 			struct media_device_info mdi;
1027 			std::string devname = std::string("/dev/") + name;
1028 
1029 			int fd = open(devname.c_str(), O_RDWR);
1030 			if (fd < 0)
1031 				continue;
1032 			if (!ioctl(fd, MEDIA_IOC_DEVICE_INFO, &mdi) &&
1033 			    bus_info == mdi.bus_info) {
1034 				closedir(dp);
1035 				return fd;
1036 			}
1037 			close(fd);
1038 		}
1039 	}
1040 	closedir(dp);
1041 	return -1;
1042 }
1043 
make_devname(const char * device,const char * devname,const std::string & media_bus_info)1044 static const char *make_devname(const char *device, const char *devname,
1045 				      const std::string &media_bus_info)
1046 {
1047 	if (device[0] >= '0' && device[0] <= '9' && strlen(device) <= 3) {
1048 		static char newdev[32];
1049 
1050 		sprintf(newdev, "/dev/%s%s", devname, device);
1051 		return newdev;
1052 	}
1053 	if (media_bus_info.empty())
1054 		return device;
1055 	int media_fd = open_media_bus_info(media_bus_info);
1056 	if (media_fd < 0)
1057 		return device;
1058 
1059 	media_v2_topology topology;
1060 	memset(&topology, 0, sizeof(topology));
1061 	if (ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology)) {
1062 		close(media_fd);
1063 		return device;
1064 	}
1065 
1066 	auto ents = new media_v2_entity[topology.num_entities];
1067 	topology.ptr_entities = (uintptr_t)ents;
1068 	auto links = new media_v2_link[topology.num_links];
1069 	topology.ptr_links = (uintptr_t)links;
1070 	auto ifaces = new media_v2_interface[topology.num_interfaces];
1071 	topology.ptr_interfaces = (uintptr_t)ifaces;
1072 
1073 	unsigned i, ent_id, iface_id = 0;
1074 
1075 	if (ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology))
1076 		goto err;
1077 
1078 	if (device[0] == '0' && device[1] == 'x')
1079 		iface_id = strtoul(device, nullptr, 16);
1080 
1081 	if (!iface_id) {
1082 		for (i = 0; i < topology.num_entities; i++)
1083 			if (!strcmp(ents[i].name, device))
1084 				break;
1085 		if (i >= topology.num_entities)
1086 			goto err;
1087 		ent_id = ents[i].id;
1088 		for (i = 0; i < topology.num_links; i++)
1089 			if (links[i].sink_id == ent_id &&
1090 			    (links[i].flags & MEDIA_LNK_FL_LINK_TYPE) ==
1091 			    MEDIA_LNK_FL_INTERFACE_LINK)
1092 				break;
1093 		if (i >= topology.num_links)
1094 			goto err;
1095 		iface_id = links[i].source_id;
1096 	}
1097 	for (i = 0; i < topology.num_interfaces; i++)
1098 		if (ifaces[i].id == iface_id)
1099 			break;
1100 	if (i >= topology.num_interfaces)
1101 		goto err;
1102 
1103 	static char newdev[32];
1104 	sprintf(newdev, "/dev/char/%d:%d",
1105 		ifaces[i].devnode.major, ifaces[i].devnode.minor);
1106 	device = newdev;
1107 
1108 err:
1109 	delete [] ents;
1110 	delete [] links;
1111 	delete [] ifaces;
1112 	close(media_fd);
1113 	return device;
1114 }
1115 
main(int argc,char ** argv)1116 int main(int argc, char **argv)
1117 {
1118 	struct event {
1119 		int type;
1120 		__u32 ev;
1121 		__u32 id;
1122 		std::string name;
1123 	};
1124 	int i;
1125 	cv4l_fd c_fd;
1126 	cv4l_fd c_out_fd;
1127 	cv4l_fd c_exp_fd;
1128 	int fd = -1;
1129 	int out_fd = -1;
1130 	int exp_fd = -1;
1131 	int media_fd = -1;
1132 	bool is_subdev = false;
1133 	std::string media_bus_info;
1134 
1135 	/* command args */
1136 	int ch;
1137 	const char *device = "/dev/video0";	/* -d device */
1138 	const char *out_device = nullptr;
1139 	const char *export_device = nullptr;
1140 	struct v4l2_capability vcap = {};
1141 	struct v4l2_subdev_capability subdevcap = {};
1142 	struct v4l2_subdev_client_capability subdevclientcap = {};
1143 	std::vector<event> events;
1144 	unsigned secs = 0;
1145 	char short_options[26 * 2 * 3 + 1];
1146 	int idx = 0;
1147 
1148 	if (argc == 1) {
1149 		common_usage();
1150 		return 0;
1151 	}
1152 	for (i = 0; long_options[i].name; i++) {
1153 		if (!isalpha(long_options[i].val))
1154 			continue;
1155 		short_options[idx++] = long_options[i].val;
1156 		if (long_options[i].has_arg == required_argument) {
1157 			short_options[idx++] = ':';
1158 		} else if (long_options[i].has_arg == optional_argument) {
1159 			short_options[idx++] = ':';
1160 			short_options[idx++] = ':';
1161 		}
1162 	}
1163 	while (true) {
1164 		int option_index = 0;
1165 		const char *name;
1166 		event new_ev;
1167 
1168 		short_options[idx] = 0;
1169 		ch = getopt_long(argc, argv, short_options,
1170 				 long_options, &option_index);
1171 		if (ch == -1)
1172 			break;
1173 
1174 		options[ch] = 1;
1175 		if (!option_index) {
1176 			for (i = 0; long_options[i].val; i++) {
1177 				if (long_options[i].val == ch) {
1178 					option_index = i;
1179 					break;
1180 				}
1181 			}
1182 		}
1183 		if (long_options[option_index].has_arg == optional_argument &&
1184 		    !optarg && argv[optind] && argv[optind][0] != '-')
1185 			optarg = argv[optind++];
1186 
1187 		switch (ch) {
1188 		case OptHelp:
1189 			common_usage();
1190 			return 0;
1191 		case OptHelpTuner:
1192 			tuner_usage();
1193 			return 0;
1194 		case OptHelpIO:
1195 			io_usage();
1196 			return 0;
1197 		case OptHelpStds:
1198 			stds_usage();
1199 			return 0;
1200 		case OptHelpVidCap:
1201 			vidcap_usage();
1202 			return 0;
1203 		case OptHelpVidOut:
1204 			vidout_usage();
1205 			return 0;
1206 		case OptHelpOverlay:
1207 			overlay_usage();
1208 			return 0;
1209 		case OptHelpVbi:
1210 			vbi_usage();
1211 			return 0;
1212 		case OptHelpSdr:
1213 			sdr_usage();
1214 			return 0;
1215 		case OptHelpMeta:
1216 			meta_usage();
1217 			return 0;
1218 		case OptHelpSubDev:
1219 			subdev_usage();
1220 			return 0;
1221 		case OptHelpSelection:
1222 			selection_usage();
1223 			return 0;
1224 		case OptHelpMisc:
1225 			misc_usage();
1226 			return 0;
1227 		case OptHelpStreaming:
1228 			streaming_usage();
1229 			return 0;
1230 		case OptHelpEdid:
1231 			edid_usage();
1232 			return 0;
1233 		case OptHelpAll:
1234 			usage_all();
1235 			return 0;
1236 		case OptSetDevice:
1237 			device = make_devname(optarg, "video", media_bus_info);
1238 			break;
1239 		case OptSetOutDevice:
1240 			out_device = make_devname(optarg, "video", media_bus_info);
1241 			break;
1242 		case OptSetExportDevice:
1243 			export_device = make_devname(optarg, "video", media_bus_info);
1244 			break;
1245 		case OptMediaBusInfo:
1246 			media_bus_info = optarg;
1247 			break;
1248 		case OptWaitForEvent:
1249 		case OptPollForEvent:
1250 		case OptEPollForEvent:
1251 			new_ev.type = ch;
1252 			new_ev.ev = parse_event(optarg, &name);
1253 			new_ev.id = 0;
1254 			if (new_ev.ev == 0)
1255 				return 1;
1256 			if (new_ev.ev == V4L2_EVENT_SOURCE_CHANGE)
1257 				new_ev.id = strtoul(name, nullptr, 0);
1258 			else if (new_ev.ev == V4L2_EVENT_CTRL)
1259 				new_ev.name = name;
1260 			events.push_back(new_ev);
1261 			break;
1262 		case OptSleep:
1263 			secs = strtoul(optarg, nullptr, 0);
1264 			break;
1265 		case OptVersion:
1266 			print_version();
1267 			return 0;
1268 		case ':':
1269 			fprintf(stderr, "Option '%s' requires a value\n",
1270 					argv[optind]);
1271 			common_usage();
1272 			return 1;
1273 		case '?':
1274 			if (argv[optind])
1275 				fprintf(stderr, "Unknown argument '%s'\n", argv[optind]);
1276 			common_usage();
1277 			return 1;
1278 		default:
1279 			common_cmd(ch, optarg);
1280 			tuner_cmd(ch, optarg);
1281 			io_cmd(ch, optarg);
1282 			stds_cmd(ch, optarg);
1283 			vidcap_cmd(ch, optarg);
1284 			vidout_cmd(ch, optarg);
1285 			overlay_cmd(ch, optarg);
1286 			vbi_cmd(ch, optarg);
1287 			sdr_cmd(ch, optarg);
1288 			meta_cmd(ch, optarg);
1289 			subdev_cmd(ch, optarg);
1290 			selection_cmd(ch, optarg);
1291 			misc_cmd(ch, optarg);
1292 			streaming_cmd(ch, optarg);
1293 			edid_cmd(ch, optarg);
1294 			break;
1295 		}
1296 	}
1297 	if (optind < argc) {
1298 		printf("unknown arguments: ");
1299 		while (optind < argc)
1300 			printf("%s ", argv[optind++]);
1301 		printf("\n");
1302 		common_usage();
1303 		return 1;
1304 	}
1305 
1306 	media_type type = mi_media_detect_type(device);
1307 	if (type == MEDIA_TYPE_CANT_STAT) {
1308 		fprintf(stderr, "Cannot open device %s, exiting.\n",
1309 			device);
1310 		std::exit(EXIT_FAILURE);
1311 	}
1312 
1313 	switch (type) {
1314 		// For now we can only handle V4L2 devices
1315 	case MEDIA_TYPE_VIDEO:
1316 	case MEDIA_TYPE_VBI:
1317 	case MEDIA_TYPE_RADIO:
1318 	case MEDIA_TYPE_SDR:
1319 	case MEDIA_TYPE_TOUCH:
1320 	case MEDIA_TYPE_SUBDEV:
1321 		break;
1322 	default:
1323 		type = MEDIA_TYPE_UNKNOWN;
1324 		break;
1325 	}
1326 
1327 	if (type == MEDIA_TYPE_UNKNOWN) {
1328 		fprintf(stderr, "Unable to detect what device %s is, exiting.\n",
1329 			device);
1330 		std::exit(EXIT_FAILURE);
1331 	}
1332 	is_subdev = type == MEDIA_TYPE_SUBDEV;
1333 	if (is_subdev)
1334 		options[OptUseWrapper] = 0;
1335 	c_fd.s_direct(!options[OptUseWrapper]);
1336 	c_out_fd.s_direct(!options[OptUseWrapper]);
1337 	c_exp_fd.s_direct(!options[OptUseWrapper]);
1338 
1339 	if (is_subdev)
1340 		fd = c_fd.subdev_open(device);
1341 	else
1342 		fd = c_fd.open(device);
1343 
1344 	if (fd < 0) {
1345 		fprintf(stderr, "Failed to open %s: %s\n", device,
1346 			strerror(errno));
1347 		std::exit(EXIT_FAILURE);
1348 	}
1349 	verbose = options[OptVerbose];
1350 	c_fd.s_trace(options[OptSilent] ? 0 : (verbose ? 2 : 1));
1351 
1352 	if (!is_subdev && doioctl(fd, VIDIOC_QUERYCAP, &vcap)) {
1353 		fprintf(stderr, "%s: not a v4l2 node\n", device);
1354 		std::exit(EXIT_FAILURE);
1355 	} else if (is_subdev) {
1356 		// This ioctl was introduced in kernel 5.10, so don't
1357 		// exit if this ioctl returns an error.
1358 		doioctl(fd, VIDIOC_SUBDEV_QUERYCAP, &subdevcap);
1359 		subdevclientcap.capabilities = ~0ULL;
1360 		if (doioctl(fd, VIDIOC_SUBDEV_S_CLIENT_CAP, &subdevclientcap))
1361 			subdevclientcap.capabilities = 0ULL;
1362 	}
1363 	if (!is_subdev) {
1364 		capabilities = vcap.capabilities;
1365 		if (capabilities & V4L2_CAP_DEVICE_CAPS)
1366 			capabilities = vcap.device_caps;
1367 	}
1368 
1369 	media_fd = mi_get_media_fd(fd, is_subdev ? 0 : (const char *)vcap.bus_info);
1370 
1371 	priv_magic = (capabilities & V4L2_CAP_EXT_PIX_FORMAT) ?
1372 			V4L2_PIX_FMT_PRIV_MAGIC : 0;
1373 	is_multiplanar = capabilities & (V4L2_CAP_VIDEO_CAPTURE_MPLANE |
1374 					 V4L2_CAP_VIDEO_M2M_MPLANE |
1375 					 V4L2_CAP_VIDEO_OUTPUT_MPLANE);
1376 
1377 	vidcap_buftype = is_multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
1378 					  V4L2_BUF_TYPE_VIDEO_CAPTURE;
1379 	vidout_buftype = is_multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
1380 					  V4L2_BUF_TYPE_VIDEO_OUTPUT;
1381 
1382 	if (out_device) {
1383 		out_fd = c_out_fd.open(out_device);
1384 		if (out_fd < 0) {
1385 			fprintf(stderr, "Failed to open %s: %s\n", out_device,
1386 					strerror(errno));
1387 			std::exit(EXIT_FAILURE);
1388 		}
1389 		c_out_fd.s_trace(options[OptSilent] ? 0 : (verbose ? 2 : 1));
1390 		if (doioctl(out_fd, VIDIOC_QUERYCAP, &vcap)) {
1391 			fprintf(stderr, "%s: not a v4l2 node\n", out_device);
1392 			std::exit(EXIT_FAILURE);
1393 		}
1394 		out_capabilities = vcap.capabilities;
1395 		if (out_capabilities & V4L2_CAP_DEVICE_CAPS)
1396 			out_capabilities = vcap.device_caps;
1397 		out_priv_magic = (out_capabilities & V4L2_CAP_EXT_PIX_FORMAT) ?
1398 				V4L2_PIX_FMT_PRIV_MAGIC : 0;
1399 	}
1400 
1401 	if (export_device) {
1402 		exp_fd = c_exp_fd.open(export_device);
1403 		if (exp_fd < 0) {
1404 			fprintf(stderr, "Failed to open %s: %s\n", export_device,
1405 					strerror(errno));
1406 			std::exit(EXIT_FAILURE);
1407 		}
1408 		c_exp_fd.s_trace(options[OptSilent] ? 0 : (verbose ? 2 : 1));
1409 		if (doioctl(exp_fd, VIDIOC_QUERYCAP, &vcap)) {
1410 			fprintf(stderr, "%s: not a v4l2 node\n", export_device);
1411 			std::exit(EXIT_FAILURE);
1412 		}
1413 	}
1414 
1415 	common_process_controls(c_fd);
1416 
1417 	for (auto &e : events) {
1418 		if (e.ev != V4L2_EVENT_CTRL)
1419 			continue;
1420 		e.id = common_find_ctrl_id(e.name.c_str());
1421 		if (!e.id) {
1422 			fprintf(stderr, "unknown control '%s'\n", e.name.c_str());
1423 			std::exit(EXIT_FAILURE);
1424 		}
1425 	}
1426 
1427 	if (options[OptAll]) {
1428 		options[OptGetVideoFormat] = 1;
1429 		options[OptGetVideoOutFormat] = 1;
1430 		options[OptGetDriverInfo] = 1;
1431 		options[OptGetInput] = 1;
1432 		options[OptGetOutput] = 1;
1433 		options[OptGetAudioInput] = 1;
1434 		options[OptGetAudioOutput] = 1;
1435 		options[OptGetStandard] = 1;
1436 		options[OptGetParm] = 1;
1437 		options[OptGetOutputParm] = 1;
1438 		options[OptGetFreq] = 1;
1439 		options[OptGetTuner] = 1;
1440 		options[OptGetModulator] = 1;
1441 		options[OptGetOverlayFormat] = 1;
1442 		options[OptGetVbiFormat] = 1;
1443 		options[OptGetVbiOutFormat] = 1;
1444 		options[OptGetSlicedVbiFormat] = 1;
1445 		options[OptGetSlicedVbiOutFormat] = 1;
1446 		options[OptGetSdrFormat] = 1;
1447 		options[OptGetSdrOutFormat] = 1;
1448 		options[OptGetMetaFormat] = 1;
1449 		options[OptGetMetaOutFormat] = 1;
1450 		options[OptGetFBuf] = 1;
1451 		options[OptGetCropCap] = 1;
1452 		options[OptGetOutputCropCap] = 1;
1453 		options[OptGetJpegComp] = 1;
1454 		options[OptGetDvTimings] = 1;
1455 		options[OptGetDvTimingsCap] = 1;
1456 		options[OptGetPriority] = 1;
1457 		options[OptGetSelection] = 1;
1458 		options[OptGetOutputSelection] = 1;
1459 		options[OptListCtrlsMenus] = 1;
1460 		options[OptSilent] = 1;
1461 	}
1462 
1463 	/* Information Opts */
1464 
1465 	if (options[OptGetDriverInfo]) {
1466 		printf("Driver Info%s:\n",
1467 				options[OptUseWrapper] ? " (using libv4l2)" : "");
1468 		if (is_subdev) {
1469 			v4l2_info_subdev_capability(subdevcap, subdevclientcap);
1470 		} else {
1471 			v4l2_info_capability(vcap);
1472 		}
1473 	}
1474 	if (options[OptGetDriverInfo] && media_fd >= 0)
1475 		mi_media_info_for_fd(media_fd, fd);
1476 
1477 	/* Set options */
1478 
1479 	common_set(c_fd);
1480 	tuner_set(c_fd);
1481 	io_set(c_fd);
1482 	stds_set(c_fd);
1483 	vidcap_set(c_fd);
1484 	vidout_set(out_device ? c_out_fd : c_fd);
1485 	overlay_set(c_fd);
1486 	vbi_set(c_fd);
1487 	sdr_set(c_fd);
1488 	meta_set(c_fd);
1489 	subdev_set(c_fd);
1490 	selection_set(c_fd);
1491 	misc_set(c_fd);
1492 	edid_set(c_fd);
1493 
1494 	/* Get options */
1495 
1496 	common_get(c_fd);
1497 	tuner_get(c_fd);
1498 	io_get(c_fd);
1499 	stds_get(c_fd);
1500 	vidcap_get(c_fd);
1501 	vidout_get(out_device ? c_out_fd : c_fd);
1502 	overlay_get(c_fd);
1503 	vbi_get(c_fd);
1504 	sdr_get(c_fd);
1505 	meta_get(c_fd);
1506 	subdev_get(c_fd);
1507 	selection_get(c_fd);
1508 	misc_get(c_fd);
1509 	edid_get(c_fd);
1510 
1511 	/* List options */
1512 
1513 	common_list(media_bus_info, c_fd);
1514 	io_list(c_fd);
1515 	stds_list(c_fd);
1516 	vidcap_list(c_fd);
1517 	vidout_list(out_device ? c_out_fd : c_fd);
1518 	overlay_list(c_fd);
1519 	vbi_list(c_fd);
1520 	sdr_list(c_fd);
1521 	meta_list(c_fd);
1522 	subdev_list(c_fd);
1523 	streaming_list(c_fd, c_out_fd);
1524 
1525 	/* Special case: handled last */
1526 
1527 	streaming_set(c_fd, c_out_fd, c_exp_fd);
1528 
1529 	for (const auto &e : events) {
1530 		struct v4l2_event_subscription sub;
1531 		struct v4l2_event ev;
1532 
1533 		if (e.type != OptWaitForEvent)
1534 			continue;
1535 		memset(&sub, 0, sizeof(sub));
1536 		sub.type = e.ev;
1537 		sub.id = e.id;
1538 		if (!doioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub))
1539 			if (!doioctl(fd, VIDIOC_DQEVENT, &ev))
1540 				print_event(fd, &ev);
1541 		doioctl(fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub);
1542 	}
1543 
1544 	for (const auto &e : events) {
1545 		struct v4l2_event_subscription sub;
1546 
1547 		if (e.type == OptWaitForEvent)
1548 			continue;
1549 		memset(&sub, 0, sizeof(sub));
1550 		sub.flags = V4L2_EVENT_SUB_FL_SEND_INITIAL;
1551 		sub.type = e.ev;
1552 		sub.id = e.id;
1553 		doioctl(fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
1554 	}
1555 
1556 	if (options[OptPollForEvent]) {
1557 		fd_set fds;
1558 		__u32 seq = 0;
1559 
1560 		fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
1561 		while (true) {
1562 			struct v4l2_event ev;
1563 			int res;
1564 
1565 			FD_ZERO(&fds);
1566 			FD_SET(fd, &fds);
1567 			res = select(fd + 1, nullptr, nullptr, &fds, nullptr);
1568 			if (res <= 0)
1569 				break;
1570 			if (doioctl(fd, VIDIOC_DQEVENT, &ev))
1571 				break;
1572 			print_event(fd, &ev);
1573 			if (ev.sequence > seq)
1574 				printf("\tMissed %d events\n", ev.sequence - seq);
1575 			seq = ev.sequence + 1;
1576 		}
1577 	}
1578 
1579 	if (options[OptEPollForEvent]) {
1580 		struct epoll_event epoll_ev;
1581 		int epollfd = -1;
1582 		__u32 seq = 0;
1583 
1584 		epollfd = epoll_create1(0);
1585 		epoll_ev.events = EPOLLPRI;
1586 		epoll_ev.data.fd = fd;
1587 
1588 		fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
1589 		epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &epoll_ev);
1590 		while (true) {
1591 			struct v4l2_event ev;
1592 			int res;
1593 
1594 			res = epoll_wait(epollfd, &epoll_ev, 1, -1);
1595 			if (res <= 0)
1596 				break;
1597 			if (doioctl(fd, VIDIOC_DQEVENT, &ev))
1598 				break;
1599 			print_event(fd, &ev);
1600 			if (ev.sequence > seq)
1601 				printf("\tMissed %d events\n", ev.sequence - seq);
1602 			seq = ev.sequence + 1;
1603 		}
1604 		close(epollfd);
1605 	}
1606 
1607 	if (options[OptSleep]) {
1608 		sleep(secs);
1609 		printf("Test VIDIOC_QUERYCAP:\n");
1610 		if (c_fd.querycap(vcap, true) == 0)
1611 			printf("\tDriver name   : %s\n", vcap.driver);
1612 		else
1613 			perror("VIDIOC_QUERYCAP");
1614 	}
1615 
1616 	c_fd.close();
1617 	if (out_device)
1618 		c_out_fd.close();
1619 	if (export_device)
1620 		c_exp_fd.close();
1621 	if (media_fd >= 0)
1622 		close(media_fd);
1623 
1624 	// --all sets --silent to avoid ioctl errors to be shown when an ioctl
1625 	// is not implemented by the driver. Which is fine, but we shouldn't
1626 	// return an application error in that specific case.
1627 	std::exit(options[OptAll] ? 0 : app_result);
1628 }
1629