diff options
Diffstat (limited to 'src/apps/lc-compliance/helpers')
-rw-r--r-- | src/apps/lc-compliance/helpers/capture.cpp | 176 | ||||
-rw-r--r-- | src/apps/lc-compliance/helpers/capture.h | 45 |
2 files changed, 221 insertions, 0 deletions
diff --git a/src/apps/lc-compliance/helpers/capture.cpp b/src/apps/lc-compliance/helpers/capture.cpp new file mode 100644 index 00000000..2a3fa3b6 --- /dev/null +++ b/src/apps/lc-compliance/helpers/capture.cpp @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020-2021, Google Inc. + * + * Simple capture helper + */ + +#include "capture.h" + +#include <assert.h> + +#include <gtest/gtest.h> + +using namespace libcamera; + +Capture::Capture(std::shared_ptr<Camera> camera) + : camera_(std::move(camera)), allocator_(camera_) +{ +} + +Capture::~Capture() +{ + stop(); +} + +void Capture::configure(libcamera::Span<const libcamera::StreamRole> roles) +{ + assert(!roles.empty()); + + config_ = camera_->generateConfiguration(roles); + if (!config_) + GTEST_SKIP() << "Roles not supported by camera"; + + ASSERT_EQ(config_->size(), roles.size()) << "Unexpected number of streams in configuration"; + + /* + * Set the buffers count to the largest value across all streams. + * \todo: Should all streams from a Camera have the same buffer count ? + */ + auto largest = + std::max_element(config_->begin(), config_->end(), + [](const StreamConfiguration &l, const StreamConfiguration &r) + { return l.bufferCount < r.bufferCount; }); + + assert(largest != config_->end()); + + for (auto &cfg : *config_) + cfg.bufferCount = largest->bufferCount; + + if (config_->validate() != CameraConfiguration::Valid) { + config_.reset(); + FAIL() << "Configuration not valid"; + } + + if (camera_->configure(config_.get())) { + config_.reset(); + FAIL() << "Failed to configure camera"; + } +} + +void Capture::run(unsigned int captureLimit, std::optional<unsigned int> queueLimit) +{ + assert(!queueLimit || captureLimit <= *queueLimit); + + captureLimit_ = captureLimit; + queueLimit_ = queueLimit; + + captureCount_ = queueCount_ = 0; + + EventLoop loop; + loop_ = &loop; + + start(); + + for (const auto &request : requests_) + queueRequest(request.get()); + + EXPECT_EQ(loop_->exec(), 0); + + stop(); + + EXPECT_LE(captureLimit_, captureCount_); + EXPECT_LE(captureCount_, queueCount_); + EXPECT_TRUE(!queueLimit_ || queueCount_ <= *queueLimit_); +} + +int Capture::queueRequest(libcamera::Request *request) +{ + if (queueLimit_ && queueCount_ >= *queueLimit_) + return 0; + + int ret = camera_->queueRequest(request); + if (ret < 0) + return ret; + + queueCount_ += 1; + return 0; +} + +void Capture::requestComplete(Request *request) +{ + captureCount_++; + if (captureCount_ >= captureLimit_) { + loop_->exit(0); + return; + } + + EXPECT_EQ(request->status(), Request::Status::RequestComplete) + << "Request didn't complete successfully"; + + request->reuse(Request::ReuseBuffers); + if (queueRequest(request)) + loop_->exit(-EINVAL); +} + +void Capture::start() +{ + assert(config_); + assert(!config_->empty()); + assert(!allocator_.allocated()); + assert(requests_.empty()); + + const auto bufferCount = config_->at(0).bufferCount; + + /* No point in testing less requests then the camera depth. */ + if (queueLimit_ && *queueLimit_ < bufferCount) { + GTEST_SKIP() << "Camera needs " << bufferCount + << " requests, can't test only " << *queueLimit_; + } + + for (std::size_t i = 0; i < bufferCount; i++) { + std::unique_ptr<Request> request = camera_->createRequest(); + ASSERT_TRUE(request) << "Can't create request"; + requests_.push_back(std::move(request)); + } + + for (const auto &cfg : *config_) { + Stream *stream = cfg.stream(); + + int count = allocator_.allocate(stream); + ASSERT_GE(count, 0) << "Failed to allocate buffers"; + + const auto &buffers = allocator_.buffers(stream); + ASSERT_EQ(buffers.size(), bufferCount) << "Mismatching buffer count"; + + for (std::size_t i = 0; i < bufferCount; i++) { + ASSERT_EQ(requests_[i]->addBuffer(stream, buffers[i].get()), 0) + << "Failed to add buffer to request"; + } + } + + ASSERT_TRUE(allocator_.allocated()); + + camera_->requestCompleted.connect(this, &Capture::requestComplete); + + ASSERT_EQ(camera_->start(), 0) << "Failed to start camera"; +} + +void Capture::stop() +{ + if (!config_ || !allocator_.allocated()) + return; + + camera_->stop(); + + camera_->requestCompleted.disconnect(this); + + requests_.clear(); + + for (const auto &cfg : *config_) { + EXPECT_EQ(allocator_.free(cfg.stream()), 0) + << "Failed to free buffers associated with stream"; + } + + EXPECT_FALSE(allocator_.allocated()); +} diff --git a/src/apps/lc-compliance/helpers/capture.h b/src/apps/lc-compliance/helpers/capture.h new file mode 100644 index 00000000..ea01c11c --- /dev/null +++ b/src/apps/lc-compliance/helpers/capture.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020-2021, Google Inc. + * + * Simple capture helper + */ + +#pragma once + +#include <memory> +#include <optional> + +#include <libcamera/libcamera.h> + +#include "../common/event_loop.h" + +class Capture +{ +public: + Capture(std::shared_ptr<libcamera::Camera> camera); + ~Capture(); + + void configure(libcamera::Span<const libcamera::StreamRole> roles); + void run(unsigned int captureLimit, std::optional<unsigned int> queueLimit = {}); + +private: + LIBCAMERA_DISABLE_COPY_AND_MOVE(Capture) + + void start(); + void stop(); + + int queueRequest(libcamera::Request *request); + void requestComplete(libcamera::Request *request); + + std::shared_ptr<libcamera::Camera> camera_; + libcamera::FrameBufferAllocator allocator_; + std::unique_ptr<libcamera::CameraConfiguration> config_; + std::vector<std::unique_ptr<libcamera::Request>> requests_; + + EventLoop *loop_ = nullptr; + unsigned int captureLimit_ = 0; + std::optional<unsigned int> queueLimit_; + unsigned int captureCount_ = 0; + unsigned int queueCount_ = 0; +}; |