From patchwork Sat Jan 16 11:47:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 10876 X-Patchwork-Delegate: niklas.soderlund@ragnatech.se Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 58B8EBD808 for ; Sat, 16 Jan 2021 11:48:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 31B6568107; Sat, 16 Jan 2021 12:48:20 +0100 (CET) Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DA80D68105 for ; Sat, 16 Jan 2021 12:48:17 +0100 (CET) X-Halon-ID: b881d676-57f0-11eb-a076-005056917f90 Authorized-sender: niklas.soderlund@fsdn.se Received: from bismarck.berto.se (p4fca2458.dip0.t-ipconnect.de [79.202.36.88]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id b881d676-57f0-11eb-a076-005056917f90; Sat, 16 Jan 2021 12:48:16 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sat, 16 Jan 2021 12:47:59 +0100 Message-Id: <20210116114805.905397-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210116114805.905397-1-niklas.soderlund@ragnatech.se> References: <20210116114805.905397-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 2/8] test: delayed_controls: Add test case for DelayedControls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" 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 Reviewed-by: Jacopo Mondi --- * Changes since v4 - Store dev_ as std::unique_ptr<>. - Update comments. - Switch from uint32_t to unsigned int - Step brightness and contrast test 1 step apart. - s/int32_t/unsigned int/ for for loops in singleControlNoDelay(). * Changes since v3 - Update commit message. * Changes since v3 - Update commit message. - Update header documentation. - Add protected and override. - Use unsigned int instead of int32_t in loops. * Changes since v2 - Remove a unused LoC. - Add and remove blank lines. - Align number of loop iterations. --- test/delayed_contols.cpp | 297 +++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 298 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..50169b12e5664020 --- /dev/null +++ b/test/delayed_contols.cpp @@ -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 + +#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 delays = { + { V4L2_CID_BRIGHTNESS, 0 }, + }; + std::unique_ptr delayed = + std::make_unique(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(); + 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 delays = { + { V4L2_CID_BRIGHTNESS, 1 }, + }; + std::unique_ptr delayed = + std::make_unique(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(); + 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 delays = { + { V4L2_CID_BRIGHTNESS, 1 }, + { V4L2_CID_CONTRAST, 2 }, + }; + std::unique_ptr delayed = + std::make_unique(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 contrast = result.get(V4L2_CID_CONTRAST).get(); + 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 delays = { + { V4L2_CID_BRIGHTNESS, 1 }, + { V4L2_CID_CONTRAST, 2 }, + }; + std::unique_ptr delayed = + std::make_unique(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 contrast = result.get(V4L2_CID_CONTRAST).get(); + 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 enumerator_; + std::shared_ptr media_; + std::unique_ptr dev_; +}; + +TEST_REGISTER(DelayedControlsTest) diff --git a/test/meson.build b/test/meson.build index 7f0682ad9efed8f4..065c55866356ff1c 100644 --- a/test/meson.build +++ b/test/meson.build @@ -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'],