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