summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2011-03-28 13:28:28 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-05-20 11:55:31 -0300
commitaee5c2f1fc9c7cd2502ff14f818fcedef666f038 (patch)
treef1eb50bc8558350d927b7624723ce7203272ceeb
parent08a31b960598adef6aa9430c2cab4b5ef4db1ab8 (diff)
[media] V4L: soc-camera: add a livecrop host operation
Add an soc-camera host livecrop operation to implement live zoom. If a host driver implements it, it should take care to preserve output frame format, then live crop doesn't break streaming. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/soc_camera.c20
-rw-r--r--include/media/soc_camera.h5
2 files changed, 19 insertions, 6 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index ddb4c091ded..3fb533c4d33 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -41,6 +41,11 @@
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
+#define is_streaming(ici, icd) \
+ (((ici)->ops->init_videobuf) ? \
+ (icd)->vb_vidq.streaming : \
+ vb2_is_streaming(&(icd)->vb2_vidq))
+
static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
@@ -662,7 +667,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
if (icd->streamer && icd->streamer != file)
return -EBUSY;
- if (icd->vb_vidq.bufs[0]) {
+ if (is_streaming(to_soc_camera_host(icd->dev.parent), icd)) {
dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
return -EBUSY;
}
@@ -903,14 +908,17 @@ static int soc_camera_s_crop(struct file *file, void *fh,
if (ret < 0) {
dev_err(&icd->dev,
"S_CROP denied: getting current crop failed\n");
- } else if (icd->vb_vidq.bufs[0] &&
- (a->c.width != current_crop.c.width ||
- a->c.height != current_crop.c.height)) {
+ } else if ((a->c.width == current_crop.c.width &&
+ a->c.height == current_crop.c.height) ||
+ !is_streaming(ici, icd)) {
+ /* same size or not streaming - use .set_crop() */
+ ret = ici->ops->set_crop(icd, a);
+ } else if (ici->ops->set_livecrop) {
+ ret = ici->ops->set_livecrop(icd, a);
+ } else {
dev_err(&icd->dev,
"S_CROP denied: queue initialised and sizes differ\n");
ret = -EBUSY;
- } else {
- ret = ici->ops->set_crop(icd, a);
}
return ret;
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index f80b5372baf..844cd09d7d3 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -80,6 +80,11 @@ struct soc_camera_host_ops {
int (*cropcap)(struct soc_camera_device *, struct v4l2_cropcap *);
int (*get_crop)(struct soc_camera_device *, struct v4l2_crop *);
int (*set_crop)(struct soc_camera_device *, struct v4l2_crop *);
+ /*
+ * The difference to .set_crop() is, that .set_livecrop is not allowed
+ * to change the output sizes
+ */
+ int (*set_livecrop)(struct soc_camera_device *, struct v4l2_crop *);
int (*set_fmt)(struct soc_camera_device *, struct v4l2_format *);
int (*try_fmt)(struct soc_camera_device *, struct v4l2_format *);
void (*init_videobuf)(struct videobuf_queue *,