summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-07-05 02:22:35 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2012-10-20 21:28:24 +0200
commit2d3f2cce4a0a520f846e1a1e01a23c55e4da05ba (patch)
tree7df85ed8077062a6dfc26e24f47faa80c992827e
parente63c0b37164a07c1a944a6597a550472abfeac75 (diff)
isp: Add scaler API
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--isp/omap3isp-priv.h2
-rw-r--r--isp/omap3isp.c238
-rw-r--r--isp/omap3isp.h17
3 files changed, 257 insertions, 0 deletions
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 <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#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