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