summaryrefslogtreecommitdiff
path: root/src/apps/lc-compliance
diff options
context:
space:
mode:
Diffstat (limited to 'src/apps/lc-compliance')
-rw-r--r--src/apps/lc-compliance/environment.h2
-rw-r--r--src/apps/lc-compliance/helpers/capture.cpp202
-rw-r--r--src/apps/lc-compliance/helpers/capture.h53
-rw-r--r--src/apps/lc-compliance/main.cpp42
-rw-r--r--src/apps/lc-compliance/tests/capture_test.cpp103
5 files changed, 180 insertions, 222 deletions
diff --git a/src/apps/lc-compliance/environment.h b/src/apps/lc-compliance/environment.h
index 543e5372..834c722e 100644
--- a/src/apps/lc-compliance/environment.h
+++ b/src/apps/lc-compliance/environment.h
@@ -23,5 +23,5 @@ private:
Environment() = default;
std::string cameraId_;
- libcamera::CameraManager *cm_;
+ libcamera::CameraManager *cm_ = nullptr;
};
diff --git a/src/apps/lc-compliance/helpers/capture.cpp b/src/apps/lc-compliance/helpers/capture.cpp
index 90c1530b..2a3fa3b6 100644
--- a/src/apps/lc-compliance/helpers/capture.cpp
+++ b/src/apps/lc-compliance/helpers/capture.cpp
@@ -7,13 +7,14 @@
#include "capture.h"
+#include <assert.h>
+
#include <gtest/gtest.h>
using namespace libcamera;
Capture::Capture(std::shared_ptr<Camera> camera)
- : loop_(nullptr), camera_(camera),
- allocator_(std::make_unique<FrameBufferAllocator>(camera))
+ : camera_(std::move(camera)), allocator_(camera_)
{
}
@@ -22,14 +23,29 @@ Capture::~Capture()
stop();
}
-void Capture::configure(StreamRole role)
+void Capture::configure(libcamera::Span<const libcamera::StreamRole> roles)
{
- config_ = camera_->generateConfiguration({ role });
+ assert(!roles.empty());
- if (!config_) {
- std::cout << "Role not supported by camera" << std::endl;
- GTEST_SKIP();
- }
+ 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();
@@ -42,155 +58,119 @@ void Capture::configure(StreamRole role)
}
}
-void Capture::start()
+void Capture::run(unsigned int captureLimit, std::optional<unsigned int> queueLimit)
{
- Stream *stream = config_->at(0).stream();
- int count = allocator_->allocate(stream);
-
- ASSERT_GE(count, 0) << "Failed to allocate buffers";
- EXPECT_EQ(count, config_->at(0).bufferCount) << "Allocated less buffers than expected";
-
- 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();
+ assert(!queueLimit || captureLimit <= *queueLimit);
- camera_->requestCompleted.disconnect(this);
+ captureLimit_ = captureLimit;
+ queueLimit_ = queueLimit;
- Stream *stream = config_->at(0).stream();
- requests_.clear();
- allocator_->free(stream);
-}
+ captureCount_ = queueCount_ = 0;
-/* CaptureBalanced */
-
-CaptureBalanced::CaptureBalanced(std::shared_ptr<Camera> camera)
- : Capture(camera)
-{
-}
+ EventLoop loop;
+ loop_ = &loop;
-void CaptureBalanced::capture(unsigned int numRequests)
-{
start();
- Stream *stream = config_->at(0).stream();
- const std::vector<std::unique_ptr<FrameBuffer>> &buffers = allocator_->buffers(stream);
-
- /* No point in testing less requests then the camera depth. */
- if (buffers.size() > numRequests) {
- std::cout << "Camera needs " + std::to_string(buffers.size())
- + " requests, can't test only "
- + std::to_string(numRequests) << std::endl;
- GTEST_SKIP();
- }
+ for (const auto &request : requests_)
+ queueRequest(request.get());
- queueCount_ = 0;
- captureCount_ = 0;
- captureLimit_ = numRequests;
+ EXPECT_EQ(loop_->exec(), 0);
- /* Queue the recommended number of requests. */
- for (const std::unique_ptr<FrameBuffer> &buffer : buffers) {
- std::unique_ptr<Request> request = camera_->createRequest();
- ASSERT_TRUE(request) << "Can't create request";
-
- ASSERT_EQ(request->addBuffer(stream, buffer.get()), 0) << "Can't set buffer for request";
-
- ASSERT_EQ(queueRequest(request.get()), 0) << "Failed to queue request";
-
- requests_.push_back(std::move(request));
- }
-
- /* Run capture session. */
- loop_ = new EventLoop();
- loop_->exec();
stop();
- delete loop_;
- ASSERT_EQ(captureCount_, captureLimit_);
+ EXPECT_LE(captureLimit_, captureCount_);
+ EXPECT_LE(captureCount_, queueCount_);
+ EXPECT_TRUE(!queueLimit_ || queueCount_ <= *queueLimit_);
}
-int CaptureBalanced::queueRequest(Request *request)
+int Capture::queueRequest(libcamera::Request *request)
{
- queueCount_++;
- if (queueCount_ > captureLimit_)
+ if (queueLimit_ && queueCount_ >= *queueLimit_)
return 0;
- return camera_->queueRequest(request);
+ int ret = camera_->queueRequest(request);
+ if (ret < 0)
+ return ret;
+
+ queueCount_ += 1;
+ return 0;
}
-void CaptureBalanced::requestComplete(Request *request)
+void Capture::requestComplete(Request *request)
{
- EXPECT_EQ(request->status(), Request::Status::RequestComplete)
- << "Request didn't complete successfully";
-
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);
}
-/* CaptureUnbalanced */
-
-CaptureUnbalanced::CaptureUnbalanced(std::shared_ptr<Camera> camera)
- : Capture(camera)
-{
-}
-
-void CaptureUnbalanced::capture(unsigned int numRequests)
+void Capture::start()
{
- start();
+ assert(config_);
+ assert(!config_->empty());
+ assert(!allocator_.allocated());
+ assert(requests_.empty());
- Stream *stream = config_->at(0).stream();
- const std::vector<std::unique_ptr<FrameBuffer>> &buffers = allocator_->buffers(stream);
+ const auto bufferCount = config_->at(0).bufferCount;
- captureCount_ = 0;
- captureLimit_ = numRequests;
+ /* 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_;
+ }
- /* Queue the recommended number of requests. */
- for (const std::unique_ptr<FrameBuffer> &buffer : buffers) {
+ 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));
+ }
- ASSERT_EQ(request->addBuffer(stream, buffer.get()), 0) << "Can't set buffer for request";
+ for (const auto &cfg : *config_) {
+ Stream *stream = cfg.stream();
- ASSERT_EQ(camera_->queueRequest(request.get()), 0) << "Failed to queue request";
+ int count = allocator_.allocate(stream);
+ ASSERT_GE(count, 0) << "Failed to allocate buffers";
- requests_.push_back(std::move(request));
+ 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";
+ }
}
- /* Run capture session. */
- loop_ = new EventLoop();
- int status = loop_->exec();
- stop();
- delete loop_;
+ ASSERT_TRUE(allocator_.allocated());
- ASSERT_EQ(status, 0);
+ camera_->requestCompleted.connect(this, &Capture::requestComplete);
+
+ ASSERT_EQ(camera_->start(), 0) << "Failed to start camera";
}
-void CaptureUnbalanced::requestComplete(Request *request)
+void Capture::stop()
{
- captureCount_++;
- if (captureCount_ >= captureLimit_) {
- loop_->exit(0);
+ if (!config_ || !allocator_.allocated())
return;
- }
- EXPECT_EQ(request->status(), Request::Status::RequestComplete)
- << "Request didn't complete successfully";
+ camera_->stop();
- request->reuse(Request::ReuseBuffers);
- if (camera_->queueRequest(request))
- loop_->exit(-EINVAL);
+ 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
index 19b6927c..ea01c11c 100644
--- a/src/apps/lc-compliance/helpers/capture.h
+++ b/src/apps/lc-compliance/helpers/capture.h
@@ -8,6 +8,7 @@
#pragma once
#include <memory>
+#include <optional>
#include <libcamera/libcamera.h>
@@ -16,51 +17,29 @@
class Capture
{
public:
- void configure(libcamera::StreamRole role);
-
-protected:
Capture(std::shared_ptr<libcamera::Camera> camera);
- virtual ~Capture();
+ ~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();
- virtual void requestComplete(libcamera::Request *request) = 0;
-
- EventLoop *loop_;
+ int queueRequest(libcamera::Request *request);
+ void requestComplete(libcamera::Request *request);
std::shared_ptr<libcamera::Camera> camera_;
- std::unique_ptr<libcamera::FrameBufferAllocator> allocator_;
+ libcamera::FrameBufferAllocator allocator_;
std::unique_ptr<libcamera::CameraConfiguration> config_;
std::vector<std::unique_ptr<libcamera::Request>> requests_;
-};
-
-class CaptureBalanced : public Capture
-{
-public:
- CaptureBalanced(std::shared_ptr<libcamera::Camera> camera);
-
- void capture(unsigned int numRequests);
-
-private:
- int queueRequest(libcamera::Request *request);
- void requestComplete(libcamera::Request *request) override;
-
- unsigned int queueCount_;
- unsigned int captureCount_;
- unsigned int captureLimit_;
-};
-
-class CaptureUnbalanced : public Capture
-{
-public:
- CaptureUnbalanced(std::shared_ptr<libcamera::Camera> camera);
-
- void capture(unsigned int numRequests);
-
-private:
- void requestComplete(libcamera::Request *request) override;
- unsigned int captureCount_;
- unsigned int captureLimit_;
+ EventLoop *loop_ = nullptr;
+ unsigned int captureLimit_ = 0;
+ std::optional<unsigned int> queueLimit_;
+ unsigned int captureCount_ = 0;
+ unsigned int queueCount_ = 0;
};
diff --git a/src/apps/lc-compliance/main.cpp b/src/apps/lc-compliance/main.cpp
index 3f1d2a61..e9f0ffbb 100644
--- a/src/apps/lc-compliance/main.cpp
+++ b/src/apps/lc-compliance/main.cpp
@@ -45,13 +45,11 @@ class ThrowListener : public testing::EmptyTestEventListener
static void listCameras(CameraManager *cm)
{
for (const std::shared_ptr<Camera> &cam : cm->cameras())
- std::cout << "- " << cam.get()->id() << std::endl;
+ std::cout << "- " << cam->id() << std::endl;
}
static int initCamera(CameraManager *cm, OptionsParser::Options options)
{
- std::shared_ptr<Camera> camera;
-
int ret = cm->start();
if (ret) {
std::cout << "Failed to start camera manager: "
@@ -66,7 +64,7 @@ static int initCamera(CameraManager *cm, OptionsParser::Options options)
}
const std::string &cameraId = options[OptCamera];
- camera = cm->get(cameraId);
+ std::shared_ptr<Camera> camera = cm->get(cameraId);
if (!camera) {
std::cout << "Camera " << cameraId << " not found, available cameras:" << std::endl;
listCameras(cm);
@@ -82,45 +80,27 @@ static int initCamera(CameraManager *cm, OptionsParser::Options options)
static int initGtestParameters(char *arg0, OptionsParser::Options options)
{
- const std::map<std::string, std::string> gtestFlags = { { "list", "--gtest_list_tests" },
- { "filter", "--gtest_filter" } };
-
- int argc = 0;
+ std::vector<const char *> argv;
std::string filterParam;
- /*
- * +2 to have space for both the 0th argument that is needed but not
- * used and the null at the end.
- */
- char **argv = new char *[(gtestFlags.size() + 2)];
- if (!argv)
- return -ENOMEM;
-
- argv[0] = arg0;
- argc++;
+ argv.push_back(arg0);
- if (options.isSet(OptList)) {
- argv[argc] = const_cast<char *>(gtestFlags.at("list").c_str());
- argc++;
- }
+ if (options.isSet(OptList))
+ argv.push_back("--gtest_list_tests");
if (options.isSet(OptFilter)) {
/*
* The filter flag needs to be passed as a single parameter, in
* the format --gtest_filter=filterStr
*/
- filterParam = gtestFlags.at("filter") + "=" +
- static_cast<const std::string &>(options[OptFilter]);
-
- argv[argc] = const_cast<char *>(filterParam.c_str());
- argc++;
+ filterParam = "--gtest_filter=" + options[OptFilter].toString();
+ argv.push_back(filterParam.c_str());
}
- argv[argc] = nullptr;
-
- ::testing::InitGoogleTest(&argc, argv);
+ argv.push_back(nullptr);
- delete[] argv;
+ int argc = argv.size();
+ ::testing::InitGoogleTest(&argc, const_cast<char **>(argv.data()));
return 0;
}
diff --git a/src/apps/lc-compliance/tests/capture_test.cpp b/src/apps/lc-compliance/tests/capture_test.cpp
index ad3a1da2..d02caa8a 100644
--- a/src/apps/lc-compliance/tests/capture_test.cpp
+++ b/src/apps/lc-compliance/tests/capture_test.cpp
@@ -8,26 +8,23 @@
#include "capture.h"
-#include <iostream>
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <vector>
#include <gtest/gtest.h>
#include "environment.h"
-using namespace libcamera;
+namespace {
-const std::vector<int> NUMREQUESTS = { 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
-const std::vector<StreamRole> ROLES = {
- StreamRole::Raw,
- StreamRole::StillCapture,
- StreamRole::VideoRecording,
- StreamRole::Viewfinder
-};
+using namespace libcamera;
-class SingleStream : public testing::TestWithParam<std::tuple<StreamRole, int>>
+class SimpleCapture : public testing::TestWithParam<std::tuple<std::vector<StreamRole>, int>>
{
public:
- static std::string nameParameters(const testing::TestParamInfo<SingleStream::ParamType> &info);
+ static std::string nameParameters(const testing::TestParamInfo<SimpleCapture::ParamType> &info);
protected:
void SetUp() override;
@@ -40,7 +37,7 @@ protected:
* We use gtest's SetUp() and TearDown() instead of constructor and destructor
* in order to be able to assert on them.
*/
-void SingleStream::SetUp()
+void SimpleCapture::SetUp()
{
Environment *env = Environment::get();
@@ -49,7 +46,7 @@ void SingleStream::SetUp()
ASSERT_EQ(camera_->acquire(), 0);
}
-void SingleStream::TearDown()
+void SimpleCapture::TearDown()
{
if (!camera_)
return;
@@ -58,19 +55,17 @@ void SingleStream::TearDown()
camera_.reset();
}
-std::string SingleStream::nameParameters(const testing::TestParamInfo<SingleStream::ParamType> &info)
+std::string SimpleCapture::nameParameters(const testing::TestParamInfo<SimpleCapture::ParamType> &info)
{
- std::map<StreamRole, std::string> rolesMap = {
- { StreamRole::Raw, "Raw" },
- { StreamRole::StillCapture, "StillCapture" },
- { StreamRole::VideoRecording, "VideoRecording" },
- { StreamRole::Viewfinder, "Viewfinder" }
- };
+ const auto &[roles, numRequests] = info.param;
+ std::ostringstream ss;
- std::string roleName = rolesMap[std::get<0>(info.param)];
- std::string numRequestsName = std::to_string(std::get<1>(info.param));
+ for (StreamRole r : roles)
+ ss << r << '_';
- return roleName + "_" + numRequestsName;
+ ss << '_' << numRequests;
+
+ return ss.str();
}
/*
@@ -80,15 +75,15 @@ std::string SingleStream::nameParameters(const testing::TestParamInfo<SingleStre
* failure is a camera that completes less requests than the number of requests
* queued.
*/
-TEST_P(SingleStream, Capture)
+TEST_P(SimpleCapture, Capture)
{
- auto [role, numRequests] = GetParam();
+ const auto &[roles, numRequests] = GetParam();
- CaptureBalanced capture(camera_);
+ Capture capture(camera_);
- capture.configure(role);
+ capture.configure(roles);
- capture.capture(numRequests);
+ capture.run(numRequests, numRequests);
}
/*
@@ -98,17 +93,17 @@ TEST_P(SingleStream, Capture)
* a camera that does not clean up correctly in its error path but is only
* tested by single-capture applications.
*/
-TEST_P(SingleStream, CaptureStartStop)
+TEST_P(SimpleCapture, CaptureStartStop)
{
- auto [role, numRequests] = GetParam();
+ const auto &[roles, numRequests] = GetParam();
unsigned int numRepeats = 3;
- CaptureBalanced capture(camera_);
+ Capture capture(camera_);
- capture.configure(role);
+ capture.configure(roles);
for (unsigned int starts = 0; starts < numRepeats; starts++)
- capture.capture(numRequests);
+ capture.run(numRequests, numRequests);
}
/*
@@ -118,19 +113,43 @@ TEST_P(SingleStream, CaptureStartStop)
* is a camera that does not handle cancelation of buffers coming back from the
* video device while stopping.
*/
-TEST_P(SingleStream, UnbalancedStop)
+TEST_P(SimpleCapture, UnbalancedStop)
{
- auto [role, numRequests] = GetParam();
+ const auto &[roles, numRequests] = GetParam();
- CaptureUnbalanced capture(camera_);
+ Capture capture(camera_);
- capture.configure(role);
+ capture.configure(roles);
- capture.capture(numRequests);
+ capture.run(numRequests);
}
-INSTANTIATE_TEST_SUITE_P(CaptureTests,
- SingleStream,
- testing::Combine(testing::ValuesIn(ROLES),
+const int NUMREQUESTS[] = { 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
+
+const std::vector<StreamRole> SINGLEROLES[] = {
+ { StreamRole::Raw, },
+ { StreamRole::StillCapture, },
+ { StreamRole::VideoRecording, },
+ { StreamRole::Viewfinder, },
+};
+
+const std::vector<StreamRole> MULTIROLES[] = {
+ { StreamRole::Raw, StreamRole::StillCapture },
+ { StreamRole::Raw, StreamRole::VideoRecording },
+ { StreamRole::StillCapture, StreamRole::VideoRecording },
+ { StreamRole::VideoRecording, StreamRole::VideoRecording },
+};
+
+INSTANTIATE_TEST_SUITE_P(SingleStream,
+ SimpleCapture,
+ testing::Combine(testing::ValuesIn(SINGLEROLES),
testing::ValuesIn(NUMREQUESTS)),
- SingleStream::nameParameters);
+ SimpleCapture::nameParameters);
+
+INSTANTIATE_TEST_SUITE_P(MultiStream,
+ SimpleCapture,
+ testing::Combine(testing::ValuesIn(MULTIROLES),
+ testing::ValuesIn(NUMREQUESTS)),
+ SimpleCapture::nameParameters);
+
+} /* namespace */