summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-07-03 01:31:46 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-10-20 21:28:24 +0200
commitfc30885b8d07ad153120d5b05d2538fab6ea8fa1 (patch)
tree5e3bbbae7277bdc3b1260250cd76ef168b461d7c
parent673222f6f296cf4b9785cd9a1f445f5790cd8e01 (diff)
live: Add digital zoom support
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--live.c185
1 files changed, 184 insertions, 1 deletions
diff --git a/live.c b/live.c
index 7fb4701..8ae386c 100644
--- a/live.c
+++ b/live.c
@@ -42,6 +42,7 @@
#include <sys/types.h>
#include <linux/fb.h>
+#include <linux/input.h>
#include <linux/spi/spidev.h>
#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
*/
@@ -152,6 +160,177 @@ static struct omap3_isp_operations isp_ops = {
};
/* -----------------------------------------------------------------------------
+ * 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);