summaryrefslogtreecommitdiff
path: root/snapshot.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-07-30 14:33:37 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2011-07-30 14:33:37 +0200
commitfebcb53ca85d911619456c09c4be49fd73c4964b (patch)
tree12ae3a93d117b56da6e1213882f5cc6de3977adb /snapshot.c
omap3-isp-live: Initial commit
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'snapshot.c')
-rw-r--r--snapshot.c418
1 files changed, 418 insertions, 0 deletions
diff --git a/snapshot.c b/snapshot.c
new file mode 100644
index 0000000..5728ae6
--- /dev/null
+++ b/snapshot.c
@@ -0,0 +1,418 @@
+/*
+ * OMAP3 ISP snapshot test application
+ *
+ * Copyright (C) 2010-2011 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 General Public License as published by the Free
+ * Software Foundation; either version 2 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 General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _BSD_SOURCE
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/time.h>
+
+#include <linux/spi/spidev.h>
+
+#include "isp/list.h"
+#include "isp/omap3isp.h"
+#include "isp/tools.h"
+#include "isp/v4l2.h"
+#include "isp/v4l2-pool.h"
+
+#define MEDIA_DEVICE "/dev/media0"
+#define SELECT_TIMEOUT 2000 /* in milliseconds */
+
+#define VIEWFINDER_WIDTH 1024
+#define VIEWFINDER_HEIGHT 768
+#define SNAPSHOT_WIDTH 2048
+#define SNAPSHOT_HEIGHT 1536
+
+static unsigned int frame_count = 0;
+static bool done = false;
+
+static unsigned int snapshot_interval = 20;
+static struct timespec snapshot_time;
+
+/* -----------------------------------------------------------------------------
+ * Events
+ */
+
+struct event_fd {
+ struct list_entry list;
+
+ int fd;
+ enum omap3_isp_event_type type;
+ void (*callback)(void *priv);
+ void *priv;
+};
+
+static struct {
+ struct list_entry events;
+
+ int maxfd;
+ fd_set rfds;
+ fd_set wfds;
+} events;
+
+static void events_watch_fd(int fd, enum omap3_isp_event_type type,
+ void(*callback)(void *), void *priv)
+{
+ struct event_fd *event;
+
+ event = malloc(sizeof *event);
+ if (event == NULL)
+ return;
+
+ event->fd = fd;
+ event->type = type;
+ event->callback = callback;
+ event->priv = priv;
+
+ if (event->type == OMAP3_ISP_EVENT_READ)
+ FD_SET(fd, &events.rfds);
+ else
+ FD_SET(fd, &events.wfds);
+
+ events.maxfd = max(events.maxfd, fd);
+
+ list_append(&event->list, &events.events);
+}
+
+static void events_unwatch_fd(int fd)
+{
+ struct event_fd *event = NULL;
+ struct event_fd *entry;
+ int maxfd = 0;
+
+ list_for_each_entry(entry, &events.events, list) {
+ if (entry->fd == fd)
+ event = entry;
+ else
+ maxfd = max(maxfd, entry->fd);
+ }
+
+ if (event == NULL)
+ return;
+
+ if (event->type == OMAP3_ISP_EVENT_READ)
+ FD_CLR(fd, &events.rfds);
+ else
+ FD_CLR(fd, &events.wfds);
+
+ events.maxfd = maxfd;
+
+ list_remove(&event->list);
+ free(event);
+}
+
+static void events_init(void)
+{
+ memset(&events, 0, sizeof events);
+
+ FD_ZERO(&events.rfds);
+ FD_ZERO(&events.wfds);
+ events.maxfd = 0;
+ list_init(&events.events);
+}
+
+static void events_dispatch(const fd_set *rfds, const fd_set *wfds)
+{
+ struct event_fd *event;
+
+ list_for_each_entry(event, &events.events, list) {
+ if (event->type == OMAP3_ISP_EVENT_READ &&
+ FD_ISSET(event->fd, rfds))
+ event->callback(event->priv);
+ if (event->type == OMAP3_ISP_EVENT_WRITE &&
+ FD_ISSET(event->fd, wfds))
+ event->callback(event->priv);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void sigint_handler(int signal __attribute__((__unused__)))
+{
+ /* Set the done flag to true when the user presses CTRL-C to interrupt
+ * the main loop.
+ */
+ done = true;
+}
+
+static void snapshot_process(struct omap3_isp_device *isp,
+ struct v4l2_video_buffer *buffer)
+{
+ static struct timespec ts;
+ int ret;
+
+ if (buffer->error) {
+ printf("warning: error in dequeued buffer, skipping\n");
+ return;
+ }
+
+ ts.tv_sec = buffer->timestamp.tv_sec - snapshot_time.tv_sec;
+ ts.tv_nsec = (buffer->timestamp.tv_usec * 1000) - snapshot_time.tv_nsec;
+ if (ts.tv_nsec < 0) {
+ ts.tv_sec--;
+ ts.tv_nsec += 1000000000;
+ }
+
+ printf("snapshot captured in %lu.%06lus.\n", ts.tv_sec, ts.tv_nsec / 1000);
+
+ /* Requeue the buffer */
+ ret = omap3_isp_snapshot_put_buffer(isp, buffer);
+ if (ret < 0) {
+ printf("error: unable to requeue buffer: %s (%d)\n",
+ strerror(-ret), ret);
+ return;
+ }
+}
+
+static void viewfinder_process(struct omap3_isp_device *isp,
+ struct v4l2_video_buffer *buffer)
+{
+ int ret;
+
+ if (buffer->error) {
+ printf("warning: error in dequeued buffer, skipping\n");
+ return;
+ }
+
+ frame_count++;
+ printf("viewfinder frame %u captured.\n", frame_count);
+
+ if ((frame_count % snapshot_interval) == 0) {
+ clock_gettime(CLOCK_MONOTONIC, &snapshot_time);
+ omap3_isp_snapshot_capture(isp);
+ }
+
+ /* Requeue the buffer */
+ ret = omap3_isp_viewfinder_put_buffer(isp, buffer);
+ if (ret < 0) {
+ printf("error: unable to requeue buffer: %s (%d)\n",
+ strerror(-ret), ret);
+ return;
+ }
+}
+
+static void usage(const char *argv0)
+{
+ printf("Usage: %s [options]\n", argv0);
+ printf("Supported options:\n");
+ printf("-h, --help Show this help screen\n");
+ printf("-s, --snap n Capture a snapshot every n frames\n");
+ printf("-y, --yuv YUV snapshots\n");
+}
+
+static struct option opts[] = {
+ { "help", 0, 0, 'h' },
+ { "snap", 0, 0, 's' },
+ { "yuv", 0, 0, 'y' },
+ { 0, 0, 0, 0 }
+};
+
+int main(int argc __attribute__((__unused__)), char *argv[] __attribute__((__unused__)))
+{
+ enum v4l2_mbus_pixelcode snap_code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ struct v4l2_mbus_framefmt view_format;
+ struct v4l2_mbus_framefmt snap_format;
+ struct v4l2_buffers_pool *pool = NULL;
+ struct omap3_isp_device *isp = NULL;
+ struct omap3_isp_operations ops;
+ struct timespec start, end;
+ unsigned int count = 0;
+ int exit_code = EXIT_FAILURE;
+ float fps;
+ int ret;
+ int c;
+
+ while ((c = getopt_long(argc, argv, "hs:y", opts, NULL)) != -1) {
+ switch (c) {
+ case 'h':
+ usage(argv[0]);
+ return 0;
+ case 's':
+ snapshot_interval = strtoul(optarg, NULL, 10);
+ if (snapshot_interval == 0) {
+ printf("snapshot interval value must be >0.\n");
+ return 1;
+ }
+ break;
+ case 'y':
+ snap_code = V4L2_MBUS_FMT_YUYV8_1X16;
+ break;
+ default:
+ printf("Invalid option -%c\n", c);
+ printf("Run %s -h for help.\n", argv[0]);
+ return 1;
+ }
+ }
+
+ events_init();
+
+ /* Register a signal handler for SIGINT, received when the user presses
+ * CTRL-C. This will allow the main loop to be interrupted, and resources
+ * to be freed cleanly.
+ */
+ signal(SIGINT, sigint_handler);
+
+ /* Open the OMAP3 ISP device and setup the capture pipeline. */
+ memset(&ops, 0, sizeof ops);
+ ops.viewfinder_ready = viewfinder_process;
+ ops.snapshot_ready = snapshot_process;
+ ops.watch_fd = events_watch_fd;
+ ops.unwatch_fd = events_unwatch_fd;
+
+ isp = omap3_isp_open(MEDIA_DEVICE, &ops);
+ if (isp == NULL) {
+ printf("error: unable to open media device %s\n", MEDIA_DEVICE);
+ goto cleanup;
+ }
+
+ memset(&view_format, 0, sizeof view_format);
+ view_format.code = V4L2_MBUS_FMT_YUYV8_1X16;
+ view_format.width = VIEWFINDER_WIDTH;
+ view_format.height = VIEWFINDER_HEIGHT;
+
+ ret = omap3_isp_viewfinder_setup(isp, &view_format);
+ if (ret < 0) {
+ printf("error: unable to setup pipeline\n");
+ goto cleanup;
+ }
+
+ printf("viewfinder configured for %04x %ux%u\n",
+ view_format.code, view_format.width, view_format.height);
+
+ memset(&snap_format, 0, sizeof snap_format);
+ snap_format.code = snap_code;
+ snap_format.width = SNAPSHOT_WIDTH;
+ snap_format.height = SNAPSHOT_HEIGHT;
+
+ ret = omap3_isp_snapshot_setup(isp, &snap_format);
+ if (ret < 0) {
+ printf("error: unable to setup pipeline\n");
+ goto cleanup;
+ }
+
+ printf("snapshot configured for %04x %ux%u\n",
+ snap_format.code, snap_format.width, snap_format.height);
+
+ /* Allocate a buffers pool and use it for the viewfinder. */
+ pool = v4l2_buffers_pool_new(4);
+ if (pool == NULL) {
+ printf("error: unable to create buffers pool\n");
+ goto cleanup;
+ }
+
+ ret = v4l2_buffers_pool_alloc(pool, view_format.width * view_format.height * 2, 4096);
+ if (ret < 0) {
+ printf("error: unable to allocate buffers memory\n");
+ goto cleanup;
+ }
+
+ ret = omap3_isp_viewfinder_set_pool(isp, pool);
+ if (ret < 0) {
+ printf("error: unable to set buffers pool\n");
+ goto cleanup;
+ }
+
+ /* Start the ISP. */
+ ret = omap3_isp_viewfinder_start(isp);
+ if (ret < 0)
+ goto cleanup;
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+
+ /* Main capture loop. Wait for a video buffer using select() and process
+ * it.
+ */
+ while (!done) {
+ struct timeval timeout;
+ fd_set rfds;
+ fd_set wfds;
+
+ timeout.tv_sec = SELECT_TIMEOUT / 1000;
+ timeout.tv_usec = (SELECT_TIMEOUT % 1000) * 1000;
+ rfds = events.rfds;
+ wfds = events.wfds;
+
+ ret = select(events.maxfd + 1, &rfds, &wfds, NULL, &timeout);
+ if (ret < 0) {
+ /* EINTR means that a signal has been received, continue
+ * to the next iteration in that case.
+ */
+ if (errno == EINTR)
+ continue;
+
+ printf("error: select failed with %d\n", errno);
+ goto cleanup;
+ }
+ if (ret == 0) {
+ /* select() should never time out as the ISP is supposed
+ * to capture images continuously. A timeout is thus
+ * considered as a fatal error.
+ */
+ printf("error: select timeout\n");
+ goto cleanup;
+ }
+
+ events_dispatch(&rfds, &wfds);
+ count++;
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &end);
+
+ /* Stop the ISP. */
+ omap3_isp_viewfinder_stop(isp);
+
+ /* Print some statistics. */
+ end.tv_sec -= start.tv_sec;
+ end.tv_nsec -= start.tv_nsec;
+ if (end.tv_nsec < 0) {
+ end.tv_sec--;
+ end.tv_nsec += 1000000000;
+ }
+
+ fps = count / (end.tv_sec + end.tv_nsec / 1000000000.0);
+
+ printf("%u images processed in %lu.%06lu seconds (%f fps)\n", count,
+ end.tv_sec, end.tv_nsec / 1000, fps);
+
+ exit_code = EXIT_SUCCESS;
+
+cleanup:
+ /* Cleanup the ISP resources. */
+ if (isp)
+ omap3_isp_close(isp);
+ if (pool)
+ v4l2_buffers_pool_delete(pool);
+
+ return exit_code;
+}