* [PATCH v1 3/4] v4l: videobuf: Add support for multi-plane buffers.
2010-02-22 16:10 [PATCH/RFC v1 0/4] Multi-plane video buffer support for V4L2 API and videobuf Pawel Osciak
2010-02-22 16:10 ` [PATCH v1 1/4] v4l: add missing checks for kzalloc returning NULL Pawel Osciak
2010-02-22 16:10 ` [PATCH v1 2/4] v4l: Add support for multi-plane buffers to V4L2 API Pawel Osciak
@ 2010-02-22 16:10 ` Pawel Osciak
2010-02-22 16:10 ` [PATCH v1 4/4] v4l: vivi: add 2- and 3-planar YCbCr422 Pawel Osciak
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Pawel Osciak @ 2010-02-22 16:10 UTC (permalink / raw)
To: linux-media; +Cc: p.osciak, m.szyprowski, kyungmin.park, hverkuil, m-karicheri2
Add support for multiplanar buffers to videobuf core, dma-contig
and vmalloc memory types.
Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/media/video/videobuf-core.c | 363 +++++++++++++++++++++++-----
drivers/media/video/videobuf-dma-contig.c | 303 ++++++++++++++++++------
drivers/media/video/videobuf-vmalloc.c | 195 +++++++++++++---
include/media/videobuf-core.h | 59 +++--
include/media/videobuf-dma-contig.h | 3 +
include/media/videobuf-vmalloc.h | 2 +
6 files changed, 723 insertions(+), 202 deletions(-)
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index bb0a1c8..7a5ed69 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -29,6 +29,10 @@
printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \
BUG(); } } while (0)
+#define is_multiplane(vb)\
+ (vb->memory == V4L2_MEMORY_MULTI_MMAP\
+ || vb->memory == V4L2_MEMORY_MULTI_USERPTR)
+
static int debug;
module_param(debug, int, 0644);
@@ -45,22 +49,24 @@ MODULE_LICENSE("GPL");
#define CALL(q, f, arg...) \
((q->int_ops->f) ? q->int_ops->f(arg) : 0)
-void *videobuf_alloc(struct videobuf_queue *q)
+void *videobuf_alloc(struct videobuf_queue *q, unsigned int num_planes)
{
struct videobuf_buffer *vb;
BUG_ON(q->msize < sizeof(*vb));
+ BUG_ON(0 == num_planes);
if (!q->int_ops || !q->int_ops->alloc) {
printk(KERN_ERR "No specific ops defined!\n");
BUG();
}
- vb = q->int_ops->alloc(q->msize);
+ vb = q->int_ops->alloc(q->msize, num_planes);
if (NULL != vb) {
init_waitqueue_head(&vb->done);
vb->magic = MAGIC_BUFFER;
+ vb->num_planes = num_planes;
}
return vb;
@@ -106,6 +112,17 @@ void *videobuf_queue_to_vmalloc (struct videobuf_queue *q,
}
EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
+void *videobuf_queue_plane_to_vmalloc(struct videobuf_queue *q,
+ struct videobuf_buffer *buf,
+ unsigned int plane)
+{
+ if (q->int_ops->plane_vmalloc)
+ return q->int_ops->plane_vmalloc(buf, plane);
+ else
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(videobuf_queue_plane_to_vmalloc);
+
/* --------------------------------------------------------------------- */
@@ -131,7 +148,8 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
q->int_ops = int_ops;
/* All buffer operations are mandatory */
- BUG_ON(!q->ops->buf_setup);
+ BUG_ON(!q->ops->buf_negotiate);
+ BUG_ON(!q->ops->buf_setup_plane);
BUG_ON(!q->ops->buf_prepare);
BUG_ON(!q->ops->buf_queue);
BUG_ON(!q->ops->buf_release);
@@ -169,7 +187,7 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
- if (q->bufs[i]->map) {
+ if (q->bufs[i]->mapped) {
dprintk(1, "busy: buffer #%d mapped\n", i);
return 1;
}
@@ -242,6 +260,8 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
struct videobuf_buffer *vb, enum v4l2_buf_type type)
{
+ unsigned int i;
+
MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
@@ -251,20 +271,50 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
b->memory = vb->memory;
switch (b->memory) {
case V4L2_MEMORY_MMAP:
- b->m.offset = vb->boff;
- b->length = vb->bsize;
+ b->m.offset = vb->planes[0].boff;
+ b->length = vb->planes[0].bsize;
break;
case V4L2_MEMORY_USERPTR:
- b->m.userptr = vb->baddr;
- b->length = vb->bsize;
+ b->m.userptr = vb->planes[0].baddr;
+ b->length = vb->planes[0].bsize;
break;
case V4L2_MEMORY_OVERLAY:
- b->m.offset = vb->boff;
+ b->m.offset = vb->planes[0].boff;
+ break;
+ case V4L2_MEMORY_MULTI_MMAP:
+ if (NULL == b->m.planes) {
+ dprintk(1, "Warning: buffer details not copied back "
+ "as no planes array has been provided\n");
+ break;
+ }
+
+ BUG_ON(b->length < vb->num_planes);
+ b->length = vb->num_planes;
+ for (i = 0; i < vb->num_planes; ++i) {
+ b->m.planes[i].m.offset = vb->planes[i].boff;
+ b->m.planes[i].length = vb->planes[i].bsize;
+ b->m.planes[i].bytesused = vb->planes[i].size;
+ }
+ break;
+ case V4L2_MEMORY_MULTI_USERPTR:
+ if (NULL == b->m.planes) {
+ dprintk(1, "Warning: buffer details not copied back "
+ "as no planes array has been provided\n");
+ break;
+ }
+
+ BUG_ON(b->length < vb->num_planes);
+ b->length = vb->num_planes;
+ for (i = 0; i < vb->num_planes; ++i) {
+ b->m.planes[i].m.userptr = vb->planes[i].baddr;
+ b->m.planes[i].length = vb->planes[i].bsize;
+ b->m.planes[i].bytesused = vb->planes[i].size;
+ }
break;
}
b->flags = 0;
- if (vb->map)
+ if (vb->mapped)
b->flags |= V4L2_BUF_FLAG_MAPPED;
switch (vb->state) {
@@ -290,7 +340,8 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
b->field = vb->field;
b->timestamp = vb->ts;
- b->bytesused = vb->size;
+ /* TODO what to do with bytesused in the main buffer structure? */
+ b->bytesused = vb->planes[0].size;
b->sequence = vb->field_count >> 1;
}
@@ -305,7 +356,6 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
-
rc = CALL(q, mmap_free, q);
q->is_mmapped = 0;
@@ -333,23 +383,83 @@ int videobuf_mmap_free(struct videobuf_queue *q)
return ret;
}
-/* Locking: Caller holds q->vb_lock */
-int __videobuf_mmap_setup(struct videobuf_queue *q,
- unsigned int bcount, unsigned int bsize,
- enum v4l2_memory memory)
+static int buf_setup_planes(struct videobuf_queue *q, unsigned int num_planes,
+ unsigned int *plane_sizes)
{
unsigned int i;
+ int ret;
+
+ BUG_ON(NULL == plane_sizes);
+
+ dprintk(1, "%s num_planes: %u\n", __func__, num_planes);
+
+ for (i = 0; i < num_planes; ++i) {
+ ret = q->ops->buf_setup_plane(q, i, &plane_sizes[i]);
+ if (ret)
+ return ret;
+ plane_sizes[i] = PAGE_ALIGN(plane_sizes[i]);
+ dprintk(1, "%s %dth plane_size: %d\n",
+ __func__, i, plane_sizes[i]);
+ }
+
+ return 0;
+}
+
+static int verify_planes_array(struct videobuf_queue *q, struct v4l2_buffer *b)
+{
+ if (is_multiplane(q->bufs[b->index])) {
+ if (NULL == b->m.planes) {
+ /* Ioctl logic has not copied planes array
+ * from userspace */
+ dprintk(1, "Multiplane buffer queried but "
+ "planes array not provided\n");
+ return -EINVAL;
+ }
+
+ if (b->length != q->bufs[b->index]->num_planes) {
+ dprintk(1, "Incorrect planes array length, "
+ "expected %d, got %d\n",
+ q->bufs[b->index]->num_planes, b->length);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/* Locking: Caller holds q->vb_lock */
+int __videobuf_mmap_setup(struct videobuf_queue *q, unsigned int bcount,
+ unsigned int pcount, enum v4l2_memory memory)
+{
+ unsigned int i = 0;
+ unsigned int j;
int err;
+ size_t curr_off = 0;
+ unsigned int *plane_sizes;
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ BUG_ON(pcount < 1);
+
+ dprintk(1, "mmap setup: bcount: %d, pcount: %d, memory: %d\n",
+ bcount, pcount, memory);
err = __videobuf_mmap_free(q);
if (0 != err)
return err;
+ plane_sizes = kzalloc(pcount * sizeof(*plane_sizes), GFP_KERNEL);
+ if (NULL == plane_sizes)
+ return -ENOMEM;
+
+ err = buf_setup_planes(q, pcount, plane_sizes);
+ if (err) {
+ dprintk(1, "mmap setup: failed setting up planes\n");
+ goto done;
+ }
+
/* Allocate and initialize buffers */
for (i = 0; i < bcount; i++) {
- q->bufs[i] = videobuf_alloc(q);
+ q->bufs[i] = videobuf_alloc(q, pcount);
if (q->bufs[i] == NULL)
break;
@@ -357,12 +467,31 @@ int __videobuf_mmap_setup(struct videobuf_queue *q,
q->bufs[i]->i = i;
q->bufs[i]->input = UNSET;
q->bufs[i]->memory = memory;
- q->bufs[i]->bsize = bsize;
+ q->bufs[i]->num_planes = pcount;
+
switch (memory) {
case V4L2_MEMORY_MMAP:
- q->bufs[i]->boff = PAGE_ALIGN(bsize) * i;
+ case V4L2_MEMORY_MULTI_MMAP:
+ for (j = 0; j < pcount; ++j) {
+ q->bufs[i]->planes[j].boff = curr_off;
+ q->bufs[i]->planes[j].bsize = plane_sizes[j];
+ curr_off += plane_sizes[j];
+ dprintk(1, "%s: buf %d plane: %d: "
+ "bsize: %d boff: %d\n",
+ __func__, i, j,
+ q->bufs[i]->planes[j].bsize,
+ q->bufs[i]->planes[j].boff);
+ }
break;
case V4L2_MEMORY_USERPTR:
+ case V4L2_MEMORY_MULTI_USERPTR:
+ for (j = 0; j < pcount; ++j) {
+ q->bufs[i]->planes[j].bsize = plane_sizes[j];
+ dprintk(1, "%s: buf: %d plane: %d bsize: %d\n",
+ __func__, i, j,
+ q->bufs[i]->planes[j].bsize);
+ }
+ break;
case V4L2_MEMORY_OVERLAY:
/* nothing */
break;
@@ -370,21 +499,21 @@ int __videobuf_mmap_setup(struct videobuf_queue *q,
}
if (!i)
- return -ENOMEM;
-
- dprintk(1, "mmap setup: %d buffers, %d bytes each\n",
- i, bsize);
+ err = -ENOMEM;
+ else
+ err = i;
- return i;
+done:
+ kfree(plane_sizes);
+ return err;
}
-int videobuf_mmap_setup(struct videobuf_queue *q,
- unsigned int bcount, unsigned int bsize,
- enum v4l2_memory memory)
+int videobuf_mmap_setup(struct videobuf_queue *q, unsigned int bcount,
+ unsigned int pcount, enum v4l2_memory memory)
{
int ret;
mutex_lock(&q->vb_lock);
- ret = __videobuf_mmap_setup(q, bcount, bsize, memory);
+ ret = __videobuf_mmap_setup(q, bcount, pcount, memory);
mutex_unlock(&q->vb_lock);
return ret;
}
@@ -392,7 +521,7 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
int videobuf_reqbufs(struct videobuf_queue *q,
struct v4l2_requestbuffers *req)
{
- unsigned int size, count;
+ unsigned int buf_count, plane_count;
int retval;
if (req->count < 1) {
@@ -402,7 +531,9 @@ int videobuf_reqbufs(struct videobuf_queue *q,
if (req->memory != V4L2_MEMORY_MMAP &&
req->memory != V4L2_MEMORY_USERPTR &&
- req->memory != V4L2_MEMORY_OVERLAY) {
+ req->memory != V4L2_MEMORY_OVERLAY &&
+ req->memory != V4L2_MEMORY_MULTI_MMAP &&
+ req->memory != V4L2_MEMORY_MULTI_USERPTR) {
dprintk(1, "reqbufs: memory type invalid\n");
return -EINVAL;
}
@@ -425,16 +556,13 @@ int videobuf_reqbufs(struct videobuf_queue *q,
goto done;
}
- count = req->count;
- if (count > VIDEO_MAX_FRAME)
- count = VIDEO_MAX_FRAME;
- size = 0;
- q->ops->buf_setup(q, &count, &size);
- dprintk(1, "reqbufs: bufs=%d, size=0x%x [%u pages total]\n",
- count, size,
- (unsigned int)((count*PAGE_ALIGN(size))>>PAGE_SHIFT) );
+ buf_count = req->count;
+ if (buf_count > VIDEO_MAX_FRAME)
+ buf_count = VIDEO_MAX_FRAME;
+ q->ops->buf_negotiate(q, &buf_count, &plane_count);
+ dprintk(1, "reqbufs: bufs=%d, planes=%d\n", buf_count, plane_count);
- retval = __videobuf_mmap_setup(q, count, size, req->memory);
+ retval = __videobuf_mmap_setup(q, buf_count, plane_count, req->memory);
if (retval < 0) {
dprintk(1, "reqbufs: mmap setup returned %d\n", retval);
goto done;
@@ -452,6 +580,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
{
int ret = -EINVAL;
+
mutex_lock(&q->vb_lock);
if (unlikely(b->type != q->type)) {
dprintk(1, "querybuf: Wrong type.\n");
@@ -466,6 +595,10 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
goto done;
}
+ ret = verify_planes_array(q, b);
+ if (ret < 0)
+ goto done;
+
videobuf_status(q, b, q->bufs[b->index], q->type);
ret = 0;
@@ -474,6 +607,63 @@ done:
return ret;
}
+static int multiusrptr_check_buf(struct videobuf_buffer *vb,
+ struct v4l2_buffer *buf)
+{
+ unsigned int i;
+
+ BUG_ON(NULL == vb->planes);
+
+ if (buf->length != vb->num_planes) {
+ dprintk(1, "%s: wrong number of planes, should be %d\n",
+ __func__, vb->num_planes);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < buf->length; ++i) {
+ dprintk(1, "%s: plane %d: addr %lu, size %u\n", __func__,
+ i, buf->m.planes[i].m.userptr, buf->m.planes[i].length);
+ if (buf->m.planes[i].length < vb->planes[i].bsize) {
+ dprintk(1, "%s: plane %u too small (%u < %u)\n",
+ __func__, i, buf->m.planes[i].length,
+ vb->planes[i].bsize);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void multiusrptr_set_addr(struct videobuf_buffer *vb,
+ struct v4l2_buffer *buf)
+{
+ struct v4l2_plane *planes = buf->m.planes;
+ struct videobuf_plane *vb_planes = vb->planes;
+ unsigned int i;
+
+ BUG_ON(NULL == vb_planes);
+
+ for (i = 0; i < vb->num_planes; ++i)
+ vb_planes[i].baddr = planes[i].m.userptr;
+}
+
+static int multiusrptr_addr_match(struct videobuf_buffer *vb,
+ struct v4l2_buffer *buf)
+{
+ struct v4l2_plane *planes = buf->m.planes;
+ struct videobuf_plane *vb_planes = vb->planes;
+ unsigned int i;
+
+ BUG_ON(NULL == vb_planes);
+
+ for (i = 0; i < vb->num_planes; ++i) {
+ if (vb_planes[i].baddr != planes[i].m.userptr)
+ return 0;
+ }
+
+ return 1;
+}
+
int videobuf_qbuf(struct videobuf_queue *q,
struct v4l2_buffer *b)
{
@@ -484,7 +674,8 @@ int videobuf_qbuf(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- if (b->memory == V4L2_MEMORY_MMAP)
+ if (b->memory == V4L2_MEMORY_MMAP ||
+ b->memory == V4L2_MEMORY_MULTI_MMAP)
down_read(¤t->mm->mmap_sem);
mutex_lock(&q->vb_lock);
@@ -529,24 +720,41 @@ int videobuf_qbuf(struct videobuf_queue *q,
switch (b->memory) {
case V4L2_MEMORY_MMAP:
- if (0 == buf->baddr) {
- dprintk(1, "qbuf: mmap requested "
- "but buffer addr is zero!\n");
+ case V4L2_MEMORY_MULTI_MMAP:
+ if (!buf->mapped) {
+ dprintk(1, "qbuf: mmap requested, but the buffer "
+ "has not been fully mapped!\n");
goto done;
}
break;
case V4L2_MEMORY_USERPTR:
- if (b->length < buf->bsize) {
+ if (b->length < buf->planes[0].bsize) {
dprintk(1, "qbuf: buffer length is not enough\n");
goto done;
}
if (VIDEOBUF_NEEDS_INIT != buf->state &&
- buf->baddr != b->m.userptr)
+ buf->planes[0].baddr != b->m.userptr)
q->ops->buf_release(q, buf);
- buf->baddr = b->m.userptr;
+ buf->planes[0].baddr = b->m.userptr;
+ break;
+ case V4L2_MEMORY_MULTI_USERPTR:
+ /* Verify sizes of each plane */
+ retval = multiusrptr_check_buf(buf, b);
+ if (retval) {
+ dprintk(1, "qbuf: invalid buffer\n");
+ goto done;
+ }
+
+ /* Verify addresses and release if changed */
+ if (VIDEOBUF_NEEDS_INIT != buf->state &&
+ !multiusrptr_addr_match(buf, b))
+ q->ops->buf_release(q, buf);
+
+ /* Set addresses again */
+ multiusrptr_set_addr(buf, b);
break;
case V4L2_MEMORY_OVERLAY:
- buf->boff = b->m.offset;
+ buf->planes[0].boff = b->m.offset;
break;
default:
dprintk(1, "qbuf: wrong memory type\n");
@@ -574,7 +782,8 @@ int videobuf_qbuf(struct videobuf_queue *q,
done:
mutex_unlock(&q->vb_lock);
- if (b->memory == V4L2_MEMORY_MMAP)
+ if (b->memory == V4L2_MEMORY_MMAP ||
+ b->memory == V4L2_MEMORY_MULTI_MMAP)
up_read(¤t->mm->mmap_sem);
return retval;
@@ -651,11 +860,19 @@ int videobuf_dqbuf(struct videobuf_queue *q,
{
struct videobuf_buffer *buf = NULL;
int retval;
+ unsigned long len;
+ void __user *usr_addr;
+
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
mutex_lock(&q->vb_lock);
+ /* There could be a verify_planes_array() call here to verify
+ * that userspace has passed the array in the buffer, but it might be
+ * too much to ask userspace to pass the array in each dqbuf call.
+ */
+
retval = stream_next_buffer(q, &buf, nonblocking);
if (retval < 0) {
dprintk(1, "dqbuf: next_buffer error: %i\n", retval);
@@ -680,7 +897,16 @@ int videobuf_dqbuf(struct videobuf_queue *q,
goto done;
}
list_del(&buf->stream);
- memset(b, 0, sizeof(*b));
+
+ if (is_multiplane(buf)) {
+ usr_addr = b->m.planes;
+ len = b->length;
+ memset(b, 0, sizeof(*b));
+ b->m.planes = usr_addr;
+ b->length = len;
+ } else {
+ memset(b, 0, sizeof(*b));
+ }
videobuf_status(q, b, buf, q->type);
done:
@@ -747,14 +973,15 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+ /* TODO has yet to be adapted to mutliplanes */
/* setup stuff */
- q->read_buf = videobuf_alloc(q);
+ q->read_buf = videobuf_alloc(q, 1);
if (NULL == q->read_buf)
return -ENOMEM;
q->read_buf->memory = V4L2_MEMORY_USERPTR;
- q->read_buf->baddr = (unsigned long)data;
- q->read_buf->bsize = count;
+ q->read_buf->planes[0].baddr = (unsigned long)data;
+ q->read_buf->planes[0].bsize = count;
field = videobuf_next_field(q);
retval = q->ops->buf_prepare(q, q->read_buf, field);
@@ -771,7 +998,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
if (VIDEOBUF_ERROR == q->read_buf->state)
retval = -EIO;
else
- retval = q->read_buf->size;
+ retval = q->read_buf->planes[0].size;
}
done:
@@ -788,14 +1015,17 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
{
enum v4l2_field field;
unsigned long flags = 0;
- unsigned size = 0, nbufs = 1;
+ unsigned size = 0, nbufs = 1, nplanes;
int retval;
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
mutex_lock(&q->vb_lock);
- q->ops->buf_setup(q, &nbufs, &size);
+ /* TODO read has yet to be verified for mutliplanes */
+ /*q->ops->buf_setup(q, &nbufs, &size);*/
+ q->ops->buf_negotiate(q, &nbufs, &nplanes);
+ q->ops->buf_setup_plane(q, 0, &size);
if (NULL == q->read_buf &&
count >= size &&
@@ -810,13 +1040,13 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
if (NULL == q->read_buf) {
/* need to capture a new frame */
retval = -ENOMEM;
- q->read_buf = videobuf_alloc(q);
+ q->read_buf = videobuf_alloc(q, 1);
dprintk(1, "video alloc=0x%p\n", q->read_buf);
if (NULL == q->read_buf)
goto done;
q->read_buf->memory = V4L2_MEMORY_USERPTR;
- q->read_buf->bsize = count; /* preferred size */
+ q->read_buf->planes[0].bsize = count; /* preferred size */
field = videobuf_next_field(q);
retval = q->ops->buf_prepare(q, q->read_buf, field);
@@ -855,7 +1085,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
goto done;
q->read_off += retval;
- if (q->read_off == q->read_buf->size) {
+ if (q->read_off == q->read_buf->planes[0].size) {
/* all data copied, cleanup */
q->ops->buf_release(q, q->read_buf);
kfree(q->read_buf);
@@ -872,17 +1102,20 @@ static int __videobuf_read_start(struct videobuf_queue *q)
{
enum v4l2_field field;
unsigned long flags = 0;
- unsigned int count = 0, size = 0;
+ unsigned int count = 0, size = 0, nplanes;
int err, i;
- q->ops->buf_setup(q, &count, &size);
+ /*q->ops->buf_setup(q, &count, &size);*/
+ q->ops->buf_negotiate(q, &count, &nplanes);
+ q->ops->buf_setup_plane(q, 0, &size);
if (count < 2)
count = 2;
if (count > VIDEO_MAX_FRAME)
count = VIDEO_MAX_FRAME;
size = PAGE_ALIGN(size);
- err = __videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR);
+ /* TODO multiplane support */
+ err = __videobuf_mmap_setup(q, count, nplanes, V4L2_MEMORY_USERPTR);
if (err < 0)
return err;
@@ -1001,13 +1234,13 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
q->read_off += rc;
} else {
/* some error */
- q->read_off = q->read_buf->size;
+ q->read_off = q->read_buf->planes[0].size;
if (0 == retval)
retval = -EIO;
}
/* requeue buffer when done with copying */
- if (q->read_off == q->read_buf->size) {
+ if (q->read_off == q->read_buf->planes[0].size) {
list_add_tail(&q->read_buf->stream,
&q->stream);
spin_lock_irqsave(q->irqlock, flags);
@@ -1098,8 +1331,8 @@ int videobuf_cgmbuf(struct videobuf_queue *q,
mbuf->frames = req.count;
mbuf->size = 0;
for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += PAGE_ALIGN(q->bufs[i]->bsize);
+ mbuf->offsets[i] = q->bufs[i]->planes[0].boff;
+ mbuf->size += q->bufs[i]->planes[0].bsize;
}
return 0;
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index 22c0109..aaaa5de 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -9,6 +9,8 @@
* Based on videobuf-vmalloc.c,
* (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
*
+ * Adapted for multi-plane buffer support by Pawel Osciak <p.osciak@samsung.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2
@@ -19,7 +21,6 @@
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/dma-mapping.h>
-#include <linux/sched.h>
#include <media/videobuf-dma-contig.h>
struct videobuf_dma_contig_memory {
@@ -37,6 +38,11 @@ struct videobuf_dma_contig_memory {
BUG(); \
}
+static int debug;
+#define dprintk(level, fmt, arg...) do { \
+ if (debug >= level) \
+ printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0)
+
static void
videobuf_vm_open(struct vm_area_struct *vma)
{
@@ -53,6 +59,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
struct videobuf_mapping *map = vma->vm_private_data;
struct videobuf_queue *q = map->q;
int i;
+ unsigned int j;
dev_dbg(map->q->dev, "vm_close %p [count=%u,vma=%08lx-%08lx]\n",
map, map->count, vma->vm_start, vma->vm_end);
@@ -72,7 +79,12 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
if (NULL == q->bufs[i])
continue;
- if (q->bufs[i]->map != map)
+ for (j = 0; j < q->bufs[i]->num_planes; ++j)
+ if (q->bufs[i]->planes[j].map == map)
+ break;
+
+ if (q->bufs[i]->num_planes == j)
+ /* Not found yet */
continue;
mem = q->bufs[i]->priv;
@@ -83,6 +95,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
in order to do memory unmap.
*/
+ /* Mem for j-th plane in the array of
+ * per-plane privs */
+ mem += j;
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
/* vfree is not atomic - can't be
@@ -96,8 +111,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
mem->vaddr = NULL;
}
- q->bufs[i]->map = NULL;
- q->bufs[i]->baddr = 0;
+ q->bufs[i]->planes[j].map = NULL;
+ q->bufs[i]->planes[j].baddr = 0;
+ q->bufs[i]->mapped = 0;
}
kfree(map);
@@ -119,8 +135,8 @@ static const struct vm_operations_struct videobuf_vm_ops = {
*/
static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
{
- mem->is_userptr = 0;
mem->dma_handle = 0;
+ mem->is_userptr = 0;
mem->size = 0;
}
@@ -134,90 +150,147 @@ static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
*
* Returns 0 if successful.
*/
-static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
- struct videobuf_buffer *vb)
+static int videobuf_dma_contig_user_get(struct videobuf_buffer *vb)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
+ struct videobuf_dma_contig_memory *mem;
+ struct videobuf_plane *plane;
unsigned long prev_pfn, this_pfn;
unsigned long pages_done, user_address;
- unsigned int offset;
+ /*unsigned long baddr;*/
int ret;
+ unsigned int i;
- offset = vb->baddr & ~PAGE_MASK;
- mem->size = PAGE_ALIGN(vb->size + offset);
- mem->is_userptr = 0;
ret = -EINVAL;
+ plane = vb->planes;
down_read(&mm->mmap_sem);
- vma = find_vma(mm, vb->baddr);
- if (!vma)
- goto out_up;
+ mem = vb->priv;
+ for (i = 0; i < vb->num_planes; ++i) {
- if ((vb->baddr + mem->size) > vma->vm_end)
- goto out_up;
+ if (!plane->baddr)
+ goto out_up;
- pages_done = 0;
- prev_pfn = 0; /* kill warning */
- user_address = vb->baddr;
+ mem->is_userptr = 0;
+ mem->size = PAGE_ALIGN(plane->bsize);
- while (pages_done < (mem->size >> PAGE_SHIFT)) {
- ret = follow_pfn(vma, user_address, &this_pfn);
- if (ret)
- break;
+ vma = find_vma(mm, plane->baddr);
+ if (!vma)
+ goto out_up;
- if (pages_done == 0)
- mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset;
- else if (this_pfn != (prev_pfn + 1))
- ret = -EFAULT;
+ if ((plane->baddr + mem->size) > vma->vm_end) {
+ dprintk(1, "Plane %u won't fit into vma "
+ "baddr: %lu, vm_end: %lu\n",
+ i, plane->baddr, vma->vm_end);
+ goto out_up;
+ }
- if (ret)
- break;
+ pages_done = 0;
+ prev_pfn = 0; /* kill warning */
+ user_address = plane->baddr;
- prev_pfn = this_pfn;
- user_address += PAGE_SIZE;
- pages_done++;
- }
+ while (pages_done < (mem->size >> PAGE_SHIFT)) {
+ ret = follow_pfn(vma, user_address, &this_pfn);
+ if (ret)
+ /*break;*/
+ goto out_up;
+
+ if (pages_done == 0)
+ mem->dma_handle = this_pfn << PAGE_SHIFT;
+ else if (this_pfn != (prev_pfn + 1))
+ ret = -EFAULT;
- if (!ret)
- mem->is_userptr = 1;
+ if (ret)
+ /*break;*/
+ goto out_up;
+
+ prev_pfn = this_pfn;
+ user_address += PAGE_SIZE;
+ pages_done++;
+ }
- out_up:
+ if (!ret)
+ mem->is_userptr = 1;
+
+ ++mem;
+ ++plane;
+ }
+
+out_up:
up_read(¤t->mm->mmap_sem);
return ret;
}
-static void *__videobuf_alloc(size_t size)
+static void *__videobuf_alloc(size_t size, unsigned int num_planes)
{
struct videobuf_dma_contig_memory *mem;
struct videobuf_buffer *vb;
+ unsigned int i;
- vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
- if (vb) {
- mem = vb->priv = ((char *)vb) + size;
+ vb = kzalloc(size, GFP_KERNEL);
+ if (!vb)
+ return vb;
+
+ /* At least one plane of memory is always needed */
+ vb->planes = kzalloc(sizeof(struct videobuf_plane) * num_planes,
+ GFP_KERNEL);
+ if (!vb->planes)
+ goto free_vb;
+
+ mem = vb->priv = kzalloc(sizeof(*mem) * num_planes, GFP_KERNEL);
+ if (!vb->priv)
+ goto free_planes;
+
+ for (i = 0; i < num_planes; ++i) {
mem->magic = MAGIC_DC_MEM;
+ ++mem;
}
return vb;
+
+free_planes:
+ kfree(vb->planes);
+free_vb:
+ kfree(vb);
+ return NULL;
}
-static void *__videobuf_to_vmalloc(struct videobuf_buffer *buf)
+/**
+ * __plane_to_vmalloc() - return vmalloc pointer to a plane
+ * @plane: Plane number (starting at 0).
+ */
+static void *__plane_to_vmalloc(struct videobuf_buffer *buf, unsigned int plane)
{
struct videobuf_dma_contig_memory *mem = buf->priv;
+ BUG_ON(NULL == buf->planes);
- BUG_ON(!mem);
+ if (plane >= buf->num_planes)
+ return NULL;
+ mem += plane;
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
return mem->vaddr;
}
+/**
+ * __videobuf_to_vmalloc() - return vmalloc pointer to a 1-plane buffer
+ *
+ * Returns vmalloc pointer to the buffer (first plane).
+ */
+static void *__videobuf_to_vmalloc(struct videobuf_buffer *buf)
+{
+ return __plane_to_vmalloc(buf, 0);
+}
+
static int __videobuf_iolock(struct videobuf_queue *q,
struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf)
{
struct videobuf_dma_contig_memory *mem = vb->priv;
+ unsigned int i;
BUG_ON(!mem);
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
@@ -236,11 +309,13 @@ static int __videobuf_iolock(struct videobuf_queue *q,
dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
/* handle pointer from user space */
- if (vb->baddr)
- return videobuf_dma_contig_user_get(mem, vb);
+ if (vb->planes[0].baddr)
+ /*return videobuf_dma_contig_user_get(mem, vb);*/
+ return videobuf_dma_contig_user_get(vb);
+ /* TODO multiplanes */
/* allocate memory for the read() method */
- mem->size = PAGE_ALIGN(vb->size);
+ mem->size = PAGE_ALIGN(vb->planes[0].size);
mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
&mem->dma_handle, GFP_KERNEL);
if (!mem->vaddr) {
@@ -252,6 +327,36 @@ static int __videobuf_iolock(struct videobuf_queue *q,
dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n",
mem->vaddr, mem->size);
break;
+ case V4L2_MEMORY_MULTI_MMAP:
+ dev_dbg(q->dev, "%s memory method MULTI_MMAP\n", __func__);
+ BUG_ON(NULL == vb->planes);
+
+ for (i = 0; i < vb->num_planes; ++i) {
+ MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+ if (!mem->vaddr) {
+ dev_err(q->dev, "plane %d memory is not "
+ "alloced/mmapped\n", i);
+ return -EINVAL;
+ }
+ ++mem;
+ }
+ break;
+ case V4L2_MEMORY_MULTI_USERPTR:
+ dev_dbg(q->dev, "%s memory method MULTI_USERPTR\n", __func__);
+ BUG_ON(NULL == vb->planes);
+
+ for (i = 0; i < vb->num_planes; ++i) {
+ MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+ if (!vb->planes[i].baddr) {
+ dev_err(q->dev, "%s read() not implemented for "
+ "MUTLI_USERPTR\n", __func__);
+ return -EINVAL;
+ }
+ ++mem;
+ }
+
+ return videobuf_dma_contig_user_get(vb);
+
case V4L2_MEMORY_OVERLAY:
default:
dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n",
@@ -264,12 +369,16 @@ static int __videobuf_iolock(struct videobuf_queue *q,
static int __videobuf_mmap_free(struct videobuf_queue *q)
{
- unsigned int i;
+ unsigned int i, j;
- dev_dbg(q->dev, "%s\n", __func__);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (q->bufs[i] && q->bufs[i]->map)
- return -EBUSY;
+ if (NULL == q->bufs[i])
+ continue;
+
+ for (j = 0; j < q->bufs[i]->num_planes; ++j) {
+ if (q->bufs[i]->planes[j].map)
+ return -EBUSY;
+ }
}
return 0;
@@ -280,7 +389,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
{
struct videobuf_dma_contig_memory *mem;
struct videobuf_mapping *map;
- unsigned int first;
+ unsigned int first, plane;
int retval;
unsigned long size, offset = vma->vm_pgoff << PAGE_SHIFT;
@@ -293,9 +402,16 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
if (!q->bufs[first])
continue;
- if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+ if (V4L2_MEMORY_MMAP != q->bufs[first]->memory &&
+ V4L2_MEMORY_MULTI_MMAP != q->bufs[first]->memory)
continue;
- if (q->bufs[first]->boff == offset)
+
+ for (plane = 0; plane < q->bufs[first]->num_planes; ++plane) {
+ if (q->bufs[first]->planes[plane].boff == offset)
+ break;
+ }
+
+ if (q->bufs[first]->num_planes != plane)
break;
}
if (VIDEO_MAX_FRAME == first) {
@@ -309,18 +425,19 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
if (!map)
return -ENOMEM;
- q->bufs[first]->map = map;
+ q->bufs[first]->planes[plane].map = map;
map->start = vma->vm_start;
map->end = vma->vm_end;
map->q = q;
- q->bufs[first]->baddr = vma->vm_start;
+ q->bufs[first]->planes[plane].baddr = vma->vm_start;
mem = q->bufs[first]->priv;
BUG_ON(!mem);
+ mem += plane;
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
- mem->size = PAGE_ALIGN(q->bufs[first]->bsize);
+ mem->size = PAGE_ALIGN(q->bufs[first]->planes[plane].bsize);
mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
&mem->dma_handle, GFP_KERNEL);
if (!mem->vaddr) {
@@ -351,13 +468,22 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
vma->vm_flags |= VM_DONTEXPAND;
vma->vm_private_data = map;
- dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
+ dev_dbg(q->dev,
+ "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d plane %u\n",
map, q, vma->vm_start, vma->vm_end,
- (long int) q->bufs[first]->bsize,
- vma->vm_pgoff, first);
+ (long int) q->bufs[first]->planes[plane].bsize,
+ vma->vm_pgoff, first, plane);
videobuf_vm_open(vma);
+ /* Mark vb as mapped after all planes are mapped */
+ for (plane = 0; plane < q->bufs[first]->num_planes; ++plane) {
+ if (0 == q->bufs[first]->planes[plane].map)
+ break;
+ }
+ if (q->bufs[first]->num_planes == plane)
+ q->bufs[first]->mapped = 1;
+
return 0;
error:
@@ -376,9 +502,10 @@ static int __videobuf_copy_to_user(struct videobuf_queue *q,
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
BUG_ON(!mem->vaddr);
+ /* TODO multiplanes */
/* copy to userspace */
- if (count > q->read_buf->size - q->read_off)
- count = q->read_buf->size - q->read_off;
+ if (count > q->read_buf->planes[0].size - q->read_off)
+ count = q->read_buf->planes[0].size - q->read_off;
vaddr = mem->vaddr;
@@ -398,13 +525,14 @@ static int __videobuf_copy_stream(struct videobuf_queue *q,
BUG_ON(!mem);
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+ /* TODO multiplanes */
if (vbihack) {
/* dirty, undocumented hack -- pass the frame counter
* within the last four bytes of each vbi data block.
* We need that one to maintain backward compatibility
* to all vbi decoding software out there ... */
fc = (unsigned int *)mem->vaddr;
- fc += (q->read_buf->size >> 2) - 1;
+ fc += (q->read_buf->planes[0].size >> 2) - 1;
*fc = q->read_buf->field_count >> 1;
dev_dbg(q->dev, "vbihack: %d\n", *fc);
}
@@ -428,6 +556,7 @@ static struct videobuf_qtype_ops qops = {
.video_copy_to_user = __videobuf_copy_to_user,
.copy_stream = __videobuf_copy_stream,
.vmalloc = __videobuf_to_vmalloc,
+ .plane_vmalloc = __plane_to_vmalloc,
};
void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
@@ -455,34 +584,54 @@ dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
}
EXPORT_SYMBOL_GPL(videobuf_to_dma_contig);
-void videobuf_dma_contig_free(struct videobuf_queue *q,
- struct videobuf_buffer *buf)
+dma_addr_t videobuf_plane_to_dma_contig(struct videobuf_buffer *buf,
+ unsigned int plane)
{
struct videobuf_dma_contig_memory *mem = buf->priv;
+ BUG_ON(!mem);
+
+ if (plane >= buf->num_planes)
+ return 0;
+
+ mem += plane;
+ MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+ return mem->dma_handle;
+}
+EXPORT_SYMBOL_GPL(videobuf_plane_to_dma_contig);
+
+void videobuf_dma_contig_free(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct videobuf_dma_contig_memory *mem = vb->priv;
+ unsigned int i ;
+
/* mmapped memory can't be freed here, otherwise mmapped region
would be released, while still needed. In this case, the memory
release should happen inside videobuf_vm_close().
So, it should free memory only if the memory were allocated for
read() operation.
*/
- if (buf->memory != V4L2_MEMORY_USERPTR)
- return;
-
- if (!mem)
+ if (vb->memory != V4L2_MEMORY_USERPTR
+ && vb->memory != V4L2_MEMORY_MULTI_USERPTR)
return;
- MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
-
- /* handle user space pointer case */
- if (buf->baddr) {
- videobuf_dma_contig_user_put(mem);
- return;
+ BUG_ON(!mem);
+ BUG_ON(!vb->planes);
+
+ for (i = 0; i < vb->num_planes; ++i) {
+ MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+ if (vb->planes[i].baddr) {
+ videobuf_dma_contig_user_put(mem);
+ } else {
+ /* read() method */
+ dma_free_coherent(q->dev, mem->size,
+ mem->vaddr, mem->dma_handle);
+ mem->vaddr = NULL;
+ }
+ ++mem;
}
-
- /* read() method */
- dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
- mem->vaddr = NULL;
}
EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 136e093..64ca194 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -8,6 +8,8 @@
*
* (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
*
+ * Adapted for multi-plane buffer support by Pawel Osciak <p.osciak@samsung.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2
@@ -62,6 +64,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
struct videobuf_mapping *map = vma->vm_private_data;
struct videobuf_queue *q = map->q;
int i;
+ unsigned int j;
dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
map->count, vma->vm_start, vma->vm_end);
@@ -81,7 +84,12 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
if (NULL == q->bufs[i])
continue;
- if (q->bufs[i]->map != map)
+ for (j = 0; j < q->bufs[i]->num_planes; ++j)
+ if (q->bufs[i]->planes[j].map == map)
+ break;
+
+ if (q->bufs[i]->num_planes == j)
+ /* Not found yet */
continue;
mem = q->bufs[i]->priv;
@@ -92,6 +100,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
in order to do memory unmap.
*/
+ /* Mem for j-th plane in the array of
+ * per-plane privs */
+ mem += j;
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
/* vfree is not atomic - can't be
@@ -104,8 +115,9 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
mem->vmalloc = NULL;
}
- q->bufs[i]->map = NULL;
- q->bufs[i]->baddr = 0;
+ q->bufs[i]->planes[j].map = NULL;
+ q->bufs[i]->planes[j].baddr = 0;
+ q->bufs[i]->mapped = 0;
}
kfree(map);
@@ -132,23 +144,43 @@ static const struct vm_operations_struct videobuf_vm_ops =
struct videobuf_dma_sg_memory
*/
-static void *__videobuf_alloc(size_t size)
+static void *__videobuf_alloc(size_t size, unsigned int num_planes)
{
struct videobuf_vmalloc_memory *mem;
struct videobuf_buffer *vb;
+ unsigned int i;
- vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+ /*vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);*/
+ vb = kzalloc(size, GFP_KERNEL);
if (!vb)
return vb;
- mem = vb->priv = ((char *)vb)+size;
- mem->magic=MAGIC_VMAL_MEM;
+ /* At least one plane of memory is always needed */
+ vb->planes = kzalloc(sizeof(struct videobuf_plane) * num_planes,
+ GFP_KERNEL);
+ if (!vb->planes)
+ goto free_vb;
+
+ mem = vb->priv = kzalloc(sizeof(*mem) * num_planes, GFP_KERNEL);
+ if (!vb->priv)
+ goto free_planes;
+
+ for (i = 0; i < num_planes; ++i) {
+ mem->magic=MAGIC_VMAL_MEM;
+ ++mem;
+ }
dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
__func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
mem,(long)sizeof(*mem));
return vb;
+
+free_planes:
+ kfree(vb->planes);
+free_vb:
+ kfree(vb);
+ return NULL;
}
static int __videobuf_iolock (struct videobuf_queue* q,
@@ -157,6 +189,7 @@ static int __videobuf_iolock (struct videobuf_queue* q,
{
struct videobuf_vmalloc_memory *mem = vb->priv;
int pages;
+ unsigned int i;
BUG_ON(!mem);
@@ -173,21 +206,17 @@ static int __videobuf_iolock (struct videobuf_queue* q,
}
break;
case V4L2_MEMORY_USERPTR:
- pages = PAGE_ALIGN(vb->size);
-
dprintk(1, "%s memory method USERPTR\n", __func__);
-
#if 1
- if (vb->baddr) {
+ if (vb->planes[0].baddr) {
printk(KERN_ERR "USERPTR is currently not supported\n");
return -EINVAL;
}
#endif
-
/* The only USERPTR currently supported is the one needed for
read() method.
*/
-
+ pages = PAGE_ALIGN(vb->planes[0].size);
mem->vmalloc = vmalloc_user(pages);
if (!mem->vmalloc) {
printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
@@ -216,6 +245,59 @@ static int __videobuf_iolock (struct videobuf_queue* q,
#endif
break;
+ case V4L2_MEMORY_MULTI_MMAP:
+ dprintk(1, "%s memory method MULTI_MMAP\n", __func__);
+ BUG_ON(NULL == vb->planes);
+
+ for (i = 0; i < vb->num_planes; ++i) {
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
+ if (!mem->vmalloc) {
+ printk(KERN_ERR
+ "memory is not alloced/mmapped.\n");
+ return -EINVAL;
+ }
+ ++mem;
+ }
+ break;
+ case V4L2_MEMORY_MULTI_USERPTR:
+ dprintk(1, "%s memory method MULTI_USERPTR\n", __func__);
+ BUG_ON(NULL == vb->planes);
+
+ for (i = 0; i < vb->num_planes; ++i) {
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
+
+ if (vb->planes[i].baddr) {
+ printk(KERN_ERR
+ "USERPTR is currently not supported\n");
+ return -EINVAL;
+ }
+ }
+
+ /* The only USERPTR currently supported is the one needed for
+ read() method.
+ */
+ for (i = 0; i < vb->num_planes; ++i) {
+ pages = PAGE_ALIGN(vb->planes[i].size);
+
+ mem->vmalloc = vmalloc_user(pages);
+ if (!mem->vmalloc) {
+ printk(KERN_ERR
+ "vmalloc for plane %d (%d pages) "
+ "failed\n", i, pages);
+ while (i > 0) {
+ --mem;
+ vfree(mem->vmalloc);
+ mem->vmalloc = NULL;
+ --i;
+ }
+ return -ENOMEM;
+ }
+
+ dprintk(1, "vmalloc is at addr %p (%d pages)\n",
+ mem->vmalloc, pages);
+ ++mem;
+ }
+ break;
case V4L2_MEMORY_OVERLAY:
default:
dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
@@ -236,12 +318,15 @@ static int __videobuf_sync(struct videobuf_queue *q,
static int __videobuf_mmap_free(struct videobuf_queue *q)
{
- unsigned int i;
+ unsigned int i, j;
dprintk(1, "%s\n", __func__);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (q->bufs[i]) {
- if (q->bufs[i]->map)
+ if (NULL == q->bufs[i])
+ continue;
+
+ for (j = 0; j < q->bufs[i]->num_planes; ++j) {
+ if (q->bufs[i]->planes[j].map)
return -EBUSY;
}
}
@@ -254,7 +339,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
{
struct videobuf_vmalloc_memory *mem;
struct videobuf_mapping *map;
- unsigned int first;
+ unsigned int first, plane;
int retval, pages;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
@@ -267,9 +352,16 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
if (NULL == q->bufs[first])
continue;
- if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+ if (V4L2_MEMORY_MMAP != q->bufs[first]->memory &&
+ V4L2_MEMORY_MULTI_MMAP != q->bufs[first]->memory)
continue;
- if (q->bufs[first]->boff == offset)
+
+ for (plane = 0; plane < q->bufs[first]->num_planes; ++plane) {
+ if (q->bufs[first]->planes[plane].boff == offset)
+ break;
+ }
+
+ if (q->bufs[first]->num_planes != plane)
break;
}
if (VIDEO_MAX_FRAME == first) {
@@ -283,15 +375,16 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
if (NULL == map)
return -ENOMEM;
- q->bufs[first]->map = map;
+ q->bufs[first]->planes[plane].map = map;
map->start = vma->vm_start;
map->end = vma->vm_end;
map->q = q;
- q->bufs[first]->baddr = vma->vm_start;
+ q->bufs[first]->planes[plane].baddr = vma->vm_start;
mem = q->bufs[first]->priv;
BUG_ON(!mem);
+ mem += plane;
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
@@ -315,13 +408,21 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
vma->vm_private_data = map;
- dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
- map, q, vma->vm_start, vma->vm_end,
- (long int) q->bufs[first]->bsize,
- vma->vm_pgoff, first);
+ dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx "
+ "buf %d plane %u\n", map, q, vma->vm_start, vma->vm_end,
+ (long int) q->bufs[first]->planes[plane].bsize,
+ vma->vm_pgoff, first, plane);
videobuf_vm_open(vma);
+ /* Mark vb as mapped after all planes are mapped */
+ for (plane = 0; plane < q->bufs[first]->num_planes; ++plane) {
+ if (0 == q->bufs[first]->planes[plane].map)
+ break;
+ }
+ if (q->bufs[first]->num_planes == plane)
+ q->bufs[first]->mapped = 1;
+
return 0;
error:
@@ -340,9 +441,10 @@ static int __videobuf_copy_to_user ( struct videobuf_queue *q,
BUG_ON (!mem->vmalloc);
+ /* TODO multiplanes */
/* copy to userspace */
- if (count > q->read_buf->size - q->read_off)
- count = q->read_buf->size - q->read_off;
+ if (count > q->read_buf->planes[0].size - q->read_off)
+ count = q->read_buf->planes[0].size - q->read_off;
if (copy_to_user(data, mem->vmalloc+q->read_off, count))
return -EFAULT;
@@ -359,13 +461,14 @@ static int __videobuf_copy_stream ( struct videobuf_queue *q,
BUG_ON (!mem);
MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+ /* TODO multiplanes */
if (vbihack) {
/* dirty, undocumented hack -- pass the frame counter
* within the last four bytes of each vbi data block.
* We need that one to maintain backward compatibility
* to all vbi decoding software out there ... */
fc = (unsigned int*)mem->vmalloc;
- fc += (q->read_buf->size>>2) -1;
+ fc += (q->read_buf->planes[0].size>>2) -1;
*fc = q->read_buf->field_count >> 1;
dprintk(1,"vbihack: %d\n",*fc);
}
@@ -417,9 +520,28 @@ void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
}
EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
+void *videobuf_plane_to_vmalloc(struct videobuf_buffer *buf, unsigned int plane)
+{
+ struct videobuf_vmalloc_memory *mem = buf->priv;
+ BUG_ON(!mem);
+
+ if (plane >= buf->num_planes) {
+ dprintk(1, "%s: invalid plane %d\n", __func__, plane);
+ return NULL;
+ }
+
+ mem += plane;
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
+ dprintk(1, "%s: plane %d, vaddr: %p\n", __func__, plane, mem->vmalloc);
+
+ return mem->vmalloc;
+}
+EXPORT_SYMBOL_GPL(videobuf_plane_to_vmalloc);
+
void videobuf_vmalloc_free (struct videobuf_buffer *buf)
{
struct videobuf_vmalloc_memory *mem = buf->priv;
+ unsigned int i;
/* mmapped memory can't be freed here, otherwise mmapped region
would be released, while still needed. In this case, the memory
@@ -427,18 +549,21 @@ void videobuf_vmalloc_free (struct videobuf_buffer *buf)
So, it should free memory only if the memory were allocated for
read() operation.
*/
- if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
+ if ((buf->memory != V4L2_MEMORY_USERPTR
+ && buf->memory != V4L2_MEMORY_MULTI_USERPTR)
+ || buf->planes[0].baddr)
return;
if (!mem)
return;
+ BUG_ON(!buf->planes);
- MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
-
- vfree(mem->vmalloc);
- mem->vmalloc = NULL;
-
- return;
+ for (i = 0; i < buf->num_planes; ++i) {
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
+ vfree(mem->vmalloc);
+ mem->vmalloc = NULL;
+ ++mem;
+ }
}
EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h
index 316fdcc..9b617d2 100644
--- a/include/media/videobuf-core.h
+++ b/include/media/videobuf-core.h
@@ -59,6 +59,18 @@ struct videobuf_mapping {
struct videobuf_queue *q;
};
+struct videobuf_plane {
+ u32 magic;
+ unsigned long size;
+ size_t bsize;
+ size_t boff;
+ unsigned int bytesperline;
+ /* For MULTI_USERPTR, userspace address */
+ unsigned long baddr;
+
+ struct videobuf_mapping *map;
+};
+
enum videobuf_state {
VIDEOBUF_NEEDS_INIT = 0,
VIDEOBUF_PREPARED = 1,
@@ -76,13 +88,14 @@ struct videobuf_buffer {
/* info about the buffer */
unsigned int width;
unsigned int height;
- unsigned int bytesperline; /* use only if != 0 */
- unsigned long size;
unsigned int input;
enum v4l2_field field;
enum videobuf_state state;
struct list_head stream; /* QBUF/DQBUF list */
+ unsigned int num_planes;
+ struct videobuf_plane *planes;
+
/* touched by irq handler */
struct list_head queue;
wait_queue_head_t done;
@@ -92,26 +105,19 @@ struct videobuf_buffer {
/* Memory type */
enum v4l2_memory memory;
- /* buffer size */
- size_t bsize;
-
- /* buffer offset (mmap + overlay) */
- size_t boff;
-
- /* buffer addr (userland ptr!) */
- unsigned long baddr;
-
- /* for mmap'ed buffers */
- struct videobuf_mapping *map;
+ /* True if all planes are mapped (for MMAP only) */
+ int mapped;
- /* Private pointer to allow specific methods to store their data */
- int privsize;
+ /* Array of per-plane pointers to allow specific methods to store
+ * their data */
void *priv;
};
struct videobuf_queue_ops {
- int (*buf_setup)(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size);
+ int (*buf_negotiate)(struct videobuf_queue *q, unsigned int *buf_count,
+ unsigned int *plane_count);
+ int (*buf_setup_plane)(struct videobuf_queue *q, unsigned int plane,
+ unsigned int *plane_size);
int (*buf_prepare)(struct videobuf_queue *q,
struct videobuf_buffer *vb,
enum v4l2_field field);
@@ -127,8 +133,10 @@ struct videobuf_queue_ops {
struct videobuf_qtype_ops {
u32 magic;
- void *(*alloc) (size_t size);
+ void *(*alloc) (size_t size, unsigned int num_planes);
void *(*vmalloc) (struct videobuf_buffer *buf);
+ void *(*plane_vmalloc) (struct videobuf_buffer *buf,
+ unsigned int plane);
int (*iolock) (struct videobuf_queue* q,
struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf);
@@ -188,11 +196,14 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr);
int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf);
-void *videobuf_alloc(struct videobuf_queue* q);
+void *videobuf_alloc(struct videobuf_queue* q, unsigned int num_planes);
/* Used on videobuf-dvb */
void *videobuf_queue_to_vmalloc (struct videobuf_queue* q,
struct videobuf_buffer *buf);
+void *videobuf_queue_plane_to_vmalloc(struct videobuf_queue *q,
+ struct videobuf_buffer *buf,
+ unsigned int plane);
void videobuf_queue_core_init(struct videobuf_queue *q,
const struct videobuf_queue_ops *ops,
@@ -235,12 +246,10 @@ unsigned int videobuf_poll_stream(struct file *file,
struct videobuf_queue *q,
poll_table *wait);
-int videobuf_mmap_setup(struct videobuf_queue *q,
- unsigned int bcount, unsigned int bsize,
- enum v4l2_memory memory);
-int __videobuf_mmap_setup(struct videobuf_queue *q,
- unsigned int bcount, unsigned int bsize,
- enum v4l2_memory memory);
+int videobuf_mmap_setup(struct videobuf_queue *q, unsigned int bcount,
+ unsigned int pcount, enum v4l2_memory memory);
+int __videobuf_mmap_setup(struct videobuf_queue *q, unsigned int bcount,
+ unsigned int pcount, enum v4l2_memory memory);
int videobuf_mmap_free(struct videobuf_queue *q);
int videobuf_mmap_mapper(struct videobuf_queue *q,
struct vm_area_struct *vma);
diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h
index ebaa9bc..9dcda78 100644
--- a/include/media/videobuf-dma-contig.h
+++ b/include/media/videobuf-dma-contig.h
@@ -26,6 +26,9 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
void *priv);
dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
+dma_addr_t videobuf_plane_to_dma_contig(struct videobuf_buffer *buf,
+ unsigned int plane);
+
void videobuf_dma_contig_free(struct videobuf_queue *q,
struct videobuf_buffer *buf);
diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h
index 4b419a2..740aedd 100644
--- a/include/media/videobuf-vmalloc.h
+++ b/include/media/videobuf-vmalloc.h
@@ -39,6 +39,8 @@ void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
void *priv);
void *videobuf_to_vmalloc (struct videobuf_buffer *buf);
+void *videobuf_plane_to_vmalloc(struct videobuf_buffer *buf,
+ unsigned int plane);
void videobuf_vmalloc_free (struct videobuf_buffer *buf);
--
1.7.0.31.g1df487
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH v1 4/4] v4l: vivi: add 2- and 3-planar YCbCr422
2010-02-22 16:10 [PATCH/RFC v1 0/4] Multi-plane video buffer support for V4L2 API and videobuf Pawel Osciak
` (2 preceding siblings ...)
2010-02-22 16:10 ` [PATCH v1 3/4] v4l: videobuf: Add support for multi-plane buffers Pawel Osciak
@ 2010-02-22 16:10 ` Pawel Osciak
2010-02-22 16:10 ` [EXAMPLE v1] Test application for multiplane vivi driver Pawel Osciak
2010-02-22 17:49 ` [PATCH/RFC v1 0/4] Multi-plane video buffer support for V4L2 API and videobuf Mauro Carvalho Chehab
5 siblings, 0 replies; 9+ messages in thread
From: Pawel Osciak @ 2010-02-22 16:10 UTC (permalink / raw)
To: linux-media; +Cc: p.osciak, m.szyprowski, kyungmin.park, hverkuil, m-karicheri2
Add example 2- and 3- planar YCbCr422 formats for multi-plane
format testing.
Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/media/video/vivi.c | 179 +++++++++++++++++++++++++++++++++++---------
include/linux/videodev2.h | 3 +
2 files changed, 147 insertions(+), 35 deletions(-)
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 37632a0..bc1ec0d 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -132,6 +132,9 @@ struct vivi_fmt {
char *name;
u32 fourcc; /* v4l2 format id */
int depth;
+ unsigned int num_planes;
+ unsigned int plane_w_shr;
+ unsigned int plane_h_shr;
};
static struct vivi_fmt formats[] = {
@@ -139,31 +142,53 @@ static struct vivi_fmt formats[] = {
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
+ .num_planes = 1,
},
{
.name = "4:2:2, packed, UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
+ .num_planes = 1,
},
{
.name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
.depth = 16,
+ .num_planes = 1,
},
{
.name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
.depth = 16,
+ .num_planes = 1,
},
{
.name = "RGB555 (LE)",
.fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
.depth = 16,
+ .num_planes = 1,
},
{
.name = "RGB555 (BE)",
.fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
.depth = 16,
+ .num_planes = 1,
+ },
+ {
+ .name = "YUV 4:2:2, 3-planar",
+ .fourcc = V4L2_PIX_FMT_YUV422PM,
+ .depth = 16,
+ .num_planes = 3,
+ .plane_w_shr = 1,
+ .plane_h_shr = 0,
+ },
+ {
+ .name = "YUV 4:2:2, 2-planar",
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .depth = 16,
+ .num_planes = 2,
+ .plane_w_shr = 1,
+ .plane_h_shr = 0,
},
};
@@ -361,6 +386,8 @@ static void precalculate_bars(struct vivi_fh *fh)
switch (fh->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUV422PM:
+ case V4L2_PIX_FMT_NV16M:
is_yuv = 1;
break;
case V4L2_PIX_FMT_RGB565:
@@ -410,6 +437,8 @@ static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
switch (fh->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YUV422PM:
+ case V4L2_PIX_FMT_NV16M:
switch (color) {
case 0:
case 2:
@@ -558,30 +587,58 @@ end:
static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
{
struct vivi_dev *dev = fh->dev;
- int h , pos = 0;
+ int i, x, h, curr_plane = 0, pos = 0;
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
- char *tmpbuf;
- void *vbuf = videobuf_to_vmalloc(&buf->vb);
+ char *tmpbuf, *p_tmpbuf;
+ char *vbuf[VIDEO_MAX_PLANES];
+
+ for (i = 0; i < fh->fmt->num_planes; ++i) {
+ vbuf[i] = videobuf_plane_to_vmalloc(&buf->vb, i);
+ if (!vbuf[i]) {
+ dprintk(dev, 1, "Failed acquiring vaddr for a plane\n");
+ return;
+ }
+ }
- if (!vbuf)
- return;
+ if (fh->fmt->num_planes > 1) {
+ tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+ if (!tmpbuf)
+ return;
+
+ for (h = 0; h < hmax; h++) {
+ gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+ dev->timestr);
+ p_tmpbuf = tmpbuf;
+
+ for (x = 0; x < wmax; ++x) {
+ *(vbuf[0]++) = *p_tmpbuf++;
+ *(vbuf[curr_plane + 1]++) = *p_tmpbuf++;
+ if (V4L2_PIX_FMT_YUV422PM == fh->fmt->fourcc)
+ curr_plane = !curr_plane;
+ }
+ }
- tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
- if (!tmpbuf)
- return;
+ dev->mv_count++;
- for (h = 0; h < hmax; h++) {
- gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
- dev->timestr);
- memcpy(vbuf + pos, tmpbuf, wmax * 2);
- pos += wmax*2;
- }
+ kfree(tmpbuf);
+ } else {
+ tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
+ if (!tmpbuf)
+ return;
+
+ for (h = 0; h < hmax; h++) {
+ gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+ dev->timestr);
+ memcpy(vbuf[0] + pos, tmpbuf, wmax * 2);
+ pos += wmax*2;
+ }
- dev->mv_count++;
+ dev->mv_count++;
- kfree(tmpbuf);
+ kfree(tmpbuf);
+ }
/* Updates stream time */
@@ -708,8 +765,6 @@ static int vivi_start_thread(struct vivi_fh *fh)
dma_q->frame = 0;
dma_q->ini_jiffies = jiffies;
- dprintk(dev, 1, "%s\n", __func__);
-
dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
if (IS_ERR(dma_q->kthread)) {
@@ -719,7 +774,6 @@ static int vivi_start_thread(struct vivi_fh *fh)
/* Wakes thread */
wake_up_interruptible(&dma_q->wq);
- dprintk(dev, 1, "returning from %s\n", __func__);
return 0;
}
@@ -738,22 +792,66 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
/* ------------------------------------------------------------------
Videobuf operations
------------------------------------------------------------------*/
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+static unsigned long get_plane_size(struct vivi_fh *fh, unsigned int plane)
{
- struct vivi_fh *fh = vq->priv_data;
- struct vivi_dev *dev = fh->dev;
+ unsigned long plane_size = 0;
+
+ if (plane >= fh->fmt->num_planes)
+ return 0;
+
+ if (1 == fh->fmt->num_planes) {
+ plane_size = fh->width * fh->height * 2;
+ } else {
+ if (0 == plane) {
+ plane_size = fh->width * fh->height;
+ } else {
+ plane_size = (fh->width >> 1) * fh->height;
+ if (2 == fh->fmt->num_planes)
+ plane_size *= 2;
+ }
+ }
+
+ return plane_size;
+}
+static int buffer_negotiate(struct videobuf_queue *vq, unsigned int *buf_count,
+ unsigned int *plane_count)
+{
+ struct vivi_fh *fh = vq->priv_data;
+ struct vivi_dev *dev = fh->dev;
+ unsigned int buf_size = 0;
+ unsigned int i;
+
+ *plane_count = fh->fmt->num_planes;
+
+ if (0 == *buf_count)
+ *buf_count = 32;
+
+ for (i = 0; i < fh->fmt->num_planes; ++i)
+ buf_size += get_plane_size(fh, i);
+
+ while (buf_size * *buf_count > vid_limit * 1024 * 1024)
+ (*buf_count)--;
+
+ dprintk(dev, 1, "%s, buffer count=%d, plane count=%d\n",
+ __func__, *buf_count, *plane_count);
- *size = fh->width*fh->height*2;
+ return 0;
+}
- if (0 == *count)
- *count = 32;
+static int buffer_setup_plane(struct videobuf_queue *vq, unsigned int plane,
+ unsigned int *plane_size)
+{
+ struct vivi_fh *fh = vq->priv_data;
+ struct vivi_dev *dev = fh->dev;
- while (*size * *count > vid_limit * 1024 * 1024)
- (*count)--;
+ if (plane >= fh->fmt->num_planes) {
+ dprintk(dev, 1, "%s, invalid plane=%d\n", __func__, plane);
+ return -EINVAL;
+ }
- dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
- *count, *size);
+ *plane_size = get_plane_size(fh, plane);
+ dprintk(dev, 1, "%s, plane=%d, size=%d\n",
+ __func__, plane, *plane_size);
return 0;
}
@@ -783,6 +881,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct vivi_dev *dev = fh->dev;
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
int rc;
+ unsigned int i;
dprintk(dev, 1, "%s, field=%d\n", __func__, field);
@@ -792,9 +891,17 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
fh->height < 32 || fh->height > norm_maxh())
return -EINVAL;
- buf->vb.size = fh->width*fh->height*2;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
+ for (i = 0; i < fh->fmt->num_planes; ++i) {
+ buf->vb.planes[i].size = get_plane_size(fh, i);
+
+ if (0 != buf->vb.planes[i].baddr
+ && buf->vb.planes[i].bsize < buf->vb.planes[i].size) {
+ dprintk(dev, 1, "%s, invalid plane %u size: (%d<%lu)\n",
+ __func__, i, buf->vb.planes[i].bsize,
+ buf->vb.planes[i].size);
+ return -EINVAL;
+ }
+ }
/* These properties only change when queue is idle, see s_fmt */
buf->fmt = fh->fmt;
@@ -846,7 +953,8 @@ static void buffer_release(struct videobuf_queue *vq,
}
static struct videobuf_queue_ops vivi_video_qops = {
- .buf_setup = buffer_setup,
+ .buf_negotiate = buffer_negotiate,
+ .buf_setup_plane = buffer_setup_plane,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
@@ -948,8 +1056,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
{
struct vivi_fh *fh = priv;
struct videobuf_queue *q = &fh->vb_vidq;
+ int ret;
- int ret = vidioc_try_fmt_vid_cap(file, fh, f);
+ ret = vidioc_try_fmt_vid_cap(file, fh, f);
if (ret < 0)
return ret;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index bf3f33d..fbce9d7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -314,6 +314,8 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */
+#define V4L2_PIX_FMT_YUV422PM v4l2_fourcc('4', '2', '2', 'M') /* 16 YUV422 multiplane */
+
#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */
#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P') /* 12 YUV 4:1:1 */
#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4') /* 16 xxxxyyyy uuuuvvvv */
@@ -329,6 +331,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */
+#define V4L2_PIX_FMT_NV16M v4l2_fourcc('N', 'M', '1', '6') /* 16 Y/CbCr multiplane 4:2:2 */
#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */
/* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */
--
1.7.0.31.g1df487
^ permalink raw reply related [flat|nested] 9+ messages in thread* [EXAMPLE v1] Test application for multiplane vivi driver.
2010-02-22 16:10 [PATCH/RFC v1 0/4] Multi-plane video buffer support for V4L2 API and videobuf Pawel Osciak
` (3 preceding siblings ...)
2010-02-22 16:10 ` [PATCH v1 4/4] v4l: vivi: add 2- and 3-planar YCbCr422 Pawel Osciak
@ 2010-02-22 16:10 ` Pawel Osciak
2010-02-22 17:49 ` [PATCH/RFC v1 0/4] Multi-plane video buffer support for V4L2 API and videobuf Mauro Carvalho Chehab
5 siblings, 0 replies; 9+ messages in thread
From: Pawel Osciak @ 2010-02-22 16:10 UTC (permalink / raw)
To: linux-media; +Cc: p.osciak, m.szyprowski, kyungmin.park, hverkuil, m-karicheri2
This is an example application for testing muliplane buffer V4L2 extensions
with the vivi driver.
---
--- /dev/null 2010-02-15 07:42:03.265396000 +0100
+++ vivi-mplane.c 2010-02-22 16:58:19.925762651 +0100
@@ -0,0 +1,582 @@
+/*
+ * Pawel Osciak, <p.osciak@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <stdint.h>
+
+#include <linux/fb.h>
+#include <linux/videodev2.h>
+
+#define VIDEO_DEV_NAME "/dev/video"
+#define FB_DEV_NAME "/dev/fb0"
+
+#define NUM_DST_BUFS 4
+
+enum io_method {
+ IO_METHOD_MMAP,
+ IO_METHOD_USERPTR,
+};
+
+#define perror_exit(cond, func)\
+ if (cond) {\
+ fprintf(stderr, "%s:%d: ", __func__, __LINE__);\
+ perror(func);\
+ exit(EXIT_FAILURE);\
+ }
+
+#define error_exit(cond, msg, ...)\
+ if (cond) {\
+ fprintf(stderr, "%s:%d: " msg "\n",\
+ __func__, __LINE__, ##__VA_ARGS__);\
+ exit(EXIT_FAILURE);\
+ }
+
+#define perror_ret(cond, func)\
+ if (cond) {\
+ fprintf(stderr, "%s:%d: ", __func__, __LINE__);\
+ perror(func);\
+ return ret;\
+ }
+
+#define memzero(x)\
+ memset(&(x), 0, sizeof (x));
+
+#define error(msg) fprintf(stderr, "%s:%d: " msg "\n", __func__, __LINE__);
+
+#define _DEBUG
+#ifdef _DEBUG
+#define debug(msg, ...)\
+ fprintf(stderr, "%s: " msg, __func__, ##__VA_ARGS__);
+#else
+#define debug(msg, ...)
+#endif
+
+#define PAGE_ALIGN(addr) (((addr) + page_size - 1) & ~(page_size -1))
+
+enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+enum format {
+ FMT_422,
+ FMT_565,
+ FMT_422P,
+};
+
+struct buffer {
+ char *addr[VIDEO_MAX_PLANES];
+ unsigned long size[VIDEO_MAX_PLANES];
+ unsigned int num_planes;
+ unsigned int index;
+ enum format fmt;
+ unsigned int width;
+ unsigned int height;
+ enum v4l2_buf_type type;
+};
+
+static int vid_fd, fb_fd;
+static void *fb_addr, *fb_alloc_ptr;
+static int width = 200, height = 200;
+static off_t fb_line_w, fb_buf_w, fb_size, fb_pix_dist;
+static struct fb_var_screeninfo fbinfo;
+static int vid_node;
+static int framesize;
+static enum format format;
+static int num_planes;
+static long page_size;
+enum io_method io_method;
+enum v4l2_memory memory;
+
+static void set_fmt(enum format format)
+{
+ struct v4l2_format fmt;
+ int ret;
+
+ memzero(fmt);
+ switch (format) {
+ case FMT_422:
+ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ fb_buf_w = 2;
+ break;
+ case FMT_565:
+ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565X;
+ fb_buf_w = 2;
+ break;
+ case FMT_422P:
+ if (2 == num_planes)
+ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV16M;
+ else if (3 == num_planes)
+ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422PM;
+ else
+ error_exit(1, "Invalid format/planes combination\n");
+ fb_buf_w = 1;
+ break;
+ default:
+ error_exit(1, "Invalid params\n");
+ break;
+ }
+
+ debug("Selected fourcc: %d\n", fmt.fmt.pix.pixelformat);
+
+ /* Set format for capture */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = width;
+ fmt.fmt.pix.height = height;
+ fmt.fmt.pix.field = V4L2_FIELD_ANY;
+
+ ret = ioctl(vid_fd, VIDIOC_S_FMT, &fmt);
+ perror_exit(ret != 0, "ioctl");
+
+ width = fmt.fmt.pix.width;
+ height = fmt.fmt.pix.height;
+ fb_buf_w *= width;
+ framesize = PAGE_ALIGN(fmt.fmt.pix.sizeimage);
+ debug("Framesize: %d\n", framesize);
+
+ switch (io_method) {
+ case IO_METHOD_MMAP:
+ if (num_planes == 1)
+ memory = V4L2_MEMORY_MMAP;
+ else
+ memory = V4L2_MEMORY_MULTI_MMAP;
+ break;
+ case IO_METHOD_USERPTR:
+ if (num_planes == 1)
+ memory = V4L2_MEMORY_USERPTR;
+ else
+ memory = V4L2_MEMORY_MULTI_USERPTR;
+ break;
+ default:
+ error_exit(1, "Invalid io method\n");
+ }
+}
+
+
+static void verify_caps(void)
+{
+ struct v4l2_capability cap;
+ int ret;
+
+ memzero(cap);
+ ret = ioctl(vid_fd, VIDIOC_QUERYCAP, &cap);
+ perror_exit(ret != 0, "ioctl");
+
+ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
+ error_exit(1, "Device does not support capture\n");
+
+ if (!(cap.capabilities & V4L2_CAP_STREAMING))
+ error_exit(1, "Device does not support streaming\n");
+}
+
+static void init_video_dev(void)
+{
+ char devname[64];
+
+ snprintf(devname, 64, "%s%d", VIDEO_DEV_NAME, vid_node);
+ vid_fd = open(devname, O_RDWR | O_NONBLOCK, 0);
+ perror_exit(vid_fd < 0, "open");
+
+ verify_caps();
+}
+
+static void init_fb(void)
+{
+ int ret;
+
+ fb_fd = open(FB_DEV_NAME, O_RDWR);
+ perror_exit(fb_fd < 0, "open");
+
+ ret = ioctl(fb_fd, FBIOGET_VSCREENINFO, &fbinfo);
+ perror_exit(ret != 0, "ioctl");
+ debug("fbinfo: xres: %d, xres_virt: %d, yres: %d, yres_virt: %d\n",
+ fbinfo.xres, fbinfo.xres_virtual,
+ fbinfo.yres, fbinfo.yres_virtual);
+
+ fb_pix_dist = fbinfo.bits_per_pixel >> 3;
+ fb_line_w = fbinfo.xres_virtual * fb_pix_dist;
+ debug("fb_buf_w: %ld, fb_line_w: %ld\n", fb_buf_w, fb_line_w);
+ fb_size = fb_line_w * fbinfo.yres_virtual;
+
+ fb_addr = fb_alloc_ptr = mmap(0, fb_size, PROT_WRITE | PROT_READ,
+ MAP_SHARED, fb_fd, 0);
+ perror_exit(fb_addr == MAP_FAILED, "mmap");
+}
+
+static void parse_args(int argc, char *argv[])
+{
+ if (argc != 5) {
+ fprintf(stderr, "Usage: "
+ "%s video_node io_method format num_planes \n"
+ "io methods: mmap, userptr \n"
+ "formats: 0: 422, 1: 565, 2: 422P\n",
+ argv[0]);
+ error_exit(1, "Invalid number of arguments\n");
+ }
+
+ vid_node = atoi(argv[1]);
+ io_method = atoi(argv[2]);
+ format = atoi(argv[3]);
+ num_planes = atoi(argv[4]);
+
+ debug("vid_node: %d, format: %d, num_planes: %d\n",
+ vid_node, format, num_planes);
+}
+
+static void alloc_buffer(struct buffer *buf)
+{
+ buf->addr[0] = fb_alloc_ptr;
+
+ switch(num_planes) {
+ case 1:
+ buf->size[0] = framesize;
+ break;
+ case 2:
+ if (FMT_422 != format)
+ error_exit(1, "Unsupported format for this number "
+ "of planes\n");
+ buf->size[0] = PAGE_ALIGN(width * height);
+ buf->addr[1] = buf->addr[0] + buf->size[0];
+ buf->size[1] = PAGE_ALIGN(width * height);
+ break;
+ case 3:
+ if (FMT_422 != format)
+ error_exit(1, "Unsupported format for this number "
+ "of planes\n");
+ buf->size[0] = PAGE_ALIGN(width * height);
+ buf->addr[1] = buf->addr[0] + buf->size[0];
+ buf->size[1] = PAGE_ALIGN(width * height / 2);
+ buf->addr[2] = buf->addr[1] + buf->size[1];
+ buf->size[2] = buf->size[1];
+ break;
+ default:
+ error_exit(1, "Unsupported number of planes\n");
+ break;
+ }
+
+ buf->fmt = format;
+ buf->width = width;
+ buf->height = height;
+ buf->num_planes = num_planes;
+ buf->type = type;
+
+ fb_alloc_ptr = buf->addr[num_planes - 1] + buf->size[num_planes - 1];
+ if (fb_alloc_ptr > fb_addr + fb_size)
+ error_exit(1, "Out of fb memory\n");
+}
+
+static void request_buffers(unsigned int *num_bufs, enum v4l2_buf_type type)
+{
+ struct v4l2_requestbuffers reqbuf;
+ int ret;
+
+ memzero(reqbuf);
+
+ reqbuf.memory = memory;
+
+ reqbuf.count = *num_bufs;
+ reqbuf.type = type;
+ ret = ioctl(vid_fd, VIDIOC_REQBUFS, &reqbuf);
+ perror_exit(ret != 0, "ioctl");
+ *num_bufs = reqbuf.count;
+}
+
+static void display(struct buffer *buf,
+ unsigned int start_x, unsigned int start_y)
+{
+ char *p_buf, *p_fb;
+ int curr_y;
+ unsigned int i, pl_h, pl_w;
+
+ p_fb = fb_addr + start_y * fb_line_w + start_x;// * fb_pix_dist;
+ p_buf = buf->addr[0];
+
+ debug("fb_buf_w: %ld, fb_line_w: %ld\n", fb_buf_w, fb_line_w);
+
+ if (1 == buf->num_planes) {
+ for (curr_y = 0; curr_y < buf->height; ++curr_y) {
+ memcpy(p_fb, p_buf, fb_buf_w);
+ p_fb += fb_line_w;
+ p_buf += fb_buf_w;
+ }
+ } else {
+ /* 0th plane */
+ for (curr_y = 0; curr_y < buf->height; ++curr_y) {
+ memcpy(p_fb, p_buf, buf->width);
+ p_fb += fb_line_w;
+ p_buf += buf->width;
+ }
+
+ if (buf->num_planes == 2) {
+ pl_w = buf->width;
+ pl_h = buf->height;
+ } else if (buf->num_planes == 3) {
+ pl_w = buf->width / 2;
+ pl_h = buf->height;
+ } else {
+ debug("Cannot display more than 3 planes\n");
+ return;
+ }
+
+ for (i = 1; i < buf->num_planes; ++i) {
+ p_buf = buf->addr[i];
+ for (curr_y = 0; curr_y < pl_h; ++curr_y) {
+ memcpy(p_fb, p_buf, pl_w);
+ p_fb += fb_line_w;
+ p_buf += pl_w;
+ }
+ }
+ }
+}
+
+static void setup_userptr(struct buffer *buffers, int num_buffers)
+{
+ int i;
+
+ for (i = 0; i < num_buffers; ++i) {
+ alloc_buffer(&buffers[i]);
+
+ buffers[i].index = i;
+ buffers[i].type = type;
+ buffers[i].num_planes = num_planes;
+ buffers[i].width = width;
+ buffers[i].height = height;
+ }
+}
+
+static void setup_mmap(struct buffer *buffers, int num_buffers)
+{
+ struct v4l2_buffer buf;
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ int ret;
+ int i, j;
+
+ for (i = 0; i < num_buffers; ++i) {
+ memzero(buf);
+
+ if (V4L2_MEMORY_MULTI_MMAP == memory) {
+ buf.memory = memory;
+ buf.m.planes = planes;
+ buf.length = num_planes;
+ }
+ buffers[i].index = buf.index = i;
+ buffers[i].type = buf.type = type;
+ buffers[i].num_planes = num_planes;
+ buffers[i].width = width;
+ buffers[i].height = height;
+
+ ret = ioctl(vid_fd, VIDIOC_QUERYBUF, &buf);
+ perror_exit(ret != 0, "ioctl");
+
+ if (V4L2_MEMORY_MULTI_MMAP == memory) {
+ if (buf.length != num_planes)
+ error_exit(1, "Driver requires %d planes, "
+ "expected %d\n",
+ buf.length, num_planes);
+
+ for (j = 0; j < buf.length; ++j) {
+ buffers[i].size[j] = buf.m.planes[j].length;
+ buffers[i].addr[j] = mmap(NULL, buffers[i].size[j],
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, vid_fd,
+ buf.m.planes[j].m.offset);
+ perror_exit(MAP_FAILED == buffers[i].addr[j], "mmap");
+ }
+ } else if (V4L2_MEMORY_MMAP == memory) {
+ buffers[i].size[0] = buf.length;
+ buffers[i].addr[0] = mmap(NULL, buffers[i].size[0],
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, vid_fd,
+ buf.m.offset);
+ perror_exit(MAP_FAILED == buffers[i].addr[0], "mmap");
+ }
+
+ }
+}
+
+static int get_frame(void)
+{
+ struct v4l2_buffer v4l2_buf;
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+
+ memzero(v4l2_buf);
+
+ switch (io_method) {
+ case IO_METHOD_MMAP:
+ v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_buf.memory = memory;
+ if (V4L2_MEMORY_MULTI_MMAP == memory) {
+ v4l2_buf.m.planes = planes;
+ v4l2_buf.length = num_planes;
+ }
+
+ if (-1 == ioctl (vid_fd, VIDIOC_DQBUF, &v4l2_buf)) {
+ switch (errno) {
+ case EAGAIN:
+ return 0;
+ case EIO:
+ /* Could ignore EIO, see spec. */
+ /* fall through */
+ default:
+ perror_exit(1, "ioctl");
+ }
+ }
+ return v4l2_buf.index;
+
+ case IO_METHOD_USERPTR:
+ v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ v4l2_buf.memory = memory;
+ if (V4L2_MEMORY_MULTI_USERPTR == memory) {
+ v4l2_buf.m.planes = planes;
+ v4l2_buf.length = num_planes;
+ }
+
+ if (-1 == ioctl (vid_fd, VIDIOC_DQBUF, &v4l2_buf)) {
+ switch (errno) {
+ case EAGAIN:
+ return 0;
+ case EIO:
+ /* Could ignore EIO, see spec. */
+ /* fall through */
+ default:
+ perror_exit(1, "ioctl");
+ }
+ }
+ return v4l2_buf.index;
+ default:
+ return -1;
+ }
+}
+
+void put_frame(struct buffer *buf)
+{
+ struct v4l2_buffer v4l2_buf;
+ struct v4l2_plane planes[VIDEO_MAX_PLANES];
+ int ret, i;
+
+ memzero(v4l2_buf);
+
+ switch (io_method) {
+ case IO_METHOD_MMAP:
+ v4l2_buf.type = buf->type;
+ v4l2_buf.memory = memory;
+ v4l2_buf.index = buf->index;
+
+ if (V4L2_MEMORY_MULTI_MMAP == memory) {
+ v4l2_buf.m.planes = planes;
+ v4l2_buf.length = num_planes;
+ }
+
+ ret = ioctl(vid_fd, VIDIOC_QBUF, &v4l2_buf);
+ perror_exit(ret != 0, "ioctl");
+ break;
+
+ case IO_METHOD_USERPTR:
+ v4l2_buf.type = buf->type;
+ v4l2_buf.memory = memory;
+ v4l2_buf.index = buf->index;
+
+ if (V4L2_MEMORY_USERPTR == memory) {
+ v4l2_buf.m.userptr = (unsigned long)buf->addr[0];
+ v4l2_buf.length = buf->size[0];
+ } else if (V4L2_MEMORY_MULTI_USERPTR == memory) {
+ v4l2_buf.m.planes = planes;
+ v4l2_buf.length = num_planes;
+
+ for (i = 0; i < num_planes; ++i) {
+ v4l2_buf.m.planes[i].m.userptr =
+ (unsigned long)buf->addr[i];
+ v4l2_buf.m.planes[i].length = buf->size[i];
+ }
+ }
+
+ ret = ioctl(vid_fd, VIDIOC_QBUF, &v4l2_buf);
+ perror_exit(ret != 0, "ioctl");
+ break;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct buffer dst_buffers[VIDEO_MAX_FRAME];
+ int ret = 0;
+ unsigned int num_dst_buffers = NUM_DST_BUFS;
+ unsigned int count = 10;
+ unsigned int i;
+ int index;
+
+ parse_args(argc, argv);
+
+ page_size = sysconf(_SC_PAGESIZE);
+
+ init_fb();
+
+ init_video_dev();
+ set_fmt(format);
+
+ request_buffers(&num_dst_buffers, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ if (IO_METHOD_MMAP == io_method) {
+ setup_mmap(dst_buffers, num_dst_buffers);
+ } else if (IO_METHOD_USERPTR == io_method) {
+ setup_userptr(dst_buffers, num_dst_buffers);
+ }
+
+ for (i = 0; i < num_dst_buffers; ++i)
+ put_frame(&dst_buffers[i]);
+
+ ret = ioctl(vid_fd, VIDIOC_STREAMON, &type);
+ perror_exit(0 != ret, "ioctl");
+
+ while (count-- > 0) {
+ for (;;) {
+ fd_set fds;
+ struct timeval tv;
+ int r;
+
+ FD_ZERO(&fds);
+ FD_SET(vid_fd, &fds);
+
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+
+ r = select(vid_fd + 1, &fds, NULL, NULL, &tv);
+
+ if (-1 == r) {
+ if (EINTR == errno)
+ continue;
+ else
+ perror_exit(1, "select");
+ }
+
+ if (0 == r) {
+ error_exit(1, "timeout!\n");
+ }
+
+ break;
+ }
+
+ index = get_frame();
+ if (index < 0 || index >= num_dst_buffers)
+ error_exit(1, "Invalid index %d\n", index);
+ display(&dst_buffers[index], 0, 0);
+ put_frame(&dst_buffers[index]);
+ }
+ if (ret)
+ return ret;
+
+ return 0;
+}
^ permalink raw reply [flat|nested] 9+ messages in thread