All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] v4l2-ctl/compliance: improve array control tests
@ 2022-06-28 12:13 Hans Verkuil
  2022-06-28 12:13 ` [PATCH 1/3] v4l2-compliance/ctl: add dynamic array support Hans Verkuil
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Hans Verkuil @ 2022-06-28 12:13 UTC (permalink / raw)
  To: linux-media; +Cc: Xavier Roumegue

The first patch adds support for dynamic array controls. The second
patch add tests for the vivid pixel array control that changes dimensions
when the video format changes. The last patch tests support for the vivid
pixel array control in a request.

It tests the control framework patch series posted here:

https://patchwork.linuxtv.org/project/linux-media/cover/20220628120523.2915913-1-hverkuil-cisco@xs4all.nl/

Regards,

	Hans

Hans Verkuil (3):
  v4l2-compliance/ctl: add dynamic array support
  v4l2-compliance: check vivid pixel array control behavior
  v4l2-compliance: test of vivid's pixel array in requests

 include/linux/videodev2.h                     |   1 +
 utils/common/v4l2-info.cpp                    |   1 +
 utils/v4l2-compliance/v4l2-compliance.h       |   2 +
 utils/v4l2-compliance/v4l2-test-buffers.cpp   | 149 +++++++++++++++++-
 utils/v4l2-compliance/v4l2-test-controls.cpp  | 147 +++++++++++++++++
 .../v4l2-test-input-output.cpp                |  48 ++++++
 utils/v4l2-ctl/v4l2-ctl-common.cpp            |   7 +
 7 files changed, 354 insertions(+), 1 deletion(-)

-- 
2.35.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] v4l2-compliance/ctl: add dynamic array support
  2022-06-28 12:13 [PATCH 0/3] v4l2-ctl/compliance: improve array control tests Hans Verkuil
@ 2022-06-28 12:13 ` Hans Verkuil
  2022-06-28 12:13 ` [PATCH 2/3] v4l2-compliance: check vivid pixel array control behavior Hans Verkuil
  2022-06-28 12:13 ` [PATCH 3/3] v4l2-compliance: test of vivid's pixel array in requests Hans Verkuil
  2 siblings, 0 replies; 4+ messages in thread
From: Hans Verkuil @ 2022-06-28 12:13 UTC (permalink / raw)
  To: linux-media; +Cc: Xavier Roumegue, Hans Verkuil

Add support for dynamic array controls, including vivid-specific
compliance tests.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 include/linux/videodev2.h                    |   1 +
 utils/common/v4l2-info.cpp                   |   1 +
 utils/v4l2-compliance/v4l2-compliance.h      |   1 +
 utils/v4l2-compliance/v4l2-test-buffers.cpp  |  90 ++++++++++++
 utils/v4l2-compliance/v4l2-test-controls.cpp | 147 +++++++++++++++++++
 utils/v4l2-ctl/v4l2-ctl-common.cpp           |   7 +
 6 files changed, 247 insertions(+)

diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 5cf38d7c..b01d8d4d 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1857,6 +1857,7 @@ struct v4l2_querymenu {
 #define V4L2_CTRL_FLAG_HAS_PAYLOAD	0x0100
 #define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE	0x0200
 #define V4L2_CTRL_FLAG_MODIFY_LAYOUT	0x0400
+#define V4L2_CTRL_FLAG_DYNAMIC_ARRAY	0x0800
 
 /*  Query flags, to be ORed with the control ID */
 #define V4L2_CTRL_FLAG_NEXT_CTRL	0x80000000
diff --git a/utils/common/v4l2-info.cpp b/utils/common/v4l2-info.cpp
index b8f2c865..00a5fada 100644
--- a/utils/common/v4l2-info.cpp
+++ b/utils/common/v4l2-info.cpp
@@ -531,6 +531,7 @@ std::string ctrlflags2s(__u32 flags)
 		{ V4L2_CTRL_FLAG_HAS_PAYLOAD,"has-payload" },
 		{ V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, "execute-on-write" },
 		{ V4L2_CTRL_FLAG_MODIFY_LAYOUT, "modify-layout" },
+		{ V4L2_CTRL_FLAG_DYNAMIC_ARRAY, "dynamic-array" },
 		{ 0, nullptr }
 	};
 	return flags2s(flags, def);
diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h
index 507187eb..d9efe2cd 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -88,6 +88,7 @@ enum poll_mode {
 
 #define VIVID_CID_CUSTOM_BASE		(V4L2_CID_USER_BASE | 0xf000)
 #define VIVID_CID_RO_INTEGER		(VIVID_CID_CUSTOM_BASE + 12)
+#define VIVID_CID_U32_DYN_ARRAY		(VIVID_CID_CUSTOM_BASE + 13)
 
 struct test_query_ext_ctrl: v4l2_query_ext_ctrl {
 	__u64 menu_mask;
diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp b/utils/v4l2-compliance/v4l2-test-buffers.cpp
index b8de7afc..f2d2ee75 100644
--- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
+++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
@@ -2007,6 +2007,30 @@ int testRequests(struct node *node, bool test_streaming)
 		.id = VIVID_CID_RO_INTEGER,
 	};
 	v4l2_ext_controls vivid_ro_ctrls = {};
+	// Note: the vivid dynamic array has range 10-90
+	// and the maximum number of elements is 100.
+	__u32 vivid_dyn_array[101] = {};
+	// Initialize with these values
+	static const __u32 vivid_dyn_array_init[16] = {
+		 6, 12, 18, 24, 30, 36, 42, 48,
+		54, 60, 66, 72, 78, 84, 90, 96
+	};
+	// This is the clamped version to compare against
+	static const __u32 vivid_dyn_array_clamped[16] = {
+		10, 12, 18, 24, 30, 36, 42, 48,
+		54, 60, 66, 72, 78, 84, 90, 90
+	};
+	const unsigned elem_size = sizeof(vivid_dyn_array[0]);
+	v4l2_ext_control vivid_dyn_array_ctrl = {
+		.id = VIVID_CID_U32_DYN_ARRAY,
+		.size = elem_size,
+		.p_u32 = vivid_dyn_array,
+	};
+	v4l2_ext_controls vivid_dyn_array_ctrls = {
+		.which = V4L2_CTRL_WHICH_REQUEST_VAL,
+		.count = 1,
+		.controls = &vivid_dyn_array_ctrl,
+	};
 	bool have_controls;
 	int ret;
 
@@ -2318,6 +2342,34 @@ int testRequests(struct node *node, bool test_streaming)
 		ctrls.request_fd = buf_req_fds[i];
 		if (i % 3 < 2)
 			fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+		if (is_vivid) {
+			// For vivid, check dynamic array support:
+			vivid_dyn_array_ctrls.request_fd = buf_req_fds[i];
+			vivid_dyn_array_ctrl.size = sizeof(vivid_dyn_array);
+			memset(vivid_dyn_array, 0xff, sizeof(vivid_dyn_array));
+			// vivid_dyn_array_ctrl.size is too large, must return ENOSPC
+			fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS,
+					     &vivid_dyn_array_ctrls) != ENOSPC);
+			// and size is set at 100 elems
+			fail_on_test(vivid_dyn_array_ctrl.size != 100 * elem_size);
+			// Check that the array is not overwritten
+			fail_on_test(vivid_dyn_array[0] != 0xffffffff);
+			if (i % 3 < 2) {
+				unsigned size = (2 + 2 * (i % 8)) * elem_size;
+
+				// Set proper size, varies per request
+				vivid_dyn_array_ctrl.size = size;
+				memcpy(vivid_dyn_array, vivid_dyn_array_init, size);
+				fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS,
+						     &vivid_dyn_array_ctrls));
+				// check that the size is as expected
+				fail_on_test(vivid_dyn_array_ctrl.size != size);
+				// and the array values are correctly clamped
+				fail_on_test(memcmp(vivid_dyn_array, vivid_dyn_array_clamped, size));
+				// and the end of the array is not overwritten
+				fail_on_test(vivid_dyn_array[size / elem_size] != 0xffffffff);
+			}
+		}
 		// Re-init the unqueued request
 		fail_on_test(doioctl_fd(buf_req_fds[i], MEDIA_REQUEST_IOC_REINIT, nullptr));
 
@@ -2330,6 +2382,15 @@ int testRequests(struct node *node, bool test_streaming)
 		ctrls.request_fd = buf_req_fds[i];
 		if (i % 3 < 2)
 			fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+		if (is_vivid && i % 3 < 2) {
+			// Set the dynamic array control again
+			vivid_dyn_array_ctrls.request_fd = buf_req_fds[i];
+			vivid_dyn_array_ctrl.size = (2 + 2 * (i % 8)) * elem_size;
+			memcpy(vivid_dyn_array, vivid_dyn_array_init,
+			       sizeof(vivid_dyn_array_init));
+			fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS,
+					     &vivid_dyn_array_ctrls));
+		}
 
 		// After the re-init the buffer is no longer marked for
 		// a request. If a request has been queued before (hence
@@ -2436,6 +2497,20 @@ int testRequests(struct node *node, bool test_streaming)
 			    vivid_ro_ctrl.value != (int)i)
 				warn_once("vivid_ro_ctrl.value (%d) != i (%u)\n",
 					  vivid_ro_ctrl.value, i);
+
+			// Check that the dynamic control array is set as
+			// expected and with the correct values.
+			vivid_dyn_array_ctrls.request_fd = buf_req_fds[i];
+			memset(vivid_dyn_array, 0xff, sizeof(vivid_dyn_array));
+			vivid_dyn_array_ctrl.size = sizeof(vivid_dyn_array);
+			fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &vivid_dyn_array_ctrls));
+			unsigned size = (2 + 2 * (i % 8)) * elem_size;
+			if (i % 3 == 2)
+				size = (2 + 2 * ((i - 1) % 8)) * elem_size;
+			fail_on_test(vivid_dyn_array_ctrl.size != size);
+			fail_on_test(memcmp(vivid_dyn_array, vivid_dyn_array_clamped,
+					    vivid_dyn_array_ctrl.size));
+			fail_on_test(vivid_dyn_array[size / elem_size] != 0xffffffff);
 		}
 		fail_on_test(buf.querybuf(node, i));
 		// Check that all the buffers of the stopped stream are
@@ -2486,6 +2561,21 @@ int testRequests(struct node *node, bool test_streaming)
 			    vivid_ro_ctrl.value != (int)(num_bufs - 1))
 				warn("vivid_ro_ctrl.value (%d) != num_bufs - 1 (%d)\n",
 				     vivid_ro_ctrl.value, num_bufs - 1);
+
+			// and the final dynamic array value
+			v4l2_query_ext_ctrl q_dyn_array = {
+				.id = VIVID_CID_U32_DYN_ARRAY,
+			};
+			fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &q_dyn_array));
+			unsigned elems = 2 + 2 * ((num_bufs - 1) % 8);
+			if ((num_bufs - 1) % 3 == 2)
+				elems = 2 + 2 * ((num_bufs - 2) % 8);
+			fail_on_test(q_dyn_array.elems != elems);
+			vivid_dyn_array_ctrls.which = 0;
+			fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &vivid_dyn_array_ctrls));
+			fail_on_test(vivid_dyn_array_ctrl.size != elems * elem_size);
+			fail_on_test(memcmp(vivid_dyn_array, vivid_dyn_array_clamped,
+					    vivid_dyn_array_ctrl.size));
 		}
 	}
 
diff --git a/utils/v4l2-compliance/v4l2-test-controls.cpp b/utils/v4l2-compliance/v4l2-test-controls.cpp
index 8731c9eb..999dbcd7 100644
--- a/utils/v4l2-compliance/v4l2-test-controls.cpp
+++ b/utils/v4l2-compliance/v4l2-test-controls.cpp
@@ -627,6 +627,150 @@ static int checkExtendedCtrl(const struct v4l2_ext_control &ctrl, const struct t
 	default:
 		break;
 	}
+	if (qctrl.flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) {
+		fail_on_test(qctrl.nr_of_dims != 1);
+		unsigned tot_elems = qctrl.dims[0];
+		fail_on_test(qctrl.elems > tot_elems);
+		fail_on_test(!qctrl.elems);
+	}
+	return 0;
+}
+
+static int checkVividDynArray(struct node *node,
+			      struct v4l2_ext_control &ctrl,
+			      const struct test_query_ext_ctrl &qctrl)
+{
+	struct v4l2_query_ext_ctrl qextctrl = {};
+	unsigned max_elems = qctrl.dims[0];
+	unsigned max_size = qctrl.elem_size * max_elems;
+
+	delete [] ctrl.string;
+	// Allocate a buffer that's one element more than the max
+	ctrl.string = new char[max_size + qctrl.elem_size];
+	ctrl.size = qctrl.elem_size;
+	ctrl.p_u32[0] = (qctrl.minimum + qctrl.maximum) / 2;
+	// Set the last element + 1, must never be overwritten
+	ctrl.p_u32[max_elems] = 0xdeadbeef;
+
+	struct v4l2_ext_controls ctrls = {};
+	ctrls.count = 1;
+	ctrls.controls = &ctrl;
+	// Set the array to a single element
+	fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+
+	qextctrl.id = ctrl.id;
+	// Check that only one element is reported
+	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
+	fail_on_test(qextctrl.elems != 1);
+
+	// If the size is less than elem_size, the ioctl must return -EFAULT
+	ctrl.size = 0;
+	fail_on_test(doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls) != EFAULT);
+	ctrl.size = qctrl.elem_size - 1;
+	fail_on_test(doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls) != EFAULT);
+	ctrl.size = max_size + qctrl.elem_size;
+	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
+	// Check that ctrl.size is reset to the current size of the array (1 element)
+	fail_on_test(ctrl.size != qctrl.elem_size);
+	ctrl.size = max_size + qctrl.elem_size;
+	// Attempting to set more than max_elems must result in -ENOSPC
+	fail_on_test(doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls) != ENOSPC);
+	fail_on_test(ctrl.size != max_size);
+	ctrl.size = max_size + qctrl.elem_size;
+	fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls) != ENOSPC);
+	fail_on_test(ctrl.size != max_size);
+	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
+	// Verify that the number of elements is still 1
+	fail_on_test(qextctrl.elems != 1);
+
+	ctrl.size = max_size;
+	for (unsigned i = 0; i < max_elems; i++)
+		ctrl.p_u32[i] = i;
+	// Try the max number of elements
+	fail_on_test(doioctl(node, VIDIOC_TRY_EXT_CTRLS, &ctrls));
+	// Check that the values are clamped
+	for (unsigned i = 0; i < max_elems; i++) {
+		unsigned j = i;
+		if (j < qctrl.minimum)
+			j = qctrl.minimum;
+		else if (j > qctrl.maximum)
+			j = qctrl.maximum;
+		fail_on_test(ctrl.p_u32[i] != j);
+	}
+	fail_on_test(ctrl.size != max_size);
+	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
+	// Verify that the number of elements is still 1
+	fail_on_test(qextctrl.elems != 1);
+	memset(ctrl.string, 0xff, max_size);
+	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
+	// Check that there is still just one element returned.
+	fail_on_test(ctrl.size != qctrl.elem_size);
+	fail_on_test(ctrl.p_u32[0] != (qctrl.minimum + qctrl.maximum) / 2);
+
+	ctrl.size = max_size;
+	for (unsigned i = 0; i < max_elems; i++)
+		ctrl.p_u32[i] = i;
+	// Set the max number of elements
+	fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+	for (unsigned i = 0; i < max_elems; i++) {
+		unsigned j = i;
+		if (j < qctrl.minimum)
+			j = qctrl.minimum;
+		else if (j > qctrl.maximum)
+			j = qctrl.maximum;
+		fail_on_test(ctrl.p_u32[i] != j);
+	}
+	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
+	// Check that it is updated
+	fail_on_test(qextctrl.elems != max_elems);
+	memset(ctrl.string, 0xff, max_size);
+	ctrl.size = qctrl.elem_size;
+	// Check that ENOSPC is returned if the size is too small
+	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != ENOSPC);
+	// And updated to the actual required size
+	fail_on_test(ctrl.size != max_size);
+	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
+	for (unsigned i = 0; i < max_elems; i++) {
+		unsigned j = i;
+		if (j < qctrl.minimum)
+			j = qctrl.minimum;
+		else if (j > qctrl.maximum)
+			j = qctrl.maximum;
+		fail_on_test(ctrl.p_u32[i] != j);
+	}
+	// Check that the end of the buffer isn't overwritten
+	fail_on_test(ctrl.p_u32[max_elems] != 0xdeadbeef);
+
+	ctrl.size = qctrl.elem_size;
+	ctrls.which = V4L2_CTRL_WHICH_DEF_VAL;
+	// Check that ENOSPC is returned if the size is too small
+	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls) != ENOSPC);
+	// And updated to the actual required size
+	fail_on_test(ctrl.size != max_size);
+	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
+	for (unsigned i = 0; i < max_elems; i++)
+		fail_on_test(ctrl.p_u32[i] != 50);
+	// Check that the end of the buffer isn't overwritten
+	fail_on_test(ctrl.p_u32[max_elems] != 0xdeadbeef);
+
+	ctrls.which = 0;
+	ctrl.size = qctrl.elem_size;
+	ctrl.p_u32[0] = (qctrl.minimum + qctrl.maximum) / 2;
+	// Back to just one element
+	fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
+	fail_on_test(doioctl(node, VIDIOC_QUERY_EXT_CTRL, &qextctrl));
+	// Check this.
+	fail_on_test(qextctrl.elems != 1);
+
+	ctrl.size = max_size;
+	ctrls.which = V4L2_CTRL_WHICH_DEF_VAL;
+	memset(ctrl.string, 0xff, max_size);
+	// And updated to the actual required size
+	fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &ctrls));
+	fail_on_test(ctrl.size != qctrl.elem_size);
+	fail_on_test(ctrl.p_u32[0] != 50);
+	fail_on_test(ctrl.p_u32[1] != 0xffffffff);
+
 	return 0;
 }
 
@@ -751,6 +895,9 @@ int testExtendedControls(struct node *node)
 				return fail("s_ext_ctrls returned invalid control contents (%08x)\n", qctrl.id);
 		}
 
+		if (is_vivid && ctrl.id == VIVID_CID_U32_DYN_ARRAY &&
+		    checkVividDynArray(node, ctrl, qctrl))
+			return fail("dynamic array tests failed\n");
 		if (qctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD)
 			delete [] ctrl.string;
 		ctrl.string = nullptr;
diff --git a/utils/v4l2-ctl/v4l2-ctl-common.cpp b/utils/v4l2-ctl/v4l2-ctl-common.cpp
index 89a9553d..ea46faf2 100644
--- a/utils/v4l2-ctl/v4l2-ctl-common.cpp
+++ b/utils/v4l2-ctl/v4l2-ctl-common.cpp
@@ -390,6 +390,9 @@ static bool fill_subset(const struct v4l2_query_ext_ctrl &qc, ctrl_subset &subse
 		subset.size[d] = qc.dims[d];
 	}
 
+	if (qc.flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY)
+		subset.size[0] = qc.elems;
+
 	std::string s = name2var(qc.name);
 
 	if (ctrl_subsets.find(s) != ctrl_subsets.end()) {
@@ -489,6 +492,8 @@ static void print_value(int fd, const v4l2_query_ext_ctrl &qc, const v4l2_ext_co
 			memset(&subset, 0, sizeof(subset));
 			for (unsigned i = 0; i < qc.nr_of_dims; i++)
 				subset.size[i] = qc.dims[i];
+			if (qc.flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY)
+				subset.size[0] = qc.elems;
 		}
 		print_array(qc, ctrl, subset);
 		return;
@@ -650,6 +655,8 @@ static void print_qctrl(int fd, const v4l2_query_ext_ctrl &qc,
 		printf(" value=");
 		print_value(fd, qc, ctrl, false, false);
 	} else {
+		if (qc.flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY)
+			printf(" elems=%u", qc.elems);
 		printf(" dims=");
 		for (i = 0; i < qc.nr_of_dims; i++)
 			printf("[%u]", qc.dims[i]);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] v4l2-compliance: check vivid pixel array control behavior
  2022-06-28 12:13 [PATCH 0/3] v4l2-ctl/compliance: improve array control tests Hans Verkuil
  2022-06-28 12:13 ` [PATCH 1/3] v4l2-compliance/ctl: add dynamic array support Hans Verkuil
@ 2022-06-28 12:13 ` Hans Verkuil
  2022-06-28 12:13 ` [PATCH 3/3] v4l2-compliance: test of vivid's pixel array in requests Hans Verkuil
  2 siblings, 0 replies; 4+ messages in thread
From: Hans Verkuil @ 2022-06-28 12:13 UTC (permalink / raw)
  To: linux-media; +Cc: Xavier Roumegue, Hans Verkuil

Changing the input will change the format, which will also change
the dimensions of the pixel array control, and reset the contents
of that array to the default value. Check that this is in fact
happening.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 utils/v4l2-compliance/v4l2-compliance.h       |  1 +
 .../v4l2-test-input-output.cpp                | 48 +++++++++++++++++++
 2 files changed, 49 insertions(+)

diff --git a/utils/v4l2-compliance/v4l2-compliance.h b/utils/v4l2-compliance/v4l2-compliance.h
index d9efe2cd..ef021ed2 100644
--- a/utils/v4l2-compliance/v4l2-compliance.h
+++ b/utils/v4l2-compliance/v4l2-compliance.h
@@ -89,6 +89,7 @@ enum poll_mode {
 #define VIVID_CID_CUSTOM_BASE		(V4L2_CID_USER_BASE | 0xf000)
 #define VIVID_CID_RO_INTEGER		(VIVID_CID_CUSTOM_BASE + 12)
 #define VIVID_CID_U32_DYN_ARRAY		(VIVID_CID_CUSTOM_BASE + 13)
+#define VIVID_CID_U8_PIXEL_ARRAY	(VIVID_CID_CUSTOM_BASE + 14)
 
 struct test_query_ext_ctrl: v4l2_query_ext_ctrl {
 	__u64 menu_mask;
diff --git a/utils/v4l2-compliance/v4l2-test-input-output.cpp b/utils/v4l2-compliance/v4l2-test-input-output.cpp
index 006e05ec..0b3be8db 100644
--- a/utils/v4l2-compliance/v4l2-test-input-output.cpp
+++ b/utils/v4l2-compliance/v4l2-test-input-output.cpp
@@ -448,6 +448,44 @@ static int checkInput(struct node *node, const struct v4l2_input &descr, unsigne
 	return 0;
 }
 
+static int checkVividPixelArray(struct node *node)
+{
+	struct v4l2_query_ext_ctrl qextctrl = {
+		.id = VIVID_CID_U8_PIXEL_ARRAY
+	};
+	cv4l_fmt fmt;
+
+	fail_on_test(node->query_ext_ctrl(qextctrl));
+	fail_on_test(node->g_fmt(fmt));
+	fail_on_test(qextctrl.nr_of_dims != 2);
+	fail_on_test(qextctrl.dims[0] != fmt.g_width());
+	fail_on_test(qextctrl.dims[1] != fmt.g_height());
+	fail_on_test(qextctrl.minimum == qextctrl.default_value);
+
+	struct v4l2_ext_control ctrl = {
+		.id = VIVID_CID_U8_PIXEL_ARRAY
+	};
+	struct v4l2_ext_controls ctrls = {
+		.count = 1
+	};
+
+	ctrl.size = qextctrl.elems * qextctrl.elem_size;
+	ctrl.p_u8 = new unsigned char[ctrl.size];
+	ctrls.controls = &ctrl;
+	fail_on_test(node->g_ext_ctrls(ctrls));
+	for (unsigned i = 0; i < qextctrl.elems; i++) {
+		fail_on_test(ctrl.p_u8[i] != qextctrl.default_value);
+		ctrl.p_u8[i] = qextctrl.minimum;
+	}
+	fail_on_test(node->s_ext_ctrls(ctrls));
+	fail_on_test(node->g_ext_ctrls(ctrls));
+	for (unsigned i = 0; i < qextctrl.elems; i++) {
+		fail_on_test(ctrl.p_u8[i] != qextctrl.minimum);
+	}
+	delete [] ctrl.p_u8;
+	return 0;
+}
+
 int testInput(struct node *node)
 {
 	struct v4l2_input descr;
@@ -479,6 +517,14 @@ int testInput(struct node *node)
 		return fail("VIDIOC_G_INPUT didn't fill in the input\n");
 	if (node->is_radio)
 		return fail("radio can't have input support\n");
+	if (is_vivid && cur_input == 0) {
+		// for vivid start off with a different input than the
+		// current one. This ensures that the checkVividPixelArray()
+		// call later succeeds since switching to input 0 will reset
+		// that control to the default values.
+		input = 1;
+		doioctl(node, VIDIOC_S_INPUT, &input);
+	}
 	for (;;) {
 		memset(&descr, 0xff, sizeof(descr));
 		descr.index = i;
@@ -494,6 +540,8 @@ int testInput(struct node *node)
 			return fail("input set to %d, but becomes %d?!\n", i, input);
 		if (checkInput(node, descr, i))
 			return fail("invalid attributes for input %d\n", i);
+		if (is_vivid && node->is_video && checkVividPixelArray(node))
+			return fail("vivid pixel array control test failed\n");
 		node->inputs++;
 		i++;
 	}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] v4l2-compliance: test of vivid's pixel array in requests
  2022-06-28 12:13 [PATCH 0/3] v4l2-ctl/compliance: improve array control tests Hans Verkuil
  2022-06-28 12:13 ` [PATCH 1/3] v4l2-compliance/ctl: add dynamic array support Hans Verkuil
  2022-06-28 12:13 ` [PATCH 2/3] v4l2-compliance: check vivid pixel array control behavior Hans Verkuil
@ 2022-06-28 12:13 ` Hans Verkuil
  2 siblings, 0 replies; 4+ messages in thread
From: Hans Verkuil @ 2022-06-28 12:13 UTC (permalink / raw)
  To: linux-media; +Cc: Xavier Roumegue, Hans Verkuil

Verify that using an array control in a request works fine.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
 utils/v4l2-compliance/v4l2-test-buffers.cpp | 61 ++++++++++++++++++++-
 1 file changed, 59 insertions(+), 2 deletions(-)

diff --git a/utils/v4l2-compliance/v4l2-test-buffers.cpp b/utils/v4l2-compliance/v4l2-test-buffers.cpp
index f2d2ee75..bc9050c8 100644
--- a/utils/v4l2-compliance/v4l2-test-buffers.cpp
+++ b/utils/v4l2-compliance/v4l2-test-buffers.cpp
@@ -2031,6 +2031,15 @@ int testRequests(struct node *node, bool test_streaming)
 		.count = 1,
 		.controls = &vivid_dyn_array_ctrl,
 	};
+	unsigned vivid_pixel_array_size = 0;
+	v4l2_ext_control vivid_pixel_array_ctrl = {
+		.id = VIVID_CID_U8_PIXEL_ARRAY,
+	};
+	v4l2_ext_controls vivid_pixel_array_ctrls = {
+		.which = V4L2_CTRL_WHICH_REQUEST_VAL,
+		.count = 1,
+		.controls = &vivid_pixel_array_ctrl,
+	};
 	bool have_controls;
 	int ret;
 
@@ -2042,6 +2051,16 @@ int testRequests(struct node *node, bool test_streaming)
 	vivid_ro_ctrls.count = 1;
 	vivid_ro_ctrls.controls = &vivid_ro_ctrl;
 
+	if (is_vivid) {
+		v4l2_query_ext_ctrl qec = { .id = VIVID_CID_U8_PIXEL_ARRAY };
+		node->query_ext_ctrl(qec);
+		vivid_pixel_array_size = qec.elems;
+	}
+	__u8 vivid_pixel_array[vivid_pixel_array_size + 1];
+	vivid_pixel_array[vivid_pixel_array_size] = 0xff;
+	vivid_pixel_array_ctrl.size = vivid_pixel_array_size;
+	vivid_pixel_array_ctrl.p_u8 = vivid_pixel_array;
+
 	// If requests are supported, then there must be a media device
 	if (node->buf_caps & V4L2_BUF_CAP_SUPPORTS_REQUESTS)
 		fail_on_test(media_fd < 0);
@@ -2343,6 +2362,13 @@ int testRequests(struct node *node, bool test_streaming)
 		if (i % 3 < 2)
 			fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
 		if (is_vivid) {
+			// For vivid, check modifiable array support
+			memset(vivid_pixel_array, i, vivid_pixel_array_size);
+			vivid_pixel_array_ctrls.request_fd = buf_req_fds[i];
+			fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS,
+					     &vivid_pixel_array_ctrls));
+			fail_on_test(vivid_pixel_array[vivid_pixel_array_size] != 0xff);
+
 			// For vivid, check dynamic array support:
 			vivid_dyn_array_ctrls.request_fd = buf_req_fds[i];
 			vivid_dyn_array_ctrl.size = sizeof(vivid_dyn_array);
@@ -2383,6 +2409,11 @@ int testRequests(struct node *node, bool test_streaming)
 		if (i % 3 < 2)
 			fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS, &ctrls));
 		if (is_vivid && i % 3 < 2) {
+			// Set the pixel array control again
+			memset(vivid_pixel_array, i, vivid_pixel_array_size);
+			vivid_pixel_array_ctrls.request_fd = buf_req_fds[i];
+			fail_on_test(doioctl(node, VIDIOC_S_EXT_CTRLS,
+					     &vivid_pixel_array_ctrls));
 			// Set the dynamic array control again
 			vivid_dyn_array_ctrls.request_fd = buf_req_fds[i];
 			vivid_dyn_array_ctrl.size = (2 + 2 * (i % 8)) * elem_size;
@@ -2511,6 +2542,20 @@ int testRequests(struct node *node, bool test_streaming)
 			fail_on_test(memcmp(vivid_dyn_array, vivid_dyn_array_clamped,
 					    vivid_dyn_array_ctrl.size));
 			fail_on_test(vivid_dyn_array[size / elem_size] != 0xffffffff);
+			// Check that the pixel array control is set as
+			// expected and with the correct values.
+			vivid_pixel_array_ctrls.request_fd = buf_req_fds[i];
+			memset(vivid_pixel_array, 0xfe, vivid_pixel_array_size);
+			fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &vivid_pixel_array_ctrls));
+			bool ok = true;
+			__u8 expected = (i % 3 == 2) ? i - 1 : i;
+			for (unsigned j = 0; j < vivid_pixel_array_size; j++)
+				if (vivid_pixel_array[j] != expected) {
+					ok = false;
+					break;
+				}
+			fail_on_test(!ok);
+			fail_on_test(vivid_pixel_array[vivid_pixel_array_size] != 0xff);
 		}
 		fail_on_test(buf.querybuf(node, i));
 		// Check that all the buffers of the stopped stream are
@@ -2554,7 +2599,7 @@ int testRequests(struct node *node, bool test_streaming)
 		fail_on_test(ctrl.value != (is_max ? valid_qctrl.maximum :
 					    valid_qctrl.minimum));
 		if (is_vivid) {
-			// For vivid check the final read-only value
+			// For vivid check the final read-only value,
 			vivid_ro_ctrls.which = 0;
 			fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &vivid_ro_ctrls));
 			if (node->is_video && !node->can_output &&
@@ -2562,7 +2607,7 @@ int testRequests(struct node *node, bool test_streaming)
 				warn("vivid_ro_ctrl.value (%d) != num_bufs - 1 (%d)\n",
 				     vivid_ro_ctrl.value, num_bufs - 1);
 
-			// and the final dynamic array value
+			// the final dynamic array value,
 			v4l2_query_ext_ctrl q_dyn_array = {
 				.id = VIVID_CID_U32_DYN_ARRAY,
 			};
@@ -2576,6 +2621,18 @@ int testRequests(struct node *node, bool test_streaming)
 			fail_on_test(vivid_dyn_array_ctrl.size != elems * elem_size);
 			fail_on_test(memcmp(vivid_dyn_array, vivid_dyn_array_clamped,
 					    vivid_dyn_array_ctrl.size));
+
+			// and the final pixel array value.
+			vivid_pixel_array_ctrls.which = 0;
+			fail_on_test(doioctl(node, VIDIOC_G_EXT_CTRLS, &vivid_pixel_array_ctrls));
+			bool ok = true;
+			__u8 expected = (num_bufs - 1) % 3 == 2 ? num_bufs - 2 : num_bufs - 1;
+			for (unsigned j = 0; j < vivid_pixel_array_size; j++)
+				if (vivid_pixel_array[j] != expected) {
+					ok = false;
+					break;
+				}
+			fail_on_test(!ok);
 		}
 	}
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-06-28 12:14 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-28 12:13 [PATCH 0/3] v4l2-ctl/compliance: improve array control tests Hans Verkuil
2022-06-28 12:13 ` [PATCH 1/3] v4l2-compliance/ctl: add dynamic array support Hans Verkuil
2022-06-28 12:13 ` [PATCH 2/3] v4l2-compliance: check vivid pixel array control behavior Hans Verkuil
2022-06-28 12:13 ` [PATCH 3/3] v4l2-compliance: test of vivid's pixel array in requests Hans Verkuil

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.