From patchwork Fri Sep 25 01:41:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 9811 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 A8F31C3B5C for ; Fri, 25 Sep 2020 01:42:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 215C060576; Fri, 25 Sep 2020 03:42:58 +0200 (CEST) Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9E89663025 for ; Fri, 25 Sep 2020 03:42:51 +0200 (CEST) X-Halon-ID: 6b8a842d-fed0-11ea-92dc-005056917a89 Authorized-sender: niklas.soderlund@fsdn.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 6b8a842d-fed0-11ea-92dc-005056917a89; Fri, 25 Sep 2020 03:42:50 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Fri, 25 Sep 2020 03:41:58 +0200 Message-Id: <20200925014207.1455796-14-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200925014207.1455796-1-niklas.soderlund@ragnatech.se> References: <20200925014207.1455796-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 13/22] libcamera: pipeline: rkisp1: Add format validation for self path 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" Extend the format validation to work with both main and self paths. The heuristics honors that the first stream in the configuration has the highest priority while still examining both streams for a best match. It is not possible to capture from the self path as the self stream is not yet exposed to applications. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- * Changes since v2 - Fix spelling in commit message. - Use Span<> instead of turning arrays to vectors. - Keep data_ const and cast 'const Streams*' to non-const using const_cast() to match the IPU3 pipeline. - Rename fitAnyPath() to fitsAllPaths(). - Expand documentation for why second stream is evaluated first if the fist stream can use either stream. - Drop support for RGB888 and RGB656 for selfpath which was present in v2 as the driver delivers odd data when the frames are observed. * Changes since v1 - Store formats in std::vector instead of std::array to avoid template usage for validate function. --- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 210 +++++++++++++++++------ 1 file changed, 162 insertions(+), 48 deletions(-) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index cd3049485746edd6..bd53183a034efaff 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include "libcamera/internal/camera_sensor.h" @@ -50,6 +52,19 @@ constexpr std::array RKISP1_RSZ_MP_FORMATS{ formats::NV12, /* \todo Add support for 8-bit greyscale to DRM formats */ }; + +constexpr Size RKISP1_RSZ_SP_SRC_MIN{ 32, 16 }; +constexpr Size RKISP1_RSZ_SP_SRC_MAX{ 1920, 1920 }; +constexpr std::array RKISP1_RSZ_SP_FORMATS{ + formats::YUYV, + formats::YVYU, + formats::VYUY, + formats::NV16, + formats::NV61, + formats::NV21, + formats::NV12, + /* \todo Add support for BGR888 and RGB565 */ +}; } /* namespace */ class PipelineHandlerRkISP1; @@ -181,6 +196,14 @@ public: private: static constexpr unsigned int RKISP1_BUFFER_COUNT = 4; + CameraConfiguration::Status validatePath(StreamConfiguration *cfg, + const Span &formats, + const Size &min, const Size &max, + V4L2VideoDevice *video); + CameraConfiguration::Status validateMainPath(StreamConfiguration *cfg); + CameraConfiguration::Status validateSelfPath(StreamConfiguration *cfg); + bool fitsAllPaths(const StreamConfiguration &cfg); + /* * The RkISP1CameraData instance is guaranteed to be valid as long as the * corresponding Camera instance is valid. In order to borrow a @@ -492,6 +515,69 @@ RkISP1CameraConfiguration::RkISP1CameraConfiguration(Camera *camera, data_ = data; } +CameraConfiguration::Status RkISP1CameraConfiguration::validatePath( + StreamConfiguration *cfg, const Span &formats, + const Size &min, const Size &max, V4L2VideoDevice *video) +{ + const StreamConfiguration reqCfg = *cfg; + Status status = Valid; + + if (std::find(formats.begin(), formats.end(), cfg->pixelFormat) == + formats.end()) + cfg->pixelFormat = formats::NV12; + + cfg->size.boundTo(max); + cfg->size.expandTo(min); + cfg->bufferCount = RKISP1_BUFFER_COUNT; + + V4L2DeviceFormat format = {}; + format.fourcc = video->toV4L2PixelFormat(cfg->pixelFormat); + format.size = cfg->size; + + int ret = video->tryFormat(&format); + if (ret) + return Invalid; + + cfg->stride = format.planes[0].bpl; + cfg->frameSize = format.planes[0].size; + + if (cfg->pixelFormat != reqCfg.pixelFormat || cfg->size != reqCfg.size) { + LOG(RkISP1, Debug) + << "Adjusting format from " << reqCfg.toString() + << " to " << cfg->toString(); + status = Adjusted; + } + + return status; +} + +CameraConfiguration::Status RkISP1CameraConfiguration::validateMainPath(StreamConfiguration *cfg) +{ + return validatePath(cfg, RKISP1_RSZ_MP_FORMATS, RKISP1_RSZ_MP_SRC_MIN, + RKISP1_RSZ_MP_SRC_MAX, data_->mainPathVideo_); +} + +CameraConfiguration::Status RkISP1CameraConfiguration::validateSelfPath(StreamConfiguration *cfg) +{ + return validatePath(cfg, RKISP1_RSZ_SP_FORMATS, RKISP1_RSZ_SP_SRC_MIN, + RKISP1_RSZ_SP_SRC_MAX, data_->selfPathVideo_); +} + +bool RkISP1CameraConfiguration::fitsAllPaths(const StreamConfiguration &cfg) +{ + StreamConfiguration config; + + config = cfg; + if (validateMainPath(&config) != Valid) + return false; + + config = cfg; + if (validateSelfPath(&config) != Valid) + return false; + + return true; +} + CameraConfiguration::Status RkISP1CameraConfiguration::validate() { const CameraSensor *sensor = data_->sensor_; @@ -501,22 +587,87 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() return Invalid; /* Cap the number of entries to the available streams. */ - if (config_.size() > 1) { - config_.resize(1); + if (config_.size() > 2) { + config_.resize(2); status = Adjusted; } - StreamConfiguration &cfg = config_[0]; - - /* Adjust the pixel format. */ - if (std::find(RKISP1_RSZ_MP_FORMATS.begin(), RKISP1_RSZ_MP_FORMATS.end(), - cfg.pixelFormat) == RKISP1_RSZ_MP_FORMATS.end()) { - LOG(RkISP1, Debug) << "Adjusting format to NV12"; - cfg.pixelFormat = formats::NV12, - status = Adjusted; + /* + * If there are more then one stream in the configuration figure out the + * order to evaluate the streams. The first stream has the highest + * priority but if both main path and self path can satisfy it evaluate + * second stream first as the first stream is guaranteed to work with + * whichever path is not used by the second one. + */ + std::vector order(config_.size()); + std::iota(order.begin(), order.end(), 0); + if (config_.size() == 2 && fitsAllPaths(config_[0])) + std::reverse(order.begin(), order.end()); + + bool mainPathAvailable = true; + bool selfPathAvailable = true; + for (unsigned int index : order) { + StreamConfiguration &cfg = config_[index]; + + /* Try to match stream without adjusting configuration. */ + if (mainPathAvailable) { + StreamConfiguration tryCfg = cfg; + if (validateMainPath(&tryCfg) == Valid) { + mainPathAvailable = false; + cfg = tryCfg; + cfg.setStream(const_cast(&data_->mainPathStream_)); + LOG(RkISP1, Debug) << "Exact match main"; + continue; + } + } + + if (selfPathAvailable) { + StreamConfiguration tryCfg = cfg; + if (validateSelfPath(&tryCfg) == Valid) { + selfPathAvailable = false; + cfg = tryCfg; + cfg.setStream(const_cast(&data_->selfPathStream_)); + LOG(RkISP1, Debug) << "Exact match self"; + continue; + } + } + + /* Try to match stream allowing adjusting configuration. */ + if (mainPathAvailable) { + StreamConfiguration tryCfg = cfg; + if (validateMainPath(&tryCfg) == Adjusted) { + mainPathAvailable = false; + cfg = tryCfg; + cfg.setStream(const_cast(&data_->mainPathStream_)); + status = Adjusted; + LOG(RkISP1, Debug) << "Adjust match main"; + continue; + } + } + + if (selfPathAvailable) { + StreamConfiguration tryCfg = cfg; + if (validateSelfPath(&tryCfg) == Adjusted) { + selfPathAvailable = false; + cfg = tryCfg; + cfg.setStream(const_cast(&data_->selfPathStream_)); + status = Adjusted; + LOG(RkISP1, Debug) << "Adjust match self"; + continue; + } + } + + /* All paths rejected configuraiton. */ + LOG(RkISP1, Debug) << "Camera configuration not supported " + << cfg.toString(); + return Invalid; } /* Select the sensor format. */ + Size maxSize; + for (const StreamConfiguration &cfg : config_) + maxSize = std::max(maxSize, cfg.size); + sensorFormat_ = sensor->getFormat({ MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGRBG12_1X12, @@ -529,47 +680,10 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8 }, - cfg.size); + maxSize); if (sensorFormat_.size.isNull()) sensorFormat_.size = sensor->resolution(); - /* - * Provide a suitable default that matches the sensor aspect - * ratio and clamp the size to the hardware bounds. - * - * \todo: Check the hardware alignment constraints. - */ - const Size size = cfg.size; - - if (cfg.size.isNull()) { - cfg.size.width = 1280; - cfg.size.height = 1280 * sensorFormat_.size.height - / sensorFormat_.size.width; - } - - cfg.size.boundTo(RKISP1_RSZ_MP_SRC_MAX); - cfg.size.expandTo(RKISP1_RSZ_MP_SRC_MIN); - - if (cfg.size != size) { - LOG(RkISP1, Debug) - << "Adjusting size from " << size.toString() - << " to " << cfg.size.toString(); - status = Adjusted; - } - - cfg.bufferCount = RKISP1_BUFFER_COUNT; - - V4L2DeviceFormat format = {}; - format.fourcc = data_->mainPathVideo_->toV4L2PixelFormat(cfg.pixelFormat); - format.size = cfg.size; - - int ret = data_->mainPathVideo_->tryFormat(&format); - if (ret) - return Invalid; - - cfg.stride = format.planes[0].bpl; - cfg.frameSize = format.planes[0].size; - return status; }