summaryrefslogtreecommitdiff
path: root/src/ipa/meson.build
AgeCommit message (Expand)Author
2020-05-16libcamera: Move internal headers to include/libcamera/internal/Laurent Pinchart
2020-05-13ipa: Only sign IPA modules that are being installedLaurent Pinchart
2020-05-13licenses: License all meson files under CC0-1.0Laurent Pinchart
2020-05-11libcamera: raspberrypi: Add components to meson buildNaushir Patuck
2020-05-11meson: Use files() instead of find_program() for internal scriptsLaurent Pinchart
2020-04-29libcamera: Regenerate IPA module signatures at install timeLaurent Pinchart
2020-04-28libcamera: ipa_proxy: Provide suport for IPA configuration filesLaurent Pinchart
2020-04-14libcamera: Add IPA module signing infrastructureLaurent Pinchart
2020-03-25libcamera: Make pipeline handlers selectable at compile timeLaurent Pinchart
2020-03-25ipa: Move vimc to a subdirectoryLaurent Pinchart
2019-11-20ipa: Switch to the plain C APIJacopo Mondi
2019-10-11libcamera: ipa: rkisp1: Add basic control of auto exposureNiklas Söderlund
2019-10-08ipa: meson: Give IPAs access to internal libcamera APIsJacopo Mondi
2019-10-08ipa: vimc: Rename ipa_dummy to ipa_vimcJacopo Mondi
2019-09-15ipa: Generate the two dummy IPA modules from the same sourceLaurent Pinchart
2019-07-12libcamera: ipa: meson: build dummy IPA that needs isolationPaul Elder
2019-06-05libcamera: ipa: add dummy IPA implementationPaul Elder
2019-06-05libcamera: ipa_manager: implement class for managing IPA modulesPaul Elder
n148'>148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * capture.cpp - Cam capture
 */

#include <chrono>
#include <iomanip>
#include <iostream>
#include <limits.h>
#include <sstream>

#include "capture.h"
#include "main.h"

using namespace libcamera;

Capture::Capture(std::shared_ptr<Camera> camera, CameraConfiguration *config)
	: camera_(camera), config_(config), writer_(nullptr)
{
}

int Capture::run(EventLoop *loop, const OptionsParser::Options &options)
{
	int ret;

	if (!camera_) {
		std::cout << "Can't capture without a camera" << std::endl;
		return -ENODEV;
	}

	ret = camera_->configure(config_);
	if (ret < 0) {
		std::cout << "Failed to configure camera" << std::endl;
		return ret;
	}

	streamName_.clear();
	for (unsigned int index = 0; index < config_->size(); ++index) {
		StreamConfiguration &cfg = config_->at(index);
		streamName_[cfg.stream()] = "stream" + std::to_string(index);
	}

	camera_->requestCompleted.connect(this, &Capture::requestComplete);

	if (options.isSet(OptFile)) {
		if (!options[OptFile].toString().empty())
			writer_ = new BufferWriter(options[OptFile]);
		else
			writer_ = new BufferWriter();
	}


	FrameBufferAllocator *allocator = new FrameBufferAllocator(camera_);

	ret = capture(loop, allocator);

	if (options.isSet(OptFile)) {
		delete writer_;
		writer_ = nullptr;
	}

	delete allocator;

	return ret;
}

int Capture::capture(EventLoop *loop, FrameBufferAllocator *allocator)
{
	int ret;

	/* Identify the stream with the least number of buffers. */
	unsigned int nbuffers = UINT_MAX;
	for (StreamConfiguration &cfg : *config_) {
		ret = allocator->allocate(cfg.stream());
		if (ret < 0) {
			std::cerr << "Can't allocate buffers" << std::endl;
			return -ENOMEM;
		}

		unsigned int allocated = allocator->buffers(cfg.stream()).size();
		nbuffers = std::min(nbuffers, allocated);
	}

	/*
	 * TODO: make cam tool smarter to support still capture by for
	 * example pushing a button. For now run all streams all the time.
	 */

	std::vector<Request *> requests;
	for (unsigned int i = 0; i < nbuffers; i++) {
		Request *request = camera_->createRequest();
		if (!request) {
			std::cerr << "Can't create request" << std::endl;
			return -ENOMEM;
		}

		for (StreamConfiguration &cfg : *config_) {
			Stream *stream = cfg.stream();
			const std::vector<std::unique_ptr<FrameBuffer>> &buffers =
				allocator->buffers(stream);
			const std::unique_ptr<FrameBuffer> &buffer = buffers[i];

			ret = request->addBuffer(stream, buffer.get());
			if (ret < 0) {
				std::cerr << "Can't set buffer for request"
					  << std::endl;
				return ret;
			}

			if (writer_)
				writer_->mapBuffer(buffer.get());
		}

		requests.push_back(request);
	}

	ret = camera_->start();
	if (ret) {
		std::cout << "Failed to start capture" << std::endl;
		return ret;
	}

	for (Request *request : requests) {
		ret = camera_->queueRequest(request);
		if (ret < 0) {
			std::cerr << "Can't queue request" << std::endl;
			camera_->stop();
			return ret;
		}
	}

	std::cout << "Capture until user interrupts by SIGINT" << std::endl;
	ret = loop->exec();
	if (ret)
		std::cout << "Failed to run capture loop" << std::endl;

	ret = camera_->stop();
	if (ret)
		std::cout << "Failed to stop capture" << std::endl;

	return ret;
}

void Capture::requestComplete(Request *request)
{
	if (request->status() == Request::RequestCancelled)
		return;

	const std::map<Stream *, FrameBuffer *> &buffers = request->buffers();

	std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
	double fps = std::chrono::duration_cast<std::chrono::milliseconds>(now - last_).count();
	fps = last_ != std::chrono::steady_clock::time_point() && fps
	    ? 1000.0 / fps : 0.0;
	last_ = now;

	std::stringstream info;
	info << "fps: " << std::fixed << std::setprecision(2) << fps;

	for (auto it = buffers.begin(); it != buffers.end(); ++it) {
		Stream *stream = it->first;
		FrameBuffer *buffer = it->second;
		const std::string &name = streamName_[stream];

		const FrameMetadata &metadata = buffer->metadata();

		info << " " << name
		     << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence
		     << " bytesused: ";

		unsigned int nplane = 0;
		for (const FrameMetadata::Plane &plane : metadata.planes) {
			info << plane.bytesused;
			if (++nplane < metadata.planes.size())
				info << "/";
		}

		if (writer_)
			writer_->write(buffer, name);
	}

	std::cout << info.str() << std::endl;

	/*
	 * Create a new request and populate it with one buffer for each
	 * stream.
	 */
	request = camera_->createRequest();
	if (!request) {
		std::cerr << "Can't create request" << std::endl;
		return;
	}

	for (auto it = buffers.begin(); it != buffers.end(); ++it) {
		Stream *stream = it->first;
		FrameBuffer *buffer = it->second;

		request->addBuffer(stream, buffer);
	}

	camera_->queueRequest(request);
}