summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2015-03-08 14:35:31 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2015-03-08 23:26:42 +0200
commit857d32bce873cc0a467e60f7f462c84594330730 (patch)
tree6126114f5549cd72d9b5e042a428552c6f9905d8
parentcbd64859e6c1509b0f2ee7728cb66b120d52c45e (diff)
isp: Add histogram supporthistogram
Support enabling the histogram statistics engine and retrieving histogram data. Histogram data is currently ignored in the image quality tuning implementation. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--iq.c9
-rw-r--r--iq.h2
-rw-r--r--isp/omap3isp-priv.h1
-rw-r--r--isp/omap3isp.h2
-rw-r--r--isp/stats-priv.h18
-rw-r--r--isp/stats.c274
-rw-r--r--isp/stats.h37
-rw-r--r--live.c7
-rw-r--r--snapshot.c7
9 files changed, 323 insertions, 34 deletions
diff --git a/iq.c b/iq.c
index dd85cfc..41fa90d 100644
--- a/iq.c
+++ b/iq.c
@@ -94,6 +94,12 @@ void iq_aewb_process(struct iq_tuning *iq,
omap3_isp_sensor_set_gain(iq->isp, iqp->gain);
}
+void iq_histogram_process(struct iq_tuning *iq __attribute__((__unused__)),
+ const struct omap3_isp_histogram_stats *stats __attribute__((__unused__)))
+{
+ printf("hist: data received\n");
+}
+
/**
* iq_params_init - Initialize IQ parameters
* @params: IQ parameters
@@ -223,7 +229,8 @@ struct iq_tuning *iq_init(struct omap3_isp_device *isp,
window.height = params->window.height * format.height;
omap3_isp_aewb_configure(isp, &window, iq->pix_max - iq->params.black_level - 1);
- omap3_isp_stats_enable(isp, true);
+ omap3_isp_histogram_configure(isp, &window);
+ omap3_isp_stats_enable(isp, OMAP3_ISP_STAT_AEWB | OMAP3_ISP_STAT_HIST);
return iq;
}
diff --git a/iq.h b/iq.h
index be13a9f..5b5217a 100644
--- a/iq.h
+++ b/iq.h
@@ -69,6 +69,8 @@ struct iq_params {
void iq_aewb_process(struct iq_tuning *iq,
const struct omap3_isp_aewb_stats *stats);
+void iq_histogram_process(struct iq_tuning *iq,
+ const struct omap3_isp_histogram_stats *stats);
void iq_params_init(struct iq_params *params);
int iq_params_parse(struct iq_params *params, const char *arg);
diff --git a/isp/omap3isp-priv.h b/isp/omap3isp-priv.h
index a31f943..3a3eee7 100644
--- a/isp/omap3isp-priv.h
+++ b/isp/omap3isp-priv.h
@@ -177,6 +177,7 @@ struct omap3_isp_device {
struct media_entity *entity;
} resizer;
struct omap3_isp_aewb aewb;
+ struct omap3_isp_histogram hist;
struct omap3_isp_pipeline viewfinder;
struct omap3_isp_pipeline snapshot;
diff --git a/isp/omap3isp.h b/isp/omap3isp.h
index 491dcdb..f31de3e 100644
--- a/isp/omap3isp.h
+++ b/isp/omap3isp.h
@@ -54,6 +54,8 @@ struct omap3_isp_operations {
struct v4l2_video_buffer *buffer);
void (*aewb_ready)(struct omap3_isp_device *isp,
const struct omap3_isp_aewb_stats *stats);
+ void (*histogram_ready)(struct omap3_isp_device *isp,
+ const struct omap3_isp_histogram_stats *hist);
void (*watch_fd)(int fd, enum omap3_isp_event_type type,
void(*callback)(void *priv), void *priv);
void (*unwatch_fd)(int fd);
diff --git a/isp/stats-priv.h b/isp/stats-priv.h
index c3f084c..43b920a 100644
--- a/isp/stats-priv.h
+++ b/isp/stats-priv.h
@@ -66,6 +66,24 @@ struct omap3_isp_aewb {
bool enabled;
};
+/*
+ * struct omap3_isp_histogram - OMAP3 ISP histogram statistics engine
+ * @entity: Histogram entity
+ * @size: buffer size
+ * @buffer: buffer memory
+ * @rect: histogram region of interest
+ * @enabled: statistics engine enabled
+ */
+struct omap3_isp_histogram {
+ struct media_entity *entity;
+ unsigned int size;
+ void *buffer;
+
+ struct v4l2_rect rect;
+
+ bool enabled;
+};
+
int omap3_isp_stats_start(struct omap3_isp_device *isp);
void omap3_isp_stats_stop(struct omap3_isp_device *isp);
int omap3_isp_stats_init(struct omap3_isp_device *isp);
diff --git a/isp/stats.c b/isp/stats.c
index a96da5e..4ff11a9 100644
--- a/isp/stats.c
+++ b/isp/stats.c
@@ -278,32 +278,7 @@ int omap3_isp_aewb_configure(struct omap3_isp_device *isp, struct v4l2_rect *rec
return 0;
}
-/* -----------------------------------------------------------------------------
- * Start/stop, init/cleanup
- */
-
-int omap3_isp_stats_get_format(struct omap3_isp_device *isp,
- struct v4l2_mbus_framefmt *format)
-{
- struct omap3_isp_aewb *aewb = &isp->aewb;
- struct media_entity_pad *source;
-
- source = media_entity_remote_source(&aewb->entity->pads[0]);
- if (source == NULL)
- return -ENOENT;
-
- return v4l2_subdev_get_format(source->entity, format, source->index,
- V4L2_SUBDEV_FORMAT_TRY);
-}
-
-void omap3_isp_stats_enable(struct omap3_isp_device *isp, bool enable)
-{
- struct omap3_isp_aewb *aewb = &isp->aewb;
-
- aewb->enabled = enable;
-}
-
-int omap3_isp_stats_start(struct omap3_isp_device *isp)
+static int omap3_isp_aewb_start(struct omap3_isp_device *isp)
{
struct omap3_isp_aewb *aewb = &isp->aewb;
struct v4l2_event_subscription esub;
@@ -342,7 +317,7 @@ int omap3_isp_stats_start(struct omap3_isp_device *isp)
return 0;
}
-void omap3_isp_stats_stop(struct omap3_isp_device *isp)
+static void omap3_isp_aewb_stop(struct omap3_isp_device *isp)
{
struct omap3_isp_aewb *aewb = &isp->aewb;
struct v4l2_event_subscription esub;
@@ -359,7 +334,7 @@ void omap3_isp_stats_stop(struct omap3_isp_device *isp)
ioctl(aewb->entity->fd, VIDIOC_UNSUBSCRIBE_EVENT, &esub);
}
-int omap3_isp_stats_init(struct omap3_isp_device *isp)
+static int omap3_isp_aewb_init(struct omap3_isp_device *isp)
{
struct omap3_isp_aewb *aewb = &isp->aewb;
@@ -370,7 +345,250 @@ int omap3_isp_stats_init(struct omap3_isp_device *isp)
return v4l2_subdev_open(aewb->entity);
}
+/* -----------------------------------------------------------------------------
+ * Histogram
+ */
+
+static void omap3_isp_histogram_process(struct omap3_isp_device *isp,
+ void *buffer,
+ size_t size __attribute__((__unused__)))
+{
+ struct omap3_isp_histogram_stats stats;
+
+ memset(&stats, 0, sizeof stats);
+ stats.nbins = 256;
+ stats.bins = (uint32_t *)buffer;
+
+ isp->ops->histogram_ready(isp, &stats);
+}
+
+static void omap3_isp_histogram_event(void *priv)
+{
+ struct omap3_isp_device *isp = priv;
+ struct omap3_isp_histogram *hist = &isp->hist;
+ struct omap3isp_stat_data data;
+ struct v4l2_event event;
+ struct omap3isp_stat_event_status *status =
+ (struct omap3isp_stat_event_status *)event.u.data;
+ int ret;
+
+ memset(&event, 0, sizeof event);
+ ret = ioctl(hist->entity->fd, VIDIOC_DQEVENT, &event);
+ if (ret < 0) {
+ printf("unable to retrieve histogram event: %s (%d).\n",
+ strerror(errno), errno);
+ return;
+ }
+
+ if (status->buf_err) {
+ printf("histogram: stats error, skipping buffer.\n");
+ return;
+ }
+
+ memset(&data, 0, sizeof data);
+ data.buf = hist->buffer;
+ data.buf_size = hist->size;
+
+ ret = ioctl(hist->entity->fd, VIDIOC_OMAP3ISP_STAT_REQ, &data);
+ if (ret < 0) {
+ printf("unable to retrieve histogram data: %s (%d).\n",
+ strerror(errno), errno);
+ return;
+ }
+
+ omap3_isp_histogram_process(isp, data.buf, data.buf_size);
+}
+
+static int omap3_isp_histogram_setup(struct omap3_isp_device *isp)
+{
+ struct omap3_isp_histogram *hist = &isp->hist;
+ struct omap3isp_hist_config config;
+ unsigned int buf_size;
+ int ret;
+
+ memset(&config, 0, sizeof config);
+ config.num_acc_frames = 1;
+ config.hist_bins = OMAP3ISP_HIST_BINS_256;
+ config.cfa = OMAP3ISP_HIST_CFA_BAYER;
+ config.wg[0] = 1 << 5;
+ config.wg[1] = 1 << 5;
+ config.wg[2] = 1 << 5;
+ config.wg[3] = 1 << 5;
+ config.num_regions = 1;
+ config.region[0].h_start = hist->rect.left;
+ config.region[0].h_end = hist->rect.left + hist->rect.width - 1;
+ config.region[0].v_start = hist->rect.top;
+ config.region[0].v_end = hist->rect.top + hist->rect.height - 1;
+
+ buf_size = OMAP3ISP_HIST_MEM_SIZE_BINS(config.hist_bins)
+ * config.num_regions;
+ config.buf_size = buf_size;
+
+ ret = ioctl(hist->entity->fd, VIDIOC_OMAP3ISP_HIST_CFG, &config);
+ if (ret < 0)
+ return -errno;
+
+ if (config.buf_size != buf_size)
+ printf("histogram: buf size was %u, is %u\n", buf_size,
+ config.buf_size);
+
+ hist->size = config.buf_size;
+ hist->buffer = malloc(config.buf_size);
+ if (hist->buffer == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+int omap3_isp_histogram_configure(struct omap3_isp_device *isp,
+ struct v4l2_rect *rect)
+{
+ struct omap3_isp_histogram *hist = &isp->hist;
+ struct v4l2_mbus_framefmt format;
+ struct media_entity_pad *source;
+ int ret;
+
+ source = media_entity_remote_source(&hist->entity->pads[0]);
+ if (source == NULL)
+ return -ENOENT;
+
+ ret = v4l2_subdev_get_format(source->entity, &format, source->index,
+ V4L2_SUBDEV_FORMAT_TRY);
+ if (ret < 0)
+ return ret;
+
+ /* Validate the requested rectangle. */
+ if (rect->left < 0 || rect->left + rect->width > (int)format.width ||
+ rect->top < 0 || rect->top + rect->height > (int)format.height)
+ return -ERANGE;
+
+ hist->rect = *rect;
+
+ return 0;
+}
+
+static int omap3_isp_histogram_start(struct omap3_isp_device *isp)
+{
+ struct omap3_isp_histogram *hist = &isp->hist;
+ struct v4l2_event_subscription esub;
+ unsigned long enable = 1;
+ int ret;
+
+ if (!hist->enabled)
+ return 0;
+
+ ret = omap3_isp_histogram_setup(isp);
+ if (ret < 0) {
+ printf("unable to configure histogram engine: %s (%d).\n",
+ strerror(errno), errno);
+ return ret;
+ }
+
+ memset(&esub, 0, sizeof esub);
+ esub.type = V4L2_EVENT_OMAP3ISP_HIST;
+ ret = ioctl(hist->entity->fd, VIDIOC_SUBSCRIBE_EVENT, &esub);
+ if (ret < 0) {
+ printf("unable to subscribe to histogram event: %s (%d).\n",
+ strerror(errno), errno);
+ return ret;
+ }
+
+ ret = ioctl(hist->entity->fd, VIDIOC_OMAP3ISP_STAT_EN, &enable);
+ if (ret < 0) {
+ printf("unable to start histogram engine: %s (%d).\n",
+ strerror(errno), errno);
+ return ret;
+ }
+
+ isp->ops->watch_fd(hist->entity->fd, OMAP3_ISP_EVENT_EXCEPTION,
+ omap3_isp_histogram_event, isp);
+
+ return 0;
+}
+
+static void omap3_isp_histogram_stop(struct omap3_isp_device *isp)
+{
+ struct omap3_isp_histogram *hist = &isp->hist;
+ struct v4l2_event_subscription esub;
+ unsigned long enable = 0;
+
+ if (!hist->enabled)
+ return;
+
+ isp->ops->unwatch_fd(hist->entity->fd);
+ ioctl(hist->entity->fd, VIDIOC_OMAP3ISP_STAT_EN, &enable);
+
+ memset(&esub, 0, sizeof esub);
+ esub.type = V4L2_EVENT_OMAP3ISP_HIST;
+ ioctl(hist->entity->fd, VIDIOC_UNSUBSCRIBE_EVENT, &esub);
+}
+
+static int omap3_isp_histogram_init(struct omap3_isp_device *isp)
+{
+ struct omap3_isp_histogram *hist = &isp->hist;
+
+ hist->entity = media_get_entity_by_name(isp->mdev, "OMAP3 ISP histogram");
+ if (hist->entity == NULL)
+ return -ENOENT;
+
+ return v4l2_subdev_open(hist->entity);
+}
+
+/* -----------------------------------------------------------------------------
+ * Start/stop, init/cleanup
+ */
+
+int omap3_isp_stats_get_format(struct omap3_isp_device *isp,
+ struct v4l2_mbus_framefmt *format)
+{
+ struct omap3_isp_aewb *aewb = &isp->aewb;
+ struct media_entity_pad *source;
+
+ source = media_entity_remote_source(&aewb->entity->pads[0]);
+ if (source == NULL)
+ return -ENOENT;
+
+ return v4l2_subdev_get_format(source->entity, format, source->index,
+ V4L2_SUBDEV_FORMAT_TRY);
+}
+
+void omap3_isp_stats_enable(struct omap3_isp_device *isp,
+ enum omap3_isp_stat_engine which)
+{
+ isp->aewb.enabled = !!(which & OMAP3_ISP_STAT_AEWB);
+ isp->hist.enabled = !!(which & OMAP3_ISP_STAT_HIST);
+}
+
+int omap3_isp_stats_start(struct omap3_isp_device *isp)
+{
+ int ret;
+
+ ret = omap3_isp_aewb_start(isp);
+ if (ret < 0)
+ return ret;
+
+ return omap3_isp_histogram_start(isp);
+}
+
+void omap3_isp_stats_stop(struct omap3_isp_device *isp)
+{
+ omap3_isp_aewb_stop(isp);
+ omap3_isp_histogram_stop(isp);
+}
+
+int omap3_isp_stats_init(struct omap3_isp_device *isp)
+{
+ int ret;
+
+ ret = omap3_isp_aewb_init(isp);
+ if (ret < 0)
+ return ret;
+
+ return omap3_isp_histogram_init(isp);
+}
+
void omap3_isp_stats_cleanup(struct omap3_isp_device *isp)
{
v4l2_subdev_close(isp->aewb.entity);
+ v4l2_subdev_close(isp->hist.entity);
}
diff --git a/isp/stats.h b/isp/stats.h
index fb6c26a..f68d4fa 100644
--- a/isp/stats.h
+++ b/isp/stats.h
@@ -27,6 +27,11 @@
struct omap3_isp_device;
+enum omap3_isp_stat_engine {
+ OMAP3_ISP_STAT_AEWB = 1 << 0,
+ OMAP3_ISP_STAT_HIST = 1 << 1,
+};
+
/*
* struct omap3_isp_aewb_stats - OMAP3 ISP AEWB statistics
* @npix: Total number of accumulated pixels
@@ -52,15 +57,28 @@ struct omap3_isp_aewb_stats {
};
/*
+ * struct omap3_isp_histogram_stats - OMAP3 ISP histogram statistics
+ * @nbins: Number of bins in the histogram
+ * @bins: Array of histogram frequency data
+ *
+ * Each bin entry is stored on 32 bits but limited to 20 bits.
+ */
+struct omap3_isp_histogram_stats {
+ unsigned int nbins;
+ uint32_t *bins;
+};
+
+/*
* omap3_isp_stats_enable - Enable or disable the statistics engine
* @isp: The ISP device
- * @enable: Whether to enable to disable the statistics engine
+ * @which: The statistics engine(s) to enable
*
- * The statistics engine must be enabled prior to starting the video stream.
- * When enabled, it statistics will be computed for every frame and delivered
- * through the ISP aewb_ready() callback.
+ * The statistics engines must be enabled prior to starting the video stream.
+ * When enabled, statistics will be computed for every frame and delivered
+ * through the ISP aewb_ready() and histogram_ready() callbacks.
*/
-void omap3_isp_stats_enable(struct omap3_isp_device *isp, bool enable);
+void omap3_isp_stats_enable(struct omap3_isp_device *isp,
+ enum omap3_isp_stat_engine which);
/*
* omap3_isp_stats_get_format - Get frame format at the statistics engine input
@@ -72,6 +90,7 @@ void omap3_isp_stats_enable(struct omap3_isp_device *isp, bool enable);
*/
int omap3_isp_stats_get_format(struct omap3_isp_device *isp,
struct v4l2_mbus_framefmt *format);
+
/*
* omap3_isp_aewb_configure - Configure the AEWB statistics engine
* @isp: The ISP device
@@ -81,4 +100,12 @@ int omap3_isp_stats_get_format(struct omap3_isp_device *isp,
int omap3_isp_aewb_configure(struct omap3_isp_device *isp, struct v4l2_rect *rect,
unsigned int saturation);
+/*
+ * omap3_isp_histogram_configure - Configure the histogram statistics engine
+ * @isp: The ISP device
+ * @rect: The region of interest, relative to the sensor output frame size
+ */
+int omap3_isp_histogram_configure(struct omap3_isp_device *isp,
+ struct v4l2_rect *rect);
+
#endif
diff --git a/live.c b/live.c
index 47e04d2..d4d14dc 100644
--- a/live.c
+++ b/live.c
@@ -103,6 +103,12 @@ static void __iq_aewb_process(struct omap3_isp_device *isp __attribute__((__unus
iq_aewb_process(iq, stats);
}
+static void __iq_histogram_process(struct omap3_isp_device *isp __attribute__((__unused__)),
+ const struct omap3_isp_histogram_stats *stats)
+{
+ iq_histogram_process(iq, stats);
+}
+
/* -----------------------------------------------------------------------------
* Events
*/
@@ -286,6 +292,7 @@ static struct omap3_isp_operations isp_ops = {
.watch_fd = __events_watch_fd,
.unwatch_fd = __events_unwatch_fd,
.aewb_ready = __iq_aewb_process,
+ .histogram_ready = __iq_histogram_process,
};
static int viewfinder_init(struct omap3_isp_device *isp,
diff --git a/snapshot.c b/snapshot.c
index 878d4bf..61e297f 100644
--- a/snapshot.c
+++ b/snapshot.c
@@ -119,6 +119,12 @@ static void __iq_aewb_process(struct omap3_isp_device *isp __attribute__((__unus
iq_aewb_process(iq, stats);
}
+static void __iq_histogram_process(struct omap3_isp_device *isp __attribute__((__unused__)),
+ const struct omap3_isp_histogram_stats *stats)
+{
+ iq_histogram_process(iq, stats);
+}
+
/* -----------------------------------------------------------------------------
* Events
*/
@@ -617,6 +623,7 @@ int main(int argc __attribute__((__unused__)), char *argv[] __attribute__((__unu
ops.watch_fd = __events_watch_fd;
ops.unwatch_fd = __events_unwatch_fd;
ops.aewb_ready = __iq_aewb_process;
+ ops.histogram_ready = __iq_histogram_process,
isp = omap3_isp_open(MEDIA_DEVICE, &ops);
if (isp == NULL) {