/* * OMAP3 ISP snapshot test application * * Copyright (C) 2010-2011 Ideas on board SPRL * * Contact: Laurent Pinchart * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "isp/list.h" #include "isp/omap3isp.h" #include "isp/tools.h" #include "isp/v4l2.h" #include "isp/v4l2-pool.h" #include "events.h" #define MEDIA_DEVICE "/dev/media0" #define VIEWFINDER_WIDTH 1024 #define VIEWFINDER_HEIGHT 768 #define SNAPSHOT_WIDTH 2048 #define SNAPSHOT_HEIGHT 1536 static unsigned int frame_count = 0; static unsigned int snapshot_interval = 20; static unsigned int snapshot_count = 0; static struct timespec snapshot_time; static bool snapshot_save = false; static struct events events; /* ----------------------------------------------------------------------------- * Events */ static void __events_watch_fd(int fd, enum omap3_isp_event_type type, void(*callback)(void *), void *priv) { events_watch_fd(&events, fd, type, callback, priv); } static void __events_unwatch_fd(int fd) { events_unwatch_fd(&events, fd); } /* -------------------------------------------------------------------------- */ static void sigint_handler(int signal __attribute__((__unused__))) { /* Stop the main loop when the user presses CTRL-C. */ events_stop(&events); } static void snapshot_process(struct omap3_isp_device *isp, struct v4l2_video_buffer *buffer) { static struct timespec ts; char name[23]; int ret; int fd; 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); if (snapshot_save) { sprintf(name, "snapshot-%06u.bin", snapshot_count); fd = open(name, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); if (fd == -1) goto requeue; write(fd, buffer->mem, buffer->bytesused); close(fd); } requeue: /* Requeue the buffer */ snapshot_count++; 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 const struct { const char *name; unsigned int fourcc; } pixel_formats[] = { { "Y8", V4L2_MBUS_FMT_Y8_1X8 }, { "Y10", V4L2_MBUS_FMT_Y10_1X10 }, { "Y12", V4L2_MBUS_FMT_Y12_1X12 }, { "YUYV", V4L2_MBUS_FMT_YUYV8_2X8 }, { "UYVY", V4L2_MBUS_FMT_UYVY8_2X8 }, { "SBGGR8", V4L2_MBUS_FMT_SBGGR8_1X8 }, { "SGBRG8", V4L2_MBUS_FMT_SGBRG8_1X8 }, { "SGRBG8", V4L2_MBUS_FMT_SGRBG8_1X8 }, { "SRGGB8", V4L2_MBUS_FMT_SRGGB8_1X8 }, { "SBGGR10", V4L2_MBUS_FMT_SBGGR10_1X10 }, { "SGBRG10", V4L2_MBUS_FMT_SGBRG10_1X10 }, { "SGRBG10", V4L2_MBUS_FMT_SGRBG10_1X10 }, { "SRGGB10", V4L2_MBUS_FMT_SRGGB10_1X10 }, { "SBGGR12", V4L2_MBUS_FMT_SBGGR12_1X12 }, { "SGBRG12", V4L2_MBUS_FMT_SGBRG12_1X12 }, { "SGRBG12", V4L2_MBUS_FMT_SGRBG12_1X12 }, { "SRGGB12", V4L2_MBUS_FMT_SRGGB12_1X12 }, }; static unsigned int parse_format(const char *name) { unsigned int i; for (i = 0; i < ARRAY_SIZE(pixel_formats); ++i) { if (strcasecmp(pixel_formats[i].name, name) == 0) return pixel_formats[i].fourcc; } return 0; } static void usage(const char *argv0) { printf("Usage: %s [options]\n", argv0); printf("Supported options:\n"); printf("-f, --format fmt Snapshot format\n"); printf("-h, --help Show this help screen\n"); printf("-i, --interval n Capture a snapshot every n frames\n"); printf("-S, --save Save snapshots to disk\n"); } static struct option opts[] = { { "format", 1, 0, 'f' }, { "help", 0, 0, 'h' }, { "interval", 1, 0, 'i' }, { "save", 0, 0, 'S' }, { 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; int exit_code = EXIT_FAILURE; float fps; int ret; int c; while ((c = getopt_long(argc, argv, "f:hi:S", opts, NULL)) != -1) { switch (c) { case 'f': snap_code = parse_format(optarg); if (snap_code == 0) { printf("invalid format %s.\n", optarg); return 1; } break; case 'h': usage(argv[0]); return 0; case 'i': snapshot_interval = strtoul(optarg, NULL, 10); if (snapshot_interval == 0) { printf("snapshot interval value must be >0.\n"); return 1; } break; case 'S': snapshot_save = true; break; default: printf("Invalid option -%c\n", c); printf("Run %s -h for help.\n", argv[0]); return 1; } } events_init(&events); /* 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. */ if (events_loop(&events)) goto cleanup; 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 = frame_count / (end.tv_sec + end.tv_nsec / 1000000000.0); printf("%u images processed in %lu.%06lu seconds (%f fps)\n", frame_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; }