From 23b31323e49efd89d1ef40ceb9488579069929e6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 3 Jul 2012 00:33:55 +0200 Subject: isp: Add live zoom support Signed-off-by: Laurent Pinchart --- isp/omap3isp-priv.h | 19 ++++++++++++ isp/omap3isp.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++- isp/omap3isp.h | 2 ++ 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/isp/omap3isp-priv.h b/isp/omap3isp-priv.h index c71ed40..2d639e1 100644 --- a/isp/omap3isp-priv.h +++ b/isp/omap3isp-priv.h @@ -112,6 +112,21 @@ struct omap3_isp_pool { #define to_omap3_isp_pool(e) container_of(e, struct omap3_isp_pool, entity) +/* + * struct omap3_isp_resizer - OMAP3 ISP resizer parameters in a pipeline + * @entity: The resizer entity + * @zoom_min: Crop rectangle at minimum zoom + * @zoom_max: Crop rectangle at maximum zoom (up to x4.0) + * @pan_x: Zoom center along X axis + * @pan_y: Zoom center along Y axis + * @zoom: Zoom level (0.0 - 1.0) + */ +struct omap3_isp_resizer { + struct omap3_isp_entity *entity; + struct v4l2_rect zoom_min; + struct v4l2_rect zoom_max; +}; + enum omap3_isp_pipeline_state { OMAP3_ISP_PIPELINE_STOPPED, OMAP3_ISP_PIPELINE_RUNNING, @@ -132,6 +147,7 @@ struct omap3_isp_pipeline { struct list_entry pools; struct omap3_isp_video *output; enum omap3_isp_pipeline_state state; + struct omap3_isp_resizer resizer; }; struct omap3_isp_device { @@ -150,6 +166,9 @@ struct omap3_isp_device { struct media_entity *entity; struct omap3isp_prev_wbal wbal; } preview; + struct { + struct media_entity *entity; + } resizer; struct omap3_isp_aewb aewb; struct omap3_isp_pipeline viewfinder; diff --git a/isp/omap3isp.c b/isp/omap3isp.c index 7ff2d7e..1e6f317 100644 --- a/isp/omap3isp.c +++ b/isp/omap3isp.c @@ -629,6 +629,8 @@ static int omap3_isp_pipeline_try_format(struct omap3_isp_device *isp, struct media_entity_pad *pad; int ret; + pipe->resizer.entity = NULL; + /* Configure formats. Start from the sensor output and propagate the * format through the pipeline. */ @@ -726,6 +728,17 @@ static int omap3_isp_pipeline_try_format(struct omap3_isp_device *isp, } sink->sink.format = format; + + if (sink->entity == isp->resizer.entity) { + ret = v4l2_subdev_get_crop(sink->entity, + &pipe->resizer.zoom_min, + 0, V4L2_SUBDEV_FORMAT_TRY); + if (ret < 0) + printf("error: failed to get minimum zoom limit, " + "zoom will be disabled.\n"); + else + pipe->resizer.entity = sink; + } } else if (sink->type == OMAP3_ISP_ENTITY_VIDEO) { video = to_omap3_isp_video(sink); @@ -756,6 +769,24 @@ static int omap3_isp_pipeline_try_format(struct omap3_isp_device *isp, source = sink; } + if (pipe->resizer.entity) { + pipe->resizer.zoom_max.left = pipe->resizer.zoom_min.left + + pipe->resizer.zoom_min.width / 2; + pipe->resizer.zoom_max.top = pipe->resizer.zoom_min.top + + pipe->resizer.zoom_min.height / 2; + pipe->resizer.zoom_max.width = 0; + pipe->resizer.zoom_max.height = 0; + + ret = v4l2_subdev_set_crop(isp->resizer.entity, + &pipe->resizer.zoom_max, 0, + V4L2_SUBDEV_FORMAT_TRY); + if (ret < 0) { + printf("error: failed to get maximum zoom limit, " + "zoom will be disabled.\n"); + pipe->resizer.entity = NULL; + } + } + return 0; } @@ -876,6 +907,48 @@ static int omap3_isp_pipeline_put_buffer(struct omap3_isp_device *isp, return omap3_isp_video_queue_buffer(pipe->output, buffer); } + +static int omap3_isp_pipeline_pan_zoom(struct omap3_isp_device *isp, + struct omap3_isp_pipeline *pipe, + float pan_x, float pan_y, float zoom) +{ + struct v4l2_mbus_framefmt *format; + struct v4l2_rect rect; + float delta; + int ret; + + if (pipe->resizer.entity == NULL) + return -ENODEV; + + format = &pipe->resizer.entity->sink.format; + + /* A x4.0 zoom level results in SBL overflows at the resizer output. */ + zoom = clamp(zoom, 1.0, 3.8); + + delta = pipe->resizer.zoom_min.width - pipe->resizer.zoom_max.width; + rect.width = format->width - (zoom - 1.0) / 3.0 * delta; + rect.left = (format->width - rect.width) * pan_x; + + delta = pipe->resizer.zoom_min.height - pipe->resizer.zoom_max.height; + rect.height = format->height - (zoom - 1.0) / 3.0 * delta; + rect.top = (format->height - rect.height) * pan_y; + + if (pipe->resizer.entity->sink.crop.left == rect.left && + pipe->resizer.entity->sink.crop.top == rect.top && + pipe->resizer.entity->sink.crop.width == rect.width && + pipe->resizer.entity->sink.crop.height == rect.height) + return 0; + + ret = v4l2_subdev_set_crop(isp->resizer.entity, &rect, 0, + V4L2_SUBDEV_FORMAT_ACTIVE); + if (ret < 0) + return ret; + + pipe->resizer.entity->sink.crop = rect; + + return 0; +} + /* ----------------------------------------------------------------------------- * Open/close */ @@ -918,8 +991,10 @@ struct omap3_isp_device *omap3_isp_open(const char *devname, */ isp->ccdc.entity = media_get_entity_by_name(isp->mdev, ENTITY_CCDC); isp->preview.entity = media_get_entity_by_name(isp->mdev, ENTITY_PREVIEW); + isp->resizer.entity = media_get_entity_by_name(isp->mdev, ENTITY_RESIZER); - if (isp->ccdc.entity == NULL || isp->preview.entity == NULL) { + if (isp->ccdc.entity == NULL || isp->preview.entity == NULL || + isp->resizer.entity == NULL) { printf("error: unable to locate one or more ISP entities.\n"); goto error; } @@ -1231,6 +1306,12 @@ static int omap3_isp_viewfinder_resume(struct omap3_isp_device *isp) return 0; } +int omap3_isp_viewfinder_pan_zoom(struct omap3_isp_device *isp, + float x, float y, float zoom) +{ + return omap3_isp_pipeline_pan_zoom(isp, &isp->viewfinder, x, y, zoom); +} + /* ----------------------------------------------------------------------------- * Snapshot * diff --git a/isp/omap3isp.h b/isp/omap3isp.h index 545c82c..16c96bd 100644 --- a/isp/omap3isp.h +++ b/isp/omap3isp.h @@ -71,6 +71,8 @@ int omap3_isp_viewfinder_start(struct omap3_isp_device *isp); int omap3_isp_viewfinder_stop(struct omap3_isp_device *isp); int omap3_isp_viewfinder_put_buffer(struct omap3_isp_device *isp, struct v4l2_video_buffer *buffer); +int omap3_isp_viewfinder_pan_zoom(struct omap3_isp_device *isp, + float x, float y, float zoom); int omap3_isp_snapshot_setup(struct omap3_isp_device *isp, struct v4l2_rect *crop, -- cgit v1.2.3