test: delayed_controls: Add test case for DelayedControls
Add a test case for DelayedControls that exercises the setting of controls and reading back what controls were used for a particular frame. Also exercise corner cases such as a V4L2 device that does 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@ragnatech.se> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
This commit is contained in:
parent
3d4b7b0059
commit
5023ad293d
2 changed files with 298 additions and 0 deletions
297
test/delayed_contols.cpp
Normal file
297
test/delayed_contols.cpp
Normal file
|
@ -0,0 +1,297 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2020, Google Inc.
|
||||
*
|
||||
* 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()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
int init() override
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
dev_ = V4L2VideoDevice::fromEntityName(media_.get(), "vivid-000-vid-cap");
|
||||
if (dev_->open()) {
|
||||
cerr << "Failed to open video device" << endl;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
const ControlInfoMap &infoMap = dev_->controls();
|
||||
|
||||
/* Make sure the controls we require are present. */
|
||||
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_.get(), delays);
|
||||
ControlList ctrls;
|
||||
|
||||
/* Reset control to value not used in test. */
|
||||
ctrls.set(V4L2_CID_BRIGHTNESS, 1);
|
||||
dev_->setControls(&ctrls);
|
||||
|
||||
/* Test control without delay are set at once. */
|
||||
for (unsigned int i = 0; i < 100; i++) {
|
||||
int32_t value = 100 + i;
|
||||
|
||||
ctrls.set(V4L2_CID_BRIGHTNESS, value);
|
||||
delayed->push(ctrls);
|
||||
|
||||
delayed->applyControls(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_.get(), delays);
|
||||
ControlList ctrls;
|
||||
|
||||
/* Reset control to value that will be first in test. */
|
||||
int32_t expected = 4;
|
||||
ctrls.set(V4L2_CID_BRIGHTNESS, expected);
|
||||
dev_->setControls(&ctrls);
|
||||
delayed->reset();
|
||||
|
||||
/* Test single control with delay. */
|
||||
for (unsigned int i = 0; i < 100; i++) {
|
||||
int32_t value = 10 + i;
|
||||
|
||||
ctrls.set(V4L2_CID_BRIGHTNESS, value);
|
||||
delayed->push(ctrls);
|
||||
|
||||
delayed->applyControls(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_.get(), 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 + 1);
|
||||
dev_->setControls(&ctrls);
|
||||
delayed->reset();
|
||||
|
||||
/* Test dual control with delay. */
|
||||
for (unsigned int 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 + 1);
|
||||
delayed->push(ctrls);
|
||||
|
||||
delayed->applyControls(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 + 1) {
|
||||
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_.get(), 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);
|
||||
dev_->setControls(&ctrls);
|
||||
delayed->reset();
|
||||
|
||||
/*
|
||||
* 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 (unsigned int i = 0; i < 15; i++) {
|
||||
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 (unsigned int i = 0; i < 16; i++) {
|
||||
int32_t value = 10 + i;
|
||||
|
||||
delayed->applyControls(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() override
|
||||
{
|
||||
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 than consumed. */
|
||||
ret = dualControlsMultiQueue();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return TestPass;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<DeviceEnumerator> enumerator_;
|
||||
std::shared_ptr<MediaDevice> media_;
|
||||
std::unique_ptr<V4L2VideoDevice> dev_;
|
||||
};
|
||||
|
||||
TEST_REGISTER(DelayedControlsTest)
|
|
@ -29,6 +29,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'],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue