From 2d3f2cce4a0a520f846e1a1e01a23c55e4da05ba Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 5 Jul 2012 02:22:35 +0200 Subject: isp: Add scaler API Signed-off-by: Laurent Pinchart --- isp/omap3isp-priv.h | 2 + isp/omap3isp.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++ isp/omap3isp.h | 17 ++++ 3 files changed, 257 insertions(+) diff --git a/isp/omap3isp-priv.h b/isp/omap3isp-priv.h index 18babcd..a31f943 100644 --- a/isp/omap3isp-priv.h +++ b/isp/omap3isp-priv.h @@ -154,6 +154,7 @@ enum omap3_isp_state { OMAP3_ISP_IDLE, OMAP3_ISP_VIEWFINDER, OMAP3_ISP_SNAPSHOT, + OMAP3_ISP_SCALER, }; struct omap3_isp_device { @@ -179,6 +180,7 @@ struct omap3_isp_device { struct omap3_isp_pipeline viewfinder; struct omap3_isp_pipeline snapshot; + struct omap3_isp_pipeline scaler; enum omap3_isp_state state; diff --git a/isp/omap3isp.c b/isp/omap3isp.c index ed5094c..eb5d2e8 100644 --- a/isp/omap3isp.c +++ b/isp/omap3isp.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "controls.h" #include "list.h" @@ -36,6 +37,7 @@ #define ENTITY_CCDC_OUTPUT "OMAP3 ISP CCDC output" #define ENTITY_PREVIEW "OMAP3 ISP preview" #define ENTITY_RESIZER "OMAP3 ISP resizer" +#define ENTITY_RESIZER_INPUT "OMAP3 ISP resizer input" #define ENTITY_RESIZER_OUTPUT "OMAP3 ISP resizer output" /* ----------------------------------------------------------------------------- @@ -1006,6 +1008,7 @@ struct omap3_isp_device *omap3_isp_open(const char *devname, omap3_isp_pipeline_init(&isp->viewfinder); omap3_isp_pipeline_init(&isp->snapshot); + omap3_isp_pipeline_init(&isp->scaler); /* Open the media device and reset all links to make sure we're in a * consistent, known state. @@ -1083,6 +1086,7 @@ void omap3_isp_close(struct omap3_isp_device *isp) omap3_isp_stats_cleanup(isp); omap3_isp_pipeline_destroy(&isp->viewfinder); omap3_isp_pipeline_destroy(&isp->snapshot); + omap3_isp_pipeline_destroy(&isp->scaler); media_close(isp->mdev); free(isp); } @@ -1462,3 +1466,237 @@ int omap3_isp_snapshot_put_buffer(struct omap3_isp_device *isp, return omap3_isp_pipeline_put_buffer(isp, &isp->snapshot, omap3_isp_snapshot_event, buffer); } + +/* ----------------------------------------------------------------------------- + * Scaler + */ + +int omap3_isp_scaler_setup(struct omap3_isp_device *isp, + struct v4l2_mbus_framefmt *ifmt, + struct v4l2_mbus_framefmt *ofmt) +{ + struct v4l2_mbus_framefmt __ifmt; + struct v4l2_mbus_framefmt __ofmt; + int ret; + + ret = omap3_isp_pipeline_build(isp, &isp->scaler, ENTITY_RESIZER_INPUT, + ENTITY_RESIZER, ENTITY_RESIZER_OUTPUT, + NULL); + if (ret < 0) { + printf("error: unable to build scaler pipeline (%d)\n", ret); + return ret; + } + + isp->scaler.scaler = OMAP3_ISP_SCALER_ISP; + + /* Try the formats and make sure the results match the requirements + * exactly. + */ + __ifmt = *ifmt; + __ofmt = *ofmt; + + ret = omap3_isp_pipeline_try_format(isp, &isp->scaler, ifmt, ofmt, NULL); + if (ret < 0) + return ret; + + if (ifmt->width != __ifmt.width || ifmt->height != __ifmt.height || + ofmt->width != __ofmt.width || ofmt->height != __ofmt.height) + return -EINVAL; + + /* Create a buffer pool for input buffers. Every buffer in the input + * pool will copy the size and reference the memory of the buffer to be + * scaled. + */ + isp->scaler.input->pool = v4l2_buffers_pool_new(2); + if (isp->scaler.input->pool == NULL) { + printf("error: unable to allocate input buffers for scaler.\n"); + return -ENOMEM; + } + + return 0; +} + +int omap3_isp_scaler_set_pool(struct omap3_isp_device *isp, + struct v4l2_buffers_pool *pool) +{ + int ret; + + isp->scaler.output->pool = pool; + + /* Allocate video buffers. */ + ret = v4l2_alloc_buffers(isp->scaler.output->video, pool, V4L2_MEMORY_USERPTR); + if (ret < 0) { + printf("error: unable to allocate output buffers for scaler.\n"); + return ret; + } + + isp->scaler.output->queued = 0; + + return 0; +} + +static void omap3_isp_scaler_input_event(void *priv) +{ + struct omap3_isp_device *isp = priv; + struct v4l2_video_buffer buffer; + int ret; + + /* Dequeue a buffer and requeue it immediately. */ + ret = omap3_isp_video_dequeue_buffer(isp->scaler.input, &buffer); + if (ret < 0) { + printf("error: unable to dequeue scaler input buffer.\n"); + return; + } + + buffer.bytesused = isp->scaler.input->pool->buffers[buffer.index].size; + + ret = omap3_isp_video_queue_buffer(isp->scaler.input, &buffer); + if (ret < 0) { + printf("error: unable to queue scaler input buffer.\n"); + return; + } +} + +static void omap3_isp_scaler_output_event(void *priv) +{ + struct omap3_isp_device *isp = priv; + struct v4l2_video_buffer buffer; + int ret; + + /* Dequeue the buffer */ + ret = omap3_isp_video_dequeue_buffer(isp->scaler.output, &buffer); + if (ret < 0) { + printf("%s: unable to dequeue buffer: %s (%d)\n", __func__, + strerror(-ret), ret); + return; + } + + if (isp->scaler.output->queued == 0) + isp->ops->unwatch_fd(isp->scaler.output->video->fd); + + isp->ops->scaler_ready(isp, &buffer); +} + +int omap3_isp_scaler_start(struct omap3_isp_device *isp, + struct v4l2_video_buffer *ibuf, + unsigned int obufs) +{ + struct v4l2_video_buffer buffer; + unsigned int i; + int ret; + + /* Configure the pipeline. */ + ret = omap3_isp_pipeline_activate(isp, &isp->scaler); + if (ret < 0) { + printf("error: unable to setup scaler pipeline.\n"); + return ret; + } + + /* Allocate input buffers. Make all buffers in the pool reference the + * same memory buffer. + */ + for (i = 0; i < isp->scaler.input->pool->nbufs; ++i) { + isp->scaler.input->pool->buffers[i].size = ibuf->size; + isp->scaler.input->pool->buffers[i].mem = ibuf->mem; + } + + ret = v4l2_alloc_buffers(isp->scaler.input->video, isp->scaler.input->pool, + V4L2_MEMORY_USERPTR); + if (ret < 0) { + printf("error: unable to allocate input buffers for scaler.\n"); + return ret; + } + + /* Queue the input and output buffers. */ + for (i = 0; i < isp->scaler.input->video->nbufs; ++i) { + buffer.index = i; + buffer.bytesused = ibuf->bytesused; + + ret = omap3_isp_video_queue_buffer(isp->scaler.input, &buffer); + if (ret < 0) { + printf("error: unable to queue scaler input buffer %u\n", i); + return ret; + } + } + + for (i = 0; i < isp->scaler.output->video->nbufs; ++i) { + /* Don't queue buffer that are under control of the application. */ + if (!(obufs & (1 << i))) + continue; + + buffer.index = i; + + ret = omap3_isp_video_queue_buffer(isp->scaler.output, &buffer); + if (ret < 0) { + printf("error: unable to queue scaler ouput buffer %u\n", i); + return ret; + } + } + + /* Watch the file descriptors. */ + isp->ops->watch_fd(isp->scaler.input->video->fd, OMAP3_ISP_EVENT_WRITE, + omap3_isp_scaler_input_event, isp); + if (isp->scaler.output->queued) + isp->ops->watch_fd(isp->scaler.output->video->fd, + OMAP3_ISP_EVENT_READ, + omap3_isp_scaler_output_event, isp); + + /* Start the resizer. */ + ret = omap3_isp_video_start(isp->scaler.output); + if (ret < 0) { + printf("error: streamon failed for scaler output\n"); + return ret; + } + + ret = omap3_isp_video_start(isp->scaler.input); + if (ret < 0) { + printf("error: streamon failed for scaler input\n"); + return ret; + } + + isp->state = OMAP3_ISP_SCALER; + return 0; +} + +int omap3_isp_scaler_stop(struct omap3_isp_device *isp) +{ + int ret; + + isp->ops->unwatch_fd(isp->scaler.input->video->fd); + isp->ops->unwatch_fd(isp->scaler.output->video->fd); + + /* FIXME: No sleep results in a hard system lockup. */ + usleep(100000); + + ret = omap3_isp_video_stop(isp->scaler.input); + if (ret < 0) { + printf("error: streamoff failed for scaler input\n"); + return ret; + } + + ret = omap3_isp_video_stop(isp->scaler.output); + if (ret < 0) { + printf("error: streamoff failed for scaler output\n"); + return ret; + } + + ret = v4l2_free_buffers(isp->scaler.input->video); + if (ret < 0) + printf("error: unable to free scaler input buffers.\n"); + + isp->state = OMAP3_ISP_IDLE; + return 0; +} + +int omap3_isp_scaler_put_buffer(struct omap3_isp_device *isp, + struct v4l2_video_buffer *buffer) +{ + return omap3_isp_pipeline_put_buffer(isp, &isp->scaler, + omap3_isp_scaler_output_event, buffer); +} + +int omap3_isp_scaler_pan_zoom(struct omap3_isp_device *isp, + float x, float y, float zoom) +{ + return omap3_isp_pipeline_pan_zoom(isp, &isp->scaler, x, y, zoom); +} diff --git a/isp/omap3isp.h b/isp/omap3isp.h index 93ddfff..491dcdb 100644 --- a/isp/omap3isp.h +++ b/isp/omap3isp.h @@ -50,6 +50,8 @@ struct omap3_isp_operations { struct v4l2_video_buffer *buffer); void (*snapshot_ready)(struct omap3_isp_device *isp, struct v4l2_video_buffer *buffer); + void (*scaler_ready)(struct omap3_isp_device *isp, + struct v4l2_video_buffer *buffer); void (*aewb_ready)(struct omap3_isp_device *isp, const struct omap3_isp_aewb_stats *stats); void (*watch_fd)(int fd, enum omap3_isp_event_type type, @@ -84,6 +86,21 @@ int omap3_isp_snapshot_done(struct omap3_isp_device *isp); int omap3_isp_snapshot_put_buffer(struct omap3_isp_device *isp, struct v4l2_video_buffer *buffer); +/* Scaler */ +int omap3_isp_scaler_setup(struct omap3_isp_device *isp, + struct v4l2_mbus_framefmt *ifmt, + struct v4l2_mbus_framefmt *ofmt); +int omap3_isp_scaler_set_pool(struct omap3_isp_device *isp, + struct v4l2_buffers_pool *pool); +int omap3_isp_scaler_start(struct omap3_isp_device *isp, + struct v4l2_video_buffer *ibuf, + unsigned int obufs); +int omap3_isp_scaler_stop(struct omap3_isp_device *isp); +int omap3_isp_scaler_put_buffer(struct omap3_isp_device *isp, + struct v4l2_video_buffer *buffer); +int omap3_isp_scaler_pan_zoom(struct omap3_isp_device *isp, + float x, float y, float zoom); + /* Processing parameters */ #define OMAP3_ISP_SENSOR_GAIN_KEEP -1 -- cgit v1.2.3