1 /*
2 V4L2 API compliance test tool.
3
4 Copyright (C) 2008, 2010 Hans Verkuil <hverkuil@xs4all.nl>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
19 */
20
21 #include <cctype>
22 #include <csignal>
23 #include <cstring>
24 #include <map>
25 #include <set>
26 #include <vector>
27
28 #include <dirent.h>
29 #include <getopt.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32
33 #include "v4l2-compliance.h"
34 #include <media-info.h>
35 #include <v4l-getsubopt.h>
36
37 /* Short option list
38
39 Please keep in alphabetical order.
40 That makes it easier to see which short options are still free.
41
42 In general the lower case is used to set something and the upper
43 case is used to retrieve a setting. */
44 enum Option {
45 OptStreamAllIO = 'a',
46 OptStreamAllColorTest = 'c',
47 OptColor = 'C',
48 OptSetDevice = 'd',
49 OptSetExpBufDevice = 'e',
50 OptExitOnFail = 'E',
51 OptStreamAllFormats = 'f',
52 OptHelp = 'h',
53 OptSetMediaDevice = 'm',
54 OptSetMediaDeviceOnly = 'M',
55 OptNoWarnings = 'n',
56 OptNoProgress = 'P',
57 OptSetRadioDevice = 'r',
58 OptStreaming = 's',
59 OptSetSWRadioDevice = 'S',
60 OptSetTouchDevice = 't',
61 OptTrace = 'T',
62 OptSetSubDevDevice = 'u',
63 OptVerbose = 'v',
64 OptSetVbiDevice = 'V',
65 OptUseWrapper = 'w',
66 OptExitOnWarn = 'W',
67 OptMediaBusInfo = 'z',
68 OptStreamFrom = 128,
69 OptStreamFromHdr,
70 OptVersion,
71 OptLast = 256
72 };
73
74 static char options[OptLast];
75
76 static int app_result;
77 static int tests_total, tests_ok;
78 static int grand_total, grand_ok, grand_warnings;
79
80 // Globals
81 bool show_info;
82 bool no_progress;
83 bool show_warnings = true;
84 bool show_colors;
85 bool exit_on_fail;
86 bool exit_on_warn;
87 bool is_vivid;
88 bool is_uvcvideo;
89 int media_fd = -1;
90 unsigned warnings;
91 bool has_mmu = true;
92
93 static unsigned color_component;
94 static unsigned color_skip;
95 static unsigned color_perc = 90;
96
97 struct dev_state {
98 struct node *node;
99 std::vector<v4l2_ext_control> control_vec;
100 v4l2_ext_controls controls;
101 v4l2_rect crop;
102 v4l2_rect compose;
103 v4l2_rect native_size;
104 v4l2_format fmt;
105 v4l2_input input;
106 v4l2_output output;
107 v4l2_audio ainput;
108 v4l2_audioout aoutput;
109 v4l2_frequency freq;
110 v4l2_tuner tuner;
111 v4l2_modulator modulator;
112 v4l2_std_id std;
113 v4l2_dv_timings timings;
114 v4l2_fract interval;
115 };
116
117 static struct dev_state state;
118
119 static struct option long_options[] = {
120 {"device", required_argument, nullptr, OptSetDevice},
121 {"radio-device", required_argument, nullptr, OptSetRadioDevice},
122 {"vbi-device", required_argument, nullptr, OptSetVbiDevice},
123 {"sdr-device", required_argument, nullptr, OptSetSWRadioDevice},
124 {"subdev-device", required_argument, nullptr, OptSetSubDevDevice},
125 {"expbuf-device", required_argument, nullptr, OptSetExpBufDevice},
126 {"touch-device", required_argument, nullptr, OptSetTouchDevice},
127 {"media-device", required_argument, nullptr, OptSetMediaDevice},
128 {"media-device-only", required_argument, nullptr, OptSetMediaDeviceOnly},
129 {"media-bus-info", required_argument, nullptr, OptMediaBusInfo},
130 {"help", no_argument, nullptr, OptHelp},
131 {"verbose", no_argument, nullptr, OptVerbose},
132 {"color", required_argument, nullptr, OptColor},
133 {"no-warnings", no_argument, nullptr, OptNoWarnings},
134 {"no-progress", no_argument, nullptr, OptNoProgress},
135 {"exit-on-fail", no_argument, nullptr, OptExitOnFail},
136 {"exit-on-warn", no_argument, nullptr, OptExitOnWarn},
137 {"trace", no_argument, nullptr, OptTrace},
138 #ifndef NO_LIBV4L2
139 {"wrapper", no_argument, nullptr, OptUseWrapper},
140 #endif
141 {"streaming", optional_argument, nullptr, OptStreaming},
142 {"stream-from", required_argument, nullptr, OptStreamFrom},
143 {"stream-from-hdr", required_argument, nullptr, OptStreamFromHdr},
144 {"stream-all-formats", optional_argument, nullptr, OptStreamAllFormats},
145 {"stream-all-io", no_argument, nullptr, OptStreamAllIO},
146 {"stream-all-color", required_argument, nullptr, OptStreamAllColorTest},
147 {"version", no_argument, nullptr, OptVersion},
148 {nullptr, 0, nullptr, 0}
149 };
150
151 #define STR(x) #x
152 #define STRING(x) STR(x)
153
print_sha()154 static void print_sha()
155 {
156 int fd = open("/dev/null", O_RDONLY);
157
158 if (fd >= 0) {
159 // FIONBIO is a write-only ioctl that takes an int argument that
160 // enables (!= 0) or disables (== 0) nonblocking mode of a fd.
161 //
162 // Passing a nullptr should return EFAULT on MMU capable machines,
163 // and it works if there is no MMU.
164 has_mmu = ioctl(fd, FIONBIO, nullptr);
165 close(fd);
166 }
167 printf("v4l2-compliance %s%s, ", PACKAGE_VERSION, STRING(GIT_COMMIT_CNT));
168 printf("%zd bits, %zd-bit time_t%s\n",
169 sizeof(void *) * 8, sizeof(time_t) * 8,
170 has_mmu ? "" : ", has no MMU");
171 if (strlen(STRING(GIT_SHA)))
172 printf("v4l2-compliance SHA: %s %s\n",
173 STRING(GIT_SHA), STRING(GIT_COMMIT_DATE));
174 }
175
usage()176 static void usage()
177 {
178 printf("Usage:\n");
179 printf("Common options:\n");
180 printf(" -d, --device <dev> Use device <dev> as the video device.\n");
181 printf(" If <dev> starts with a digit, then /dev/video<dev> is used.\n");
182 printf(" Otherwise if -z was specified earlier, then <dev> is the entity name\n");
183 printf(" or interface ID (if prefixed with 0x) as found in the topology of the\n");
184 printf(" media device with the bus info string as specified by the -z option.\n");
185 printf(" -V, --vbi-device <dev>\n");
186 printf(" Use device <dev> as the vbi device.\n");
187 printf(" If <dev> starts with a digit, then /dev/vbi<dev> is used.\n");
188 printf(" See the -d description of how <dev> is used in combination with -z.\n");
189 printf(" -r, --radio-device <dev>\n");
190 printf(" Use device <dev> as the radio device.\n");
191 printf(" If <dev> starts with a digit, then /dev/radio<dev> is used.\n");
192 printf(" See the -d description of how <dev> is used in combination with -z.\n");
193 printf(" -S, --sdr-device <dev>\n");
194 printf(" Use device <dev> as the SDR device.\n");
195 printf(" If <dev> starts with a digit, then /dev/swradio<dev> is used.\n");
196 printf(" See the -d description of how <dev> is used in combination with -z.\n");
197 printf(" -t, --touch-device <dev>\n");
198 printf(" Use device <dev> as the touch device.\n");
199 printf(" If <dev> starts with a digit, then /dev/v4l-touch<dev> is used.\n");
200 printf(" See the -d description of how <dev> is used in combination with -z.\n");
201 printf(" -u, --subdev-device <dev>\n");
202 printf(" Use device <dev> as the v4l-subdev device.\n");
203 printf(" If <dev> starts with a digit, then /dev/v4l-subdev<dev> is used.\n");
204 printf(" See the -d description of how <dev> is used in combination with -z.\n");
205 printf(" -e, --expbuf-device <dev>\n");
206 printf(" Use video device <dev> to obtain DMABUF handles.\n");
207 printf(" If <dev> starts with a digit, then /dev/video<dev> is used.\n");
208 printf(" See the -d description of how <dev> is used in combination with -z.\n");
209 printf(" -z, --media-bus-info <bus-info>\n");
210 printf(" Find the media device with the given bus info string. If set, then\n");
211 printf(" the options above can use the entity name or interface ID to refer\n");
212 printf(" to the device nodes.\n");
213 printf(" -m, --media-device <dev>\n");
214 printf(" Use device <dev> as the media controller device. Besides this\n");
215 printf(" device it also tests all interfaces it finds.\n");
216 printf(" If <dev> starts with a digit, then /dev/media<dev> is used.\n");
217 printf(" If <dev> doesn't exist, then attempt to find a media device with a\n");
218 printf(" bus info string equal to <dev>.\n");
219 printf(" -M, --media-device-only <dev>\n");
220 printf(" Use device <dev> as the media controller device. Only test this\n");
221 printf(" device, don't walk over all the interfaces.\n");
222 printf(" If <dev> starts with a digit, then /dev/media<dev> is used.\n");
223 printf(" If <dev> doesn't exist, then attempt to find a media device with a\n");
224 printf(" bus info string equal to <dev>.\n");
225 printf(" -s, --streaming <count>\n");
226 printf(" Enable the streaming tests. Set <count> to the number of\n");
227 printf(" frames to stream (default 60). Requires a valid input/output\n");
228 printf(" and frequency (when dealing with a tuner). For DMABUF testing\n");
229 printf(" --expbuf-device needs to be set as well.\n");
230 printf(" --stream-from [<pixelformat>=]<file>\n");
231 printf(" --stream-from-hdr [<pixelformat>=]<file>\n");
232 printf(" Use the contents of the file to fill in output buffers.\n");
233 printf(" If the fourcc of the pixelformat is given, then use the file\n");
234 printf(" for output buffers using that pixelformat only.\n");
235 printf(" The --stream-from-hdr variant uses the format written by\n");
236 printf(" v4l2-ctl --stream-to-hdr where the payload sizes for each\n");
237 printf(" buffer are stored in a header. Useful for compressed formats.\n");
238 printf(" -f, --stream-all-formats [<count>]\n");
239 printf(" Test streaming all available formats.\n");
240 printf(" This attempts to stream using MMAP mode or read/write\n");
241 printf(" for one second for all formats, at all sizes, at all intervals\n");
242 printf(" and with all field values. If <count> is given, then stream\n");
243 printf(" for that many frames instead of one second.\n");
244 printf(" -a, --stream-all-io\n");
245 printf(" Do streaming tests for all inputs or outputs instead of just\n");
246 printf(" the current input or output. This requires that a valid video\n");
247 printf(" signal is present on all inputs and all outputs are hooked up.\n");
248 printf(" -c, --stream-all-color color=red|green|blue,skip=<skip>,perc=<percentage>\n");
249 printf(" For all formats stream <skip + 1> frames and check if\n");
250 printf(" the last frame has at least <perc> percent of the pixels with\n");
251 printf(" a <color> component that is higher than the other two color\n");
252 printf(" components. This requires that a valid red, green or blue video\n");
253 printf(" signal is present on the input(s). If <skip> is not specified,\n");
254 printf(" then just capture the first frame. If <perc> is not specified,\n");
255 printf(" then this defaults to 90%%.\n");
256 printf(" -E, --exit-on-fail Exit on the first fail.\n");
257 printf(" -h, --help Display this help message.\n");
258 printf(" -C, --color <when> Highlight OK/warn/fail/FAIL strings with colors\n");
259 printf(" <when> can be set to always, never, or auto (the default)\n");
260 printf(" -n, --no-warnings Turn off warning messages.\n");
261 printf(" -P, --no-progress Turn off progress messages.\n");
262 printf(" -T, --trace Trace all called ioctls.\n");
263 printf(" -v, --verbose Turn on verbose reporting.\n");
264 printf(" --version Show version information.\n");
265 #ifndef NO_LIBV4L2
266 printf(" -w, --wrapper Use the libv4l2 wrapper library.\n");
267 #endif
268 printf(" -W, --exit-on-warn Exit on the first warning.\n");
269 }
270
ok(int res)271 const char *ok(int res)
272 {
273 static char buf[100];
274
275 if (res == ENOTTY) {
276 strcpy(buf, show_colors ?
277 COLOR_GREEN("OK") " (Not Supported)" :
278 "OK (Not Supported)");
279 res = 0;
280 } else {
281 strcpy(buf, show_colors ? COLOR_GREEN("OK") : "OK");
282 }
283 tests_total++;
284 if (res) {
285 app_result = res;
286 sprintf(buf, show_colors ? COLOR_RED("FAIL") : "FAIL");
287 } else {
288 tests_ok++;
289 }
290 return buf;
291 }
292
check_string(const char * s,size_t len)293 int check_string(const char *s, size_t len)
294 {
295 size_t sz = strnlen(s, len);
296
297 if (sz == 0)
298 return fail("string empty\n");
299 if (sz == len)
300 return fail("string not 0-terminated\n");
301 return 0;
302 }
303
check_ustring(const __u8 * s,int len)304 int check_ustring(const __u8 *s, int len)
305 {
306 return check_string(reinterpret_cast<const char *>(s), len);
307 }
308
check_0(const void * p,int len)309 int check_0(const void *p, int len)
310 {
311 const __u8 *q = static_cast<const __u8 *>(p);
312
313 while (len--)
314 if (*q++)
315 return 1;
316 return 0;
317 }
318
319 static std::map<std::string, std::string> stream_from_map;
320 static std::map<std::string, bool> stream_hdr_map;
321
stream_from(const std::string & pixelformat,bool & use_hdr)322 std::string stream_from(const std::string &pixelformat, bool &use_hdr)
323 {
324 if (stream_from_map.find(pixelformat) == stream_from_map.end()) {
325 if (pixelformat.empty())
326 return "";
327 return stream_from("", use_hdr);
328 }
329 use_hdr = stream_hdr_map[pixelformat];
330 return stream_from_map[pixelformat];
331 }
332
storeStateTimings(struct node * node,__u32 caps)333 static void storeStateTimings(struct node *node, __u32 caps)
334 {
335 if (caps & V4L2_IN_CAP_STD)
336 node->g_std(state.std);
337 if (caps & V4L2_IN_CAP_DV_TIMINGS)
338 node->g_dv_timings(state.timings);
339 if (caps & V4L2_IN_CAP_NATIVE_SIZE) {
340 v4l2_selection sel = {
341 node->g_selection_type(),
342 V4L2_SEL_TGT_NATIVE_SIZE
343 };
344
345 node->g_selection(sel);
346 state.native_size = sel.r;
347 }
348 }
349
storeState(struct node * node)350 static void storeState(struct node *node)
351 {
352 state.node = node;
353 if (node->has_inputs) {
354 __u32 input;
355
356 node->g_input(input);
357 node->enum_input(state.input, true, input);
358 if (state.input.audioset)
359 node->g_audio(state.ainput);
360 if (node->g_caps() & V4L2_CAP_TUNER) {
361 node->g_tuner(state.tuner, state.input.tuner);
362 node->g_frequency(state.freq, state.input.tuner);
363 }
364 storeStateTimings(node, state.input.capabilities);
365 }
366 if (node->has_outputs) {
367 __u32 output;
368
369 node->g_output(output);
370 node->enum_output(state.output, true, output);
371 if (state.output.audioset)
372 node->g_audout(state.aoutput);
373 if (node->g_caps() & V4L2_CAP_MODULATOR) {
374 node->g_modulator(state.modulator, state.output.modulator);
375 node->g_frequency(state.freq, state.output.modulator);
376 }
377 storeStateTimings(node, state.output.capabilities);
378 }
379 node->g_fmt(state.fmt);
380
381 v4l2_selection sel = {
382 node->g_selection_type(),
383 V4L2_SEL_TGT_CROP
384 };
385 if (!node->g_selection(sel))
386 state.crop = sel.r;
387 sel.target = V4L2_SEL_TGT_COMPOSE;
388 if (!node->g_selection(sel))
389 state.compose = sel.r;
390 node->get_interval(state.interval);
391
392 v4l2_query_ext_ctrl qec = { 0 };
393
394 while (!node->query_ext_ctrl(qec, true, true)) {
395 if (qec.flags & (V4L2_CTRL_FLAG_DISABLED |
396 V4L2_CTRL_FLAG_READ_ONLY |
397 V4L2_CTRL_FLAG_WRITE_ONLY |
398 V4L2_CTRL_FLAG_VOLATILE))
399 continue;
400 v4l2_ext_control ctrl = { qec.id };
401 if (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) {
402 ctrl.size = qec.elems * qec.elem_size;
403 ctrl.ptr = malloc(ctrl.size);
404 }
405 state.control_vec.push_back(ctrl);
406 }
407 if (state.control_vec.empty())
408 return;
409 state.controls.count = state.control_vec.size();
410 state.controls.controls = &state.control_vec[0];
411 node->g_ext_ctrls(state.controls);
412 }
413
restoreStateTimings(struct node * node,__u32 caps)414 static void restoreStateTimings(struct node *node, __u32 caps)
415 {
416 if (caps & V4L2_IN_CAP_STD)
417 node->s_std(state.std);
418 if (caps & V4L2_IN_CAP_DV_TIMINGS)
419 node->s_dv_timings(state.timings);
420 if (caps & V4L2_IN_CAP_NATIVE_SIZE) {
421 v4l2_selection sel = {
422 node->g_selection_type(),
423 V4L2_SEL_TGT_NATIVE_SIZE,
424 0, state.native_size
425 };
426
427 node->s_selection(sel);
428 }
429 }
430
restoreState()431 static void restoreState()
432 {
433 struct node *node = state.node;
434
435 node->reopen();
436 if (node->has_inputs) {
437 node->s_input(state.input.index);
438 if (state.input.audioset)
439 node->s_audio(state.ainput.index);
440 if (node->g_caps() & V4L2_CAP_TUNER) {
441 node->s_tuner(state.tuner);
442 node->s_frequency(state.freq);
443 }
444 restoreStateTimings(node, state.input.capabilities);
445 }
446 if (node->has_outputs) {
447 node->s_output(state.output.index);
448 if (state.output.audioset)
449 node->s_audout(state.aoutput.index);
450
451 if (node->g_caps() & V4L2_CAP_MODULATOR) {
452 node->s_modulator(state.modulator);
453 node->s_frequency(state.freq);
454 }
455 restoreStateTimings(node, state.output.capabilities);
456 }
457
458 /* First restore the format */
459 node->s_fmt(state.fmt);
460
461 v4l2_selection sel_compose = {
462 node->g_selection_type(),
463 V4L2_SEL_TGT_COMPOSE,
464 0, state.compose
465 };
466 v4l2_selection sel_crop = {
467 node->g_selection_type(),
468 V4L2_SEL_TGT_CROP,
469 0, state.crop
470 };
471 if (node->has_inputs) {
472 /*
473 * For capture restore the compose rectangle
474 * before the crop rectangle.
475 */
476 if (sel_compose.r.width && sel_compose.r.height)
477 node->s_selection(sel_compose);
478 if (sel_crop.r.width && sel_crop.r.height)
479 node->s_selection(sel_crop);
480 }
481 if (node->has_outputs) {
482 /*
483 * For output the crop rectangle should be
484 * restored before the compose rectangle.
485 */
486 if (sel_crop.r.width && sel_crop.r.height)
487 node->s_selection(sel_crop);
488 if (sel_compose.r.width && sel_compose.r.height)
489 node->s_selection(sel_compose);
490 }
491 if (state.interval.denominator)
492 node->set_interval(state.interval);
493
494 node->s_ext_ctrls(state.controls);
495 // We need to reopen again so QUERYCAP is called again.
496 // The vivid driver has controls (RDS related) that change
497 // the capabilities, and if we don't do this, then the
498 // internal caps stored in v4l_fd is out-of-sync with the
499 // actual caps.
500 node->reopen();
501 }
502
503 __attribute__((noreturn))
signal_handler_interrupt(int signum)504 static void signal_handler_interrupt(int signum)
505 {
506 restoreState();
507 printf("\n");
508 std::exit(EXIT_FAILURE);
509 }
510
determine_codec_mask(struct node & node)511 static void determine_codec_mask(struct node &node)
512 {
513 struct v4l2_fmtdesc fmt_desc;
514 int num_cap_fmts = 0;
515 int num_compressed_cap_fmts = 0;
516 int num_out_fmts = 0;
517 int num_compressed_out_fmts = 0;
518 unsigned mask = 0;
519
520 node.codec_mask = 0;
521 if (!node.has_vid_m2m())
522 return;
523
524 if (node.enum_fmt(fmt_desc, true, 0, node.g_type()))
525 return;
526
527 do {
528 if (fmt_desc.flags & V4L2_FMT_FLAG_COMPRESSED) {
529 num_compressed_cap_fmts++;
530 switch (fmt_desc.pixelformat) {
531 case V4L2_PIX_FMT_JPEG:
532 case V4L2_PIX_FMT_MJPEG:
533 mask |= JPEG_ENCODER;
534 break;
535 case V4L2_PIX_FMT_H263:
536 case V4L2_PIX_FMT_H264:
537 case V4L2_PIX_FMT_H264_NO_SC:
538 case V4L2_PIX_FMT_H264_MVC:
539 case V4L2_PIX_FMT_MPEG1:
540 case V4L2_PIX_FMT_MPEG2:
541 case V4L2_PIX_FMT_MPEG4:
542 case V4L2_PIX_FMT_XVID:
543 case V4L2_PIX_FMT_VC1_ANNEX_G:
544 case V4L2_PIX_FMT_VC1_ANNEX_L:
545 case V4L2_PIX_FMT_VP8:
546 case V4L2_PIX_FMT_VP9:
547 case V4L2_PIX_FMT_HEVC:
548 case V4L2_PIX_FMT_FWHT:
549 mask |= STATEFUL_ENCODER;
550 break;
551 #if 0 // There are no stateless encoders (yet)
552 case V4L2_PIX_FMT_MPEG2_SLICE:
553 mask |= STATELESS_ENCODER;
554 break;
555 #endif
556 case V4L2_PIX_FMT_QC08C:
557 case V4L2_PIX_FMT_QC10C:
558 num_compressed_cap_fmts--;
559 break;
560 default:
561 return;
562 }
563 }
564 num_cap_fmts++;
565 } while (!node.enum_fmt(fmt_desc));
566
567
568 if (node.enum_fmt(fmt_desc, true, 0, v4l_type_invert(node.g_type())))
569 return;
570
571 do {
572 if (fmt_desc.flags & V4L2_FMT_FLAG_COMPRESSED) {
573 num_compressed_out_fmts++;
574 switch (fmt_desc.pixelformat) {
575 case V4L2_PIX_FMT_JPEG:
576 case V4L2_PIX_FMT_MJPEG:
577 mask |= JPEG_DECODER;
578 break;
579 case V4L2_PIX_FMT_H263:
580 case V4L2_PIX_FMT_H264:
581 case V4L2_PIX_FMT_H264_NO_SC:
582 case V4L2_PIX_FMT_H264_MVC:
583 case V4L2_PIX_FMT_MPEG1:
584 case V4L2_PIX_FMT_MPEG2:
585 case V4L2_PIX_FMT_MPEG4:
586 case V4L2_PIX_FMT_XVID:
587 case V4L2_PIX_FMT_VC1_ANNEX_G:
588 case V4L2_PIX_FMT_VC1_ANNEX_L:
589 case V4L2_PIX_FMT_VP8:
590 case V4L2_PIX_FMT_VP9:
591 case V4L2_PIX_FMT_HEVC:
592 case V4L2_PIX_FMT_FWHT:
593 mask |= STATEFUL_DECODER;
594 break;
595 case V4L2_PIX_FMT_MPEG2_SLICE:
596 case V4L2_PIX_FMT_H264_SLICE:
597 case V4L2_PIX_FMT_HEVC_SLICE:
598 case V4L2_PIX_FMT_VP8_FRAME:
599 case V4L2_PIX_FMT_VP9_FRAME:
600 case V4L2_PIX_FMT_AV1_FRAME:
601 case V4L2_PIX_FMT_FWHT_STATELESS:
602 mask |= STATELESS_DECODER;
603 break;
604 case V4L2_PIX_FMT_QC08C:
605 case V4L2_PIX_FMT_QC10C:
606 num_compressed_out_fmts--;
607 break;
608 default:
609 return;
610 }
611 }
612 num_out_fmts++;
613 } while (!node.enum_fmt(fmt_desc));
614
615 if (num_compressed_out_fmts == 0 && num_compressed_cap_fmts == num_cap_fmts)
616 node.codec_mask = mask;
617 else if (num_compressed_cap_fmts == 0 && num_compressed_out_fmts == num_out_fmts)
618 node.codec_mask = mask;
619 }
620
testCap(struct node * node)621 static int testCap(struct node *node)
622 {
623 struct v4l2_capability vcap;
624 __u32 caps, dcaps;
625 const __u32 video_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
626 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
627 V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE |
628 V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
629 const __u32 vbi_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE |
630 V4L2_CAP_VBI_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT;
631 const __u32 sdr_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_SDR_OUTPUT;
632 const __u32 radio_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR;
633 const __u32 input_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
634 V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE |
635 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_HW_FREQ_SEEK |
636 V4L2_CAP_TUNER | V4L2_CAP_SDR_CAPTURE | V4L2_CAP_META_CAPTURE;
637 const __u32 output_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
638 V4L2_CAP_VIDEO_OUTPUT_OVERLAY | V4L2_CAP_VBI_OUTPUT |
639 V4L2_CAP_SDR_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT |
640 V4L2_CAP_MODULATOR | V4L2_CAP_META_OUTPUT;
641 const __u32 overlay_caps = V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
642 const __u32 m2m_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE;
643 const __u32 io_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
644 const __u32 mplane_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
645 V4L2_CAP_VIDEO_M2M_MPLANE;
646 const __u32 splane_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
647 V4L2_CAP_VIDEO_M2M;
648
649 memset(&vcap, 0xff, sizeof(vcap));
650 fail_on_test(doioctl(node, VIDIOC_QUERYCAP, &vcap));
651 if (has_mmu)
652 fail_on_test(doioctl(node, VIDIOC_QUERYCAP, nullptr) != EFAULT);
653 fail_on_test(check_ustring(vcap.driver, sizeof(vcap.driver)));
654 fail_on_test(check_ustring(vcap.card, sizeof(vcap.card)));
655 fail_on_test(check_ustring(vcap.bus_info, sizeof(vcap.bus_info)));
656 // Check for valid prefixes
657 if (memcmp(vcap.bus_info, "usb-", 4) &&
658 memcmp(vcap.bus_info, "PCI:", 4) &&
659 memcmp(vcap.bus_info, "PCIe:", 5) &&
660 memcmp(vcap.bus_info, "ISA:", 4) &&
661 memcmp(vcap.bus_info, "I2C:", 4) &&
662 memcmp(vcap.bus_info, "parport", 7) &&
663 memcmp(vcap.bus_info, "platform:", 9) &&
664 memcmp(vcap.bus_info, "rmi4:", 5) &&
665 memcmp(vcap.bus_info, "libcamera:", 10) &&
666 memcmp(vcap.bus_info, "gadget.", 7))
667 return fail("missing bus_info prefix ('%s')\n", vcap.bus_info);
668 if (!node->media_bus_info.empty() &&
669 node->media_bus_info != std::string(reinterpret_cast<const char *>(vcap.bus_info)))
670 warn("media bus_info '%s' differs from V4L2 bus_info '%s'\n",
671 node->media_bus_info.c_str(), vcap.bus_info);
672 fail_on_test((vcap.version >> 16) < 3);
673 if (vcap.version >= 0x050900) // Present from 5.9.0 onwards
674 node->might_support_cache_hints = true;
675 fail_on_test(check_0(vcap.reserved, sizeof(vcap.reserved)));
676 caps = vcap.capabilities;
677 dcaps = vcap.device_caps;
678 node->is_m2m = dcaps & m2m_caps;
679 fail_on_test(caps == 0);
680 fail_on_test(!(caps & V4L2_CAP_DEVICE_CAPS));
681 fail_on_test(dcaps & V4L2_CAP_DEVICE_CAPS);
682 fail_on_test(dcaps & ~caps);
683 fail_on_test(!(dcaps & caps));
684 // set by the core, so this really should always be there
685 // for a modern driver for both caps and dcaps
686 fail_on_test(!(caps & V4L2_CAP_EXT_PIX_FORMAT));
687 //fail_on_test(!(dcaps & V4L2_CAP_EXT_PIX_FORMAT));
688 fail_on_test(node->is_video && !(dcaps & video_caps));
689 fail_on_test(node->is_radio && !(dcaps & radio_caps));
690 // V4L2_CAP_AUDIO is invalid for radio and sdr
691 fail_on_test(node->is_radio && (dcaps & V4L2_CAP_AUDIO));
692 fail_on_test(node->is_sdr && (dcaps & V4L2_CAP_AUDIO));
693 fail_on_test(node->is_vbi && !(dcaps & vbi_caps));
694 fail_on_test(node->is_sdr && !(dcaps & sdr_caps));
695 // You can't have both set due to missing buffer type in VIDIOC_G/S_FBUF
696 fail_on_test((dcaps & overlay_caps) == overlay_caps);
697 // Overlay support makes no sense for m2m devices
698 fail_on_test((dcaps & m2m_caps) && (dcaps & overlay_caps));
699 fail_on_test(node->is_video && (dcaps & (vbi_caps | radio_caps | sdr_caps)));
700 fail_on_test(node->is_radio && (dcaps & (vbi_caps | video_caps | sdr_caps)));
701 fail_on_test(node->is_vbi && (dcaps & (video_caps | radio_caps | sdr_caps)));
702 fail_on_test(node->is_sdr && (dcaps & (video_caps | V4L2_CAP_RADIO | vbi_caps)));
703 if (node->is_m2m) {
704 fail_on_test((dcaps & input_caps) && (dcaps & output_caps));
705 } else {
706 if (dcaps & input_caps)
707 fail_on_test(dcaps & output_caps);
708 if (dcaps & output_caps)
709 fail_on_test(dcaps & input_caps);
710 }
711 if (node->can_capture || node->can_output) {
712 // whether io_caps need to be set for RDS capture/output is
713 // checked elsewhere as that depends on the tuner/modulator
714 // capabilities.
715 if (!(dcaps & (V4L2_CAP_RDS_CAPTURE | V4L2_CAP_RDS_OUTPUT)))
716 fail_on_test(!(dcaps & io_caps));
717 } else {
718 fail_on_test(dcaps & io_caps);
719 }
720 // having both mplane and splane caps is not allowed (at least for now)
721 fail_on_test((dcaps & mplane_caps) && (dcaps & splane_caps));
722
723 if (node->codec_mask) {
724 bool found_bit = false;
725
726 // Only one bit may be set in the mask
727 for (unsigned i = 0; i < 32; i++)
728 if (node->codec_mask & (1U << i)) {
729 fail_on_test(found_bit);
730 found_bit = true;
731 }
732 }
733
734 return 0;
735 }
736
737 #define NR_OPENS 100
testUnlimitedOpens(struct node * node)738 static int testUnlimitedOpens(struct node *node)
739 {
740 int fds[NR_OPENS];
741 unsigned i;
742 bool ok;
743
744 /*
745 * There should *not* be an artificial limit to the number
746 * of open()s you can do on a V4L2 device node. So test whether
747 * you can open a device node at least 100 times.
748 *
749 * And please don't start rejecting opens in your driver at 101!
750 * There really shouldn't be a limit in the driver.
751 *
752 * If there are resource limits, then check against those limits
753 * where they are actually needed.
754 */
755 for (i = 0; i < NR_OPENS; i++) {
756 fds[i] = open(node->device, O_RDWR);
757 if (fds[i] < 0)
758 break;
759 }
760 ok = i == NR_OPENS;
761 while (i--)
762 close(fds[i]);
763 fail_on_test(!ok);
764 return 0;
765 }
766
check_prio(struct node * node,struct node * node2,enum v4l2_priority match)767 static int check_prio(struct node *node, struct node *node2, enum v4l2_priority match)
768 {
769 enum v4l2_priority prio;
770
771 // Must be able to get priority
772 fail_on_test(doioctl(node, VIDIOC_G_PRIORITY, &prio));
773 // Must match the expected prio
774 fail_on_test(prio != match);
775 fail_on_test(doioctl(node2, VIDIOC_G_PRIORITY, &prio));
776 fail_on_test(prio != match);
777 return 0;
778 }
779
testPrio(struct node * node,struct node * node2)780 static int testPrio(struct node *node, struct node *node2)
781 {
782 enum v4l2_priority prio;
783 int err;
784
785 err = check_prio(node, node2, V4L2_PRIORITY_DEFAULT);
786 if (err)
787 return err;
788
789 prio = V4L2_PRIORITY_RECORD;
790 // Must be able to change priority
791 fail_on_test(doioctl(node, VIDIOC_S_PRIORITY, &prio));
792 // Must match the new prio
793 fail_on_test(check_prio(node, node2, V4L2_PRIORITY_RECORD));
794
795 prio = V4L2_PRIORITY_INTERACTIVE;
796 // Going back to interactive on the other node must fail
797 fail_on_test(!doioctl(node2, VIDIOC_S_PRIORITY, &prio));
798 prio = V4L2_PRIORITY_INTERACTIVE;
799 // Changing it on the first node must work.
800 fail_on_test(doioctl(node, VIDIOC_S_PRIORITY, &prio));
801 fail_on_test(check_prio(node, node2, V4L2_PRIORITY_INTERACTIVE));
802 return 0;
803 }
804
testInvalidIoctls(struct node * node,char type)805 static int testInvalidIoctls(struct node *node, char type)
806 {
807 unsigned ioc = _IOC(_IOC_NONE, type, 0xff, 0);
808 unsigned char buf[0x4000] = {};
809
810 fail_on_test(doioctl(node, ioc, nullptr) != ENOTTY);
811 ioc = _IOC(_IOC_NONE, type, 0, 0x3fff);
812 fail_on_test(doioctl(node, ioc, nullptr) != ENOTTY);
813 ioc = _IOC(_IOC_READ, type, 0, 0x3fff);
814 fail_on_test(doioctl(node, ioc, buf) != ENOTTY);
815 fail_on_test(check_0(buf, sizeof(buf)));
816 ioc = _IOC(_IOC_WRITE, type, 0, 0x3fff);
817 fail_on_test(doioctl(node, ioc, buf) != ENOTTY);
818 fail_on_test(check_0(buf, sizeof(buf)));
819 ioc = _IOC(_IOC_READ | _IOC_WRITE, type, 0, 0x3fff);
820 fail_on_test(doioctl(node, ioc, buf) != ENOTTY);
821 fail_on_test(check_0(buf, sizeof(buf)));
822 return 0;
823 }
824
streamingSetup(struct node * node)825 static void streamingSetup(struct node *node)
826 {
827 if (node->can_capture) {
828 v4l2_fract min_period = { 1, 1000 };
829 struct v4l2_input input;
830
831 memset(&input, 0, sizeof(input));
832 doioctl(node, VIDIOC_G_INPUT, &input.index);
833 doioctl(node, VIDIOC_ENUMINPUT, &input);
834 node->cur_io_caps = input.capabilities;
835 node->set_interval(min_period);
836 } else if (node->can_output) {
837 struct v4l2_output output;
838
839 memset(&output, 0, sizeof(output));
840 doioctl(node, VIDIOC_G_OUTPUT, &output.index);
841 doioctl(node, VIDIOC_ENUMOUTPUT, &output);
842 node->cur_io_caps = output.capabilities;
843 }
844 }
845
parse_subopt(char ** subs,const char * const * subopts,char ** value)846 static int parse_subopt(char **subs, const char * const *subopts, char **value)
847 {
848 int opt = v4l_getsubopt(subs, const_cast<char * const *>(subopts), value);
849
850 if (opt == -1) {
851 fprintf(stderr, "Invalid suboptions specified\n");
852 return -1;
853 }
854 if (*value == nullptr) {
855 fprintf(stderr, "No value given to suboption <%s>\n",
856 subopts[opt]);
857 return -1;
858 }
859 return opt;
860 }
861
open_media_bus_info(const std::string & bus_info,std::string & media_devname)862 static int open_media_bus_info(const std::string &bus_info, std::string &media_devname)
863 {
864 DIR *dp;
865 struct dirent *ep;
866
867 dp = opendir("/dev");
868 if (dp == nullptr)
869 return -1;
870
871 while ((ep = readdir(dp))) {
872 const char *name = ep->d_name;
873
874 if (!memcmp(name, "media", 5) && isdigit(name[5])) {
875 struct media_device_info mdi;
876 media_devname = std::string("/dev/") + name;
877
878 int fd = open(media_devname.c_str(), O_RDWR);
879 if (fd < 0)
880 continue;
881 if (!ioctl(fd, MEDIA_IOC_DEVICE_INFO, &mdi) &&
882 bus_info == mdi.bus_info) {
883 closedir(dp);
884 return fd;
885 }
886 close(fd);
887 }
888 }
889 closedir(dp);
890 return -1;
891 }
892
make_devname(const char * device,const char * devname,const std::string & media_bus_info,bool is_media=false)893 static std::string make_devname(const char *device, const char *devname,
894 const std::string &media_bus_info, bool is_media = false)
895 {
896 if (device[0] >= '0' && device[0] <= '9' && strlen(device) <= 3) {
897 char newdev[32];
898
899 sprintf(newdev, "/dev/%s%s", devname, device);
900 return newdev;
901 }
902 if (media_bus_info.empty())
903 return device;
904
905 std::string media_devname;
906 int media_fd = open_media_bus_info(media_bus_info, media_devname);
907 if (media_fd < 0)
908 return device;
909 if (is_media) {
910 close(media_fd);
911 return media_devname;
912 }
913
914 media_v2_topology topology;
915 memset(&topology, 0, sizeof(topology));
916 if (ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology)) {
917 close(media_fd);
918 return device;
919 }
920
921 auto ents = new media_v2_entity[topology.num_entities];
922 topology.ptr_entities = (uintptr_t)ents;
923 auto links = new media_v2_link[topology.num_links];
924 topology.ptr_links = (uintptr_t)links;
925 auto ifaces = new media_v2_interface[topology.num_interfaces];
926 topology.ptr_interfaces = (uintptr_t)ifaces;
927
928 unsigned i, ent_id, iface_id = 0;
929
930 std::string result(device);
931
932 if (ioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology))
933 goto err;
934
935 if (device[0] == '0' && device[1] == 'x')
936 iface_id = strtoul(device, nullptr, 16);
937
938 if (!iface_id) {
939 for (i = 0; i < topology.num_entities; i++)
940 if (!strcmp(ents[i].name, device))
941 break;
942 if (i >= topology.num_entities)
943 goto err;
944 ent_id = ents[i].id;
945 for (i = 0; i < topology.num_links; i++)
946 if (links[i].sink_id == ent_id &&
947 (links[i].flags & MEDIA_LNK_FL_LINK_TYPE) ==
948 MEDIA_LNK_FL_INTERFACE_LINK)
949 break;
950 if (i >= topology.num_links)
951 goto err;
952 iface_id = links[i].source_id;
953 }
954 for (i = 0; i < topology.num_interfaces; i++)
955 if (ifaces[i].id == iface_id)
956 break;
957 if (i >= topology.num_interfaces)
958 goto err;
959
960 result = mi_media_get_device(ifaces[i].devnode.major, ifaces[i].devnode.minor);
961
962 err:
963 delete [] ents;
964 delete [] links;
965 delete [] ifaces;
966 close(media_fd);
967 return result;
968 }
969
testNode(struct node & node,struct node & node_m2m_cap,struct node & expbuf_node,media_type type,unsigned frame_count,unsigned all_fmt_frame_count,int parent_media_fd)970 void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_node, media_type type,
971 unsigned frame_count, unsigned all_fmt_frame_count, int parent_media_fd)
972 {
973 struct node node2;
974 struct v4l2_capability vcap = {};
975 struct v4l2_subdev_capability subdevcap = {};
976 struct v4l2_subdev_client_capability subdevclientcap = {};
977 std::string driver;
978
979 tests_total = tests_ok = warnings = 0;
980
981 node.is_video = type == MEDIA_TYPE_VIDEO;
982 node.is_vbi = type == MEDIA_TYPE_VBI;
983 node.is_radio = type == MEDIA_TYPE_RADIO;
984 node.is_sdr = type == MEDIA_TYPE_SDR;
985 node.is_touch = type == MEDIA_TYPE_TOUCH;
986
987 if (node.is_v4l2()) {
988 doioctl(&node, VIDIOC_QUERYCAP, &vcap);
989 driver = reinterpret_cast<const char *>(vcap.driver);
990 is_uvcvideo = driver == "uvcvideo";
991 is_vivid = driver == "vivid";
992 if (is_vivid)
993 node.bus_info = reinterpret_cast<const char *>(vcap.bus_info);
994 determine_codec_mask(node);
995 } else if (node.is_subdev()) {
996 doioctl(&node, VIDIOC_SUBDEV_QUERYCAP, &subdevcap);
997 subdevclientcap.capabilities = ~0ULL;
998 if (doioctl(&node, VIDIOC_SUBDEV_S_CLIENT_CAP, &subdevclientcap))
999 subdevclientcap.capabilities = 0ULL;
1000 } else {
1001 memset(&vcap, 0, sizeof(vcap));
1002 }
1003
1004 if (!node.is_media()) {
1005 if (parent_media_fd >= 0)
1006 media_fd = parent_media_fd;
1007 else
1008 media_fd = mi_get_media_fd(node.g_fd(), node.bus_info);
1009 }
1010
1011 int fd = node.is_media() ? node.g_fd() : media_fd;
1012 if (fd >= 0) {
1013 struct media_device_info mdinfo;
1014
1015 if (!ioctl(fd, MEDIA_IOC_DEVICE_INFO, &mdinfo)) {
1016 if (!node.is_v4l2())
1017 driver = mdinfo.driver;
1018 node.media_bus_info = mdinfo.bus_info;
1019 node.has_media = true;
1020 }
1021 }
1022
1023 if (driver.empty())
1024 printf("Compliance test for device ");
1025 else
1026 printf("Compliance test for %s device ", driver.c_str());
1027 printf("%s%s:\n\n", node.device, node.g_direct() ? "" : " (using libv4l2)");
1028
1029 if (node.g_caps() & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
1030 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_SLICED_VBI_CAPTURE |
1031 V4L2_CAP_META_CAPTURE))
1032 node.has_inputs = true;
1033 if (node.g_caps() & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VBI_OUTPUT |
1034 V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_SLICED_VBI_OUTPUT |
1035 V4L2_CAP_META_OUTPUT))
1036 node.has_outputs = true;
1037 if (node.g_caps() & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
1038 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE |
1039 V4L2_CAP_VIDEO_M2M | V4L2_CAP_SLICED_VBI_CAPTURE |
1040 V4L2_CAP_RDS_CAPTURE | V4L2_CAP_SDR_CAPTURE |
1041 V4L2_CAP_META_CAPTURE))
1042 node.can_capture = true;
1043 if (node.g_caps() & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VBI_OUTPUT |
1044 V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE |
1045 V4L2_CAP_VIDEO_M2M | V4L2_CAP_SLICED_VBI_OUTPUT |
1046 V4L2_CAP_RDS_OUTPUT | V4L2_CAP_SDR_OUTPUT |
1047 V4L2_CAP_META_OUTPUT))
1048 node.can_output = true;
1049 if (node.g_caps() & (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
1050 V4L2_CAP_VIDEO_M2M_MPLANE))
1051 node.is_planar = true;
1052 if (node.g_caps() & (V4L2_CAP_META_CAPTURE | V4L2_CAP_META_OUTPUT)) {
1053 node.is_video = false;
1054 node.is_meta = true;
1055 }
1056 if (node.g_caps() & V4L2_CAP_IO_MC)
1057 node.is_io_mc = true;
1058
1059 /* Information Opts */
1060
1061 if (node.is_v4l2()) {
1062 printf("Driver Info:\n");
1063 v4l2_info_capability(vcap);
1064 switch (node.codec_mask) {
1065 case JPEG_ENCODER:
1066 printf("\tDetected JPEG Encoder\n");
1067 break;
1068 case JPEG_DECODER:
1069 printf("\tDetected JPEG Decoder\n");
1070 break;
1071 case STATEFUL_ENCODER:
1072 printf("\tDetected Stateful Encoder\n");
1073 break;
1074 case STATEFUL_DECODER:
1075 printf("\tDetected Stateful Decoder\n");
1076 break;
1077 case STATELESS_ENCODER:
1078 printf("\tDetected Stateless Encoder\n");
1079 break;
1080 case STATELESS_DECODER:
1081 printf("\tDetected Stateless Decoder\n");
1082 break;
1083 }
1084 } else if (node.is_subdev()) {
1085 printf("Driver Info:\n");
1086 v4l2_info_subdev_capability(subdevcap, subdevclientcap);
1087 }
1088
1089 __u32 ent_id = 0;
1090 bool is_invalid = false;
1091
1092 if (node.is_media())
1093 mi_media_info_for_fd(node.g_fd(), -1, &is_invalid);
1094 else if (media_fd >= 0)
1095 ent_id = mi_media_info_for_fd(media_fd, node.g_fd(), &is_invalid, &node.function);
1096
1097 if (ent_id != MEDIA_ENT_F_UNKNOWN) {
1098 memset(&node.entity, 0, sizeof(node.entity));
1099 node.entity.id = ent_id;
1100 if (!ioctl(media_fd, MEDIA_IOC_ENUM_ENTITIES, &node.entity)) {
1101 struct media_links_enum links_enum;
1102
1103 node.pads = new media_pad_desc[node.entity.pads];
1104 node.links = new media_link_desc[node.entity.links];
1105 memset(&links_enum, 0, sizeof(links_enum));
1106 links_enum.entity = ent_id;
1107 links_enum.pads = node.pads;
1108 links_enum.links = node.links;
1109 if (ioctl(media_fd, MEDIA_IOC_ENUM_LINKS, &links_enum))
1110 node.entity.id = 0;
1111 } else {
1112 node.entity.id = 0;
1113 }
1114 }
1115
1116 /* Required ioctls */
1117
1118 printf("\nRequired ioctls:\n");
1119
1120 if (ent_id)
1121 printf("\ttest MC information (see 'Media Driver Info' above): %s\n", ok(is_invalid ? -1 : 0));
1122
1123 if (node.is_v4l2())
1124 printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&node)));
1125 else if (node.is_subdev())
1126 printf("\ttest VIDIOC_SUDBEV_QUERYCAP: %s\n", ok(testSubDevCap(&node)));
1127
1128 if (node.is_v4l2() || node.is_subdev())
1129 printf("\ttest invalid ioctls: %s\n", ok(testInvalidIoctls(&node, 'V')));
1130
1131 if (node.is_media()) {
1132 printf("\ttest MEDIA_IOC_DEVICE_INFO: %s\n",
1133 ok(testMediaDeviceInfo(&node)));
1134 printf("\ttest invalid ioctls: %s\n", ok(testInvalidIoctls(&node, '|')));
1135 }
1136 printf("\n");
1137
1138 /* Multiple opens */
1139
1140 printf("Allow for multiple opens:\n");
1141 node2 = node;
1142 switch (type) {
1143 case MEDIA_TYPE_SUBDEV:
1144 printf("\ttest second %s open: %s\n", node.device,
1145 ok(node2.subdev_open(node.device, false) >= 0 ? 0 : errno));
1146 if (node2.g_fd() >= 0)
1147 printf("\ttest VIDIOC_SUBDEV_QUERYCAP: %s\n", ok(testSubDevCap(&node2)));
1148 break;
1149 case MEDIA_TYPE_MEDIA:
1150 printf("\ttest second %s open: %s\n", node.device,
1151 ok(node2.media_open(node.device, false) >= 0 ? 0 : errno));
1152 if (node2.g_fd() >= 0)
1153 printf("\ttest MEDIA_IOC_DEVICE_INFO: %s\n", ok(testMediaDeviceInfo(&node2)));
1154 break;
1155 default:
1156 printf("\ttest second %s open: %s\n", node.device,
1157 ok(node2.open(node.device, false) >= 0 ? 0 : errno));
1158 if (node2.g_fd() >= 0) {
1159 printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&node2)));
1160 printf("\ttest VIDIOC_G/S_PRIORITY: %s\n",
1161 ok(testPrio(&node, &node2)));
1162 }
1163 break;
1164 }
1165 if (node2.g_fd() >= 0)
1166 node.node2 = &node2;
1167
1168 printf("\ttest for unlimited opens: %s\n",
1169 ok(testUnlimitedOpens(&node)));
1170
1171 printf("\n");
1172 storeState(&node);
1173
1174 /* register signal handler for interrupt signal, to exit gracefully */
1175 signal(SIGINT, signal_handler_interrupt);
1176
1177 unsigned cur_io = 0;
1178 unsigned min_io = 0;
1179 unsigned max_io = 0;
1180
1181 /* Media ioctls */
1182
1183 if (node.is_media()) {
1184 printf("Media Controller ioctls:\n");
1185 printf("\ttest MEDIA_IOC_G_TOPOLOGY: %s\n", ok(testMediaTopology(&node)));
1186 if (node.topology)
1187 printf("\tEntities: %u Interfaces: %u Pads: %u Links: %u\n",
1188 node.topology->num_entities,
1189 node.topology->num_interfaces,
1190 node.topology->num_pads,
1191 node.topology->num_links);
1192 printf("\ttest MEDIA_IOC_ENUM_ENTITIES/LINKS: %s\n", ok(testMediaEnum(&node)));
1193 printf("\ttest MEDIA_IOC_SETUP_LINK: %s\n", ok(testMediaSetupLink(&node)));
1194 printf("\n");
1195 goto show_total;
1196 }
1197
1198 /* Debug ioctls */
1199
1200 printf("Debug ioctls:\n");
1201 if (node.is_v4l2())
1202 printf("\ttest VIDIOC_DBG_G/S_REGISTER: %s\n", ok(testRegister(&node)));
1203 printf("\ttest VIDIOC_LOG_STATUS: %s\n", ok(testLogStatus(&node)));
1204 printf("\n");
1205
1206 /* Input ioctls */
1207
1208 printf("Input ioctls:\n");
1209 printf("\ttest VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: %s\n", ok(testTuner(&node)));
1210 printf("\ttest VIDIOC_G/S_FREQUENCY: %s\n", ok(testTunerFreq(&node)));
1211 printf("\ttest VIDIOC_S_HW_FREQ_SEEK: %s\n", ok(testTunerHwSeek(&node)));
1212 printf("\ttest VIDIOC_ENUMAUDIO: %s\n", ok(testEnumInputAudio(&node)));
1213 printf("\ttest VIDIOC_G/S/ENUMINPUT: %s\n", ok(testInput(&node)));
1214 printf("\ttest VIDIOC_G/S_AUDIO: %s\n", ok(testInputAudio(&node)));
1215 printf("\tInputs: %d Audio Inputs: %d Tuners: %d\n",
1216 node.inputs, node.audio_inputs, node.tuners);
1217 printf("\n");
1218
1219 /* Output ioctls */
1220
1221 printf("Output ioctls:\n");
1222 printf("\ttest VIDIOC_G/S_MODULATOR: %s\n", ok(testModulator(&node)));
1223 printf("\ttest VIDIOC_G/S_FREQUENCY: %s\n", ok(testModulatorFreq(&node)));
1224 printf("\ttest VIDIOC_ENUMAUDOUT: %s\n", ok(testEnumOutputAudio(&node)));
1225 printf("\ttest VIDIOC_G/S/ENUMOUTPUT: %s\n", ok(testOutput(&node)));
1226 printf("\ttest VIDIOC_G/S_AUDOUT: %s\n", ok(testOutputAudio(&node)));
1227 printf("\tOutputs: %d Audio Outputs: %d Modulators: %d\n",
1228 node.outputs, node.audio_outputs, node.modulators);
1229 printf("\n");
1230
1231 /* I/O configuration ioctls */
1232
1233 printf("Input/Output configuration ioctls:\n");
1234 printf("\ttest VIDIOC_ENUM/G/S/QUERY_STD: %s\n", ok(testStd(&node)));
1235 printf("\ttest VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: %s\n", ok(testTimings(&node)));
1236 printf("\ttest VIDIOC_DV_TIMINGS_CAP: %s\n", ok(testTimingsCap(&node)));
1237 printf("\ttest VIDIOC_G/S_EDID: %s\n", ok(testEdid(&node)));
1238 printf("\n");
1239
1240 /* Sub-device ioctls */
1241
1242 if (node.is_subdev()) {
1243 bool has_source = false;
1244 bool has_sink = false;
1245 struct v4l2_subdev_routing sd_routing[2] = {};
1246 struct v4l2_subdev_route sd_routes[2][NUM_ROUTES_MAX] = {};
1247 bool has_routes = !!(subdevcap.capabilities & V4L2_SUBDEV_CAP_STREAMS);
1248 int ret;
1249
1250 node.frame_interval_pad = -1;
1251 node.enum_frame_interval_pad = -1;
1252 for (unsigned pad = 0; pad < node.entity.pads; pad++) {
1253 if (node.pads[pad].flags & MEDIA_PAD_FL_SINK)
1254 has_sink = true;
1255 if (node.pads[pad].flags & MEDIA_PAD_FL_SOURCE)
1256 has_source = true;
1257 }
1258 node.is_passthrough_subdev = has_source && has_sink;
1259
1260 if (has_routes) {
1261 printf("Sub-Device routing ioctls:\n");
1262
1263 for (unsigned which = V4L2_SUBDEV_FORMAT_TRY;
1264 which <= V4L2_SUBDEV_FORMAT_ACTIVE; which++) {
1265
1266 printf("\ttest %s VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING: %s\n",
1267 which ? "Active" : "Try",
1268 ok(testSubDevRouting(&node, which)));
1269 }
1270
1271 printf("\n");
1272
1273 for (unsigned which = V4L2_SUBDEV_FORMAT_TRY;
1274 which <= V4L2_SUBDEV_FORMAT_ACTIVE; which++) {
1275 struct v4l2_subdev_routing &routing = sd_routing[which];
1276
1277 routing.which = which;
1278 routing.routes = (uintptr_t)sd_routes[which];
1279 routing.len_routes = NUM_ROUTES_MAX;
1280 routing.num_routes = 0;
1281
1282 ret = doioctl(&node, VIDIOC_SUBDEV_G_ROUTING, &routing);
1283 if (ret) {
1284 fail("VIDIOC_SUBDEV_G_ROUTING: failed to get routing\n");
1285 routing.num_routes = 0;
1286 }
1287 }
1288 }
1289
1290 for (unsigned pad = 0; pad < node.entity.pads; pad++) {
1291 printf("Sub-Device ioctls (%s Pad %u):\n",
1292 (node.pads[pad].flags & MEDIA_PAD_FL_SINK) ?
1293 "Sink" : "Source", pad);
1294 node.has_subdev_enum_code = 0;
1295 node.has_subdev_enum_fsize = 0;
1296 node.has_subdev_enum_fival = 0;
1297 for (unsigned which = V4L2_SUBDEV_FORMAT_TRY;
1298 which <= V4L2_SUBDEV_FORMAT_ACTIVE; which++) {
1299 struct v4l2_subdev_routing dummy_routing;
1300 struct v4l2_subdev_route dummy_routes[1];
1301
1302 const struct v4l2_subdev_routing *routing;
1303 const struct v4l2_subdev_route *routes;
1304
1305 if (has_routes) {
1306 routing = &sd_routing[which];
1307 routes = sd_routes[which];
1308 } else {
1309 dummy_routing.num_routes = 1;
1310 dummy_routing.routes = (uintptr_t)&dummy_routes;
1311 dummy_routes[0].source_pad = pad;
1312 dummy_routes[0].source_stream = 0;
1313 dummy_routes[0].sink_pad = pad;
1314 dummy_routes[0].sink_stream = 0;
1315 dummy_routes[0].flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE;
1316
1317 routing = &dummy_routing;
1318 routes = dummy_routes;
1319 }
1320
1321 for (unsigned i = 0; i < routing->num_routes; ++i) {
1322 const struct v4l2_subdev_route *r = &routes[i];
1323 unsigned stream;
1324
1325 if (!(r->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
1326 continue;
1327
1328 if ((node.pads[pad].flags & MEDIA_PAD_FL_SINK) &&
1329 (r->sink_pad == pad))
1330 stream = r->sink_stream;
1331 else if ((node.pads[pad].flags & MEDIA_PAD_FL_SOURCE) &&
1332 (r->source_pad == pad))
1333 stream = r->source_stream;
1334 else
1335 continue;
1336
1337 printf("\t%s Stream %u\n",which ? "Active" : "Try",
1338 stream);
1339
1340 printf("\ttest %s VIDIOC_SUBDEV_ENUM_MBUS_CODE/FRAME_SIZE/FRAME_INTERVAL: %s\n",
1341 which ? "Active" : "Try",
1342 ok(testSubDevEnum(&node, which, pad, stream)));
1343 printf("\ttest %s VIDIOC_SUBDEV_G/S_FMT: %s\n",
1344 which ? "Active" : "Try",
1345 ok(testSubDevFormat(&node, which, pad, stream)));
1346 printf("\ttest %s VIDIOC_SUBDEV_G/S_SELECTION/CROP: %s\n",
1347 which ? "Active" : "Try",
1348 ok(testSubDevSelection(&node, which, pad, stream)));
1349 if (which)
1350 printf("\ttest %s VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: %s\n",
1351 which ? "Active" : "Try",
1352 ok(testSubDevFrameInterval(&node, which, pad, stream)));
1353 }
1354 }
1355
1356 /*
1357 * These tests do not make sense for subdevs with multiplexed streams,
1358 * as the try & active cases may have different routing and thus different
1359 * behavior.
1360 */
1361 if (!has_routes) {
1362 if (node.has_subdev_enum_code && node.has_subdev_enum_code < 3)
1363 fail("VIDIOC_SUBDEV_ENUM_MBUS_CODE: try/active mismatch\n");
1364 if (node.has_subdev_enum_fsize && node.has_subdev_enum_fsize < 3)
1365 fail("VIDIOC_SUBDEV_ENUM_FRAME_SIZE: try/active mismatch\n");
1366 if (node.has_subdev_enum_fival && node.has_subdev_enum_fival < 3)
1367 fail("VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: try/active mismatch\n");
1368 if (node.has_subdev_fmt && node.has_subdev_fmt < 3)
1369 fail("VIDIOC_SUBDEV_G/S_FMT: try/active mismatch\n");
1370 if (node.has_subdev_selection && node.has_subdev_selection < 3)
1371 fail("VIDIOC_SUBDEV_G/S_SELECTION: try/active mismatch\n");
1372 if (node.has_subdev_selection &&
1373 node.has_subdev_selection != node.has_subdev_fmt)
1374 fail("VIDIOC_SUBDEV_G/S_SELECTION: fmt/selection mismatch\n");
1375 if (node.has_ival_uses_which()) {
1376 if (node.has_subdev_frame_interval && node.has_subdev_frame_interval < 3)
1377 fail("VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: try/active mismatch\n");
1378 if (node.has_subdev_frame_interval &&
1379 node.has_subdev_frame_interval != node.has_subdev_fmt)
1380 fail("VIDIOC_SUBDEV_G/S_FRAME_INTERVAL: fmt/frame_interval mismatch\n");
1381 }
1382 }
1383 printf("\n");
1384 }
1385 }
1386
1387 max_io = node.inputs > node.outputs ? node.inputs : node.outputs;
1388
1389 for (unsigned io = 0; io < (max_io ? max_io : 1); io++) {
1390 v4l2_fract min_period = { 1, 1000 };
1391 char suffix[100] = "";
1392
1393 node.std_controls = node.priv_controls = 0;
1394 node.std_compound_controls = node.priv_compound_controls = 0;
1395 node.controls.clear();
1396 node.frmsizes.clear();
1397 node.frmsizes_count.clear();
1398 node.has_frmintervals = false;
1399 node.has_enc_cap_frame_interval = false;
1400 node.valid_buftypes = 0;
1401 node.valid_memorytype = 0;
1402 node.buf_caps = 0;
1403 for (auto &buftype_pixfmt : node.buftype_pixfmts)
1404 buftype_pixfmt.clear();
1405
1406 if (max_io) {
1407 sprintf(suffix, " (%s %u)",
1408 node.can_capture ? "Input" : "Output", io);
1409 if (node.can_capture) {
1410 struct v4l2_input descr;
1411
1412 doioctl(&node, VIDIOC_S_INPUT, &io);
1413 descr.index = io;
1414 doioctl(&node, VIDIOC_ENUMINPUT, &descr);
1415 node.cur_io_caps = descr.capabilities;
1416 } else {
1417 struct v4l2_output descr;
1418
1419 doioctl(&node, VIDIOC_S_OUTPUT, &io);
1420 descr.index = io;
1421 doioctl(&node, VIDIOC_ENUMOUTPUT, &descr);
1422 node.cur_io_caps = descr.capabilities;
1423 }
1424 }
1425
1426 /* Control ioctls */
1427
1428 printf("Control ioctls%s:\n", suffix);
1429 printf("\ttest VIDIOC_QUERY_EXT_CTRL/QUERYMENU: %s\n", ok(testQueryExtControls(&node)));
1430 printf("\ttest VIDIOC_QUERYCTRL: %s\n", ok(testQueryControls(&node)));
1431 printf("\ttest VIDIOC_G/S_CTRL: %s\n", ok(testSimpleControls(&node)));
1432 printf("\ttest VIDIOC_G/S/TRY_EXT_CTRLS: %s\n", ok(testExtendedControls(&node)));
1433 printf("\ttest VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: %s\n", ok(testEvents(&node)));
1434 printf("\ttest VIDIOC_G/S_JPEGCOMP: %s\n", ok(testJpegComp(&node)));
1435 printf("\tStandard Controls: %d Private Controls: %d\n",
1436 node.std_controls - node.std_compound_controls,
1437 node.priv_controls - node.priv_compound_controls);
1438 if (node.std_compound_controls || node.priv_compound_controls)
1439 printf("\tStandard Compound Controls: %d Private Compound Controls: %d\n",
1440 node.std_compound_controls, node.priv_compound_controls);
1441 printf("\n");
1442
1443 /* Format ioctls */
1444
1445 printf("Format ioctls%s:\n", suffix);
1446 printf("\ttest VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: %s\n", ok(testEnumFormats(&node)));
1447 printf("\ttest VIDIOC_G/S_PARM: %s\n", ok(testParm(&node)));
1448 printf("\ttest VIDIOC_G_FBUF: %s\n", ok(testFBuf(&node)));
1449 printf("\ttest VIDIOC_G_FMT: %s\n", ok(testGetFormats(&node)));
1450 printf("\ttest VIDIOC_TRY_FMT: %s\n", ok(testTryFormats(&node)));
1451 printf("\ttest VIDIOC_S_FMT: %s\n", ok(testSetFormats(&node)));
1452 printf("\ttest VIDIOC_G_SLICED_VBI_CAP: %s\n", ok(testSlicedVBICap(&node)));
1453 printf("\ttest Cropping: %s\n", ok(testCropping(&node)));
1454 printf("\ttest Composing: %s\n", ok(testComposing(&node)));
1455 printf("\ttest Scaling: %s\n", ok(testScaling(&node)));
1456 printf("\n");
1457
1458 /* Codec ioctls */
1459
1460 printf("Codec ioctls%s:\n", suffix);
1461 printf("\ttest VIDIOC_(TRY_)ENCODER_CMD: %s\n", ok(testEncoder(&node)));
1462 printf("\ttest VIDIOC_G_ENC_INDEX: %s\n", ok(testEncIndex(&node)));
1463 printf("\ttest VIDIOC_(TRY_)DECODER_CMD: %s\n", ok(testDecoder(&node)));
1464 printf("\n");
1465
1466 /* Buffer ioctls */
1467
1468 printf("Buffer ioctls%s:\n", suffix);
1469 printf("\ttest VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: %s\n", ok(testReqBufs(&node)));
1470 printf("\ttest CREATE_BUFS maximum buffers: %s\n", ok(testCreateBufsMax(&node)));
1471 printf("\ttest VIDIOC_REMOVE_BUFS: %s\n", ok(testRemoveBufs(&node)));
1472 // Reopen after each streaming test to reset the streaming state
1473 // in case of any errors in the preceeding test.
1474 node.reopen();
1475 printf("\ttest VIDIOC_EXPBUF: %s\n", ok(testExpBuf(&node)));
1476 if (node.can_capture)
1477 node.set_interval(min_period);
1478 printf("\ttest Requests: %s\n", ok(testRequests(&node, options[OptStreaming])));
1479 if (sizeof(void *) == 4)
1480 printf("\ttest TIME32/64: %s\n", ok(testTime32_64(&node)));
1481 // Reopen after each streaming test to reset the streaming state
1482 // in case of any errors in the preceeding test.
1483 node.reopen();
1484 printf("\n");
1485 }
1486
1487 cur_io = node.has_inputs ? state.input.index : state.output.index;
1488 min_io = 0;
1489
1490 if (!options[OptStreamAllIO]) {
1491 min_io = cur_io;
1492 max_io = min_io + 1;
1493 }
1494
1495 for (unsigned io = min_io; io < (max_io ? max_io : 1); io++) {
1496 restoreState();
1497
1498 if (!node.is_v4l2())
1499 break;
1500
1501 if (options[OptStreaming] || (node.is_video && options[OptStreamAllFormats]) ||
1502 (node.is_video && node.can_capture && options[OptStreamAllColorTest]))
1503 printf("Test %s %d:\n\n",
1504 node.can_capture ? "input" : "output", io);
1505
1506 if (node.can_capture)
1507 doioctl(&node, VIDIOC_S_INPUT, &io);
1508 else
1509 doioctl(&node, VIDIOC_S_OUTPUT, &io);
1510
1511 if (options[OptStreaming]) {
1512 printf("Streaming ioctls:\n");
1513 streamingSetup(&node);
1514
1515 printf("\ttest read/write: %s\n", ok(testReadWrite(&node)));
1516 // Reopen after each streaming test to reset the streaming state
1517 // in case of any errors in the preceeding test.
1518 node.reopen();
1519 printf("\ttest blocking wait: %s\n", ok(testBlockingWait(&node)));
1520 node.reopen();
1521 if (!(node.codec_mask & (STATEFUL_ENCODER | STATEFUL_DECODER))) {
1522 printf("\ttest MMAP (no poll): %s\n",
1523 ok(testMmap(&node, &node_m2m_cap, frame_count, POLL_MODE_NONE)));
1524 node.reopen();
1525 }
1526 printf("\ttest MMAP (select): %s\n",
1527 ok(testMmap(&node, &node_m2m_cap, frame_count, POLL_MODE_SELECT)));
1528 node.reopen();
1529 printf("\ttest MMAP (epoll): %s\n",
1530 ok(testMmap(&node, &node_m2m_cap, frame_count, POLL_MODE_EPOLL)));
1531 node.reopen();
1532 if (!(node.codec_mask & (STATEFUL_ENCODER | STATEFUL_DECODER))) {
1533 printf("\ttest USERPTR (no poll): %s\n",
1534 ok(testUserPtr(&node, &node_m2m_cap, frame_count, POLL_MODE_NONE)));
1535 node.reopen();
1536 }
1537 printf("\ttest USERPTR (select): %s\n",
1538 ok(testUserPtr(&node, &node_m2m_cap, frame_count, POLL_MODE_SELECT)));
1539 node.reopen();
1540 if (options[OptSetExpBufDevice] ||
1541 !(node.valid_memorytype & (1 << V4L2_MEMORY_DMABUF))) {
1542 if (!(node.codec_mask & (STATEFUL_ENCODER | STATEFUL_DECODER))) {
1543 printf("\ttest DMABUF (no poll): %s\n",
1544 ok(testDmaBuf(&expbuf_node, &node, &node_m2m_cap,
1545 frame_count, POLL_MODE_NONE)));
1546 node.reopen();
1547 }
1548 printf("\ttest DMABUF (select): %s\n",
1549 ok(testDmaBuf(&expbuf_node, &node, &node_m2m_cap, frame_count, POLL_MODE_SELECT)));
1550 node.reopen();
1551 } else if (!options[OptSetExpBufDevice]) {
1552 printf("\ttest DMABUF: Cannot test, specify --expbuf-device\n");
1553 }
1554
1555 printf("\n");
1556 }
1557
1558 if (node.is_video && options[OptStreamAllFormats]) {
1559 printf("Stream using all formats:\n");
1560
1561 if (node.is_m2m) {
1562 if (node.codec_mask &
1563 (JPEG_DECODER | STATEFUL_DECODER | STATELESS_DECODER)) {
1564 printf("\tNot supported for decoder devices\n");
1565 } else {
1566 streamM2MAllFormats(&node, all_fmt_frame_count);
1567 }
1568 } else {
1569 streamingSetup(&node);
1570 streamAllFormats(&node, all_fmt_frame_count);
1571 }
1572 }
1573
1574 if (node.is_video && node.can_capture && options[OptStreamAllColorTest]) {
1575 printf("Stream using all formats and do a color check:\n");
1576
1577 if (node.is_m2m) {
1578 printf("\tNot supported for M2M devices\n");
1579 } else {
1580 streamingSetup(&node);
1581 testColorsAllFormats(&node, color_component,
1582 color_skip, color_perc);
1583 }
1584 }
1585 }
1586
1587 /*
1588 * TODO: VIDIOC_S_FBUF/OVERLAY
1589 * S_SELECTION flags tests
1590 */
1591
1592 if (is_vivid &&
1593 node.controls.find(VIVID_CID_DISCONNECT) != node.controls.end()) {
1594 if (node.node2)
1595 node.node2->close();
1596 node.node2 = nullptr;
1597 printf("\ttest Disconnect: %s\n\n", ok(testVividDisconnect(&node)));
1598 }
1599
1600 restoreState();
1601
1602 show_total:
1603 /* Final test report */
1604 if (driver.empty())
1605 printf("Total for device %s%s: %d, Succeeded: %d, Failed: %d, Warnings: %d\n",
1606 node.device, node.g_direct() ? "" : " (using libv4l2)",
1607 tests_total, tests_ok, tests_total - tests_ok, warnings);
1608 else
1609 printf("Total for %s device %s%s: %d, Succeeded: %d, Failed: %d, Warnings: %d\n",
1610 driver.c_str(), node.device, node.g_direct() ? "" : " (using libv4l2)",
1611 tests_total, tests_ok, tests_total - tests_ok, warnings);
1612 grand_total += tests_total;
1613 grand_ok += tests_ok;
1614 grand_warnings += warnings;
1615
1616 if (node.is_media() && options[OptSetMediaDevice]) {
1617 walkTopology(node, expbuf_node,
1618 frame_count, all_fmt_frame_count);
1619 /* Final test report */
1620 printf("\nGrand Total for %s device %s: %d, Succeeded: %d, Failed: %d, Warnings: %d\n",
1621 driver.c_str(), node.device,
1622 grand_total, grand_ok, grand_total - grand_ok, grand_warnings);
1623 }
1624
1625 node.close();
1626 if (node.node2)
1627 node.node2->close();
1628 }
1629
main(int argc,char ** argv)1630 int main(int argc, char **argv)
1631 {
1632 int i;
1633 struct node node;
1634 media_type type = MEDIA_TYPE_UNKNOWN;
1635 struct node expbuf_node;
1636 std::string media_bus_info;
1637 const char *env_media_apps_color = getenv("MEDIA_APPS_COLOR");
1638
1639 /* command args */
1640 int ch;
1641 std::string device("/dev/video0");
1642 std::string expbuf_device; /* --expbuf-device device */
1643 unsigned frame_count = 60;
1644 unsigned all_fmt_frame_count = 0;
1645 char short_options[26 * 2 * 3 + 1];
1646 char *value, *subs;
1647 int idx = 0;
1648
1649 if (!env_media_apps_color || !strcmp(env_media_apps_color, "auto"))
1650 show_colors = isatty(STDOUT_FILENO);
1651 else if (!strcmp(env_media_apps_color, "always"))
1652 show_colors = true;
1653 else if (!strcmp(env_media_apps_color, "never"))
1654 show_colors = false;
1655 else {
1656 fprintf(stderr,
1657 "v4l2-compliance: invalid value for MEDIA_APPS_COLOR environment variable\n");
1658 }
1659
1660 for (i = 0; long_options[i].name; i++) {
1661 if (!isalpha(long_options[i].val))
1662 continue;
1663 short_options[idx++] = long_options[i].val;
1664 if (long_options[i].has_arg == required_argument) {
1665 short_options[idx++] = ':';
1666 } else if (long_options[i].has_arg == optional_argument) {
1667 short_options[idx++] = ':';
1668 short_options[idx++] = ':';
1669 }
1670 }
1671 while (true) {
1672 int option_index = 0;
1673
1674 short_options[idx] = 0;
1675 ch = getopt_long(argc, argv, short_options,
1676 long_options, &option_index);
1677 if (ch == -1)
1678 break;
1679
1680 options[ch] = 1;
1681 if (!option_index) {
1682 for (i = 0; long_options[i].val; i++) {
1683 if (long_options[i].val == ch) {
1684 option_index = i;
1685 break;
1686 }
1687 }
1688 }
1689 if (long_options[option_index].has_arg == optional_argument &&
1690 !optarg && argv[optind] && argv[optind][0] != '-')
1691 optarg = argv[optind++];
1692
1693 switch (ch) {
1694 case OptHelp:
1695 usage();
1696 std::exit(EXIT_FAILURE);
1697 case OptSetDevice:
1698 device = make_devname(optarg, "video", media_bus_info);
1699 break;
1700 case OptSetVbiDevice:
1701 device = make_devname(optarg, "vbi", media_bus_info);
1702 break;
1703 case OptSetRadioDevice:
1704 device = make_devname(optarg, "radio", media_bus_info);
1705 break;
1706 case OptSetSWRadioDevice:
1707 device = make_devname(optarg, "swradio", media_bus_info);
1708 break;
1709 case OptSetTouchDevice:
1710 device = make_devname(optarg, "v4l-touch", media_bus_info);
1711 break;
1712 case OptSetSubDevDevice:
1713 device = make_devname(optarg, "v4l-subdev", media_bus_info);
1714 break;
1715 case OptSetMediaDevice:
1716 case OptSetMediaDeviceOnly:
1717 device = make_devname(optarg, "media", optarg, true);
1718 type = MEDIA_TYPE_MEDIA;
1719 break;
1720 case OptMediaBusInfo:
1721 media_bus_info = optarg;
1722 break;
1723 case OptSetExpBufDevice:
1724 expbuf_device = make_devname(optarg, "video", media_bus_info);
1725 break;
1726 case OptStreaming:
1727 if (optarg)
1728 frame_count = strtoul(optarg, nullptr, 0);
1729 break;
1730 case OptStreamFrom:
1731 case OptStreamFromHdr: {
1732 char *equal = std::strchr(optarg, '=');
1733 bool has_hdr = ch == OptStreamFromHdr;
1734
1735 if (equal == optarg)
1736 equal = nullptr;
1737 if (equal) {
1738 *equal = '\0';
1739 stream_from_map[optarg] = equal + 1;
1740 stream_hdr_map[optarg] = has_hdr;
1741 } else {
1742 stream_from_map[""] = optarg;
1743 stream_hdr_map[""] = has_hdr;
1744 }
1745 break;
1746 }
1747 case OptStreamAllFormats:
1748 if (optarg)
1749 all_fmt_frame_count = strtoul(optarg, nullptr, 0);
1750 break;
1751 case OptStreamAllColorTest:
1752 subs = optarg;
1753 while (*subs != '\0') {
1754 static constexpr const char *subopts[] = {
1755 "color",
1756 "skip",
1757 "perc",
1758 nullptr
1759 };
1760
1761 switch (parse_subopt(&subs, subopts, &value)) {
1762 case 0:
1763 if (!strcmp(value, "red"))
1764 color_component = 0;
1765 else if (!strcmp(value, "green"))
1766 color_component = 1;
1767 else if (!strcmp(value, "blue"))
1768 color_component = 2;
1769 else {
1770 usage();
1771 std::exit(EXIT_FAILURE);
1772 }
1773 break;
1774 case 1:
1775 color_skip = strtoul(value, nullptr, 0);
1776 break;
1777 case 2:
1778 color_perc = strtoul(value, nullptr, 0);
1779 if (color_perc == 0)
1780 color_perc = 90;
1781 if (color_perc > 100)
1782 color_perc = 100;
1783 break;
1784 default:
1785 usage();
1786 std::exit(EXIT_FAILURE);
1787 }
1788 }
1789 break;
1790 case OptColor:
1791 if (!strcmp(optarg, "always"))
1792 show_colors = true;
1793 else if (!strcmp(optarg, "never"))
1794 show_colors = false;
1795 else if (!strcmp(optarg, "auto"))
1796 show_colors = isatty(STDOUT_FILENO);
1797 else {
1798 usage();
1799 std::exit(EXIT_FAILURE);
1800 }
1801 break;
1802 case OptNoWarnings:
1803 show_warnings = false;
1804 break;
1805 case OptExitOnWarn:
1806 exit_on_warn = true;
1807 break;
1808 case OptExitOnFail:
1809 exit_on_fail = true;
1810 break;
1811 case OptVerbose:
1812 show_info = true;
1813 break;
1814 case OptNoProgress:
1815 no_progress = true;
1816 break;
1817 case OptVersion:
1818 print_sha();
1819 std::exit(EXIT_SUCCESS);
1820 case ':':
1821 fprintf(stderr, "Option `%s' requires a value\n",
1822 argv[optind]);
1823 usage();
1824 std::exit(EXIT_FAILURE);
1825 case '?':
1826 if (argv[optind])
1827 fprintf(stderr, "Unknown argument `%s'\n",
1828 argv[optind]);
1829 usage();
1830 std::exit(EXIT_FAILURE);
1831 }
1832 }
1833 if (optind < argc) {
1834 fprintf(stderr, "unknown arguments: ");
1835 while (optind < argc)
1836 fprintf(stderr, "%s ", argv[optind++]);
1837 fprintf(stderr, "\n");
1838 usage();
1839 std::exit(EXIT_FAILURE);
1840 }
1841
1842 print_sha();
1843 printf("\n");
1844
1845 bool direct = !options[OptUseWrapper];
1846 int fd;
1847
1848 if (type == MEDIA_TYPE_UNKNOWN)
1849 type = mi_media_detect_type(device.c_str());
1850 if (type == MEDIA_TYPE_CANT_STAT) {
1851 fprintf(stderr, "Cannot open device %s, exiting.\n",
1852 device.c_str());
1853 std::exit(EXIT_FAILURE);
1854 }
1855 if (type == MEDIA_TYPE_UNKNOWN) {
1856 fprintf(stderr, "Unable to detect what device %s is, exiting.\n",
1857 device.c_str());
1858 std::exit(EXIT_FAILURE);
1859 }
1860
1861 node.device = device.c_str();
1862 node.s_trace(options[OptTrace]);
1863 switch (type) {
1864 case MEDIA_TYPE_MEDIA:
1865 node.s_direct(true);
1866 fd = node.media_open(device.c_str(), false);
1867 break;
1868 case MEDIA_TYPE_SUBDEV:
1869 node.s_direct(true);
1870 fd = node.subdev_open(device.c_str(), false);
1871 break;
1872 default:
1873 node.s_direct(direct);
1874 fd = node.open(device.c_str(), false);
1875 break;
1876 }
1877 if (fd < 0) {
1878 fprintf(stderr, "Failed to open %s: %s\n", device.c_str(),
1879 strerror(errno));
1880 std::exit(EXIT_FAILURE);
1881 }
1882
1883 if (!expbuf_device.empty()) {
1884 expbuf_node.s_trace(options[OptTrace]);
1885 expbuf_node.s_direct(true);
1886 fd = expbuf_node.open(expbuf_device.c_str(), false);
1887 if (fd < 0) {
1888 fprintf(stderr, "Failed to open %s: %s\n", expbuf_device.c_str(),
1889 strerror(errno));
1890 std::exit(EXIT_FAILURE);
1891 }
1892 }
1893
1894 testNode(node, node, expbuf_node, type, frame_count, all_fmt_frame_count);
1895
1896 if (!expbuf_device.empty())
1897 expbuf_node.close();
1898 if (media_fd >= 0)
1899 close(media_fd);
1900
1901 std::exit(app_result);
1902 }
1903