/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2020, Google Inc. * * simple_capture.cpp - Simple capture helper */ #include "simple_capture.h" using namespace libcamera; SimpleCapture::SimpleCapture(std::shared_ptr<Camera> camera) : loop_(nullptr), camera_(camera), allocator_(std::make_unique<FrameBufferAllocator>(camera)) { } SimpleCapture::~SimpleCapture() { } Results::Result SimpleCapture::configure(StreamRole role) { config_ = camera_->generateConfiguration({ role }); if (!config_) return { Results::Skip, "Role not supported by camera" }; if (config_->validate() != CameraConfiguration::Valid) { config_.reset(); return { Results::Fail, "Configuration not valid" }; } if (camera_->configure(config_.get())) { config_.reset(); return { Results::Fail, "Failed to configure camera" }; } return { Results::Pass, "Configure camera" }; } Results::Result SimpleCapture::start() { Stream *stream = config_->at(0).stream(); if (allocator_->allocate(stream) < 0) return { Results::Fail, "Failed to allocate buffers" }; if (camera_->start()) return { Results::Fail, "Failed to start camera" }; camera_->requestCompleted.connect(this, &SimpleCapture::requestComplete); return { Results::Pass, "Started camera" }; } void SimpleCapture::stop() { Stream *stream = config_->at(0).stream(); camera_->stop(); camera_->requestCompleted.disconnect(this, &SimpleCapture::requestComplete); allocator_->free(stream); } /* SimpleCaptureBalanced */ SimpleCaptureBalanced::SimpleCaptureBalanced(std::shared_ptr<Camera> camera) : SimpleCapture(camera) { } Results::Result SimpleCaptureBalanced::capture(unsigned int numRequests) { Results::Result ret = start(); if (ret.first != Results::Pass) return ret; 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) { /* Cache buffers.size() before we destroy it in stop() */ int buffers_size = buffers.size(); stop(); return { Results::Skip, "Camera needs " + std::to_string(buffers_size) + " requests, can't test only " + std::to_string(numRequests) }; } queueCount_ = 0; captureCount_ = 0; captureLimit_ = numRequests; /* Queue the recommended number of reqeuests. */ std::vector<std::unique_ptr<libcamera::Request>> requests; for (const std::unique_ptr<FrameBuffer> &buffer : buffers) { std::unique_ptr<Request> request = camera_->createRequest(); if (!request) { stop(); return { Results::Fail, "Can't create request" }; } if (request->addBuffer(stream, buffer.get())) { stop(); return { Results::Fail, "Can't set buffer for request" }; } if (queueRequest(request.get()) < 0) { stop(); return { Results::Fail, "Failed to queue request" }; } requests.push_back(std::move(request)); } /* Run capture session. */ loop_ = new EventLoop(); loop_->exec(); stop(); delete loop_; if (captureCount_ != captureLimit_) return { Results::Fail, "Got " + std::to_string(captureCount_) + " request, wanted " + std::to_string(captureLimit_) }; return { Results::Pass, "Balanced capture of " + std::to_string(numRequests) + " requests" }; } int SimpleCaptureBalanced::queueRequest(Request *request) { queueCount_++; if (queueCount_ > captureLimit_) return 0; return camera_->queueRequest(request); } void SimpleCaptureBalanced::requestComplete(Request *request) { captureCount_++; if (captureCount_ >= captureLimit_) { loop_->exit(0); return; } request->reuse(Request::ReuseBuffers); if (queueRequest(request)) loop_->exit(-EINVAL); } /* SimpleCaptureUnbalanced */ SimpleCaptureUnbalanced::SimpleCaptureUnbalanced(std::shared_ptr<Camera> camera) : SimpleCapture(camera) { } Results::Result SimpleCaptureUnbalanced::capture(unsigned int numRequests) { Results::Result ret = start(); if (ret.first != Results::Pass) return ret; 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 reqeuests. */ std::vector<std::unique_ptr<libcamera::Request>> requests; for (const std::unique_ptr<FrameBuffer> &buffer : buffers) { std::unique_ptr<Request> request = camera_->createRequest(); if (!request) { stop(); return { Results::Fail, "Can't create request" }; } if (request->addBuffer(stream, buffer.get())) { stop(); return { Results::Fail, "Can't set buffer for request" }; } if (camera_->queueRequest(request.get()) < 0) { stop(); return { Results::Fail, "Failed to queue request" }; } requests.push_back(std::move(request)); } /* Run capture session. */ loop_ = new EventLoop(); int status = loop_->exec(); stop(); delete loop_; return { status ? Results::Fail : Results::Pass, "Unbalanced capture of " + std::to_string(numRequests) + " requests" }; } void SimpleCaptureUnbalanced::requestComplete(Request *request) { captureCount_++; if (captureCount_ >= captureLimit_) { loop_->exit(0); return; } request->reuse(Request::ReuseBuffers); if (camera_->queueRequest(request)) loop_->exit(-EINVAL); }