apps: lc-compliance: Merge CaptureBalanced and CaptureUnbalanced

The above two classes have very similar implementations, in fact, the
only essential difference is how many requests are queued. `CaptureBalanced`
queues a predetermined number of requests, while `CaptureUnbalanced`
queues requests without limit.

This can be addressed by introducing a "capture" and a "queue" limit
into the `Capture` class, which determine at most how many requests
can be queued, and how many request completions are expected before
stopping.

Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
This commit is contained in:
Barnabás Pőcze 2024-12-19 16:58:42 +01:00
parent 995bb7e507
commit 74c0e8cbf1
3 changed files with 102 additions and 169 deletions

View file

@ -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_(std::move(camera)),
allocator_(camera_)
: camera_(std::move(camera)), allocator_(camera_)
{
}
@ -40,14 +41,91 @@ void Capture::configure(StreamRole role)
}
}
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());
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";
const std::vector<std::unique_ptr<FrameBuffer>> &buffers = allocator_.buffers(stream);
/* No point in testing less requests then the camera depth. */
if (queueLimit_ && *queueLimit_ < buffers.size()) {
GTEST_SKIP() << "Camera needs " << buffers.size()
<< " requests, can't test only " << *queueLimit_;
}
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";
requests_.push_back(std::move(request));
}
camera_->requestCompleted.connect(this, &Capture::requestComplete);
ASSERT_EQ(camera_->start(), 0) << "Failed to start camera";
@ -66,127 +144,3 @@ void Capture::stop()
requests_.clear();
allocator_.free(stream);
}
/* CaptureBalanced */
CaptureBalanced::CaptureBalanced(std::shared_ptr<Camera> camera)
: Capture(std::move(camera))
{
}
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) {
GTEST_SKIP() << "Camera needs " << buffers.size()
<< " requests, can't test only " << numRequests;
}
queueCount_ = 0;
captureCount_ = 0;
captureLimit_ = numRequests;
/* 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_);
}
int CaptureBalanced::queueRequest(Request *request)
{
queueCount_++;
if (queueCount_ > captureLimit_)
return 0;
return camera_->queueRequest(request);
}
void CaptureBalanced::requestComplete(Request *request)
{
EXPECT_EQ(request->status(), Request::Status::RequestComplete)
<< "Request didn't complete successfully";
captureCount_++;
if (captureCount_ >= captureLimit_) {
loop_->exit(0);
return;
}
request->reuse(Request::ReuseBuffers);
if (queueRequest(request))
loop_->exit(-EINVAL);
}
/* CaptureUnbalanced */
CaptureUnbalanced::CaptureUnbalanced(std::shared_ptr<Camera> camera)
: Capture(std::move(camera))
{
}
void CaptureUnbalanced::capture(unsigned int numRequests)
{
start();
Stream *stream = config_->at(0).stream();
const std::vector<std::unique_ptr<FrameBuffer>> &buffers = allocator_.buffers(stream);
captureCount_ = 0;
captureLimit_ = numRequests;
/* 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(camera_->queueRequest(request.get()), 0) << "Failed to queue request";
requests_.push_back(std::move(request));
}
/* Run capture session. */
loop_ = new EventLoop();
int status = loop_->exec();
stop();
delete loop_;
ASSERT_EQ(status, 0);
}
void CaptureUnbalanced::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 (camera_->queueRequest(request))
loop_->exit(-EINVAL);
}

View file

@ -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::StreamRole role);
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_;
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;
};

View file

@ -87,11 +87,11 @@ TEST_P(SingleStream, Capture)
{
auto [role, numRequests] = GetParam();
CaptureBalanced capture(camera_);
Capture capture(camera_);
capture.configure(role);
capture.capture(numRequests);
capture.run(numRequests, numRequests);
}
/*
@ -106,12 +106,12 @@ TEST_P(SingleStream, CaptureStartStop)
auto [role, numRequests] = GetParam();
unsigned int numRepeats = 3;
CaptureBalanced capture(camera_);
Capture capture(camera_);
capture.configure(role);
for (unsigned int starts = 0; starts < numRepeats; starts++)
capture.capture(numRequests);
capture.run(numRequests, numRequests);
}
/*
@ -125,11 +125,11 @@ TEST_P(SingleStream, UnbalancedStop)
{
auto [role, numRequests] = GetParam();
CaptureUnbalanced capture(camera_);
Capture capture(camera_);
capture.configure(role);
capture.capture(numRequests);
capture.run(numRequests);
}
INSTANTIATE_TEST_SUITE_P(CaptureTests,