[libcamera-devel] [PATCH v3 2/8] test: delayed_controls: Add test case for DelayedControls

Jacopo Mondi jacopo at jmondi.org
Fri Nov 27 10:50:54 CET 2020


Hi Niklas,

On Mon, Nov 23, 2020 at 11:12:28PM +0100, Niklas Söderlund wrote:
> Add a test-case for DelayedControls that exercise the setting of

exercizes

> controls and reading back what controls where used for a particular

s/where/were

> frame. Also exercise corner case such as a V4L2 devices that do not
> reset its sequence number to 0 at stream on and sequence number wrapping
> around the uint32_t value space.
>
> Signed-off-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> ---
> * Changes since v2
> - Remove a unused LoC.
> - Add and remove blank lines.
> - Align number of loop iterations.
> ---
>  test/delayed_contols.cpp | 300 +++++++++++++++++++++++++++++++++++++++
>  test/meson.build         |   1 +
>  2 files changed, 301 insertions(+)
>  create mode 100644 test/delayed_contols.cpp
>
> diff --git a/test/delayed_contols.cpp b/test/delayed_contols.cpp
> new file mode 100644
> index 0000000000000000..aaf321bf4f1b4cd8
> --- /dev/null
> +++ b/test/delayed_contols.cpp
> @@ -0,0 +1,300 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2020, Google Inc.
> + *
> + * libcamera delayed controls tests

We usually prefix this with the file name.
ie.
    * delayed_controls.cpp - libcamera delayed controls test

> + */
> +
> +#include <iostream>
> +
> +#include "libcamera/internal/delayed_controls.h"
> +#include "libcamera/internal/device_enumerator.h"
> +#include "libcamera/internal/media_device.h"
> +#include "libcamera/internal/v4l2_videodevice.h"
> +
> +#include "test.h"
> +
> +using namespace std;
> +using namespace libcamera;
> +
> +class DelayedControlsTest : public Test
> +{
> +public:
> +	DelayedControlsTest()
> +		: dev_(nullptr)
> +	{
> +	}
> +
These following methods are usually in the protected scope.
Also missing 'override' keyword

> +	int init()
> +	{
> +		enumerator_ = DeviceEnumerator::create();
> +		if (!enumerator_) {
> +			cerr << "Failed to create device enumerator" << endl;
> +			return TestFail;
> +		}
> +
> +		if (enumerator_->enumerate()) {
> +			cerr << "Failed to enumerate media devices" << endl;
> +			return TestFail;
> +		}
> +
> +		DeviceMatch dm("vivid");
> +		dm.add("vivid-000-vid-cap");
> +
> +		media_ = enumerator_->search(dm);
> +		if (!media_) {
> +			cerr << "vivid video device found" << endl;
> +			return TestSkip;
> +		}
> +
> +		MediaEntity *entity = media_->getEntityByName("vivid-000-vid-cap");
> +		dev_ = new V4L2VideoDevice(entity->deviceNode());
> +		if (dev_->open()) {
> +			cerr << "Failed to open video device" << endl;
> +			return TestFail;
> +		}
> +
> +		const ControlInfoMap &infoMap = dev_->controls();
> +
> +		/* Test control enumeration. */
> +		if (infoMap.empty()) {
> +			cerr << "Failed to enumerate controls" << endl;
> +			return TestFail;
> +		}
> +
> +		if (infoMap.find(V4L2_CID_BRIGHTNESS) == infoMap.end() ||
> +		    infoMap.find(V4L2_CID_CONTRAST) == infoMap.end()) {
> +			cerr << "Missing controls" << endl;
> +			return TestFail;
> +		}
> +
> +		return TestPass;
> +	}
> +
> +	int singleControlNoDelay()
> +	{
> +		std::unordered_map<uint32_t, unsigned int> delays = {
> +			{ V4L2_CID_BRIGHTNESS, 0 },
> +		};
> +		std::unique_ptr<DelayedControls> delayed =
> +			std::make_unique<DelayedControls>(dev_, delays);
> +		ControlList ctrls;
> +
> +		/* Reset control to value not used in test. */
> +		ctrls.set(V4L2_CID_BRIGHTNESS, 1);
> +		delayed->reset(&ctrls);
> +
> +		/* Test control without delay are set at once. */
> +		for (int32_t i = 0; i < 100; i++) {
> +			int32_t value = 100 + i;
> +
> +			ctrls.set(V4L2_CID_BRIGHTNESS, value);
> +			delayed->push(ctrls);
> +
> +			delayed->frameStart(i);
> +
> +			ControlList result = delayed->get(i);
> +			int32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();
> +			if (brightness != value) {
> +				cerr << "Failed single control without delay"
> +				     << " frame " << i
> +				     << " expected " << value
> +				     << " got " << brightness
> +				     << endl;
> +				return TestFail;
> +			}
> +		}
> +
> +		return TestPass;
> +	}
> +
> +	int singleControlWithDelay()
> +	{
> +		std::unordered_map<uint32_t, unsigned int> delays = {
> +			{ V4L2_CID_BRIGHTNESS, 1 },
> +		};
> +		std::unique_ptr<DelayedControls> delayed =
> +			std::make_unique<DelayedControls>(dev_, delays);
> +		ControlList ctrls;
> +
> +		/* Reset control to value that will be first in test. */
> +		int32_t expected = 4;
> +		ctrls.set(V4L2_CID_BRIGHTNESS, expected);
> +		delayed->reset(&ctrls);
> +
> +		/* Test single control with delay. */
> +		for (int32_t i = 0; i < 100; i++) {
> +			int32_t value = 10 + i;
> +
> +			ctrls.set(V4L2_CID_BRIGHTNESS, value);
> +			delayed->push(ctrls);
> +
> +			delayed->frameStart(i);
> +
> +			ControlList result = delayed->get(i);
> +			int32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();
> +			if (brightness != expected) {
> +				cerr << "Failed single control with delay"
> +				     << " frame " << i
> +				     << " expected " << expected
> +				     << " got " << brightness
> +				     << endl;
> +				return TestFail;
> +			}
> +
> +			expected = value;
> +		}
> +
> +		return TestPass;
> +	}
> +
> +	int dualControlsWithDelay(uint32_t startOffset)
> +	{
> +		std::unordered_map<uint32_t, unsigned int> delays = {
> +			{ V4L2_CID_BRIGHTNESS, 1 },
> +			{ V4L2_CID_CONTRAST, 2 },
> +		};
> +		std::unique_ptr<DelayedControls> delayed =
> +			std::make_unique<DelayedControls>(dev_, delays);
> +		ControlList ctrls;
> +
> +		/* Reset control to value that will be first two frames in test. */
> +		int32_t expected = 200;
> +		ctrls.set(V4L2_CID_BRIGHTNESS, expected);
> +		ctrls.set(V4L2_CID_CONTRAST, expected);
> +		delayed->reset(&ctrls);
> +
> +		/* Test dual control with delay. */
> +		for (int32_t i = 0; i < 100; i++) {
> +			uint32_t frame = startOffset + i;
> +			int32_t value = 10 + i;
> +
> +			ctrls.set(V4L2_CID_BRIGHTNESS, value);
> +			ctrls.set(V4L2_CID_CONTRAST, value);
> +			delayed->push(ctrls);
> +
> +			delayed->frameStart(frame);
> +
> +			ControlList result = delayed->get(frame);
> +			int32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();
> +			int32_t contrast = result.get(V4L2_CID_CONTRAST).get<int32_t>();
> +			if (brightness != expected || contrast != expected) {
> +				cerr << "Failed dual controls"
> +				     << " frame " << frame
> +				     << " brightness " << brightness
> +				     << " contrast " << contrast
> +				     << " expected " << expected
> +				     << endl;
> +				return TestFail;
> +			}
> +
> +			expected = i < 1 ? expected : value - 1;
> +		}
> +
> +		return TestPass;
> +	}
> +
> +	int dualControlsMultiQueue()
> +	{
> +		std::unordered_map<uint32_t, unsigned int> delays = {
> +			{ V4L2_CID_BRIGHTNESS, 1 },
> +			{ V4L2_CID_CONTRAST, 2 },
> +		};
> +		std::unique_ptr<DelayedControls> delayed =
> +			std::make_unique<DelayedControls>(dev_, delays);
> +		ControlList ctrls;
> +
> +		/* Reset control to value that will be first two frames in test. */
> +		int32_t expected = 100;
> +		ctrls.set(V4L2_CID_BRIGHTNESS, expected);
> +		ctrls.set(V4L2_CID_CONTRAST, expected);
> +		delayed->reset(&ctrls);

nit: the &ctrls does not align with the prototype of push(const
ControlList &ctrls);

Instead of defining
                DelayedControls::reset(ControlList *ctrls = nullptr);

I would override this as:
                DelayedControls::reset();
                DelayedControls::reset(const ControlList &ctrls);

it should be trivial to define one based on the other and you will
have a nicer:
                DelayedControls::reset(const ControlList &ctrls);
                DelayedControls::push(const ControlList &ctrls);

> +
> +		/*
> +		 * Queue all controls before any fake frame start. Note we
> +		 * can't queue up more then the delayed controls history size
> +		 * which is 16. Where one spot is used by the reset control.
> +		 */
> +		for (int32_t i = 0; i < 15; i++) {

i can be unsigned int here and in the next loop ?

Test looks good
Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>

Thanks
  j

> +			int32_t value = 10 + i;
> +
> +			ctrls.set(V4L2_CID_BRIGHTNESS, value);
> +			ctrls.set(V4L2_CID_CONTRAST, value);
> +			delayed->push(ctrls);
> +		}
> +
> +		/* Process all queued controls. */
> +		for (int32_t i = 0; i < 16; i++) {
> +			int32_t value = 10 + i;
> +
> +			delayed->frameStart(i);
> +
> +			ControlList result = delayed->get(i);
> +
> +			int32_t brightness = result.get(V4L2_CID_BRIGHTNESS).get<int32_t>();
> +			int32_t contrast = result.get(V4L2_CID_CONTRAST).get<int32_t>();
> +			if (brightness != expected || contrast != expected) {
> +				cerr << "Failed multi queue"
> +				     << " frame " << i
> +				     << " brightness " << brightness
> +				     << " contrast " << contrast
> +				     << " expected " << expected
> +				     << endl;
> +				return TestFail;
> +			}
> +
> +			expected = i < 1 ? expected : value - 1;
> +		}
> +
> +		return TestPass;
> +	}
> +
> +	int run()
> +	{
> +		int ret;
> +
> +		/* Test single control without delay. */
> +		ret = singleControlNoDelay();
> +		if (ret)
> +			return ret;
> +
> +		/* Test single control with delay. */
> +		ret = singleControlWithDelay();
> +		if (ret)
> +			return ret;
> +
> +		/* Test dual controls with different delays. */
> +		ret = dualControlsWithDelay(0);
> +		if (ret)
> +			return ret;
> +
> +		/* Test dual controls with non-zero sequence start. */
> +		ret = dualControlsWithDelay(10000);
> +		if (ret)
> +			return ret;
> +
> +		/* Test dual controls with sequence number wraparound. */
> +		ret = dualControlsWithDelay(UINT32_MAX - 50);
> +		if (ret)
> +			return ret;
> +
> +		/* Test control values produced faster then consumed. */
> +		ret = dualControlsMultiQueue();
> +		if (ret)
> +			return ret;
> +
> +		return TestPass;
> +	}
> +
> +	void cleanup()
> +	{
> +		delete dev_;
> +	}
> +
> +private:
> +	std::unique_ptr<DeviceEnumerator> enumerator_;
> +	std::shared_ptr<MediaDevice> media_;
> +	V4L2VideoDevice *dev_;
> +};
> +
> +TEST_REGISTER(DelayedControlsTest)
> diff --git a/test/meson.build b/test/meson.build
> index 0a1d434e399641bb..a683a657a439b4ff 100644
> --- a/test/meson.build
> +++ b/test/meson.build
> @@ -25,6 +25,7 @@ public_tests = [
>  internal_tests = [
>      ['byte-stream-buffer',              'byte-stream-buffer.cpp'],
>      ['camera-sensor',                   'camera-sensor.cpp'],
> +    ['delayed_contols',                 'delayed_contols.cpp'],
>      ['event',                           'event.cpp'],
>      ['event-dispatcher',                'event-dispatcher.cpp'],
>      ['event-thread',                    'event-thread.cpp'],
> --
> 2.29.2
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel


More information about the libcamera-devel mailing list