| #include <cctype> |
| |
| #include "v4l2-ctl.h" |
| |
| static v4l2_std_id standard; /* get_std/set_std */ |
| static struct v4l2_dv_timings dv_timings; /* set_dv_bt_timings/get_dv_timings/query_dv_timings */ |
| static bool query_and_set_dv_timings = false; |
| static bool cleared_dv_timings = false; |
| static int enum_and_set_dv_timings = -1; |
| static unsigned set_dv_timing_opts; |
| static __u32 list_dv_timings_pad; |
| static __u32 dv_timings_cap_pad; |
| |
| void stds_usage() |
| { |
| printf("\nStandards/Timings options:\n" |
| " --list-standards display supported video standards [VIDIOC_ENUMSTD]\n" |
| " -S, --get-standard\n" |
| " query the video standard [VIDIOC_G_STD]\n" |
| " -s, --set-standard <num>\n" |
| " set the video standard to <num> [VIDIOC_S_STD]\n" |
| " <num> a numerical v4l2_std value, or one of:\n" |
| " pal or pal-X (X = B/G/H/N/Nc/I/D/K/M/60) (V4L2_STD_PAL)\n" |
| " ntsc or ntsc-X (X = M/J/K) (V4L2_STD_NTSC)\n" |
| " secam or secam-X (X = B/G/H/D/K/L/Lc) (V4L2_STD_SECAM)\n" |
| " --get-detected-standard\n" |
| " display detected input video standard [VIDIOC_QUERYSTD]\n" |
| " --list-dv-timings [<pad>]\n" |
| " list supp. standard dv timings [VIDIOC_ENUM_DV_TIMINGS]\n" |
| " for subdevs the pad can be specified (default is 0)\n" |
| " --set-dv-bt-timings\n" |
| " query: use the output of VIDIOC_QUERY_DV_TIMINGS\n" |
| " index=<index>: use the index as provided by --list-dv-timings\n" |
| " or specify timings using cvt/gtf options as follows:\n" |
| " cvt/gtf,width=<width>,height=<height>,fps=<frames per sec>\n" |
| " interlaced=<0/1>,reduced-blanking=<0/1/2>,reduced-fps=<0/1>\n" |
| " The value of reduced-blanking, if greater than 0, indicates\n" |
| " that reduced blanking is to be used and the value indicate the\n" |
| " version. For gtf, there is no version 2 for reduced blanking, and\n" |
| " the value 1 or 2 will give same results.\n" |
| " reduced-fps = 1, slows down pixel clock by factor of 1000 / 1001, allowing\n" |
| " to support NTSC frame rates like 29.97 or 59.94.\n" |
| " Reduced fps flag takes effect only with reduced blanking version 2 and,\n" |
| " when refresh rate is an integer multiple of 6, say, fps = 24,30,60 etc.\n" |
| " or update all or part of the current timings fields:\n" |
| " width=<width>,height=<height>,interlaced=<0/1>,\n" |
| " polarities=<polarities mask>,pixelclock=<pixelclock Hz>,\n" |
| " hfp=<horizontal front porch>,hs=<horizontal sync>,\n" |
| " hbp=<horizontal back porch>,vfp=<vertical front porch>,\n" |
| " vs=<vertical sync>,vbp=<vertical back porch>,\n" |
| " il_vfp=<vertical front porch for bottom field>,\n" |
| " il_vs=<vertical sync for bottom field>,\n" |
| " il_vbp=<vertical back porch for bottom field>.\n" |
| " clear: start with zeroed timings instead of the current timings.\n" |
| " set the digital video timings according to the BT 656/1120\n" |
| " standard [VIDIOC_S_DV_TIMINGS]\n" |
| " --get-dv-timings get the digital video timings in use [VIDIOC_G_DV_TIMINGS]\n" |
| " --query-dv-timings query the detected dv timings [VIDIOC_QUERY_DV_TIMINGS]\n" |
| " --get-dv-timings-cap [<pad>]\n" |
| " get the dv timings capabilities [VIDIOC_DV_TIMINGS_CAP]\n" |
| " for subdevs the pad can be specified (default is 0)\n" |
| ); |
| } |
| |
| static v4l2_std_id parse_pal(const char *pal) |
| { |
| if (pal[0] == '-') { |
| switch (tolower(pal[1])) { |
| case '6': |
| return V4L2_STD_PAL_60; |
| case 'b': |
| case 'g': |
| return V4L2_STD_PAL_BG; |
| case 'h': |
| return V4L2_STD_PAL_H; |
| case 'n': |
| if (tolower(pal[2]) == 'c') |
| return V4L2_STD_PAL_Nc; |
| return V4L2_STD_PAL_N; |
| case 'i': |
| return V4L2_STD_PAL_I; |
| case 'd': |
| case 'k': |
| return V4L2_STD_PAL_DK; |
| case 'm': |
| return V4L2_STD_PAL_M; |
| } |
| } |
| fprintf(stderr, "pal specifier not recognised\n"); |
| stds_usage(); |
| std::exit(EXIT_FAILURE); |
| } |
| |
| static v4l2_std_id parse_secam(const char *secam) |
| { |
| if (secam[0] == '-') { |
| switch (tolower(secam[1])) { |
| case 'b': |
| case 'g': |
| case 'h': |
| return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; |
| case 'd': |
| case 'k': |
| return V4L2_STD_SECAM_DK; |
| case 'l': |
| if (tolower(secam[2]) == 'c') |
| return V4L2_STD_SECAM_LC; |
| return V4L2_STD_SECAM_L; |
| } |
| } |
| fprintf(stderr, "secam specifier not recognised\n"); |
| stds_usage(); |
| std::exit(EXIT_FAILURE); |
| } |
| |
| static v4l2_std_id parse_ntsc(const char *ntsc) |
| { |
| if (ntsc[0] == '-') { |
| switch (tolower(ntsc[1])) { |
| case 'm': |
| return V4L2_STD_NTSC_M; |
| case 'j': |
| return V4L2_STD_NTSC_M_JP; |
| case 'k': |
| return V4L2_STD_NTSC_M_KR; |
| } |
| } |
| fprintf(stderr, "ntsc specifier not recognised\n"); |
| stds_usage(); |
| std::exit(EXIT_FAILURE); |
| } |
| |
| enum timing_opts { |
| WIDTH = 0, |
| HEIGHT, |
| INTERLACED, |
| POLARITIES, |
| PIXEL_CLOCK, |
| HORZ_FRONT_PORCH, |
| HORZ_SYNC, |
| HORZ_BACK_PORCH, |
| VERT_FRONT_PORCH, |
| VERT_SYNC, |
| VERT_BACK_PORCH, |
| IL_VERT_FRONT_PORCH, |
| IL_VERT_SYNC, |
| IL_VERT_BACK_PORCH, |
| INDEX, |
| CVT, |
| GTF, |
| FPS, |
| REDUCED_BLANK, |
| REDUCED_FPS, |
| CLEAR, |
| MAX_TIMINGS_OPTIONS |
| }; |
| |
| static int parse_timing_subopt(char **subopt_str, int *value) |
| { |
| int opt; |
| char *opt_str; |
| |
| static constexpr const char *subopt_list[] = { |
| "width", |
| "height", |
| "interlaced", |
| "polarities", |
| "pixelclock", |
| "hfp", |
| "hs", |
| "hbp", |
| "vfp", |
| "vs", |
| "vbp", |
| "il_vfp", |
| "il_vs", |
| "il_vbp", |
| "index", |
| "cvt", |
| "gtf", |
| "fps", |
| "reduced-blanking", |
| "reduced-fps", |
| "clear", |
| nullptr |
| }; |
| |
| opt = v4l_getsubopt(subopt_str, (char* const*) subopt_list, &opt_str); |
| |
| if (opt == -1) { |
| fprintf(stderr, "Invalid suboptions specified\n"); |
| stds_usage(); |
| std::exit(EXIT_FAILURE); |
| } |
| if (opt_str == nullptr && opt != CVT && opt != GTF && opt != CLEAR) { |
| fprintf(stderr, "No value given to suboption <%s>\n", |
| subopt_list[opt]); |
| stds_usage(); |
| std::exit(EXIT_FAILURE); |
| } |
| |
| if (opt_str) |
| *value = strtol(opt_str, nullptr, 0); |
| return opt; |
| } |
| |
| static void get_cvt_gtf_timings(char *subopt, int standard, |
| struct v4l2_bt_timings *bt) |
| { |
| int width = 0; |
| int height = 0; |
| int fps = 0; |
| int r_blank = 0; |
| bool interlaced = false; |
| bool reduced_fps = false; |
| bool timings_valid = false; |
| |
| char *subopt_str = subopt; |
| while (*subopt_str != '\0') { |
| int opt; |
| int opt_val; |
| |
| opt = parse_timing_subopt(&subopt_str, &opt_val); |
| |
| switch (opt) { |
| case WIDTH: |
| width = opt_val; |
| break; |
| case HEIGHT: |
| height = opt_val; |
| break; |
| case FPS: |
| fps = opt_val; |
| break; |
| case REDUCED_BLANK: |
| r_blank = opt_val; |
| break; |
| case INTERLACED: |
| interlaced = opt_val; |
| break; |
| case REDUCED_FPS: |
| reduced_fps = opt_val; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (standard == V4L2_DV_BT_STD_CVT) |
| timings_valid = calc_cvt_modeline(width, height, fps, r_blank, |
| interlaced, reduced_fps, bt); |
| else |
| timings_valid = calc_gtf_modeline(width, height, fps, r_blank, |
| interlaced, bt); |
| |
| if (!timings_valid) { |
| stds_usage(); |
| std::exit(EXIT_FAILURE); |
| } |
| } |
| |
| static void parse_dv_bt_timings(char *optarg, struct v4l2_dv_timings *dv_timings) |
| { |
| char *subs = optarg; |
| struct v4l2_bt_timings *bt = &dv_timings->bt; |
| bool parse_cvt_gtf = false; |
| |
| dv_timings->type = V4L2_DV_BT_656_1120; |
| |
| if (!strcmp(subs, "query")) { |
| query_and_set_dv_timings = true; |
| return; |
| } |
| |
| while (*subs != '\0' && !parse_cvt_gtf) { |
| int opt; |
| int opt_val; |
| |
| opt = parse_timing_subopt(&subs, &opt_val); |
| |
| switch (opt) { |
| case WIDTH: |
| bt->width = opt_val; |
| break; |
| case HEIGHT: |
| bt->height = opt_val; |
| break; |
| case INTERLACED: |
| bt->interlaced = opt_val; |
| break; |
| case POLARITIES: |
| bt->polarities = opt_val; |
| break; |
| case PIXEL_CLOCK: |
| bt->pixelclock = opt_val; |
| break; |
| case HORZ_FRONT_PORCH: |
| bt->hfrontporch = opt_val; |
| break; |
| case HORZ_SYNC: |
| bt->hsync = opt_val; |
| break; |
| case HORZ_BACK_PORCH: |
| bt->hbackporch = opt_val; |
| break; |
| case VERT_FRONT_PORCH: |
| bt->vfrontporch = opt_val; |
| break; |
| case VERT_SYNC: |
| bt->vsync = opt_val; |
| break; |
| case VERT_BACK_PORCH: |
| bt->vbackporch = opt_val; |
| break; |
| case IL_VERT_FRONT_PORCH: |
| bt->il_vfrontporch = opt_val; |
| break; |
| case IL_VERT_SYNC: |
| bt->il_vsync = opt_val; |
| break; |
| case IL_VERT_BACK_PORCH: |
| bt->il_vbackporch = opt_val; |
| break; |
| case INDEX: |
| enum_and_set_dv_timings = opt_val; |
| break; |
| case CVT: |
| parse_cvt_gtf = true; |
| cleared_dv_timings = true; |
| get_cvt_gtf_timings(subs, V4L2_DV_BT_STD_CVT, bt); |
| break; |
| case GTF: |
| parse_cvt_gtf = true; |
| cleared_dv_timings = true; |
| get_cvt_gtf_timings(subs, V4L2_DV_BT_STD_GTF, bt); |
| break; |
| case REDUCED_FPS: |
| bt->flags |= opt_val ? V4L2_DV_FL_REDUCED_FPS : 0; |
| break; |
| case CLEAR: |
| cleared_dv_timings = true; |
| break; |
| default: |
| stds_usage(); |
| std::exit(EXIT_FAILURE); |
| } |
| set_dv_timing_opts |= 1 << opt; |
| } |
| } |
| |
| static void print_dv_timings(const struct v4l2_dv_timings *t) |
| { |
| const struct v4l2_bt_timings *bt; |
| double tot_width, tot_height; |
| |
| switch (t->type) { |
| case V4L2_DV_BT_656_1120: |
| bt = &t->bt; |
| |
| tot_height = bt->height + |
| bt->vfrontporch + bt->vsync + bt->vbackporch + |
| bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch; |
| tot_width = bt->width + |
| bt->hfrontporch + bt->hsync + bt->hbackporch; |
| if (options[OptConcise]) { |
| printf("\t%dx%d%c%.2f %s\n", bt->width, bt->height, |
| bt->interlaced ? 'i' : 'p', |
| static_cast<double>(bt->pixelclock) / |
| (tot_width * (tot_height / (bt->interlaced ? 2 : 1))), |
| dvflags2s(bt->vsync, bt->flags).c_str()); |
| break; |
| } |
| printf("\tActive width: %d\n", bt->width); |
| printf("\tActive height: %d\n", bt->height); |
| printf("\tTotal width: %d\n",bt->width + |
| bt->hfrontporch + bt->hsync + bt->hbackporch); |
| printf("\tTotal height: %d\n", bt->height + |
| bt->vfrontporch + bt->vsync + bt->vbackporch + |
| bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch); |
| |
| printf("\tFrame format: %s\n", bt->interlaced ? "interlaced" : "progressive"); |
| printf("\tPolarities: %cvsync %chsync\n", |
| (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? '+' : '-', |
| (bt->polarities & V4L2_DV_HSYNC_POS_POL) ? '+' : '-'); |
| printf("\tPixelclock: %lld Hz", bt->pixelclock); |
| if (bt->width && bt->height) { |
| if (bt->interlaced) |
| printf(" (%.2f fields per second)", static_cast<double>(bt->pixelclock) / |
| (tot_width * (tot_height / 2))); |
| else |
| printf(" (%.2f frames per second)", static_cast<double>(bt->pixelclock) / |
| (tot_width * tot_height)); |
| } |
| printf("\n"); |
| printf("\tHorizontal frontporch: %d\n", bt->hfrontporch); |
| printf("\tHorizontal sync: %d\n", bt->hsync); |
| printf("\tHorizontal backporch: %d\n", bt->hbackporch); |
| if (bt->interlaced) |
| printf("\tField 1:\n"); |
| printf("\tVertical frontporch: %d\n", bt->vfrontporch); |
| printf("\tVertical sync: %d\n", bt->vsync); |
| printf("\tVertical backporch: %d\n", bt->vbackporch); |
| if (bt->interlaced) { |
| printf("\tField 2:\n"); |
| printf("\tVertical frontporch: %d\n", bt->il_vfrontporch); |
| printf("\tVertical sync: %d\n", bt->il_vsync); |
| printf("\tVertical backporch: %d\n", bt->il_vbackporch); |
| } |
| printf("\tStandards: %s\n", dv_standards2s(bt->standards).c_str()); |
| if (bt->flags & V4L2_DV_FL_HAS_PICTURE_ASPECT) |
| printf("\tPicture aspect: %u:%u\n", |
| bt->picture_aspect.numerator, |
| bt->picture_aspect.denominator); |
| if (bt->flags & V4L2_DV_FL_HAS_CEA861_VIC) |
| printf("\tCTA-861 VIC: %u\n", bt->cea861_vic); |
| if (bt->flags & V4L2_DV_FL_HAS_HDMI_VIC) |
| printf("\tHDMI VIC: %u\n", bt->hdmi_vic); |
| printf("\tFlags: %s\n", dvflags2s(bt->vsync, bt->flags).c_str()); |
| break; |
| default: |
| printf("Timing type not defined\n"); |
| break; |
| } |
| } |
| |
| void stds_cmd(int ch, char *optarg) |
| { |
| switch (ch) { |
| case OptSetStandard: |
| if (!strncasecmp(optarg, "pal", 3)) { |
| if (optarg[3]) |
| standard = parse_pal(optarg + 3); |
| else |
| standard = V4L2_STD_PAL; |
| } |
| else if (!strncasecmp(optarg, "ntsc", 4)) { |
| if (optarg[4]) |
| standard = parse_ntsc(optarg + 4); |
| else |
| standard = V4L2_STD_NTSC; |
| } |
| else if (!strncasecmp(optarg, "secam", 5)) { |
| if (optarg[5]) |
| standard = parse_secam(optarg + 5); |
| else |
| standard = V4L2_STD_SECAM; |
| } |
| else if (isdigit(optarg[0])) { |
| standard = strtol(optarg, nullptr, 0) | (1ULL << 63); |
| } else { |
| fprintf(stderr, "Unknown standard '%s'\n", optarg); |
| stds_usage(); |
| std::exit(EXIT_FAILURE); |
| } |
| break; |
| case OptSetDvBtTimings: |
| parse_dv_bt_timings(optarg, &dv_timings); |
| break; |
| case OptListDvTimings: |
| if (optarg) |
| list_dv_timings_pad = strtoul(optarg, nullptr, 0); |
| break; |
| case OptGetDvTimingsCap: |
| if (optarg) |
| dv_timings_cap_pad = strtoul(optarg, nullptr, 0); |
| break; |
| } |
| } |
| |
| void stds_set(cv4l_fd &_fd) |
| { |
| int fd = _fd.g_fd(); |
| |
| if (options[OptSetStandard]) { |
| if (standard & (1ULL << 63)) { |
| struct v4l2_standard vs; |
| |
| vs.index = standard & 0xffff; |
| if (test_ioctl(fd, VIDIOC_ENUMSTD, &vs) >= 0) { |
| standard = vs.id; |
| } |
| } |
| if (doioctl(fd, VIDIOC_S_STD, &standard) == 0) |
| printf("Standard set to %08llx\n", static_cast<unsigned long long>(standard)); |
| } |
| |
| if (options[OptSetDvBtTimings]) { |
| struct v4l2_enum_dv_timings et = {}; |
| struct v4l2_dv_timings new_dv_timings = {}; |
| |
| if (query_and_set_dv_timings) |
| doioctl(fd, VIDIOC_QUERY_DV_TIMINGS, &new_dv_timings); |
| else if (enum_and_set_dv_timings >= 0) { |
| __u32 reduced_fps = dv_timings.bt.flags & V4L2_DV_FL_REDUCED_FPS; |
| |
| et.index = enum_and_set_dv_timings; |
| doioctl(fd, VIDIOC_ENUM_DV_TIMINGS, &et); |
| et.timings.bt.flags |= reduced_fps; |
| new_dv_timings = et.timings; |
| } else if (cleared_dv_timings) { |
| new_dv_timings = dv_timings; |
| } else { |
| struct v4l2_bt_timings *bt = &new_dv_timings.bt; |
| struct v4l2_bt_timings *update_bt = &dv_timings.bt; |
| |
| doioctl(fd, VIDIOC_G_DV_TIMINGS, &new_dv_timings); |
| for (unsigned i = 0; i < MAX_TIMINGS_OPTIONS; i++) { |
| if (!(set_dv_timing_opts & (1 << i))) |
| continue; |
| switch (i) { |
| case WIDTH: |
| bt->width = update_bt->width; |
| break; |
| case HEIGHT: |
| bt->height = update_bt->height; |
| break; |
| case INTERLACED: |
| bt->interlaced = update_bt->interlaced; |
| break; |
| case POLARITIES: |
| bt->polarities = update_bt->polarities; |
| break; |
| case PIXEL_CLOCK: |
| bt->pixelclock = update_bt->pixelclock; |
| break; |
| case HORZ_FRONT_PORCH: |
| bt->hfrontporch = update_bt->hfrontporch; |
| break; |
| case HORZ_SYNC: |
| bt->hsync = update_bt->hsync; |
| break; |
| case HORZ_BACK_PORCH: |
| bt->hbackporch = update_bt->hbackporch; |
| break; |
| case VERT_FRONT_PORCH: |
| bt->vfrontporch = update_bt->vfrontporch; |
| break; |
| case VERT_SYNC: |
| bt->vsync = update_bt->vsync; |
| break; |
| case VERT_BACK_PORCH: |
| bt->vbackporch = update_bt->vbackporch; |
| break; |
| case IL_VERT_FRONT_PORCH: |
| bt->il_vfrontporch = update_bt->il_vfrontporch; |
| break; |
| case IL_VERT_SYNC: |
| bt->il_vsync = update_bt->il_vsync; |
| break; |
| case IL_VERT_BACK_PORCH: |
| bt->il_vbackporch = update_bt->il_vbackporch; |
| break; |
| case REDUCED_FPS: |
| bt->flags &= ~V4L2_DV_FL_REDUCED_FPS; |
| bt->flags |= update_bt->flags & V4L2_DV_FL_REDUCED_FPS; |
| break; |
| } |
| } |
| } |
| if (verbose) |
| print_dv_timings(&new_dv_timings); |
| if (doioctl(fd, VIDIOC_S_DV_TIMINGS, &new_dv_timings) >= 0) { |
| printf("BT timings set\n"); |
| } |
| } |
| } |
| |
| void stds_get(cv4l_fd &_fd) |
| { |
| int fd = _fd.g_fd(); |
| |
| if (options[OptGetStandard]) { |
| if (doioctl(fd, VIDIOC_G_STD, &standard) == 0) { |
| printf("Video Standard = 0x%08llx\n", static_cast<unsigned long long>(standard)); |
| printf("\t%s\n", std2s(standard, "\n\t").c_str()); |
| } |
| } |
| |
| if (options[OptGetDvTimings]) { |
| if (doioctl(fd, VIDIOC_G_DV_TIMINGS, &dv_timings) >= 0) { |
| printf("DV timings:\n"); |
| print_dv_timings(&dv_timings); |
| } |
| } |
| |
| if (options[OptGetDvTimingsCap]) { |
| struct v4l2_dv_timings_cap dv_timings_cap = {}; |
| |
| dv_timings_cap.pad = dv_timings_cap_pad; |
| if (doioctl(fd, VIDIOC_DV_TIMINGS_CAP, &dv_timings_cap) >= 0) { |
| struct v4l2_bt_timings_cap *bt = &dv_timings_cap.bt; |
| |
| printf("DV timings capabilities:\n"); |
| if (dv_timings_cap.type != V4L2_DV_BT_656_1120) |
| printf("\tUnknown type\n"); |
| else { |
| printf("\tMinimum Width: %u\n", bt->min_width); |
| printf("\tMaximum Width: %u\n", bt->max_width); |
| printf("\tMinimum Height: %u\n", bt->min_height); |
| printf("\tMaximum Height: %u\n", bt->max_height); |
| printf("\tMinimum PClock: %llu\n", bt->min_pixelclock); |
| printf("\tMaximum PClock: %llu\n", bt->max_pixelclock); |
| printf("\tStandards: %s\n", |
| dv_standards2s(bt->standards).c_str()); |
| printf("\tCapabilities: %s\n", |
| dv_caps2s(bt->capabilities).c_str()); |
| } |
| } |
| } |
| |
| if (options[OptQueryStandard]) { |
| if (doioctl(fd, VIDIOC_QUERYSTD, &standard) == 0) { |
| printf("Video Standard = 0x%08llx\n", static_cast<unsigned long long>(standard)); |
| printf("\t%s\n", std2s(standard, "\n\t").c_str()); |
| } |
| } |
| |
| if (options[OptQueryDvTimings]) { |
| doioctl(fd, VIDIOC_QUERY_DV_TIMINGS, &dv_timings); |
| print_dv_timings(&dv_timings); |
| } |
| } |
| |
| void stds_list(cv4l_fd &_fd) |
| { |
| int fd = _fd.g_fd(); |
| |
| if (options[OptListStandards]) { |
| struct v4l2_standard vs; |
| |
| printf("ioctl: VIDIOC_ENUMSTD\n"); |
| vs.index = 0; |
| while (test_ioctl(fd, VIDIOC_ENUMSTD, &vs) >= 0) { |
| if (options[OptConcise]) { |
| printf("\t%2d: 0x%016llX %s\n", vs.index, |
| static_cast<unsigned long long>(vs.id), vs.name); |
| } else { |
| if (vs.index) |
| printf("\n"); |
| printf("\tIndex : %d\n", vs.index); |
| printf("\tID : 0x%016llX\n", static_cast<unsigned long long>(vs.id)); |
| printf("\tName : %s\n", vs.name); |
| printf("\tFrame period: %d/%d\n", |
| vs.frameperiod.numerator, |
| vs.frameperiod.denominator); |
| printf("\tFrame lines : %d\n", vs.framelines); |
| } |
| vs.index++; |
| } |
| } |
| |
| if (options[OptListDvTimings]) { |
| struct v4l2_enum_dv_timings dv_enum_timings = {}; |
| |
| printf("ioctl: VIDIOC_ENUM_DV_TIMINGS\n"); |
| dv_enum_timings.pad = list_dv_timings_pad; |
| while (test_ioctl(fd, VIDIOC_ENUM_DV_TIMINGS, &dv_enum_timings) >= 0) { |
| if (options[OptConcise]) { |
| printf("\t%d:", dv_enum_timings.index); |
| } else { |
| if (dv_enum_timings.index) |
| printf("\n"); |
| printf("\tIndex: %d\n", dv_enum_timings.index); |
| } |
| print_dv_timings(&dv_enum_timings.timings); |
| dv_enum_timings.index++; |
| } |
| } |
| } |