@@ -764,6 +764,10 @@ public:
{
return v4l_queue_reqbufs(fd->g_v4l_fd(), this, count, flags);
}
+ int delete_bufs(cv4l_fd *fd, unsigned index = 0, unsigned count = 0)
+ {
+ return v4l_queue_delete_bufs(fd->g_v4l_fd(), this, index, count);
+ }
bool has_create_bufs(cv4l_fd *fd) const
{
return v4l_queue_has_create_bufs(fd->g_v4l_fd(), this);
@@ -1513,12 +1513,29 @@ static inline void *v4l_queue_g_dataptr(const struct v4l_queue *q, unsigned inde
return v4l_queue_g_mmapping(q, index, plane);
}
-static inline int v4l_queue_querybufs(struct v4l_fd *f, struct v4l_queue *q, unsigned from)
+static inline int v4l_queue_delete_bufs(struct v4l_fd *f, struct v4l_queue *q, unsigned index, unsigned count)
{
- unsigned b, p;
+ struct v4l2_delete_buffers deletebufs;
int ret;
- for (b = from; b < v4l_queue_g_buffers(q); b++) {
+ memset(&deletebufs, 0, sizeof(deletebufs));
+ deletebufs.type = q->type;
+ deletebufs.index = index;
+ deletebufs.count = count;
+
+ ret = v4l_ioctl(f, VIDIOC_DELETE_BUFS, &deletebufs);
+ if (!ret)
+ q->buffers -= deletebufs.count;
+
+ return ret;
+}
+
+static inline int v4l_queue_querybufs(struct v4l_fd *f, struct v4l_queue *q, unsigned from, unsigned count)
+{
+ unsigned b, p, max = from + count;
+ int ret;
+
+ for (b = from; b < max; b++) {
struct v4l_buffer buf;
v4l_buffer_init(&buf, v4l_queue_g_type(q), v4l_queue_g_memory(q), b);
@@ -1556,7 +1573,7 @@ static inline int v4l_queue_reqbufs(struct v4l_fd *f,
return ret;
q->buffers = reqbufs.count;
q->capabilities = reqbufs.capabilities;
- return v4l_queue_querybufs(f, q, 0);
+ return v4l_queue_querybufs(f, q, 0, reqbufs.count);
}
static inline bool v4l_queue_has_create_bufs(struct v4l_fd *f, const struct v4l_queue *q)
@@ -1596,7 +1613,7 @@ static inline int v4l_queue_create_bufs(struct v4l_fd *f,
if (q->capabilities & V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS)
q->max_num_buffers = createbufs.max_num_buffers;
q->buffers += createbufs.count;
- return v4l_queue_querybufs(f, q, q->buffers - createbufs.count);
+ return v4l_queue_querybufs(f, q, createbufs.index, createbufs.count);
}
static inline int v4l_queue_mmap_bufs(struct v4l_fd *f,
@@ -1466,6 +1466,7 @@ void testNode(struct node &node, struct node &node_m2m_cap, struct node &expbuf_
printf("Buffer ioctls%s:\n", suffix);
printf("\ttest VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: %s\n", ok(testReqBufs(&node)));
printf("\ttest CREATE_BUFS maximum buffers: %s\n", ok(testCreateBufsMax(&node)));
+ printf("\ttest VIDIOC_DELETE_BUFS: %s\n", ok(testDeleteBufs(&node)));
// Reopen after each streaming test to reset the streaming state
// in case of any errors in the preceeding test.
node.reopen();
@@ -385,6 +385,7 @@ int testReadWrite(struct node *node);
int testExpBuf(struct node *node);
int testBlockingWait(struct node *node);
int testCreateBufsMax(struct node *node);
+int testDeleteBufs(struct node *node);
// 32-bit architecture, 32/64-bit time_t tests
int testTime32_64(struct node *node);
@@ -529,6 +529,105 @@ static int testCanSetSameTimings(struct node *node)
return 0;
}
+int testDeleteBufs(struct node *node)
+{
+ int ret;
+ unsigned i;
+
+ node->reopen();
+
+ for (i = 1; i <= V4L2_BUF_TYPE_LAST; i++) {
+ struct v4l2_delete_buffers delbufs = { };
+
+ if (!(node->valid_buftypes & (1 << i)))
+ continue;
+
+ cv4l_queue q(i, V4L2_MEMORY_MMAP);
+
+ if (testSetupVbi(node, i))
+ continue;
+ ret = q.delete_bufs(node, 0, 0);
+ if (ret == ENOTTY) {
+ warn("VIDIOC_DELETE_BUFS not supported\n");
+ continue;
+ }
+
+ q.init(i, V4L2_MEMORY_MMAP);
+ ret = q.create_bufs(node, 0);
+ fail_on_test_val(ret && ret != EINVAL, ret);
+
+ memset(&delbufs, 0xff, sizeof(delbufs));
+ delbufs.index = 0;
+ delbufs.count = 0;
+ delbufs.type = q.g_type();
+ fail_on_test(doioctl(node, VIDIOC_DELETE_BUFS, &delbufs));
+ fail_on_test(check_0(delbufs.reserved, sizeof(delbufs.reserved)));
+
+ if (!ret) {
+ unsigned buffers;
+ buffer buf(i);
+
+ /* Create only 1 buffer */
+ fail_on_test(q.create_bufs(node, 1));
+ buffers = q.g_buffers();
+ fail_on_test(buffers == 0);
+ /* Delete buffer index 1 must fail */
+ fail_on_test(q.delete_bufs(node, 1, buffers) != EINVAL);
+ /* Delete buffer index 0 is valid */
+ fail_on_test(q.delete_bufs(node, 0, buffers));
+ /* Delete buffer index 0 again must fail */
+ fail_on_test(q.delete_bufs(node, 0, 1) != EINVAL);
+ /* Create 3 buffers indexes 0 to 2 */
+ fail_on_test(q.create_bufs(node, 3));
+ /* Delete them one by one */
+ fail_on_test(q.delete_bufs(node, 2, 1));
+ fail_on_test(q.delete_bufs(node, 0, 1));
+ fail_on_test(q.delete_bufs(node, 1, 1));
+ /* Delete buffer index 0 again must fail */
+ fail_on_test(q.delete_bufs(node, 0, 1) != EINVAL);
+
+ /* for the next test the queue needs to be able to allocate 7 buffers */
+ if (q.g_max_num_buffers() < 7)
+ continue;
+
+ /* Create 4 buffers indexes 0 to 3 */
+ fail_on_test(q.create_bufs(node, 4));
+ /* Delete buffers index 1 and 2 */
+ fail_on_test(q.delete_bufs(node, 1, 2));
+ /* Add 3 more buffers should be indexes 4 to 6 */
+ fail_on_test(q.create_bufs(node, 3));
+ /* Query buffers:
+ * 1 and 2 have been deleted they must fail
+ * 0 and 4 to 6 must exist*/
+ fail_on_test(buf.querybuf(node, 0));
+ fail_on_test(buf.querybuf(node, 1) != EINVAL);
+ fail_on_test(buf.querybuf(node, 2) != EINVAL);
+ fail_on_test(buf.querybuf(node, 4));
+ fail_on_test(buf.querybuf(node, 5));
+ fail_on_test(buf.querybuf(node, 6));
+ /* Delete existing buffer index 6 with bad type must fail */
+ memset(&delbufs, 0xff, sizeof(delbufs));
+ delbufs.index = 6;
+ delbufs.count = 1;
+ delbufs.type = 0;
+ fail_on_test(doioctl(node, VIDIOC_DELETE_BUFS, &delbufs) != EINVAL);
+
+ /* Delete crossing max allowed buffers boundary must fail */
+ fail_on_test(q.delete_bufs(node, q.g_max_num_buffers() - 2, 7) != EINVAL);
+
+ /* Delete overflow must fail */
+ fail_on_test(q.delete_bufs(node, 3, 0xfffffff) != EINVAL);
+
+ /* Create 2 buffers, that must fill the hole */
+ fail_on_test(q.create_bufs(node, 2));
+ /* Remove all buffers */
+ fail_on_test(q.delete_bufs(node, 0, 7));
+ }
+ }
+
+ return 0;
+}
+
int testReqBufs(struct node *node)
{
struct v4l2_create_buffers crbufs = { };
Add new test for DELETE_BUFS ioctl. It create buffers and check if they could be removed from queue. It also check that removing non existing buffer or a queued buffer failed. Since using DELETE_BUFS can create "holes" v4l_queue_querybufs() function needs to be modify to do a range check between [from..from+count-1]. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com> --- version 7: - Remove V4L2_BUF_CAP_SUPPORTS_DELETE_BUFS to be aligned with the v18 of the kernel patches - v4l_queue_querybufs() take care of a range of buffers. utils/common/cv4l-helpers.h | 4 + utils/common/v4l-helpers.h | 27 ++++-- utils/v4l2-compliance/v4l2-compliance.cpp | 1 + utils/v4l2-compliance/v4l2-compliance.h | 1 + utils/v4l2-compliance/v4l2-test-buffers.cpp | 99 +++++++++++++++++++++ 5 files changed, 127 insertions(+), 5 deletions(-)