/* * Media controller test application * * Copyright (C) 2010-2014 Ideas on board SPRL * * Contact: Laurent Pinchart * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #ifndef __ANDROID__ #include #endif #include #include #include "options.h" #include "v4l2subdev.h" #define MEDIA_DEVNAME_DEFAULT "/dev/media0" struct media_options media_opts = { .devname = MEDIA_DEVNAME_DEFAULT, }; static void usage(const char* argv0) { unsigned int i; printf("%s [options]\n", argv0); printf("-d, --device dev Media device name (default: %s)\n", MEDIA_DEVNAME_DEFAULT); printf("-e, --entity name Print the device name associated with the " "given " "entity\n"); printf("-V, --set-v4l2 v4l2 Comma-separated list of formats to setup\n"); printf(" --get-v4l2 pad Print the active format on a given pad\n"); printf(" --get-dv pad Print detected and current DV timings on a " "given pad\n"); printf(" --set-dv pad Configure DV timings on a given pad\n"); printf("-h, --help Show verbose help and exit\n"); printf("-i, --interactive Modify links interactively\n"); printf("-l, --links links Comma-separated list of link descriptors to " "setup\n"); printf(" --known-mbus-fmts List known media bus formats and their " "numeric values\n"); printf("-p, --print-topology Print the device topology. If an entity\n"); printf(" is specified through the -e option, print\n"); printf(" information for that entity only.\n"); printf(" --print-dot Print the device topology as a dot " "graph\n"); printf("-r, --reset Reset all links to inactive\n"); printf("-v, --verbose Be verbose\n"); printf("\n"); printf("Links and formats are defined as\n"); printf("\tlinks = link { ',' link } ;\n"); printf("\tlink = pad '->' pad '[' flags ']' ;\n"); printf("\tpad = entity ':' pad-number ;\n"); printf("\tentity = entity-number | ( '\"' entity-name '\"' ) ;\n"); printf("\n"); printf("\tv4l2 = pad '[' v4l2-properties ']' ;\n"); printf("\tv4l2-properties = v4l2-property { ',' v4l2-property } ;\n"); printf("\tv4l2-property = v4l2-mbusfmt | v4l2-crop | v4l2-interval\n"); printf("\t | v4l2-compose | v4l2-interval ;\n"); printf("\tv4l2-mbusfmt = 'fmt:' fcc '/' size ; { 'field:' v4l2-field ; } " "{ 'colorspace:' v4l2-colorspace ; }\n"); printf("\t { 'xfer:' v4l2-xfer-func ; } { 'ycbcr-enc:' " "v4l2-ycbcr-enc-func ; }\n"); printf("\t { 'quantization:' v4l2-quant ; }\n"); printf("\tv4l2-crop = 'crop:' rectangle ;\n"); printf("\tv4l2-compose = 'compose:' rectangle ;\n"); printf("\tv4l2-interval = '@' numerator '/' denominator ;\n"); printf("\n"); printf("\trectangle = '(' left ',' top, ')' '/' size ;\n"); printf("\tsize = width 'x' height ;\n"); printf("\n"); printf("where the fields are\n"); printf("\tentity-number Entity numeric identifier\n"); printf("\tentity-name Entity name (string) \n"); printf("\tpad-number Pad numeric identifier\n"); printf("\tflags Link flags (0: inactive, 1: active)\n"); printf("\tfcc Format FourCC\n"); printf("\twidth Image width in pixels\n"); printf("\theight Image height in pixels\n"); printf("\tnumerator Frame interval numerator\n"); printf("\tdenominator Frame interval denominator\n"); printf("\tv4l2-field One of the following:\n"); for (i = V4L2_FIELD_ANY; i <= V4L2_FIELD_INTERLACED_BT; i++) { printf("\t %s\n", v4l2_subdev_field_to_string(i)); } printf("\tv4l2-colorspace One of the following:\n"); for (i = V4L2_COLORSPACE_DEFAULT; i <= V4L2_COLORSPACE_DCI_P3; i++) { printf("\t %s\n", v4l2_subdev_colorspace_to_string(i)); } printf("\tv4l2-xfer-func One of the following:\n"); for (i = V4L2_XFER_FUNC_DEFAULT; i <= V4L2_XFER_FUNC_SMPTE2084; i++) { printf("\t %s\n", v4l2_subdev_xfer_func_to_string(i)); } printf("\tv4l2-quant One of the following:\n"); for (i = V4L2_QUANTIZATION_DEFAULT; i <= V4L2_QUANTIZATION_LIM_RANGE; i++) { printf("\t %s\n", v4l2_subdev_quantization_to_string(i)); } } #define OPT_PRINT_DOT 256 #define OPT_GET_FORMAT 257 #define OPT_SET_DV 258 #define OPT_LIST_KNOWN_MBUS_FMTS 259 #define OPT_GET_DV 260 static struct option opts[] = { {"device", 1, 0, 'd'}, {"entity", 1, 0, 'e'}, {"set-format", 1, 0, 'f'}, {"set-v4l2", 1, 0, 'V'}, {"get-format", 1, 0, OPT_GET_FORMAT}, {"get-v4l2", 1, 0, OPT_GET_FORMAT}, {"get-dv", 1, 0, OPT_GET_DV}, {"set-dv", 1, 0, OPT_SET_DV}, {"help", 0, 0, 'h'}, {"interactive", 0, 0, 'i'}, {"links", 1, 0, 'l'}, {"known-mbus-fmts", 0, 0, OPT_LIST_KNOWN_MBUS_FMTS}, {"print-dot", 0, 0, OPT_PRINT_DOT}, {"print-topology", 0, 0, 'p'}, {"reset", 0, 0, 'r'}, {"verbose", 0, 0, 'v'}, {}, }; static void list_known_mbus_formats(void) { unsigned int ncodes; const unsigned int* code = v4l2_subdev_pixelcode_list(&ncodes); while (ncodes--) { const char* str = v4l2_subdev_pixelcode_to_string(*code); int spaces = 30 - (int)strlen(str); if (*code == 0) { break; } if (spaces < 0) { spaces = 0; } printf("%s %*c 0x%4.4x\n", str, spaces, ' ', *code); code++; } } static const char* make_devname(const char* device) { static char newdev[300]; struct dirent* ep; DIR* dp; if (!access(device, F_OK)) { return device; } if (device[0] >= '0' && device[0] <= '9' && strlen(device) <= 3) { snprintf(newdev, sizeof(newdev), "/dev/media%s", device); return newdev; } dp = opendir("/dev"); if (dp == NULL) { return device; } while ((ep = readdir(dp))) { const char* name = ep->d_name; if (!memcmp(name, "media", 5) && isdigit(name[5])) { struct media_device_info mdi; int ret; int fd; snprintf(newdev, sizeof(newdev), "/dev/%s", name); fd = open(newdev, O_RDWR); if (fd < 0) { continue; } ret = ioctl(fd, MEDIA_IOC_DEVICE_INFO, &mdi); close(fd); if (!ret && !strcmp(device, mdi.bus_info)) { closedir(dp); return newdev; } } } closedir(dp); return device; } int parse_cmdline(int argc, char** argv) { int opt; if (argc == 1) { usage(argv[0]); return 1; } /* parse options */ while ((opt = getopt_long(argc, argv, "d:e:f:hil:prvV:", opts, NULL)) != -1) { switch (opt) { case 'd': media_opts.devname = make_devname(optarg); break; case 'e': media_opts.entity = optarg; break; /* 'f' is supported for backward compatibility reasons and will * be removed later. */ case 'f': fprintf(stderr, "Warning: the -f option is deprecated " "and has been replaced by -V.\n"); /* fall through */ case 'V': media_opts.formats = optarg; break; case 'h': usage(argv[0]); exit(0); case 'i': media_opts.interactive = 1; break; case 'l': media_opts.links = optarg; break; case 'p': media_opts.print = 1; break; case 'r': media_opts.reset = 1; break; case 'v': media_opts.verbose = 1; break; case OPT_PRINT_DOT: media_opts.print_dot = 1; break; case OPT_GET_FORMAT: media_opts.fmt_pad = optarg; break; case OPT_GET_DV: media_opts.get_dv_pad = optarg; break; case OPT_SET_DV: media_opts.dv_pad = optarg; break; case OPT_LIST_KNOWN_MBUS_FMTS: list_known_mbus_formats(); exit(0); default: printf("Invalid option -%c\n", opt); printf("Run %s -h for help.\n", argv[0]); return 1; } } return 0; }