From patchwork Thu Sep 16 13:20:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 13862 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 9C11FBF01C for ; Thu, 16 Sep 2021 13:20:25 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BA35469188; Thu, 16 Sep 2021 15:20:24 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="Sf1vZJFe"; dkim-atps=neutral Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1422F6916F for ; Thu, 16 Sep 2021 15:20:23 +0200 (CEST) Received: by mail-wr1-x433.google.com with SMTP id g16so9468401wrb.3 for ; Thu, 16 Sep 2021 06:20:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=xPux191sneH09IHtVU0TV9Nyl0lEEsyPR4HtpznDQf8=; b=Sf1vZJFetFuaaa5d1XAPytPkZ8/Z5HlmiNjoLAHGGjcaXAFy8Cw6ZjbV9Y4RtFRqJ8 IW3cfRerHGbq2ECRsGf09AbsnJ/CU01LLNNnbbWpYpQePhfg7h7Dz7un1tAndiB73WPr I2qGk3ckggAQiKP50sEUhl4xniBuG/p2+kVE5gNY3cy5Da/TzhiVy36BJnrr6qrTIvG0 SzWRLeTNmGjWY2bsLGumtwzYp+BVMLzPxJWPd9wFq4DGKpnbyngVzUPNfkZiyGduaRBG LnchmTErRhUEAsSIPRzJXQR/WSZe0PC9+ZCixT/01rSK5vuJiTqARX7ldMcdNyifi5hP syhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=xPux191sneH09IHtVU0TV9Nyl0lEEsyPR4HtpznDQf8=; b=K1NkFY5yGwtGpIWE0kMEu3o7AyERuQXns9ctVhuYVirLgf3ZwxHTatTYv2F3I/3D3W hsdm+33X60AQgUXny29bCHmvMWfEzEgIiNuq48zXsqBfYapZ5yjiAQr7KCmx0EzwS69f lkDgzskvCpbb50wXuOuEn/CH+vxiyw8pjiIYOFhE0L9JF1VQ5NlkzIYXUOPk34RQOp9Q BR0FBa0LjnksSyTU6brO+nTA929U3YwMOZpbsXmKeNKLYByguorkSbGnH1kx5Lod5lGX 7e/a3rRJGDpneE5XsceZCYtrY9pvnqlBR9b6K6RU/li+T5Xhq9ahIEOnx7YzNl/bP0+U 1k2A== X-Gm-Message-State: AOAM532EuiloViLvrJ4Tma2nFfJRMSZhRr+guYF1POMgpsx1xBaYUPyX +3sHuYnYvDajH6qyD0hiKT/zmS7Ujh9W6YtD X-Google-Smtp-Source: ABdhPJwa1PdN2ckpRc4WVdo8IGbxfzaBCTxFbQV0S9D71tnPIaKGOKNaQOG5yY81HQLOAcNz8rkWPg== X-Received: by 2002:adf:df0d:: with SMTP id y13mr6002989wrl.335.1631798422401; Thu, 16 Sep 2021 06:20:22 -0700 (PDT) Received: from pi4-davidp.pitowers.org ([2a00:1098:3142:14:1ce1:9965:4328:89c4]) by smtp.gmail.com with ESMTPSA id f3sm3233425wmj.28.2021.09.16.06.20.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Sep 2021 06:20:21 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Date: Thu, 16 Sep 2021 14:20:14 +0100 Message-Id: <20210916132015.1790-2-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210916132015.1790-1-david.plowman@raspberrypi.com> References: <20210916132015.1790-1-david.plowman@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 1/2] libcamera: Add SensorMode class 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The CameraSensor gains the getSensorModes method which returns the modes that the sensor supports. A user can browse this list and select modes and sort them. The CameraConfiguration acquires a field containing a SensorMode where the application can configure "hints" about what the pipeline handler should choose. Signed-off-by: David Plowman --- include/libcamera/camera.h | 3 ++ include/libcamera/internal/camera_sensor.h | 4 ++ include/libcamera/meson.build | 1 + include/libcamera/sensor_mode.h | 50 ++++++++++++++++++ src/libcamera/camera_sensor.cpp | 15 ++++++ src/libcamera/meson.build | 1 + src/libcamera/sensor_mode.cpp | 60 ++++++++++++++++++++++ 7 files changed, 134 insertions(+) create mode 100644 include/libcamera/sensor_mode.h create mode 100644 src/libcamera/sensor_mode.cpp diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h index 601ee46e..c07edc1b 100644 --- a/include/libcamera/camera.h +++ b/include/libcamera/camera.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -66,6 +67,8 @@ public: Transform transform; + SensorMode sensorMode; + protected: CameraConfiguration(); diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index d25a1165..5701d23d 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -16,6 +16,8 @@ #include #include +#include + #include #include "libcamera/internal/formats.h" @@ -60,6 +62,8 @@ public: void updateControlInfo(); + SensorModeList getSensorModes() const; + protected: std::string logPrefix() const override; diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 5b25ef84..821b5aa2 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -12,6 +12,7 @@ libcamera_public_headers = files([ 'logging.h', 'pixel_format.h', 'request.h', + 'sensor_mode.h', 'stream.h', 'transform.h', ]) diff --git a/include/libcamera/sensor_mode.h b/include/libcamera/sensor_mode.h new file mode 100644 index 00000000..9b51b7f9 --- /dev/null +++ b/include/libcamera/sensor_mode.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Raspberry Pi (Trading) Ltd. + * + * sensor_mode.h - Definition of a sensor mode + */ + +#ifndef __LIBCAMERA_SENSOR_MODE_H__ +#define __LIBCAMERA_SENSOR_MODE_H__ + +#include +#include +#include + +#include + +namespace libcamera { + +class SensorMode +{ +public: + SensorMode() + : bitDepth(0) + { + } + + SensorMode(unsigned int b, const SizeRange &s) + : bitDepth(b), sizeRange(s) + { + } + + std::string toString() const; + + unsigned int bitDepth; + SizeRange sizeRange; +}; + +using SensorModeList = std::vector; + +using SensorModeSelectFunction = std::function; + +SensorModeList selectSensorModes(const SensorModeList &modes, SensorModeSelectFunction selectFn); + +using SensorModeScoreFunction = std::function; + +void sortSensorModes(SensorModeList &modes, SensorModeScoreFunction scoreFn); + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_SENSOR_MODE_H__ */ diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index 87668509..88fae2bf 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -833,4 +833,19 @@ int CameraSensor::generateId() return -EINVAL; } +SensorModeList CameraSensor::getSensorModes() const +{ + SensorModeList modes; + + for (const auto &format : formats_) { + const BayerFormat &bayerFmt = BayerFormat::fromMbusCode(format.first); + if (bayerFmt.isValid()) { + for (const auto &range : format.second) + modes.emplace_back(bayerFmt.bitDepth, range); + } + } + + return modes; +} + } /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index e9230b98..d64f7038 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -36,6 +36,7 @@ libcamera_sources = files([ 'process.cpp', 'pub_key.cpp', 'request.cpp', + 'sensor_mode.cpp', 'source_paths.cpp', 'stream.cpp', 'sysfs.cpp', diff --git a/src/libcamera/sensor_mode.cpp b/src/libcamera/sensor_mode.cpp new file mode 100644 index 00000000..09317ff7 --- /dev/null +++ b/src/libcamera/sensor_mode.cpp @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2021, Raspberry Pi (Trading) Ltd. + * + * sensor_mode.cpp - Functions related to sensor modes + */ + +#include +#include + +#include + +#include + +/** + * \file sensor_mode.h + * \brief Data structures and procedures related to sensor modes + */ + +namespace libcamera { + +std::string SensorMode::toString() const +{ + std::stringstream ss; + + ss << bitDepth << ":"; + + if (sizeRange.min == sizeRange.max) + ss << sizeRange.min.toString(); + else + ss << sizeRange.toString(); + + return ss.str(); +} + +/* + * Select modes from a list that match certain criteria, for example "all the modes that can + * output at least 720p", or "all the 12-bit modes". + */ + +SensorModeList selectSensorModes(const SensorModeList &modes, SensorModeSelectFunction selectFn) +{ + SensorModeList selection; + + std::copy_if(modes.begin(), modes.end(), std::back_inserter(selection), selectFn); + + return selection; +} + +/* + * Sort a list of modes according to an arbitrary scoring function. You might simply order them + * from smallest to largest, or use it to obtain the modes closest to a particular "target". + */ + +void sortSensorModes(SensorModeList &modes, SensorModeScoreFunction scoreFn) +{ + std::sort(modes.begin(), modes.end(), [&scoreFn](const auto &lhs, const auto &rhs) { return scoreFn(lhs) < scoreFn(rhs); }); +} + +} /* namespace libcamera */ From patchwork Thu Sep 16 13:20:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Plowman X-Patchwork-Id: 13863 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 B7982BF01C for ; Thu, 16 Sep 2021 13:20:27 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 86B816918E; Thu, 16 Sep 2021 15:20:27 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="ctmHWQC2"; dkim-atps=neutral Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1615469183 for ; Thu, 16 Sep 2021 15:20:25 +0200 (CEST) Received: by mail-wr1-x42b.google.com with SMTP id d21so9416446wra.12 for ; Thu, 16 Sep 2021 06:20:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ckvChxHSv2XABFiPTYYH31puU2SrDdDENu7zj+2KEZM=; b=ctmHWQC2vKGoY9OWd+GzyHuvEzWYt4QL8v5DGQwkAhsbrSzvSbcfHmcPddcxhAGA6S rIYWgCNPMwgRw05rtNVVNjGwk0MWXwjaYOtwoUjGSCdV/dAqZ9wcM1ISU+/WM1CYCxjh E6rkjwet5IFL6GqO88wI5P7aVPBlX3pO0azaPEq6Kws9/T7yv9tyHpRvsj9lrNsqSnA7 +FJMmQ+HAIDG0ETYdkwezZDWggINo4pGaU2GBt/HkVH5M3j6WwEDuBYLn3IPKDQAS+Oh kjIdw/xzgG0r5nuKNtDxvzEet8NdukeEHEWHt/w6lGB3bjwen+8hIYNXGgapXOIrZvtG VI4A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ckvChxHSv2XABFiPTYYH31puU2SrDdDENu7zj+2KEZM=; b=rS4gSJiWO1RctyT48YUdxq26r5bAx0tlzVdzKPRAj8sDEQi7oWsTYXIpULIWLmMjbz qPStaeFbqtkapiHG4b5iTYxwxeTm8gvatGdmqbtXQYklBAFLbpsnbRGPNkZpy/K3NHKg abAzoKWDqKBQBDK6ukQGUXeato2+6HPCjwEgTHCQtlko+iJtgHXOj6pN+LceX8gdXm/8 wDFBdSbbX/Zra68iiRuMGHds414FrI7OIvcGoZ4p5+IqLgqw4Xhxn/FV02PrLoVud3Ww xaWIjcACdOVyepTfl2kEGfaDoVuSpuoLv0iclcD086/PlZSFauGpuDDjkPEQrMaMs+n9 h3XQ== X-Gm-Message-State: AOAM5308V2W2FnVI0wziNuMhuQNrfyfYy43jyPwY87gR5L4tt6rLvJPF oPG/SD0M94ArPBx+2e54faj3/QwRTUcJYYcY X-Google-Smtp-Source: ABdhPJxehE3lxJkePc/K0+Mewp7NWGXdPHZtrVYozKa0eFb4Syt0wq23bElpsTDEIW60Hd3J/3XTIA== X-Received: by 2002:a5d:53c8:: with SMTP id a8mr6041273wrw.168.1631798424373; Thu, 16 Sep 2021 06:20:24 -0700 (PDT) Received: from pi4-davidp.pitowers.org ([2a00:1098:3142:14:1ce1:9965:4328:89c4]) by smtp.gmail.com with ESMTPSA id f3sm3233425wmj.28.2021.09.16.06.20.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Sep 2021 06:20:22 -0700 (PDT) From: David Plowman To: libcamera-devel@lists.libcamera.org Date: Thu, 16 Sep 2021 14:20:15 +0100 Message-Id: <20210916132015.1790-3-david.plowman@raspberrypi.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210916132015.1790-1-david.plowman@raspberrypi.com> References: <20210916132015.1790-1-david.plowman@raspberrypi.com> MIME-Version: 1.0 Subject: [libcamera-devel] [RFC PATCH 2/2] libcamera: pipeline_handler: raspberrypi: Handle the new SensorMode hint 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: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" If no SensorMode hint is supplied the code will fill it in using the stream condfigurations so as to give the same result as before. Then the SensorMode hint will be used in place of the largest output size to guide the mode selection. Signed-off-by: David Plowman --- .../pipeline/raspberrypi/raspberrypi.cpp | 105 +++++++++++++----- 1 file changed, 78 insertions(+), 27 deletions(-) diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 0bdfa727..5d1c5e64 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -48,6 +48,12 @@ LOG_DEFINE_CATEGORY(RPI) namespace { +constexpr int PREFERRED_BIT_DEPTH = 12; + +constexpr double PENALTY_AR = 1500.0; +constexpr double PENALTY_BITDEPTH = 500.0; +constexpr double PENALTY_UNPACKED = 50.0; + bool isRaw(PixelFormat &pixFmt) { /* @@ -61,58 +67,91 @@ bool isRaw(PixelFormat &pixFmt) return info.colourEncoding == PixelFormatInfo::ColourEncodingRAW; } -double scoreFormat(double desired, double actual) +struct Interval { + static Interval XRange(const SizeRange &s) + { + return { static_cast(s.min.width), static_cast(s.max.width) }; + } + static Interval YRange(const SizeRange &s) + { + return { static_cast(s.min.height), static_cast(s.max.height) }; + } + int min, max; + int separation(const Interval &other) const + { + /* + * The separation between two intervals is positive if "this" interval lies + * wholly above "other", zero if they overlap and otherwise negative. + */ + if (min > other.max) + return min - other.max; + else if (other.min > max) + return max - other.min; + return 0; + } + int clamp(int value) const + { + return std::clamp(value, min, max); + } +}; + +double sizeAr(const Size &s) +{ + return static_cast(s.width) / s.height; +} + +double scoreSeparation(int separation) { - double score = desired - actual; + double score = separation; /* Smaller desired dimensions are preferred. */ - if (score < 0.0) + if (score < 0) score = (-score) / 8; /* Penalise non-exact matches. */ - if (actual != desired) + if (separation != 0) score *= 2; return score; } V4L2DeviceFormat findBestMode(V4L2VideoDevice::Formats &formatsMap, - const Size &req) + const SensorMode &hintMode) { double bestScore = std::numeric_limits::max(), score; V4L2DeviceFormat bestMode; -#define PENALTY_AR 1500.0 -#define PENALTY_8BIT 2000.0 -#define PENALTY_10BIT 1000.0 -#define PENALTY_12BIT 0.0 -#define PENALTY_UNPACKED 500.0 + LOG(RPI, Info) << "Hinted mode: " << hintMode.toString(); + + Interval hintX = Interval::XRange(hintMode.sizeRange); + Interval hintY = Interval::YRange(hintMode.sizeRange); + double hintAr = sizeAr(hintMode.sizeRange.max); - /* Calculate the closest/best mode from the user requested size. */ + /* Calculate the closest/best mode from the hinted sensor mode. */ for (const auto &iter : formatsMap) { V4L2PixelFormat v4l2Format = iter.first; const PixelFormatInfo &info = PixelFormatInfo::info(v4l2Format); for (const SizeRange &sz : iter.second) { - double modeWidth = sz.contains(req) ? req.width : sz.max.width; - double modeHeight = sz.contains(req) ? req.height : sz.max.height; - double reqAr = static_cast(req.width) / req.height; - double modeAr = modeWidth / modeHeight; + Interval sensorX = Interval::XRange(sz); + Interval sensorY = Interval::YRange(sz); + double sensorAr = sizeAr(sz.max); + + double widthSeparation = hintX.separation(sensorX); + double heightSeparation = hintY.separation(sensorY); /* Score the dimensions for closeness. */ - score = scoreFormat(req.width, modeWidth); - score += scoreFormat(req.height, modeHeight); - score += PENALTY_AR * scoreFormat(reqAr, modeAr); + score = scoreSeparation(widthSeparation); + score += scoreSeparation(heightSeparation); + score += PENALTY_AR * std::abs(hintAr - sensorAr); /* Add any penalties... this is not an exact science! */ if (!info.packed) score += PENALTY_UNPACKED; - if (info.bitsPerPixel == 12) - score += PENALTY_12BIT; - else if (info.bitsPerPixel == 10) - score += PENALTY_10BIT; - else if (info.bitsPerPixel == 8) - score += PENALTY_8BIT; + int bitDifference = info.bitsPerPixel - hintMode.bitDepth; + score += std::abs(bitDifference) * PENALTY_BITDEPTH; + int modeWidth = sensorX.clamp(hintMode.sizeRange.max.width); + int modeHeight = sensorY.clamp(hintMode.sizeRange.max.height); if (score <= bestScore) { bestScore = score; bestMode.fourcc = v4l2Format; @@ -353,7 +392,8 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() * the user request. */ V4L2VideoDevice::Formats fmts = data_->unicam_[Unicam::Image].dev()->formats(); - V4L2DeviceFormat sensorFormat = findBestMode(fmts, cfg.size); + SensorMode mode(PREFERRED_BIT_DEPTH, SizeRange(cfg.size)); + V4L2DeviceFormat sensorFormat = findBestMode(fmts, mode); int ret = data_->unicam_[Unicam::Image].dev()->tryFormat(&sensorFormat); if (ret) return Invalid; @@ -484,11 +524,13 @@ CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera, unsigned int rawCount = 0; unsigned int outCount = 0; for (const StreamRole role : roles) { + SensorMode mode; switch (role) { case StreamRole::Raw: size = data->sensor_->resolution(); fmts = data->unicam_[Unicam::Image].dev()->formats(); - sensorFormat = findBestMode(fmts, size); + mode = SensorMode(PREFERRED_BIT_DEPTH, SizeRange(size)); + sensorFormat = findBestMode(fmts, mode); pixelFormat = sensorFormat.fourcc.toPixelFormat(); ASSERT(pixelFormat.isValid()); bufferCount = 2; @@ -598,9 +640,18 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config) } } + /* + * If any parts of the hinted sensor mode are unset, fill them in now. + */ + if (config->sensorMode.bitDepth == 0) + config->sensorMode.bitDepth = PREFERRED_BIT_DEPTH; + + if (config->sensorMode.sizeRange.max == Size(0, 0)) + config->sensorMode.sizeRange = SizeRange(rawStream ? sensorSize : maxSize); + /* First calculate the best sensor mode we can use based on the user request. */ V4L2VideoDevice::Formats fmts = data->unicam_[Unicam::Image].dev()->formats(); - V4L2DeviceFormat sensorFormat = findBestMode(fmts, rawStream ? sensorSize : maxSize); + V4L2DeviceFormat sensorFormat = findBestMode(fmts, config->sensorMode); /* * Unicam image output format. The ISP input format gets set at start,