summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-07-05 02:35:42 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-10-20 21:28:24 +0200
commitcb8e1c98a612f7b5460b5d8cfe1078369de6a8af (patch)
tree454ff27e86484d1e713987d94eaad7a4813e9f05
parent2d3f2cce4a0a520f846e1a1e01a23c55e4da05ba (diff)
live: Add snapshot and scaler support
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--live.c320
1 files changed, 259 insertions, 61 deletions
diff --git a/live.c b/live.c
index 97a4e12..47e04d2 100644
--- a/live.c
+++ b/live.c
@@ -59,6 +59,9 @@
#define MEDIA_DEVICE "/dev/media0"
#define VIDEOOUT_DEVICE "/dev/video0"
+#define SNAPSHOT_WIDTH 2048
+#define SNAPSHOT_HEIGHT 1536
+
static struct timespec fps_ts = { 0, 0 };
static unsigned int fps_last = 0;
static bool fps_show = true;
@@ -68,8 +71,17 @@ static unsigned int frame_skip = 0;
static struct omap3_isp_device *isp = NULL;
static struct videoout *vo = NULL;
+static unsigned int vo_bufmask = -1;
static struct iq_tuning *iq = NULL;
+enum state {
+ STATE_VIEWFINDER,
+ STATE_SNAPSHOT,
+ STATE_DISPLAY,
+};
+
+static enum state state = STATE_VIEWFINDER;
+
static struct events events;
struct input {
@@ -79,6 +91,8 @@ struct input {
float y;
};
+static struct input input;
+
/* -----------------------------------------------------------------------------
* Image quality
*/
@@ -105,7 +119,118 @@ static void __events_unwatch_fd(int fd)
}
/* -----------------------------------------------------------------------------
- * Video input
+ * Snapshots
+ */
+
+static void scaler_process(struct omap3_isp_device *isp,
+ struct v4l2_video_buffer *buffer)
+{
+ if (state != STATE_DISPLAY)
+ return;
+
+ if (buffer->error) {
+ printf("%s: error in dequeued buffer, skipping\n", __func__);
+ omap3_isp_scaler_put_buffer(isp, buffer);
+ return;
+ }
+
+ /* Queue the buffer to the display. */
+ vo_queue_buffer(vo, buffer);
+ vo_bufmask &= ~(1 << buffer->index);
+}
+
+static void snapshot_process(struct omap3_isp_device *isp,
+ struct v4l2_video_buffer *buffer)
+{
+ int ret;
+
+
+ if (buffer->error) {
+ printf("%s: error in dequeued buffer, skipping\n", __func__);
+ /* 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);
+ state = STATE_VIEWFINDER;
+ }
+
+ return;
+ }
+
+ ret = omap3_isp_snapshot_done(isp);
+ if (ret < 0) {
+ printf("error: unable to stop snapshot: %s (%d)\n",
+ strerror(-ret), ret);
+ return;
+ }
+
+ printf("displaying snapshot\n");
+ state = STATE_DISPLAY;
+ input.zoom = 1.0;
+ input.x = 0.5;
+ input.y = 0.5;
+
+ ret = omap3_isp_scaler_start(isp, buffer, vo_bufmask);
+ if (ret < 0) {
+ printf("error: unable to start scaler: %s (%d)\n",
+ strerror(-ret), ret);
+ return;
+ }
+}
+
+static int snapshot_init(struct omap3_isp_device *isp,
+ const struct v4l2_rect *rect)
+{
+ struct v4l2_mbus_framefmt ifmt;
+ struct v4l2_mbus_framefmt ofmt;
+ struct v4l2_buffers_pool *pool;
+ int ret;
+
+ /* Snapshot */
+ ifmt.code = V4L2_MBUS_FMT_YUYV8_1X16;
+ ifmt.width = SNAPSHOT_WIDTH;
+ ifmt.height = SNAPSHOT_HEIGHT;
+
+ ret = omap3_isp_snapshot_setup(isp, NULL, &ifmt);
+ if (ret < 0) {
+ printf("error: unable to setup snapshot\n");
+ return ret;
+ }
+
+ printf("snapshot configured for %04x %ux%u\n",
+ ifmt.code, ifmt.width, ifmt.height);
+
+ /* Scaler */
+ ofmt.code = V4L2_MBUS_FMT_YUYV8_1X16;
+ ofmt.width = rect->width;
+ ofmt.height = rect->height;
+
+ ret = omap3_isp_scaler_setup(isp, &ifmt, &ofmt);
+ if (ret < 0) {
+ printf("error: unable to setup scaler\n");
+ return ret;
+ }
+
+ /* Use the video output buffers pool. */
+ pool = vo_get_pool(vo);
+ if (pool == NULL) {
+ printf("error: unable to get video output buffers pool\n");
+ return ret;
+ }
+
+ ret = omap3_isp_scaler_set_pool(isp, pool);
+ if (ret < 0) {
+ printf("error: unable to set scaler buffers pool\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/* -----------------------------------------------------------------------------
+ * Viewfinder
*/
static void viewfinder_process(struct omap3_isp_device *isp __attribute__((__unused__)),
@@ -134,8 +259,8 @@ static void viewfinder_process(struct omap3_isp_device *isp __attribute__((__unu
}
if (buffer->error) {
- printf("warning: error in dequeued buffer, skipping\n");
- return;
+ printf("%s: error in dequeued buffer, skipping\n", __func__);
+ goto requeue;
}
/* Queue the buffer to the display, or requeue it to the viewfinder if
@@ -143,9 +268,11 @@ static void viewfinder_process(struct omap3_isp_device *isp __attribute__((__unu
*/
if ((frame_count % (frame_skip + 1)) == 0) {
vo_queue_buffer(vo, buffer);
+ vo_bufmask &= ~(1 << buffer->index);
return;
}
+requeue:
ret = omap3_isp_viewfinder_put_buffer(isp, buffer);
if (ret < 0)
printf("error: unable to requeue buffer: %s (%d)\n",
@@ -154,15 +281,105 @@ static void viewfinder_process(struct omap3_isp_device *isp __attribute__((__unu
static struct omap3_isp_operations isp_ops = {
.viewfinder_ready = viewfinder_process,
+ .snapshot_ready = snapshot_process,
+ .scaler_ready = scaler_process,
.watch_fd = __events_watch_fd,
.unwatch_fd = __events_unwatch_fd,
.aewb_ready = __iq_aewb_process,
};
+static int viewfinder_init(struct omap3_isp_device *isp,
+ const struct v4l2_rect *rect)
+{
+ struct v4l2_mbus_framefmt view_format;
+ struct v4l2_buffers_pool *pool;
+ int ret;
+
+ memset(&view_format, 0, sizeof view_format);
+ view_format.code = V4L2_MBUS_FMT_YUYV8_1X16;
+ view_format.width = rect->width;
+ view_format.height = rect->height;
+
+ ret = omap3_isp_viewfinder_setup(isp, &view_format);
+ if (ret < 0) {
+ printf("error: unable to setup viewfinder\n");
+ return ret;
+ }
+
+ printf("viewfinder configured for %04x %ux%u\n",
+ view_format.code, view_format.width, view_format.height);
+
+ /* Use the video output buffers pool. */
+ pool = vo_get_pool(vo);
+ if (pool == NULL) {
+ printf("error: unable to get video output buffers pool\n");
+ return ret;
+ }
+
+ ret = omap3_isp_viewfinder_set_pool(isp, pool);
+ if (ret < 0) {
+ printf("error: unable to set viewfinder buffers pool\n");
+ return ret;
+ }
+
+ return 0;
+}
+
/* -----------------------------------------------------------------------------
* Input device
*/
+static void input_process_key(struct input_event *iev)
+{
+ if (iev->value != 1)
+ return;
+
+ switch (iev->code) {
+ case BTN_LEFT:
+ /* Capture a snapshot */
+ if (state == STATE_VIEWFINDER) {
+ printf("taking snapshot\n");
+ omap3_isp_viewfinder_stop(isp);
+ omap3_isp_snapshot_capture(isp);
+ state = STATE_SNAPSHOT;
+ }
+ break;
+
+ case BTN_RIGHT:
+ /* Resume the viewfinder */
+ if (state == STATE_DISPLAY) {
+ printf("resuming viewfinder (%08x)\n", vo_bufmask);
+ omap3_isp_scaler_stop(isp);
+ omap3_isp_viewfinder_start(isp, vo_bufmask);
+ input.zoom = 1.0;
+ input.x = 0.5;
+ input.y = 0.5;
+ state = STATE_VIEWFINDER;
+ }
+ break;
+ }
+}
+
+static void input_process_rel(struct input *input, struct input_event *iev)
+{
+ switch (iev->code) {
+ case REL_X:
+ input->x += iev->value * 0.01;
+ input->x = clamp(input->x, 0.0, 1.0);
+ break;
+
+ case REL_Y:
+ input->y += iev->value * 0.01;
+ input->y = clamp(input->y, 0.0, 1.0);
+ break;
+
+ case REL_WHEEL:
+ input->zoom += iev->value * 0.1;
+ input->zoom = clamp(input->zoom, 1.0, 4.0);
+ break;
+ }
+}
+
static void input_process(void *priv)
{
struct input_event iev[8];
@@ -176,23 +393,12 @@ static void input_process(void *priv)
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);
+ switch (iev[i].type) {
+ case EV_KEY:
+ input_process_key(&iev[i]);
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);
+ case EV_REL:
+ input_process_rel(input, &iev[i]);
break;
}
}
@@ -201,7 +407,12 @@ static void input_process(void *priv)
input->zoom == last_zoom)
return;
- omap3_isp_viewfinder_pan_zoom(isp, input->x, input->y, input->zoom);
+ if (state == STATE_VIEWFINDER)
+ omap3_isp_viewfinder_pan_zoom(isp, input->x, input->y,
+ input->zoom);
+ else if (STATE_DISPLAY)
+ omap3_isp_scaler_pan_zoom(isp, input->x, input->y,
+ input->zoom);
}
static const char *input_find_device(void)
@@ -343,8 +554,16 @@ static void video_out_process(void *priv __attribute__((__unused__)))
if (ret < 0)
return;
+ vo_bufmask |= 1 << buffer.index;
+
/* Requeue the buffer */
- ret = omap3_isp_viewfinder_put_buffer(isp, &buffer);
+ if (state == STATE_VIEWFINDER)
+ ret = omap3_isp_viewfinder_put_buffer(isp, &buffer);
+ else if (state == STATE_DISPLAY)
+ ret = omap3_isp_scaler_put_buffer(isp, &buffer);
+ else
+ return;
+
if (ret < 0) {
printf("error: unable to requeue buffer: %s (%d)\n",
strerror(-ret), ret);
@@ -583,8 +802,6 @@ static struct option opts[] = {
int main(int argc __attribute__((__unused__)), char *argv[] __attribute__((__unused__)))
{
- struct v4l2_mbus_framefmt view_format;
- struct v4l2_buffers_pool *pool = NULL;
struct v4l2_pix_format format;
struct timespec start, end;
struct iq_params iq_params;
@@ -594,7 +811,6 @@ 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;
@@ -652,35 +868,6 @@ int main(int argc __attribute__((__unused__)), char *argv[] __attribute__((__unu
*/
signal(SIGINT, sigint_handler);
- /* Open the OMAP3 ISP device and setup the capture pipeline. */
- isp = omap3_isp_open(MEDIA_DEVICE, &isp_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 = rect.width;
- view_format.height = rect.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);
-
- if (enable_aewb) {
- iq = iq_init(isp, &iq_params);
- if (iq == NULL) {
- printf("error: unable to initialize image quality tuning\n");
- goto cleanup;
- }
- }
-
/* Initialize video output. */
vo_devname = video_out_find();
if (vo_devname == NULL) {
@@ -700,21 +887,32 @@ int main(int argc __attribute__((__unused__)), char *argv[] __attribute__((__unu
vo_enable_colorkey(vo, colorkey);
- /* Allocate a buffers pool and use it for the viewfinder. */
- pool = vo_get_pool(vo);
- if (pool == NULL) {
- printf("error: unable to get video output buffers pool\n");
+ /* Open the OMAP3 ISP device and setup the capture pipeline. */
+ isp = omap3_isp_open(MEDIA_DEVICE, &isp_ops);
+ if (isp == NULL) {
+ printf("error: unable to open media device %s\n", MEDIA_DEVICE);
goto cleanup;
}
- ret = omap3_isp_viewfinder_set_pool(isp, pool);
- if (ret < 0) {
- printf("error: unable to set buffers pool\n");
+ ret = viewfinder_init(isp, &rect);
+ if (ret < 0)
goto cleanup;
+
+ /* Configure snapshot, scaler and AEWB. */
+ ret = snapshot_init(isp, &rect);
+ if (ret < 0)
+ goto cleanup;
+
+ if (enable_aewb) {
+ iq = iq_init(isp, &iq_params);
+ if (iq == NULL) {
+ printf("error: unable to initialize image quality tuning\n");
+ goto cleanup;
+ }
}
/* Start the ISP. */
- ret = omap3_isp_viewfinder_start(isp, -1);
+ ret = omap3_isp_viewfinder_start(isp, vo_bufmask);
if (ret < 0)
goto cleanup;