From patchwork Mon Sep 14 14:21:48 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: 9604 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 E3C33BF01C for ; Mon, 14 Sep 2020 14:22:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BFCD162E1F; Mon, 14 Sep 2020 16:22:18 +0200 (CEST) Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B073D62E1B for ; Mon, 14 Sep 2020 16:22:15 +0200 (CEST) X-Halon-ID: af8e5a68-f695-11ea-a39b-005056917f90 Authorized-sender: niklas.soderlund@fsdn.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-02.atm.binero.net (Halon) with ESMTPA id af8e5a68-f695-11ea-a39b-005056917f90; Mon, 14 Sep 2020 16:22:14 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 14 Sep 2020 16:21:48 +0200 Message-Id: <20200914142149.63857-13-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200914142149.63857-1-niklas.soderlund@ragnatech.se> References: <20200914142149.63857-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 12/13] 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 man and self path. The heuristics honors that the first stream in the configuration have the highest priority while still examining both streams for a best match. This change extends the formats supported by the Cameras backed by this pipeline to also include RGB888 and RGB656, that is only available on the self path. 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 --- * 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 | 222 +++++++++++++++++------ 1 file changed, 171 insertions(+), 51 deletions(-) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index bc961f8e78f2c979..851ff68f138b98dd 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 @@ -40,7 +41,7 @@ LOG_DEFINE_CATEGORY(RkISP1) namespace { constexpr Size RKISP1_RSZ_MP_SRC_MIN { 32, 16 }; constexpr Size RKISP1_RSZ_MP_SRC_MAX { 4416, 3312 }; - constexpr std::array RKISP1_RSZ_MP_FORMATS{ + const std::vector RKISP1_RSZ_MP_FORMATS{ formats::YUYV, formats::YVYU, formats::VYUY, @@ -50,7 +51,21 @@ namespace { 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 }; + const std::vector RKISP1_RSZ_SP_FORMATS{ + formats::YUYV, + formats::YVYU, + formats::VYUY, + formats::NV16, + formats::NV61, + formats::NV21, + formats::NV12, + formats::BGR888, + formats::RGB565, + }; +}; class PipelineHandlerRkISP1; class RkISP1ActionQueueBuffers; @@ -181,13 +196,22 @@ public: private: static constexpr unsigned int RKISP1_BUFFER_COUNT = 4; + bool fitAnyPath(const StreamConfiguration &cfg); + + CameraConfiguration::Status validatePath(StreamConfiguration *cfg, + const std::vector &formats, + const Size &min, const Size &max, + V4L2VideoDevice *video); + CameraConfiguration::Status validateMainPath(StreamConfiguration *cfg); + CameraConfiguration::Status validateSelfPath(StreamConfiguration *cfg); + /* * The RkISP1CameraData instance is guaranteed to be valid as long as the * corresponding Camera instance is valid. In order to borrow a * reference to the camera data, store a new reference to the camera. */ std::shared_ptr camera_; - const RkISP1CameraData *data_; + RkISP1CameraData *data_; V4L2SubdeviceFormat sensorFormat_; }; @@ -497,6 +521,75 @@ RkISP1CameraConfiguration::RkISP1CameraConfiguration(Camera *camera, data_ = data; } +bool RkISP1CameraConfiguration::fitAnyPath(const StreamConfiguration &cfg) +{ + if (std::find(RKISP1_RSZ_MP_FORMATS.begin(), + RKISP1_RSZ_MP_FORMATS.end(), cfg.pixelFormat) == + RKISP1_RSZ_MP_FORMATS.end()) + return false; + + if (cfg.size < RKISP1_RSZ_MP_SRC_MIN || cfg.size > RKISP1_RSZ_MP_SRC_MAX) + return false; + + if (std::find(RKISP1_RSZ_SP_FORMATS.begin(), + RKISP1_RSZ_SP_FORMATS.end(), cfg.pixelFormat) == + RKISP1_RSZ_SP_FORMATS.end()) + return false; + + if (cfg.size < RKISP1_RSZ_SP_SRC_MIN || cfg.size > RKISP1_RSZ_SP_SRC_MAX) + return false; + + return true; +} + +CameraConfiguration::Status RkISP1CameraConfiguration::validatePath( + StreamConfiguration *cfg, const std::vector &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_); +} + CameraConfiguration::Status RkISP1CameraConfiguration::validate() { const CameraSensor *sensor = data_->sensor_; @@ -506,22 +599,86 @@ 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 them streams. The first stream have the highest + * priority but if both main path and self path can satisfy it evaluate + * second stream first. + */ + std::vector order(config_.size()); + std::iota(order.begin(), order.end(), 0); + if (config_.size() == 2 && fitAnyPath(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(&data_->mainPathStream_); + LOG(RkISP1, Debug) << "Exact match main"; + continue; + } + } + + if (selfPathAvailable) { + StreamConfiguration tryCfg = cfg; + if (validateSelfPath(&tryCfg) == Valid) { + selfPathAvailable = false; + cfg = tryCfg; + cfg.setStream(&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(&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(&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, @@ -534,47 +691,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; }