1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <inttypes.h>
6 #include <getopt.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <ctype.h>
11 #include <errno.h>
12 #include <sys/ioctl.h>
13 #include <sys/time.h>
14 #include <dirent.h>
15 #include <math.h>
16 #include <cstdlib>
17
18 #include "v4l2-ctl.h"
19
20 struct mbus_name {
21 const char *name;
22 uint32_t code;
23 };
24
25 static struct mbus_name mbus_names[] = {
26 { "Fixed", MEDIA_BUS_FMT_FIXED },
27 #include "media-bus-format-names.h"
28 { NULL, 0 }
29 };
30
31 /* selection specified */
32 #define SelectionWidth (1L<<0)
33 #define SelectionHeight (1L<<1)
34 #define SelectionLeft (1L<<2)
35 #define SelectionTop (1L<<3)
36 #define SelectionFlags (1L<<4)
37
38 static uint32_t list_mbus_codes_pad;
39 static uint32_t get_fmt_pad;
40 static uint32_t get_sel_pad;
41 static uint32_t get_fps_pad;
42 static int get_sel_target = -1;
43 static unsigned int set_selection;
44 static struct v4l2_subdev_selection vsel;
45 static unsigned int set_fmt;
46 static uint32_t set_fmt_pad;
47 static struct v4l2_mbus_framefmt ffmt;
48 static struct v4l2_subdev_frame_size_enum frmsize;
49 static struct v4l2_subdev_frame_interval_enum frmival;
50 static uint32_t set_fps_pad;
51 static double set_fps;
52
subdev_usage()53 void subdev_usage()
54 {
55 printf("\nSub-Device options:\n"
56 " --list-subdev-mbus-codes <pad>\n"
57 " display supported mediabus codes for this pad (0 is default)\n"
58 " [VIDIOC_SUBDEV_ENUM_MBUS_CODE]\n"
59 " --list-subdev-framesizes pad=<pad>,code=<code>\n"
60 " list supported framesizes for this pad and code\n"
61 " [VIDIOC_SUBDEV_ENUM_FRAME_SIZE]\n"
62 " <code> is the value of the mediabus code\n"
63 " --list-subdev-frameintervals pad=<pad>,width=<w>,height=<h>,code=<code>\n"
64 " list supported frame intervals for this pad and code and\n"
65 " the given width and height [VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL]\n"
66 " <code> is the value of the mediabus code\n"
67 " --get-subdev-fmt [<pad>]\n"
68 " query the frame format for the given pad [VIDIOC_SUBDEV_G_FMT]\n"
69 " --get-subdev-selection pad=<pad>,target=<target>\n"
70 " query the frame selection rectangle [VIDIOC_SUBDEV_G_SELECTION]\n"
71 " See --set-subdev-selection command for the valid <target> values.\n"
72 " --get-subdev-fps [<pad>]\n"
73 " query the frame rate [VIDIOC_SUBDEV_G_FRAME_INTERVAL]\n"
74 " --set-subdev-fmt (for testing only, otherwise use media-ctl)\n"
75 " --try-subdev-fmt pad=<pad>,width=<w>,height=<h>,code=<code>,field=<f>,colorspace=<c>,\n"
76 " xfer=<xf>,ycbcr=<y>,hsv=<hsv>,quantization=<q>\n"
77 " set the frame format [VIDIOC_SUBDEV_S_FMT]\n"
78 " <code> is the value of the mediabus code\n"
79 " <f> can be one of the following field layouts:\n"
80 " any, none, top, bottom, interlaced, seq_tb, seq_bt,\n"
81 " alternate, interlaced_tb, interlaced_bt\n"
82 " <c> can be one of the following colorspaces:\n"
83 " smpte170m, smpte240m, rec709, 470m, 470bg, jpeg, srgb,\n"
84 " oprgb, bt2020, dcip3\n"
85 " <xf> can be one of the following transfer functions:\n"
86 " default, 709, srgb, oprgb, smpte240m, smpte2084, dcip3, none\n"
87 " <y> can be one of the following Y'CbCr encodings:\n"
88 " default, 601, 709, xv601, xv709, bt2020, bt2020c, smpte240m\n"
89 " <hsv> can be one of the following HSV encodings:\n"
90 " default, 180, 256\n"
91 " <q> can be one of the following quantization methods:\n"
92 " default, full-range, lim-range\n"
93 " --set-subdev-selection (for testing only, otherwise use media-ctl)\n"
94 " --try-subdev-selection pad=<pad>,target=<target>,flags=<flags>,\n"
95 " top=<x>,left=<y>,width=<w>,height=<h>\n"
96 " set the video capture selection rectangle [VIDIOC_SUBDEV_S_SELECTION]\n"
97 " target=crop|crop_bounds|crop_default|compose|compose_bounds|\n"
98 " compose_default|compose_padded|native_size\n"
99 " flags=le|ge|keep-config\n"
100 " --set-subdev-fps pad=<pad>,fps=<fps> (for testing only, otherwise use media-ctl)\n"
101 " set the frame rate [VIDIOC_SUBDEV_S_FRAME_INTERVAL]\n"
102 );
103 }
104
subdev_cmd(int ch,char * optarg)105 void subdev_cmd(int ch, char *optarg)
106 {
107 char *value, *subs;
108
109 switch (ch) {
110 case OptListSubDevMBusCodes:
111 if (optarg)
112 list_mbus_codes_pad = strtoul(optarg, 0L, 0);
113 break;
114 case OptListSubDevFrameSizes:
115 subs = optarg;
116 while (*subs != '\0') {
117 static const char *const subopts[] = {
118 "pad",
119 "code",
120 NULL
121 };
122
123 switch (parse_subopt(&subs, subopts, &value)) {
124 case 0:
125 frmsize.pad = strtoul(value, 0L, 0);
126 break;
127 case 1:
128 frmsize.code = strtoul(value, 0L, 0);
129 break;
130 default:
131 subdev_usage();
132 std::exit(EXIT_FAILURE);
133 }
134 }
135 break;
136 case OptListSubDevFrameIntervals:
137 subs = optarg;
138 while (*subs != '\0') {
139 static const char *const subopts[] = {
140 "pad",
141 "code",
142 "width",
143 "height",
144 NULL
145 };
146
147 switch (parse_subopt(&subs, subopts, &value)) {
148 case 0:
149 frmival.pad = strtoul(value, 0L, 0);
150 break;
151 case 1:
152 frmival.code = strtoul(value, 0L, 0);
153 break;
154 case 2:
155 frmival.width = strtoul(value, 0L, 0);
156 break;
157 case 3:
158 frmival.height = strtoul(value, 0L, 0);
159 break;
160 default:
161 subdev_usage();
162 std::exit(EXIT_FAILURE);
163 }
164 }
165 break;
166 case OptGetSubDevFormat:
167 if (optarg)
168 get_fmt_pad = strtoul(optarg, 0L, 0);
169 break;
170 case OptGetSubDevSelection:
171 subs = optarg;
172 while (*subs != '\0') {
173 static const char *const subopts[] = {
174 "pad",
175 "target",
176 NULL
177 };
178 unsigned int target;
179
180 switch (parse_subopt(&subs, subopts, &value)) {
181 case 0:
182 get_sel_pad = strtoul(value, 0L, 0);
183 break;
184 case 1:
185 if (parse_selection_target(value, target)) {
186 fprintf(stderr, "Unknown selection target\n");
187 subdev_usage();
188 std::exit(EXIT_FAILURE);
189 }
190 get_sel_target = target;
191 break;
192 default:
193 subdev_usage();
194 std::exit(EXIT_FAILURE);
195 }
196 }
197 break;
198 case OptGetSubDevFPS:
199 if (optarg)
200 get_fps_pad = strtoul(optarg, 0L, 0);
201 break;
202 case OptSetSubDevFormat:
203 case OptTrySubDevFormat:
204 ffmt.field = V4L2_FIELD_ANY;
205 subs = optarg;
206 while (*subs != '\0') {
207 static const char *const subopts[] = {
208 "width",
209 "height",
210 "code",
211 "field",
212 "colorspace",
213 "ycbcr",
214 "hsv",
215 "quantization",
216 "xfer",
217 "pad",
218 NULL
219 };
220
221 switch (parse_subopt(&subs, subopts, &value)) {
222 case 0:
223 ffmt.width = strtoul(value, 0L, 0);
224 set_fmt |= FmtWidth;
225 break;
226 case 1:
227 ffmt.height = strtoul(value, 0L, 0);
228 set_fmt |= FmtHeight;
229 break;
230 case 2:
231 ffmt.code = strtoul(value, 0L, 0);
232 set_fmt |= FmtPixelFormat;
233 break;
234 case 3:
235 ffmt.field = parse_field(value);
236 set_fmt |= FmtField;
237 break;
238 case 4:
239 ffmt.colorspace = parse_colorspace(value);
240 if (ffmt.colorspace)
241 set_fmt |= FmtColorspace;
242 else
243 fprintf(stderr, "unknown colorspace %s\n", value);
244 break;
245 case 5:
246 ffmt.ycbcr_enc = parse_ycbcr(value);
247 set_fmt |= FmtYCbCr;
248 break;
249 case 6:
250 ffmt.ycbcr_enc = parse_hsv(value);
251 set_fmt |= FmtYCbCr;
252 break;
253 case 7:
254 ffmt.quantization = parse_quantization(value);
255 set_fmt |= FmtQuantization;
256 break;
257 case 8:
258 ffmt.xfer_func = parse_xfer_func(value);
259 set_fmt |= FmtXferFunc;
260 break;
261 case 9:
262 set_fmt_pad = strtoul(value, 0L, 0);
263 break;
264 default:
265 fprintf(stderr, "Unknown option\n");
266 subdev_usage();
267 std::exit(EXIT_FAILURE);
268 }
269 }
270 break;
271 case OptSetSubDevSelection:
272 case OptTrySubDevSelection:
273 subs = optarg;
274
275 while (*subs != '\0') {
276 static const char *const subopts[] = {
277 "target",
278 "flags",
279 "left",
280 "top",
281 "width",
282 "height",
283 "pad",
284 NULL
285 };
286
287 switch (parse_subopt(&subs, subopts, &value)) {
288 case 0:
289 if (parse_selection_target(value, vsel.target)) {
290 fprintf(stderr, "Unknown selection target\n");
291 subdev_usage();
292 std::exit(EXIT_FAILURE);
293 }
294 break;
295 case 1:
296 vsel.flags = parse_selection_flags(value);
297 set_selection |= SelectionFlags;
298 break;
299 case 2:
300 vsel.r.left = strtol(value, 0L, 0);
301 set_selection |= SelectionLeft;
302 break;
303 case 3:
304 vsel.r.top = strtol(value, 0L, 0);
305 set_selection |= SelectionTop;
306 break;
307 case 4:
308 vsel.r.width = strtoul(value, 0L, 0);
309 set_selection |= SelectionWidth;
310 break;
311 case 5:
312 vsel.r.height = strtoul(value, 0L, 0);
313 set_selection |= SelectionHeight;
314 break;
315 case 6:
316 vsel.pad = strtoul(value, 0L, 0);
317 break;
318 default:
319 fprintf(stderr, "Unknown option\n");
320 subdev_usage();
321 std::exit(EXIT_FAILURE);
322 }
323 }
324 break;
325 case OptSetSubDevFPS:
326 subs = optarg;
327
328 while (*subs != '\0') {
329 static const char *const subopts[] = {
330 "pad",
331 "fps",
332 NULL
333 };
334
335 switch (parse_subopt(&subs, subopts, &value)) {
336 case 0:
337 set_fps_pad = strtoul(value, 0L, 0);
338 break;
339 case 1:
340 set_fps = strtod(value, NULL);
341 break;
342 default:
343 fprintf(stderr, "Unknown option\n");
344 subdev_usage();
345 std::exit(EXIT_FAILURE);
346 }
347 }
348 break;
349 default:
350 break;
351 }
352 }
353
is_rgb_or_hsv_code(uint32_t code)354 static bool is_rgb_or_hsv_code(uint32_t code)
355 {
356 return code < 0x2000 || code >= 0x3000;
357 }
358
print_framefmt(const struct v4l2_mbus_framefmt & fmt)359 static void print_framefmt(const struct v4l2_mbus_framefmt &fmt)
360 {
361 uint32_t colsp = fmt.colorspace;
362 uint32_t ycbcr_enc = fmt.ycbcr_enc;
363 unsigned int i;
364
365 for (i = 0; mbus_names[i].name; i++)
366 if (mbus_names[i].code == fmt.code)
367 break;
368 printf("\tWidth/Height : %u/%u\n", fmt.width, fmt.height);
369 printf("\tMediabus Code : ");
370 if (mbus_names[i].name)
371 printf("0x%04x (MEDIA_BUS_FMT_%s)\n",
372 fmt.code, mbus_names[i].name);
373 else
374 printf("0x%04x\n", fmt.code);
375
376 printf("\tField : %s\n", field2s(fmt.field).c_str());
377 printf("\tColorspace : %s\n", colorspace2s(colsp).c_str());
378 printf("\tTransfer Function : %s", xfer_func2s(fmt.xfer_func).c_str());
379 if (fmt.xfer_func == V4L2_XFER_FUNC_DEFAULT)
380 printf(" (maps to %s)",
381 xfer_func2s(V4L2_MAP_XFER_FUNC_DEFAULT(colsp)).c_str());
382 printf("\n");
383 printf("\tYCbCr/HSV Encoding: %s", ycbcr_enc2s(ycbcr_enc).c_str());
384 if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
385 ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colsp);
386 printf(" (maps to %s)", ycbcr_enc2s(ycbcr_enc).c_str());
387 }
388 printf("\n");
389 printf("\tQuantization : %s", quantization2s(fmt.quantization).c_str());
390 if (fmt.quantization == V4L2_QUANTIZATION_DEFAULT)
391 printf(" (maps to %s)",
392 quantization2s(V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb_or_hsv_code(fmt.code),
393 colsp, ycbcr_enc)).c_str());
394 printf("\n");
395 }
396
print_subdev_selection(const struct v4l2_subdev_selection & sel)397 static void print_subdev_selection(const struct v4l2_subdev_selection &sel)
398 {
399 printf("Selection: %s, Left %d, Top %d, Width %d, Height %d, Flags: %s\n",
400 seltarget2s(sel.target).c_str(),
401 sel.r.left, sel.r.top, sel.r.width, sel.r.height,
402 selflags2s(sel.flags).c_str());
403 }
404
subdev_set(cv4l_fd & _fd)405 void subdev_set(cv4l_fd &_fd)
406 {
407 int fd = _fd.g_fd();
408
409 if (options[OptSetSubDevFormat] || options[OptTrySubDevFormat]) {
410 struct v4l2_subdev_format fmt;
411
412 memset(&fmt, 0, sizeof(fmt));
413 fmt.pad = set_fmt_pad;
414 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
415
416 if (doioctl(fd, VIDIOC_SUBDEV_G_FMT, &fmt) == 0) {
417 int ret;
418
419 if (set_fmt & FmtWidth)
420 fmt.format.width = ffmt.width;
421 if (set_fmt & FmtHeight)
422 fmt.format.height = ffmt.height;
423 if (set_fmt & FmtPixelFormat)
424 fmt.format.code = ffmt.code;
425 if (set_fmt & FmtField)
426 fmt.format.field = ffmt.field;
427 if (set_fmt & FmtColorspace)
428 fmt.format.colorspace = ffmt.colorspace;
429 if (set_fmt & FmtXferFunc)
430 fmt.format.xfer_func = ffmt.xfer_func;
431 if (set_fmt & FmtYCbCr)
432 fmt.format.ycbcr_enc = ffmt.ycbcr_enc;
433 if (set_fmt & FmtQuantization)
434 fmt.format.quantization = ffmt.quantization;
435
436 if (options[OptSetSubDevFormat])
437 printf("Note: --set-subdev-fmt is only for testing.\n"
438 "Normally media-ctl is used to configure the video pipeline.\n");
439 else
440 fmt.which = V4L2_SUBDEV_FORMAT_TRY;
441
442 printf("ioctl: VIDIOC_SUBDEV_S_FMT (pad=%u)\n", fmt.pad);
443 ret = doioctl(fd, VIDIOC_SUBDEV_S_FMT, &fmt);
444 if (ret == 0 && (verbose || !options[OptSetSubDevFormat]))
445 print_framefmt(fmt.format);
446 }
447 }
448 if (options[OptSetSubDevSelection] || options[OptTrySubDevSelection]) {
449 struct v4l2_subdev_selection sel;
450
451 memset(&sel, 0, sizeof(sel));
452 sel.pad = vsel.pad;
453 sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
454 sel.target = vsel.target;
455
456 if (doioctl(fd, VIDIOC_SUBDEV_G_SELECTION, &sel) == 0) {
457 if (set_selection & SelectionWidth)
458 sel.r.width = vsel.r.width;
459 if (set_selection & SelectionHeight)
460 sel.r.height = vsel.r.height;
461 if (set_selection & SelectionLeft)
462 sel.r.left = vsel.r.left;
463 if (set_selection & SelectionTop)
464 sel.r.top = vsel.r.top;
465 sel.flags = (set_selection & SelectionFlags) ? vsel.flags : 0;
466
467 if (options[OptSetSubDevSelection])
468 printf("Note: --set-subdev-selection is only for testing.\n"
469 "Normally media-ctl is used to configure the video pipeline.\n");
470 else
471 sel.which = V4L2_SUBDEV_FORMAT_TRY;
472
473 printf("ioctl: VIDIOC_SUBDEV_S_SELECTION (pad=%u)\n", sel.pad);
474 int ret = doioctl(fd, VIDIOC_SUBDEV_S_SELECTION, &sel);
475 if (ret == 0 && (verbose || !options[OptSetSubDevSelection]))
476 print_subdev_selection(sel);
477 }
478 }
479 if (options[OptSetSubDevFPS]) {
480 struct v4l2_subdev_frame_interval fival;
481
482 memset(&fival, 0, sizeof(fival));
483 fival.pad = set_fps_pad;
484
485 if (set_fps <= 0) {
486 fprintf(stderr, "invalid fps %f\n", set_fps);
487 subdev_usage();
488 std::exit(EXIT_FAILURE);
489 }
490 fival.interval.numerator = 1000;
491 fival.interval.denominator = static_cast<uint32_t>(set_fps * fival.interval.numerator);
492 printf("Note: --set-subdev-fps is only for testing.\n"
493 "Normally media-ctl is used to configure the video pipeline.\n");
494 printf("ioctl: VIDIOC_SUBDEV_S_FRAME_INTERVAL (pad=%u)\n", fival.pad);
495 if (doioctl(fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival) == 0) {
496 if (!fival.interval.denominator || !fival.interval.numerator)
497 printf("\tFrames per second: invalid (%d/%d)\n",
498 fival.interval.denominator, fival.interval.numerator);
499 else
500 printf("\tFrames per second: %.3f (%d/%d)\n",
501 (1.0 * fival.interval.denominator) / fival.interval.numerator,
502 fival.interval.denominator, fival.interval.numerator);
503 }
504 }
505 }
506
subdev_get(cv4l_fd & _fd)507 void subdev_get(cv4l_fd &_fd)
508 {
509 int fd = _fd.g_fd();
510
511 if (options[OptGetSubDevFormat]) {
512 struct v4l2_subdev_format fmt;
513
514 memset(&fmt, 0, sizeof(fmt));
515 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
516 fmt.pad = get_fmt_pad;
517
518 printf("ioctl: VIDIOC_SUBDEV_G_FMT (pad=%u)\n", fmt.pad);
519 if (doioctl(fd, VIDIOC_SUBDEV_G_FMT, &fmt) == 0)
520 print_framefmt(fmt.format);
521 }
522
523 if (options[OptGetSubDevSelection]) {
524 struct v4l2_subdev_selection sel;
525 unsigned idx = 0;
526
527 memset(&sel, 0, sizeof(sel));
528 sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
529 sel.pad = get_sel_pad;
530
531 printf("ioctl: VIDIOC_SUBDEV_G_SELECTION (pad=%u)\n", sel.pad);
532 if (options[OptAll] || get_sel_target == -1) {
533 while (valid_seltarget_at_idx(idx)) {
534 sel.target = seltarget_at_idx(idx);
535 if (test_ioctl(fd, VIDIOC_SUBDEV_G_SELECTION, &sel) == 0)
536 print_subdev_selection(sel);
537 idx++;
538 }
539 } else {
540 sel.target = get_sel_target;
541 if (doioctl(fd, VIDIOC_SUBDEV_G_SELECTION, &sel) == 0)
542 print_subdev_selection(sel);
543 }
544 }
545 if (options[OptGetSubDevFPS]) {
546 struct v4l2_subdev_frame_interval fival;
547
548 memset(&fival, 0, sizeof(fival));
549 fival.pad = get_fps_pad;
550
551 printf("ioctl: VIDIOC_SUBDEV_G_FRAME_INTERVAL (pad=%u)\n", fival.pad);
552 if (doioctl(fd, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &fival) == 0) {
553 if (!fival.interval.denominator || !fival.interval.numerator)
554 printf("\tFrames per second: invalid (%d/%d)\n",
555 fival.interval.denominator, fival.interval.numerator);
556 else
557 printf("\tFrames per second: %.3f (%d/%d)\n",
558 (1.0 * fival.interval.denominator) / fival.interval.numerator,
559 fival.interval.denominator, fival.interval.numerator);
560 }
561 }
562 }
563
print_mbus_code(uint32_t code)564 static void print_mbus_code(uint32_t code)
565 {
566 unsigned int i;
567
568 for (i = 0; mbus_names[i].name; i++)
569 if (mbus_names[i].code == code)
570 break;
571 if (mbus_names[i].name)
572 printf("\t0x%04x: MEDIA_BUS_FMT_%s\n",
573 mbus_names[i].code, mbus_names[i].name);
574 else
575 printf("\t0x%04x\n", code);
576 }
577
print_mbus_codes(int fd,uint32_t pad)578 static void print_mbus_codes(int fd, uint32_t pad)
579 {
580 struct v4l2_subdev_mbus_code_enum mbus_code;
581
582 memset(&mbus_code, 0, sizeof(mbus_code));
583 mbus_code.pad = pad;
584 mbus_code.which = V4L2_SUBDEV_FORMAT_TRY;
585
586 for (;;) {
587 int ret = test_ioctl(fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_code);
588
589 if (ret)
590 break;
591 print_mbus_code(mbus_code.code);
592 mbus_code.index++;
593 }
594 }
595
fract2sec(const struct v4l2_fract & f)596 static std::string fract2sec(const struct v4l2_fract &f)
597 {
598 char buf[100];
599
600 sprintf(buf, "%.3f", (1.0 * f.numerator) / f.denominator);
601 return buf;
602 }
603
fract2fps(const struct v4l2_fract & f)604 static std::string fract2fps(const struct v4l2_fract &f)
605 {
606 char buf[100];
607
608 sprintf(buf, "%.3f", (1.0 * f.denominator) / f.numerator);
609 return buf;
610 }
611
print_frmsize(const struct v4l2_subdev_frame_size_enum & frmsize)612 static void print_frmsize(const struct v4l2_subdev_frame_size_enum &frmsize)
613 {
614 printf("\tSize Range: %dx%d - %dx%d\n",
615 frmsize.min_width, frmsize.min_height,
616 frmsize.max_width, frmsize.max_height);
617 }
618
print_frmival(const struct v4l2_subdev_frame_interval_enum & frmival)619 static void print_frmival(const struct v4l2_subdev_frame_interval_enum &frmival)
620 {
621 printf("\tInterval: %ss (%s fps)\n", fract2sec(frmival.interval).c_str(),
622 fract2fps(frmival.interval).c_str());
623 }
624
subdev_list(cv4l_fd & _fd)625 void subdev_list(cv4l_fd &_fd)
626 {
627 int fd = _fd.g_fd();
628
629 if (options[OptListSubDevMBusCodes]) {
630 printf("ioctl: VIDIOC_SUBDEV_ENUM_MBUS_CODE (pad=%u)\n",
631 list_mbus_codes_pad);
632 print_mbus_codes(fd, list_mbus_codes_pad);
633 }
634 if (options[OptListSubDevFrameSizes]) {
635 printf("ioctl: VIDIOC_SUBDEV_ENUM_FRAME_SIZE (pad=%u)\n",
636 frmsize.pad);
637 frmsize.index = 0;
638 frmsize.which = V4L2_SUBDEV_FORMAT_TRY;
639 while (test_ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &frmsize) >= 0) {
640 print_frmsize(frmsize);
641 frmsize.index++;
642 }
643 }
644 if (options[OptListSubDevFrameIntervals]) {
645 printf("ioctl: VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL (pad=%u)\n",
646 frmival.pad);
647 frmival.index = 0;
648 frmival.which = V4L2_SUBDEV_FORMAT_TRY;
649 while (test_ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &frmival) >= 0) {
650 print_frmival(frmival);
651 frmival.index++;
652 }
653 }
654 }
655