From c13258a74fd7345828fce8fab117247e3f61e6e5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 29 Jun 2010 12:09:35 +0200 Subject: 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 --- main.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- options.c | 28 ++++++++++++++++++---- subdev.c | 45 +++++++++++++++++++++++++++++++++++ subdev.h | 4 ++++ 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 -- cgit v1.2.3