@@ -760,6 +760,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);
@@ -1510,6 +1510,23 @@ 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_delete_bufs(struct v4l_fd *f, struct v4l_queue *q, unsigned index, unsigned count)
+{
+ struct v4l2_delete_buffers deletebufs;
+ int ret;
+
+ 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 b, p;
@@ -207,6 +207,7 @@ static constexpr flag_def bufcap_def[] = {
{ V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF, "m2m-hold-capture-buf" },
{ V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS, "mmap-cache-hints" },
{ V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS, "set-max-num-buffers" },
+ { V4L2_BUF_CAP_SUPPORTS_DELETE_BUFS, "delete-bufs" },
{ 0, nullptr }
};
@@ -1454,6 +1454,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();
@@ -384,6 +384,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,97 @@ 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;
+
+ q.init(i, V4L2_MEMORY_MMAP);
+ ret = q.create_bufs(node, 0);
+ fail_on_test_val(ret && ret != EINVAL, ret);
+ if (!(q.g_capabilities() & V4L2_BUF_CAP_SUPPORTS_DELETE_BUFS))
+ continue;
+
+ 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(q);
+
+ /* 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);
+
+ /* Create 5 buffers indexes 0 to 4*/
+ fail_on_test(q.create_bufs(node, 5));
+ /* Delete buffers index 1 and 2 */
+ fail_on_test(q.delete_bufs(node, 1, 2));
+ /* Add 3 more buffers should be indexes 5 to 7*/
+ fail_on_test(q.create_bufs(node, 3));
+ /* Query buffers:
+ * 1 and 2 have been deleted they must fail
+ * 5 to 7 must exist*/
+ fail_on_test(buf.querybuf(node, 1) != EINVAL);
+ fail_on_test(buf.querybuf(node, 2) != EINVAL);
+ fail_on_test(buf.querybuf(node, 5));
+ fail_on_test(buf.querybuf(node, 6));
+ fail_on_test(buf.querybuf(node, 7));
+ /* Delete existing buffer index 7 with bad type must fail */
+ memset(&delbufs, 0xff, sizeof(delbufs));
+ delbufs.index = 7;
+ 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, 8) != 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, 8));
+ }
+ }
+
+ 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. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com> --- utils/common/cv4l-helpers.h | 4 + utils/common/v4l-helpers.h | 17 ++++ utils/common/v4l2-info.cpp | 1 + utils/v4l2-compliance/v4l2-compliance.cpp | 1 + utils/v4l2-compliance/v4l2-compliance.h | 1 + utils/v4l2-compliance/v4l2-test-buffers.cpp | 91 +++++++++++++++++++++ 6 files changed, 115 insertions(+)