summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2010-06-29 12:09:35 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2010-06-29 12:09:35 +0200
commitc13258a74fd7345828fce8fab117247e3f61e6e5 (patch)
treeb29a1420ce9648b283cc32fc35ff9504f93e229b
parent0c4da2bb2f4d7d3cd2cdea1369374d5b4f7e3b29 (diff)
V4L2 subdev crop support
Extend the V4L2 media bus format syntax to support an optional crop rectangle. If specified, the crop rectangle is set on the subdev pad. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--main.c82
-rw-r--r--options.c28
-rw-r--r--subdev.c45
-rw-r--r--subdev.h4
4 files changed, 147 insertions, 12 deletions
diff --git a/main.c b/main.c
index c59b633..9b8951a 100644
--- a/main.c
+++ b/main.c
@@ -203,8 +203,36 @@ static int parse_format(struct v4l2_mbus_framefmt *format, const char *p, char *
return 0;
}
+static int parse_crop(struct v4l2_rect *crop, const char *p, char **endp)
+{
+ char *end;
+
+ for (; isspace(*p); ++p);
+
+ crop->left = strtoul(p, &end, 10);
+ if (*end != ',')
+ return -EINVAL;
+
+ p = end + 1;
+ crop->top = strtoul(p, &end, 10);
+ if (*end != '/')
+ return -EINVAL;
+
+ p = end + 1;
+ crop->width = strtoul(p, &end, 10);
+ if (*end != 'x')
+ return -EINVAL;
+
+ p = end + 1;
+ crop->height = strtoul(p, &end, 10);
+ *endp = end;
+
+ return 0;
+}
+
static struct media_entity_pad *parse_pad_format(struct media_device *media,
- struct v4l2_mbus_framefmt *format, const char *p, char **endp)
+ struct v4l2_mbus_framefmt *format, struct v4l2_rect *crop,
+ const char *p, char **endp)
{
struct media_entity_pad *pad;
char *end;
@@ -225,10 +253,18 @@ static struct media_entity_pad *parse_pad_format(struct media_device *media,
return NULL;
for (p = end; isspace(*p); p++);
- if (*p++ != ']')
+ if (*p != ']') {
+ ret = parse_crop(crop, p, &end);
+ if (ret < 0)
+ return NULL;
+
+ for (p = end; isspace(*p); p++);
+ }
+
+ if (*p != ']')
return NULL;
- *endp = (char *)p;
+ *endp = (char *)p + 1;
return pad;
}
@@ -253,23 +289,55 @@ static int set_format(struct media_entity_pad *pad, struct v4l2_mbus_framefmt *f
return 0;
}
+static int set_crop(struct media_entity_pad *pad, struct v4l2_rect *crop)
+{
+ int ret;
+
+ printf("Setting up crop rectangle %u,%u/%ux%u on pad %s/%u\n",
+ crop->left, crop->top, crop->width, crop->height,
+ pad->entity->info.name, pad->index);
+
+ ret = v4l2_subdev_set_crop(pad->entity, crop, pad->index,
+ V4L2_SUBDEV_FORMAT_ACTIVE);
+ if (ret < 0) {
+ printf("Unable to set crop rectangle: %s (%d)", strerror(-ret), ret);
+ return ret;
+ }
+
+ printf("Crop rectangle set: %u,%u/%ux%u\n",
+ crop->left, crop->top, crop->width, crop->height);
+
+ return 0;
+}
+
static int setup_format(struct media_device *media, const char *p, char **endp)
{
struct v4l2_mbus_framefmt format;
struct media_entity_pad *pad;
+ struct v4l2_rect crop = { -1, -1, -1, -1 };
unsigned int i;
char *end;
int ret;
- pad = parse_pad_format(media, &format, p, &end);
+ pad = parse_pad_format(media, &format, &crop, p, &end);
if (pad == NULL) {
printf("Unable to parse format\n");
return -EINVAL;
}
ret = set_format(pad, &format);
- if (ret < 0)
+ if (ret < 0) {
+ printf("Unable to set format\n");
return ret;
+ }
+
+ if (crop.left != -1 && crop.top != -1) {
+ ret = set_crop(pad, &crop);
+ if (ret < 0) {
+ printf("Unable to set crop rectangle\n");
+ return ret;
+ }
+ }
/* If the pad is an output pad, automatically set the same format on
* the remote subdev input pads, if any.
@@ -301,10 +369,8 @@ static int setup_formats(struct media_device *media, const char *p)
do {
ret = setup_format(media, p, &end);
- if (ret < 0) {
- printf("Unable to parse format\n");
+ if (ret < 0)
return ret;
- }
p = end + 1;
} while (*end == ',');
diff --git a/options.c b/options.c
index 5e4c9f7..69ff9d5 100644
--- a/options.c
+++ b/options.c
@@ -30,19 +30,39 @@ struct media_options media_opts = {
.devname = MEDIA_DEVNAME_DEFAULT,
};
-static void usage(const char *argv0)
+static void usage(const char *argv0, int verbose)
{
printf("%s [options] device\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("-f, --formats Comma-separated list of formats to setup\n");
- printf("-h, --help Show this help screen\n");
+ printf("-h, --help Show verbose help and exit\n");
printf("-i, --interactive Modify links interactively\n");
printf("-l, --links Comma-separated list of links descriptors to setup\n");
printf("-p, --print-topology Print the device topology (implies -v)\n");
printf(" --print-dot Print the device topology as a dot graph (implies -v)\n");
printf("-r, --reset Reset all links to inactive\n");
printf("-v, --verbose Be verbose\n");
+
+ if (!verbose)
+ return;
+
+ printf("\n");
+ printf("Links and formats are defined as\n");
+ printf("\tlink = pad, '->', pad, '[', flags, ']' ;\n");
+ printf("\tformat = pad, '[', fcc, ' ', size, [ ' ', crop ], ']' ;\n");
+ printf("\tpad = entity, ':', pad number ;\n");
+ printf("\tentity = entity number | ( '\"', entity name, '\"' ) ;\n");
+ printf("\tsize = width, 'x', height ;\n");
+ printf("\tcrop = left, ',', top, '/', size ;\n");
+ printf("where the fields are\n");
+ printf("\tentity number Entity numeric identifier\n");
+ printf("\tentity name Entify 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");
}
#define OPT_PRINT_DOT 256
@@ -65,7 +85,7 @@ int parse_cmdline(int argc, char **argv)
int opt;
if (argc == 1) {
- usage(argv[0]);
+ usage(argv[0], 0);
return 1;
}
@@ -85,7 +105,7 @@ int parse_cmdline(int argc, char **argv)
break;
case 'h':
- usage(argv[0]);
+ usage(argv[0], 1);
exit(0);
case 'i':
diff --git a/subdev.c b/subdev.c
index c35b5b4..ac14324 100644
--- a/subdev.c
+++ b/subdev.c
@@ -133,3 +133,48 @@ int v4l2_subdev_set_format(struct media_entity *entity,
return 0;
}
+int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect,
+ unsigned int pad, enum v4l2_subdev_format which)
+{
+ struct v4l2_subdev_pad_crop crop;
+ int ret;
+
+ ret = v4l2_subdev_open(entity);
+ if (ret < 0)
+ return ret;
+
+ memset(&crop, 0, sizeof(crop));
+ crop.pad = pad;
+ crop.which = which;
+
+ ret = ioctl(entity->fd, VIDIOC_SUBDEV_G_CROP, &crop);
+ if (ret < 0)
+ return -errno;
+
+ *rect = crop.rect;
+ return 0;
+}
+
+int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect,
+ unsigned int pad, enum v4l2_subdev_format which)
+{
+ struct v4l2_subdev_pad_crop crop;
+ int ret;
+
+ ret = v4l2_subdev_open(entity);
+ if (ret < 0)
+ return ret;
+
+ memset(&crop, 0, sizeof(crop));
+ crop.pad = pad;
+ crop.which = which;
+ crop.rect = *rect;
+
+ ret = ioctl(entity->fd, VIDIOC_SUBDEV_S_CROP, &crop);
+ if (ret < 0)
+ return -errno;
+
+ *rect = crop.rect;
+ return 0;
+}
+
diff --git a/subdev.h b/subdev.h
index c431271..e3106e6 100644
--- a/subdev.h
+++ b/subdev.h
@@ -34,6 +34,10 @@ int v4l2_subdev_get_format(struct media_entity *entity,
int v4l2_subdev_set_format(struct media_entity *entity,
struct v4l2_mbus_framefmt *format, unsigned int pad,
enum v4l2_subdev_format which);
+int v4l2_subdev_get_crop(struct media_entity *entity, struct v4l2_rect *rect,
+ unsigned int pad, enum v4l2_subdev_format which);
+int v4l2_subdev_set_crop(struct media_entity *entity, struct v4l2_rect *rect,
+ unsigned int pad, enum v4l2_subdev_format which);
#endif