From cb8e1c98a612f7b5460b5d8cfe1078369de6a8af Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 5 Jul 2012 02:35:42 +0200 Subject: live: Add snapshot and scaler support Signed-off-by: Laurent Pinchart --- live.c | 320 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file 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; -- cgit v1.2.3