/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2020-2021, Google Inc. * * simple_capture.cpp - Simple capture helper */ #include "capture.h" #include #include using namespace libcamera; Capture::Capture(std::shared_ptr camera) : loop_(nullptr), camera_(camera), allocator_(std::make_unique(camera)) { } Capture::~Capture() { stop(); } void Capture::configure(Span roles) { config_ = camera_->generateConfiguration(roles); if (!config_) { std::cout << "Roles not supported by camera" << std::endl; GTEST_SKIP(); } /* * 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(), [](StreamConfiguration &l, StreamConfiguration &r) { return l.bufferCount < r.bufferCount; }); for (auto &stream : *config_) stream.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::start() { unsigned int i = 0; for (auto const &config : *config_) { Stream *stream = config.stream(); int count = allocator_->allocate(stream); ASSERT_GE(count, 0) << "Failed to allocate buffers for stream " << i; EXPECT_EQ(count, config.bufferCount) << "Allocated less buffers than expected for stream " << i; ++i; } 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 (auto const &config : *config_) { Stream *stream = config.stream(); allocator_->free(stream); } } /* CaptureBalanced */ CaptureBalanced::CaptureBalanced(std::shared_ptr camera) : Capture(camera) { } void CaptureBalanced::capture(unsigned int numRequests) { start(); /* No point in testing less requests then the camera depth. */ const unsigned int bufferCount = config_->at(0).bufferCount; if (bufferCount > numRequests) { std::cout << "Camera needs " << bufferCount << " requests, can't test only " << numRequests << std::endl; GTEST_SKIP(); } queueCount_ = 0; captureCount_ = 0; captureLimit_ = numRequests; /* Queue the recommended number of requests. */ for (unsigned int bufferIdx = 0; bufferIdx < bufferCount; ++bufferIdx) { std::unique_ptr request = camera_->createRequest(); ASSERT_TRUE(request) << "Can't create request"; /* Add buffers for each stream. */ unsigned int i = 0; for (const auto &config : *config_) { Stream *stream = config.stream(); const auto &buffers = allocator_->buffers(stream); ASSERT_EQ(request->addBuffer(stream, buffers[bufferIdx].get()), 0) << "Can't add buffers for stream " << i; ++i; } 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) : Capture(camera) { } void CaptureUnbalanced::capture(unsigned int numRequests) { start(); captureCount_ = 0; captureLimit_ = numRequests; /* Queue the recommended number of requests. */ const unsigned int bufferCount = config_->at(0).bufferCount; for (unsigned int bufferIdx = 0; bufferIdx < bufferCount; ++bufferIdx) { std::unique_ptr request = camera_->createRequest(); ASSERT_TRUE(request) << "Can't create request"; /* Add buffers for each stream. */ unsigned int i = 0; for (const auto &config : *config_) { Stream *stream = config.stream(); const auto &buffers = allocator_->buffers(stream); ASSERT_EQ(request->addBuffer(stream, buffers[bufferIdx].get()), 0) << "Can't add buffers for stream " << i; ++i; } 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); }