/*
|
* Media controller test application
|
*
|
* Copyright (C) 2010-2014 Ideas on board SPRL
|
*
|
* Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
*
|
* 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 <http://www.gnu.org/licenses/>.
|
*/
|
|
#include <ctype.h>
|
#include <dirent.h>
|
#include <fcntl.h>
|
#include <getopt.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <sys/ioctl.h>
|
#include <unistd.h>
|
#ifndef __ANDROID__
|
#include <v4l2subdev.h>
|
#endif
|
#include <linux/media.h>
|
#include <linux/videodev2.h>
|
|
#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;
|
}
|