From fc30885b8d07ad153120d5b05d2538fab6ea8fa1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 3 Jul 2012 01:31:46 +0200 Subject: live: Add digital zoom support Signed-off-by: Laurent Pinchart --- live.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 1 deletion(-) diff --git a/live.c b/live.c index 7fb4701..8ae386c 100644 --- a/live.c +++ b/live.c @@ -42,6 +42,7 @@ #include #include +#include #include #include "isp/list.h" @@ -71,6 +72,13 @@ static struct iq_tuning *iq = NULL; static struct events events; +struct input { + int fd; + float zoom; + float x; + float y; +}; + /* ----------------------------------------------------------------------------- * Image quality */ @@ -151,6 +159,177 @@ static struct omap3_isp_operations isp_ops = { .aewb_ready = __iq_aewb_process, }; +/* ----------------------------------------------------------------------------- + * Input device + */ + +static void input_process(void *priv) +{ + struct input_event iev[8]; + struct input *input = priv; + float last_x = input->x; + float last_y = input->y; + float last_zoom = input->zoom; + unsigned int i; + ssize_t nbytes; + + nbytes = read(input->fd, iev, sizeof iev); + + for (i = 0; i < nbytes / sizeof iev[0]; ++i) { + if (iev[i].type != EV_REL) + continue; + + switch (iev[i].code) { + case REL_X: + input->x += iev[i].value * 0.01; + input->x = clamp(input->x, 0.0, 1.0); + break; + + case REL_Y: + input->y += iev[i].value * 0.01; + input->y = clamp(input->y, 0.0, 1.0); + break; + + case REL_WHEEL: + input->zoom += iev[i].value * 0.1; + input->zoom = clamp(input->zoom, 1.0, 4.0); + break; + } + } + + if (input->x == last_x && input->y == last_y && + input->zoom == last_zoom) + return; + + omap3_isp_viewfinder_pan_zoom(isp, input->x, input->y, input->zoom); +} + +static const char *input_find_device(void) +{ + unsigned int rel_mask = (1 << REL_X) | (1 << REL_Y) | (1 << REL_WHEEL); + unsigned int input_idx = 256; + unsigned int major; + unsigned int minor; + struct stat devstat; + struct dirent *ent; + static char path[50]; + char buffer[16]; + unsigned int rel; + char *end; + DIR *dir; + int ret; + int fd; + + /* Locate the first mouse device in sysfs that supports X, Y and wheel + * relative axis. + */ + dir = opendir("/sys/class/input"); + if (dir == NULL) + return NULL; + + while ((ent = readdir(dir)) != NULL) { + + if (strncmp(ent->d_name, "event", 5)) + continue; + + sprintf(path, "/sys/class/input/%s/device/capabilities/rel", + ent->d_name); + + fd = open(path, O_RDONLY); + if (fd == -1) + continue; + + ret = read(fd, buffer, sizeof buffer - 1); + close(fd); + if (ret < 0) + continue; + + buffer[ret] = '\0'; + rel = strtoul(buffer, &end, 16); + if (*end != '\0' && *end != '\n') + continue; + + if ((rel & rel_mask) != rel_mask) + continue; + + input_idx = strtoul(ent->d_name + 5, NULL, 10); + break; + } + + closedir(dir); + + if (input_idx == 256) + return NULL; + + /* Read the device major and minor from sysfs. */ + sprintf(path, "/sys/class/input/event%u/dev", input_idx); + fd = open(path, O_RDONLY); + if (fd == -1) + return NULL; + + ret = read(fd, buffer, sizeof buffer - 1); + close(fd); + if (ret < 0) + return NULL; + + buffer[ret] = '\0'; + major = strtoul(buffer, &end, 10); + if (*end != ':') + return NULL; + + minor = strtoul(end + 1, &end, 10); + if (!isspace(*end) && end != '\0') + return NULL; + + /* Verify that the device node exists. udev might have reordered the + * device nodes, make sure the major/minor match as a sanity check. We + * should really use libudev. + */ + sprintf(path, "/dev/input/event%u", input_idx); + ret = stat(path, &devstat); + if (ret < 0) + return NULL; + + if (major(devstat.st_rdev) != major || minor(devstat.st_rdev) != minor) + return NULL; + + return path; +} + +static int input_init(struct input *input) +{ + const char *devname; + + input->fd = -1; + input->zoom = 1.0; + input->x = 0.5; + input->y = 0.5; + + devname = input_find_device(); + if (devname == NULL) { + printf("No compatible input device found, disabling digital zoom\n"); + return -ENODEV; + } + + input->fd = open(devname, O_RDWR); + if (input->fd == -1) + return -errno; + + events_watch_fd(&events, input->fd, OMAP3_ISP_EVENT_READ, input_process, + input); + + return 0; +} + +static void input_cleanup(struct input *input) +{ + if (input->fd == -1) + return; + + events_unwatch_fd(&events, input->fd); + close(input->fd); +} + /* ----------------------------------------------------------------------------- * Video output */ @@ -415,13 +594,14 @@ int main(int argc __attribute__((__unused__)), char *argv[] __attribute__((__unu const char *vo_devname; unsigned int colorkey; bool enable_aewb = true; + struct input input; float fps; int ret; int c; iq_params_init(&iq_params); - while ((c = getopt_long(argc, argv, "b:hs:", opts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "b:hs:z", opts, NULL)) != -1) { switch (c) { case 'b': buffers = atoi(optarg); @@ -455,6 +635,7 @@ int main(int argc __attribute__((__unused__)), char *argv[] __attribute__((__unu } events_init(&events); + input_init(&input); memset(&rect, 0, sizeof rect); ret = fb_init(&rect); @@ -564,6 +745,8 @@ int main(int argc __attribute__((__unused__)), char *argv[] __attribute__((__unu exit_code = EXIT_SUCCESS; cleanup: + input_cleanup(&input); + /* Cleanup the ISP and video output resources. */ if (isp) omap3_isp_close(isp); -- cgit v1.2.3