From patchwork Fri May 20 16:52:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 15992 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id BE620C3256 for ; Fri, 20 May 2022 16:52:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8C07C65663; Fri, 20 May 2022 18:52:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1653065567; bh=hEJJe5w8QJJooa3hPsDePFHdlUX+koyav8Jth3XZw0Q=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=afsyK0abCyeGLFNTSa+utl8S+/ZDH7NEBi34ok2uL4klL+D6KAPLdxYgxU/2XcD13 0LKKB7u7hvSQEXx3iW8N2Zd8Y5LocIv8Emt4FMJLshNpbsXbypsTLvMb5ClnZ91UHb f1KHXIRzto3fNDrkpNwr2O6cyDW2Ocr6fihKT6s+ax1G4oiXgqfqgCRGG4GGIIT6cP bJB8O+mvvdYpt/jsyZDrNv3SXBd8h892ZdDZnAf2r/IIhIjpUAc9tvJbuQz7osMfPD enh8jemMIRmTD0Nr0hRr1AW8XZJYoRJdIACUZahyqJ7jBBIXdoUw3dgS4ORhDhh6xd vzgDeNKH9WQiQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 62FD761FB9 for ; Fri, 20 May 2022 18:52:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="RibV+j8c"; dkim-atps=neutral Received: from localhost.localdomain (unknown [45.131.31.124]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F0A826D1; Fri, 20 May 2022 18:52:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1653065565; bh=hEJJe5w8QJJooa3hPsDePFHdlUX+koyav8Jth3XZw0Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RibV+j8cat45zTyGzvOzMesNDCuXYh21TMaZw/jHW6nIRZLZJsw5N7AxOId0uDBwk SXGg87Rm/GZfVNmM9GZJAndHMczc/DsBHmeN0JRTlf6PYm3BYSj7n1L+cmZct8MTLo G5gpKmbmLVkOgZ4BLhGhDTu70qYDxgatb69A6Lvc= To: libcamera-devel@lists.libcamera.org Date: Fri, 20 May 2022 19:52:32 +0300 Message-Id: <20220520165234.7642-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220520165234.7642-1-laurent.pinchart@ideasonboard.com> References: <20220520165234.7642-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 1/3] cam: Add a parser for capture scripts X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Jacopo Mondi Add a parser class to the cam test application to control the capture operations through a yaml script. The capture script currently allow to specify a list of controls and their associated values to be applied per-frame. Also add a trivial capture script example to showcase the intended script structure. Signed-off-by: Jacopo Mondi Reviewed-by: Jacopo Mondi --- Changes since v1: - Add SPDX license identifier to capture-script.yaml - Drop gcc 7 support as libcamera requires gcc 8 or newer - Make scriptPath_ a local variable in CaptureScript constructor - Drop file check as we want to accept symlinks too - Pass const reference to fileName to CaptureScript constructor - Avoid manual deletes of tokens - Simplify and improve error message handling - Print line and column number in error message - Simplify handling of key/value parsing - Simplify parser deletion - Don't consume last tokens as that's not needed. - Simplify CaptureScript::unpackFailure() - Switch to the simpler event API - Typo fixes --- src/cam/capture-script.yaml | 46 +++++ src/cam/capture_script.cpp | 334 ++++++++++++++++++++++++++++++++++++ src/cam/capture_script.h | 60 +++++++ src/cam/meson.build | 2 + 4 files changed, 442 insertions(+) create mode 100644 src/cam/capture-script.yaml create mode 100644 src/cam/capture_script.cpp create mode 100644 src/cam/capture_script.h diff --git a/src/cam/capture-script.yaml b/src/cam/capture-script.yaml new file mode 100644 index 000000000000..6a749bc60cf7 --- /dev/null +++ b/src/cam/capture-script.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: CC0-1.0 + +# Capture script example +# +# A capture script allows to associate a list of controls and their values +# to frame numbers. + +# \todo Formally define the capture script structure with a schema + +# Notes: +# - Controls have to be specified by name, as defined in the +# libcamera::controls:: enumeration +# - Controls not supported by the camera currently operated are ignored +# - Frame numbers shall be monotonically incrementing, gaps are allowed + +# Example: +frames: + - 1: + Brightness: 0.0 + + - 40: + Brightness: 0.2 + + - 80: + Brightness: 0.4 + + - 120: + Brightness: 0.8 + + - 160: + Brightness: 0.4 + + - 200: + Brightness: 0.2 + + - 240: + Brightness: 0.0 + + - 280: + Brightness: -0.2 + + - 300: + Brightness: -0.4 + + - 340: + Brightness: -0.8 diff --git a/src/cam/capture_script.cpp b/src/cam/capture_script.cpp new file mode 100644 index 000000000000..8e9120321a25 --- /dev/null +++ b/src/cam/capture_script.cpp @@ -0,0 +1,334 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * capture_script.cpp - Capture session configuration script + */ + +#include "capture_script.h" + +#include +#include +#include + +using namespace libcamera; + +CaptureScript::CaptureScript(std::shared_ptr camera, + const std::string &fileName) + : camera_(camera), valid_(false) +{ + FILE *fh = fopen(fileName.c_str(), "r"); + if (!fh) { + int ret = -errno; + std::cerr << "Failed to open capture script " << fileName + << ": " << strerror(-ret) << std::endl; + return; + } + + /* + * Map the camera's controls to their name so that they can be + * easily identified when parsing the script file. + */ + for (const auto &[control, info] : camera_->controls()) + controls_[control->name()] = control; + + int ret = parseScript(fh); + fclose(fh); + if (ret) + return; + + valid_ = true; +} + +/* Retrieve the control list associated with a frame number. */ +const ControlList &CaptureScript::frameControls(unsigned int frame) +{ + static ControlList controls{}; + + auto it = frameControls_.find(frame); + if (it == frameControls_.end()) + return controls; + + return it->second; +} + +CaptureScript::EventPtr CaptureScript::nextEvent(yaml_event_type_t expectedType) +{ + EventPtr event(new yaml_event_t); + + if (!yaml_parser_parse(&parser_, event.get())) + return nullptr; + + if (expectedType != YAML_NO_EVENT && !checkEvent(event, expectedType)) + return nullptr; + + return event; +} + +bool CaptureScript::checkEvent(const EventPtr &event, yaml_event_type_t expectedType) const +{ + if (event->type != expectedType) { + std::cerr << "Capture script error on line " << event->start_mark.line + << " column " << event->start_mark.column << ": " + << "Expected " << eventTypeName(expectedType) + << " event, got " << eventTypeName(event->type) + << std::endl; + return false; + } + + return true; +} + +std::string CaptureScript::eventScalarValue(const EventPtr &event) +{ + return std::string(reinterpret_cast(event->data.scalar.value), + event->data.scalar.length); +} + +std::string CaptureScript::eventTypeName(yaml_event_type_t type) +{ + static const std::map typeNames = { + { YAML_STREAM_START_EVENT, "stream-start" }, + { YAML_STREAM_END_EVENT, "stream-end" }, + { YAML_DOCUMENT_START_EVENT, "document-start" }, + { YAML_DOCUMENT_END_EVENT, "document-end" }, + { YAML_ALIAS_EVENT, "alias" }, + { YAML_SCALAR_EVENT, "scalar" }, + { YAML_SEQUENCE_START_EVENT, "sequence-start" }, + { YAML_SEQUENCE_END_EVENT, "sequence-end" }, + { YAML_MAPPING_START_EVENT, "mapping-start" }, + { YAML_MAPPING_END_EVENT, "mapping-end" }, + }; + + auto it = typeNames.find(type); + if (it == typeNames.end()) + return "[type " + std::to_string(type) + "]"; + + return it->second; +} + +int CaptureScript::parseScript(FILE *script) +{ + int ret = yaml_parser_initialize(&parser_); + if (!ret) { + std::cerr << "Failed to initialize yaml parser" << std::endl; + return ret; + } + + /* Delete the parser upon function exit. */ + struct ParserDeleter { + ParserDeleter(yaml_parser_t *parser) : parser_(parser) { } + ~ParserDeleter() { yaml_parser_delete(parser_); } + yaml_parser_t *parser_; + } deleter(&parser_); + + yaml_parser_set_input_file(&parser_, script); + + EventPtr event = nextEvent(YAML_STREAM_START_EVENT); + if (!event) + return -EINVAL; + + event = nextEvent(YAML_DOCUMENT_START_EVENT); + if (!event) + return -EINVAL; + + event = nextEvent(YAML_MAPPING_START_EVENT); + if (!event) + return -EINVAL; + + while (1) { + event = nextEvent(); + if (!event) + return -EINVAL; + + if (event->type == YAML_MAPPING_END_EVENT) + return 0; + + if (!checkEvent(event, YAML_SCALAR_EVENT)) + return -EINVAL; + + std::string section = eventScalarValue(event); + + if (section == "frames") { + parseFrames(); + } else { + std::cerr << "Unsupported section '" << section << "'" + << std::endl; + return -EINVAL; + } + } +} + +int CaptureScript::parseFrames() +{ + EventPtr event = nextEvent(YAML_SEQUENCE_START_EVENT); + if (!event) + return -EINVAL; + + while (1) { + event = nextEvent(); + if (!event) + return -EINVAL; + + if (event->type == YAML_SEQUENCE_END_EVENT) + return 0; + + int ret = parseFrame(std::move(event)); + if (ret) + return ret; + } +} + +int CaptureScript::parseFrame(EventPtr event) +{ + if (!checkEvent(event, YAML_MAPPING_START_EVENT)) + return -EINVAL; + + std::string key = parseScalar(); + if (key.empty()) + return -EINVAL; + + unsigned int frameId = atoi(key.c_str()); + + event = nextEvent(YAML_MAPPING_START_EVENT); + if (!event) + return -EINVAL; + + ControlList controls{}; + + while (1) { + event = nextEvent(); + if (!event) + return -EINVAL; + + if (event->type == YAML_MAPPING_END_EVENT) + break; + + int ret = parseControl(std::move(event), controls); + if (ret) + return ret; + } + + frameControls_[frameId] = std::move(controls); + + event = nextEvent(YAML_MAPPING_END_EVENT); + if (!event) + return -EINVAL; + + return 0; +} + +int CaptureScript::parseControl(EventPtr event, ControlList &controls) +{ + /* We expect a value after a key. */ + std::string name = eventScalarValue(event); + if (name.empty()) + return -EINVAL; + + /* If the camera does not support the control just ignore it. */ + auto it = controls_.find(name); + if (it == controls_.end()) { + std::cerr << "Unsupported control '" << name << "'" << std::endl; + return -EINVAL; + } + + std::string value = parseScalar(); + if (value.empty()) + return -EINVAL; + + const ControlId *controlId = it->second; + ControlValue val = unpackControl(controlId, value); + controls.set(controlId->id(), val); + + return 0; +} + +std::string CaptureScript::parseScalar() +{ + EventPtr event = nextEvent(YAML_SCALAR_EVENT); + if (!event) + return ""; + + return eventScalarValue(event); +} + +void CaptureScript::unpackFailure(const ControlId *id, const std::string &repr) +{ + static const std::map typeNames = { + { ControlTypeNone, "none" }, + { ControlTypeBool, "bool" }, + { ControlTypeByte, "byte" }, + { ControlTypeInteger32, "int32" }, + { ControlTypeInteger64, "int64" }, + { ControlTypeFloat, "float" }, + { ControlTypeString, "string" }, + { ControlTypeRectangle, "Rectangle" }, + { ControlTypeSize, "Size" }, + }; + + const char *typeName; + auto it = typeNames.find(id->type()); + if (it != typeNames.end()) + typeName = it->second; + else + typeName = "unknown"; + + std::cerr << "Unsupported control '" << repr << "' for " + << typeName << " control " << id->name() << std::endl; +} + +ControlValue CaptureScript::unpackControl(const ControlId *id, + const std::string &repr) +{ + ControlValue value{}; + + switch (id->type()) { + case ControlTypeNone: + break; + case ControlTypeBool: { + bool val; + + if (repr == "true") { + val = true; + } else if (repr == "false") { + val = false; + } else { + unpackFailure(id, repr); + return value; + } + + value.set(val); + break; + } + case ControlTypeByte: { + uint8_t val = strtol(repr.c_str(), NULL, 10); + value.set(val); + break; + } + case ControlTypeInteger32: { + int32_t val = strtol(repr.c_str(), NULL, 10); + value.set(val); + break; + } + case ControlTypeInteger64: { + int64_t val = strtoll(repr.c_str(), NULL, 10); + value.set(val); + break; + } + case ControlTypeFloat: { + float val = strtof(repr.c_str(), NULL); + value.set(val); + break; + } + case ControlTypeString: { + value.set(repr); + break; + } + case ControlTypeRectangle: + /* \todo Parse rectangles. */ + break; + case ControlTypeSize: + /* \todo Parse Sizes. */ + break; + } + + return value; +} diff --git a/src/cam/capture_script.h b/src/cam/capture_script.h new file mode 100644 index 000000000000..44368f63f34c --- /dev/null +++ b/src/cam/capture_script.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * capture_script.h - Capture session configuration script + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#include + +class CaptureScript +{ +public: + CaptureScript(std::shared_ptr camera, + const std::string &fileName); + + bool valid() const { return valid_; } + + const libcamera::ControlList &frameControls(unsigned int frame); + +private: + struct EventDeleter { + void operator()(yaml_event_t *event) const + { + yaml_event_delete(event); + delete event; + } + }; + using EventPtr = std::unique_ptr; + + std::map controls_; + std::map frameControls_; + std::shared_ptr camera_; + yaml_parser_t parser_; + bool valid_; + + EventPtr nextEvent(yaml_event_type_t expectedType = YAML_NO_EVENT); + bool checkEvent(const EventPtr &event, yaml_event_type_t expectedType) const; + static std::string eventScalarValue(const EventPtr &event); + static std::string eventTypeName(yaml_event_type_t type); + + int parseScript(FILE *script); + + int parseFrames(); + int parseFrame(EventPtr event); + int parseControl(EventPtr event, libcamera::ControlList &controls); + + std::string parseScalar(); + + void unpackFailure(const libcamera::ControlId *id, + const std::string &repr); + libcamera::ControlValue unpackControl(const libcamera::ControlId *id, + const std::string &repr); +}; diff --git a/src/cam/meson.build b/src/cam/meson.build index 5bab8c9e331b..c47a85592478 100644 --- a/src/cam/meson.build +++ b/src/cam/meson.build @@ -11,6 +11,7 @@ cam_enabled = true cam_sources = files([ 'camera_session.cpp', + 'capture_script.cpp', 'event_loop.cpp', 'file_sink.cpp', 'frame_sink.cpp', @@ -38,6 +39,7 @@ cam = executable('cam', cam_sources, libcamera_public, libdrm, libevent, + libyaml, ], cpp_args : cam_cpp_args, install : true) From patchwork Fri May 20 16:52:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 15993 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 411EDC3256 for ; Fri, 20 May 2022 16:52:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 463F16566F; Fri, 20 May 2022 18:52:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1653065568; bh=CsJGxDB+lznfsPzdwGWvVrfUxFStto0ILMnvgpVn4XE=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=o+fEw79MTc3NPsN2BD23/1pOBfB4m6hDP85LqV/hIsfl0s2r7iAl9EiwSVmyin3OC NfkIptQc03B4pi9nMxHpmqCkiProJA3WlOMd6Gdp48+k6V6PeWAJUKFvuEGSjEG3ug e/Hbx3mdugL0qaQ3+3FidqHD3jl8pLMGMHc1u7r/BMG4YL5NZt8Kik4+FbIKBsajmZ 3HhLKtVBn/3lEUP23wm7+Y5C316rC1a7qOTsniL8FrNVu421hTvPZvhZORA29w1s/s JlwZMusP7M+QaVTZIVHULvvS1YAd0yiLyL3yFtXmsRF9a6BEVZIdWrZqxGNhiEDcQx 53f/++9kXy4QA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CB20865653 for ; Fri, 20 May 2022 18:52:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="H/JkwRSa"; dkim-atps=neutral Received: from localhost.localdomain (unknown [45.131.31.124]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 669E85A4; Fri, 20 May 2022 18:52:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1653065565; bh=CsJGxDB+lznfsPzdwGWvVrfUxFStto0ILMnvgpVn4XE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=H/JkwRSaOGMx3nY0qOYyMm8mV1vV3STbkW0jDCCSYqqhWcaxtHIA+wvINRzeIdRnY Y7nXRE+3J4Oec5qTYvhyKRbZTWRI4Qmscyc19D6P2bD2Yb5UWyp7kNVMoAc/C6MeAe W+eMMoWHYcVQWJMIEt7+V4m2pgFsRC7aP4hx+n2E= To: libcamera-devel@lists.libcamera.org Date: Fri, 20 May 2022 19:52:33 +0300 Message-Id: <20220520165234.7642-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220520165234.7642-1-laurent.pinchart@ideasonboard.com> References: <20220520165234.7642-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 2/3] cam: Queue requests through CameraSession::queueRequest() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Jacopo Mondi The CameraSession::processRequest() frame completion handler currently re-queues completed requests by calling Camera::queueRequests() explicitely. In order to maintain the CameraSession::queuedRequest_ counter up to date with the actual number of queued requests, call the CameraSession::queueRequest() instead of operating the Camera directly. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/cam/camera_session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp index efffafbf9e9a..0bb95c8bf682 100644 --- a/src/cam/camera_session.cpp +++ b/src/cam/camera_session.cpp @@ -418,7 +418,7 @@ void CameraSession::processRequest(Request *request) return; request->reuse(Request::ReuseBuffers); - camera_->queueRequest(request); + queueRequest(request); } void CameraSession::sinkRelease(Request *request) From patchwork Fri May 20 16:52:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 15994 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C8BF7C326C for ; Fri, 20 May 2022 16:52:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E3B1365671; Fri, 20 May 2022 18:52:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1653065569; bh=ma1XlaQ7qDzPbqc883R/RCy76hX2MGSNlKCM/5fGHr8=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=gZWcaHIicpJ7sn0MlVl1m8S2MY7f/jUkGfKVS84WWx7IflP6TSNyIKyQxEbTwxA94 O1GwBej64Yw7r29e1HQdHMwl6rAGITkDPDBnECWqBiN5p3gcQcy1mGH/2IpahYNAUn mreelpkvjcw1plhEx6lCOUzWpa0PLlfuMe1iwMvNEz1I3GHk79bjEiJnO7PM/RYB6w NFCehvCe+RvTAIURGIJbi0KwDPjIqyR80prNMmo+vJmBzWrhhbH8r5DuliFApqch35 QWSMhzyIKQ/37k9d1tKL/YQ8DMU6oAJtuRZVbkeZNaIZm7kv6IiepjUVOxcYbbQtBP c/RmqjC3SewrQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2D02A65668 for ; Fri, 20 May 2022 18:52:46 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="B8doWS1t"; dkim-atps=neutral Received: from localhost.localdomain (unknown [45.131.31.124]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C00556D1; Fri, 20 May 2022 18:52:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1653065566; bh=ma1XlaQ7qDzPbqc883R/RCy76hX2MGSNlKCM/5fGHr8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=B8doWS1tgjqaqqqOZX71Dxv3GspS8KVXY4URuCQt/p6NxanzX4mnJd1+11LtMtiBM SNqiCKalVpVbt16wFBzwLyGQNrWtc944gchO3/O9MwOKxFOSpTv2RAlHdgKgKv1mp7 kCjEcznV7N/4HG5NnvwEJfBj54W7S6FkRJIw5Pw8= To: libcamera-devel@lists.libcamera.org Date: Fri, 20 May 2022 19:52:34 +0300 Message-Id: <20220520165234.7642-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220520165234.7642-1-laurent.pinchart@ideasonboard.com> References: <20220520165234.7642-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 3/3] cam: Use script parser to set controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Jacopo Mondi Add a "--script" option to the cam test application to allow specify a capture script to be used to drive the capture session. Add to the CameraSession class a script parser instance, created conditionally to the OptCaptureScript option. If the script parser has been created, use it at queueRequest time to retrieve the list of controls that has to be associated with a Request, and populate Request::controls() with it before queueing it to the Camera. Signed-off-by: Jacopo Mondi --- Changes since v1: - Add error message if the capture script is invalid - Forward-declare CaptureScript - Remove stray \n in help text - Squash with "cam: Add a --script option" --- src/cam/camera_session.cpp | 14 ++++++++++++++ src/cam/camera_session.h | 3 +++ src/cam/main.cpp | 4 ++++ src/cam/main.h | 1 + 4 files changed, 22 insertions(+) diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp index 0bb95c8bf682..76d552d98917 100644 --- a/src/cam/camera_session.cpp +++ b/src/cam/camera_session.cpp @@ -14,6 +14,7 @@ #include #include "camera_session.h" +#include "capture_script.h" #include "event_loop.h" #include "file_sink.h" #ifdef HAVE_KMS @@ -91,6 +92,16 @@ CameraSession::CameraSession(CameraManager *cm, } #endif + if (options_.isSet(OptCaptureScript)) { + std::string scriptName = options_[OptCaptureScript].toString(); + script_ = std::make_unique(camera_, scriptName); + if (!script_->valid()) { + std::cerr << "Invalid capture script '" << scriptName + << "'" << std::endl; + return; + } + } + switch (config->validate()) { case CameraConfiguration::Valid: break; @@ -322,6 +333,9 @@ int CameraSession::queueRequest(Request *request) if (captureLimit_ && queueCount_ >= captureLimit_) return 0; + if (script_) + request->controls() = script_->frameControls(queueCount_); + queueCount_++; return camera_->queueRequest(request); diff --git a/src/cam/camera_session.h b/src/cam/camera_session.h index bf966bd15ab0..d562caae0794 100644 --- a/src/cam/camera_session.h +++ b/src/cam/camera_session.h @@ -23,6 +23,7 @@ #include "options.h" +class CaptureScript; class FrameSink; class CameraSession @@ -60,6 +61,8 @@ private: std::shared_ptr camera_; std::unique_ptr config_; + std::unique_ptr script_; + std::map streamNames_; std::unique_ptr sink_; unsigned int cameraIndex_; diff --git a/src/cam/main.cpp b/src/cam/main.cpp index c7f664b903e0..9c3370d7951f 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -158,6 +158,10 @@ int CamApp::parseOptions(int argc, char *argv[]) "Print the metadata for completed requests", "metadata", ArgumentNone, nullptr, false, OptCamera); + parser.addOption(OptCaptureScript, OptionString, + "Load a capture session configuration script from a file", + "script", ArgumentRequired, "script", false, + OptCamera); options_ = parser.parse(argc, argv); if (!options_.valid()) diff --git a/src/cam/main.h b/src/cam/main.h index 62f7bbc9d181..51b87927837f 100644 --- a/src/cam/main.h +++ b/src/cam/main.h @@ -21,4 +21,5 @@ enum { OptListControls = 256, OptStrictFormats = 257, OptMetadata = 258, + OptCaptureScript = 259, };