/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2020-2021, Google Inc. * * Simple capture helper */ #include "capture.h" #include #include using namespace libcamera; Capture::Capture(std::shared_ptr camera) : camera_(std::move(camera)), allocator_(camera_) { } Capture::~Capture() { stop(); } void Capture::configure(StreamRole role) { config_ = camera_->generateConfiguration({ role }); if (!config_) GTEST_SKIP() << "Role not supported by camera"; 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 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> &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 &buffer : buffers) { std::unique_ptr 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"; } void Capture::stop() { if (!config_ || !allocator_.allocated()) return; camera_->stop(); camera_->requestCompleted.disconnect(this); Stream *stream = config_->at(0).stream(); requests_.clear(); allocator_.free(stream); }