Show a patch.

GET /api/1.1/patches/18913/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 18913,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/18913/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/18913/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20230731113115.5915-5-jacopo.mondi@ideasonboard.com>",
    "date": "2023-07-31T11:31:15",
    "name": "[libcamera-devel,v2,4/4] libcamera: rpi: Handle SensorConfiguration",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "739f5afe60ab15158d5e31a844427020ff936320",
    "submitter": {
        "id": 143,
        "url": "https://patchwork.libcamera.org/api/1.1/people/143/?format=api",
        "name": "Jacopo Mondi",
        "email": "jacopo.mondi@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/18913/mbox/",
    "series": [
        {
            "id": 3997,
            "url": "https://patchwork.libcamera.org/api/1.1/series/3997/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=3997",
            "date": "2023-07-31T11:31:11",
            "name": "libcamera: Introduce SensorConfiguration",
            "version": 2,
            "mbox": "https://patchwork.libcamera.org/series/3997/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/18913/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/18913/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id ABE77BDB13\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 31 Jul 2023 11:31:41 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id B55ED627F5;\n\tMon, 31 Jul 2023 13:31:40 +0200 (CEST)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 73FC2627E9\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 31 Jul 2023 13:31:36 +0200 (CEST)",
            "from uno.localdomain (mob-5-90-53-43.net.vodafone.it [5.90.53.43])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 21F6613FE; \n\tMon, 31 Jul 2023 13:30:34 +0200 (CEST)"
        ],
        "DKIM-Signature": [
            "v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1690803100;\n\tbh=Wp56nl5npdu8C15sqpEX9otS5fjQOvWpzNhLTxIHg4Y=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc:\n\tFrom;\n\tb=Eh/p2RGBlUcLsx7Zd+rzlS0afGBc8t24mm2tEn7OcUbSKh4yvHWm/Z7rJpKJwiqbN\n\t/O+OHzP1Yt+fsFXyESDIgwCxME1ezE9xVHQEb0GcjAXPZXX6sEkTQDcWtrkDzKPxTT\n\tCQyVpNxQrFZYTHDtQRTaYpp8NeXQk6Tb2FQNK/Jk5koobfztTDd4LY8nhUimtYdt5p\n\trUSI4E6bTHDvdCHFk6h0XJlwBQnzOA8sAbiFxi0VJCWDgZky+SGhhq2tVTY/n80j9A\n\t9yxB1FJLKzAsfnwSg3TdP3pENVBJsWuKgTv+fSFp8dRTqXBUtYIyb+rQrYzLAUvydJ\n\t1keswWu0Vf47g==",
            "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1690803034;\n\tbh=Wp56nl5npdu8C15sqpEX9otS5fjQOvWpzNhLTxIHg4Y=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=FQThiTKazO6x9OHfPsY+Re/3C3zh5Ef4KA5dFstKX5noE5BXmz5q6DNhHJv5fjC5w\n\tZ/KgN5/dIJwBb8ISb9AFo4q6zI2Op8IKBEkZMfnA419tTmE6iYRKtUUNQYVuNMb2jZ\n\t6bwxaGfG3AYfBYldPz683Hk9gOEZvnVolINSMvZo="
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"FQThiTKa\"; dkim-atps=neutral",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Mon, 31 Jul 2023 13:31:15 +0200",
        "Message-Id": "<20230731113115.5915-5-jacopo.mondi@ideasonboard.com>",
        "X-Mailer": "git-send-email 2.40.1",
        "In-Reply-To": "<20230731113115.5915-1-jacopo.mondi@ideasonboard.com>",
        "References": "<20230731113115.5915-1-jacopo.mondi@ideasonboard.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "Subject": "[libcamera-devel] [PATCH v2 4/4] libcamera: rpi: Handle\n\tSensorConfiguration",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "From": "Jacopo Mondi via libcamera-devel <libcamera-devel@lists.libcamera.org>",
        "Reply-To": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Handle the SensorConfiguration provided by the application in the\npipeline validate() and configure() call chains.\n\nDuring validation, first make sure SensorConfiguration is valid, then\nhandle it to compute the sensor format.\n\nFor the VC4 platform where the RAW stream follows the sensor's\nconfiguration adjust the RAW stream configuration to match the sensor\nconfiguration.\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n .../pipeline/rpi/common/pipeline_base.cpp     | 62 ++++++++++++++++---\n .../pipeline/rpi/common/pipeline_base.h       |  4 +-\n src/libcamera/pipeline/rpi/vc4/vc4.cpp        | 30 ++++++++-\n 3 files changed, 82 insertions(+), 14 deletions(-)",
    "diff": "diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\nindex 97acafbbb728..15c7a5c72bdd 100644\n--- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp\n@@ -180,6 +180,11 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n \tif (config_.empty())\n \t\treturn Invalid;\n \n+\tif (!sensorConfig.valid()) {\n+\t\tLOG(RPI, Error) << \"Invalid sensor configuration request\";\n+\t\treturn Invalid;\n+\t}\n+\n \tstatus = validateColorSpaces(ColorSpaceFlag::StreamsShareColorSpace);\n \n \t/*\n@@ -207,19 +212,43 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n \tstd::sort(outStreams.begin(), outStreams.end(),\n \t\t  [](auto &l, auto &r) { return l.cfg->size > r.cfg->size; });\n \n-\t/* Compute the sensor configuration. */\n-\tunsigned int bitDepth = defaultRawBitDepth;\n-\tif (!rawStreams.empty()) {\n+\t/* Compute the sensor's format then do any platform specific fixups. */\n+\tunsigned int bitDepth;\n+\tSize sensorSize;\n+\n+\tif (sensorConfig) {\n+\t\t/* Use the application provided sensor configuration. */\n+\t\tbitDepth = sensorConfig.bitDepth;\n+\t\tsensorSize = sensorConfig.outputSize;\n+\t} else if (!rawStreams.empty()) {\n+\t\t/* Use the RAW stream format and size. */\n \t\tBayerFormat bayerFormat = BayerFormat::fromPixelFormat(rawStreams[0].cfg->pixelFormat);\n \t\tbitDepth = bayerFormat.bitDepth;\n+\t\tsensorSize = rawStreams[0].cfg->size;\n+\t} else {\n+\t\tbitDepth = defaultRawBitDepth;\n+\t\tsensorSize = outStreams[0].cfg->size;\n \t}\n \n-\tsensorFormat_ = data_->findBestFormat(rawStreams.empty() ? outStreams[0].cfg->size\n-\t\t\t\t\t\t\t\t : rawStreams[0].cfg->size,\n-\t\t\t\t\t      bitDepth);\n+\tsensorFormat_ = data_->findBestFormat(sensorSize, bitDepth);\n+\n+\t/*\n+\t * If a sensor configuration has been requested, it should apply\n+\t * without modifications.\n+\t */\n+\tif (sensorConfig) {\n+\t\tBayerFormat bayer = BayerFormat::fromMbusCode(sensorFormat_.mbus_code);\n+\n+\t\tif (bayer.bitDepth != sensorConfig.bitDepth ||\n+\t\t    sensorFormat_.size != sensorConfig.outputSize) {\n+\t\t\tLOG(RPI, Error) << \"Invalid sensor configuration: \"\n+\t\t\t\t\t<< \"bitDepth/size mismatch\";\n+\t\t\treturn Invalid;\n+\t\t}\n+\t}\n \n \t/* Do any platform specific fixups. */\n-\tstatus = data_->platformValidate(rawStreams, outStreams);\n+\tstatus = data_->platformValidate(this, rawStreams, outStreams);\n \tif (status == Invalid)\n \t\treturn Invalid;\n \n@@ -467,12 +496,25 @@ int PipelineHandlerBase::configure(Camera *camera, CameraConfiguration *config)\n \tstd::sort(ispStreams.begin(), ispStreams.end(),\n \t\t  [](auto &l, auto &r) { return l.cfg->size > r.cfg->size; });\n \n-\t/* Apply the format on the sensor with any cached transform. */\n+\t/*\n+\t * Apply the format on the sensor with any cached transform.\n+\t *\n+\t * If the application has provided a sensor configuration apply it\n+\t * instead of just applying a format.\n+\t */\n \tconst RPiCameraConfiguration *rpiConfig =\n \t\t\t\tstatic_cast<const RPiCameraConfiguration *>(config);\n-\tV4L2SubdeviceFormat sensorFormat = rpiConfig->sensorFormat_;\n+\tV4L2SubdeviceFormat sensorFormat;\n \n-\tret = data->sensor_->setFormat(&sensorFormat, rpiConfig->combinedTransform_);\n+\tif (rpiConfig->sensorConfig) {\n+\t\tret = data->sensor_->applyConfiguration(rpiConfig->sensorConfig,\n+\t\t\t\t\t\t\trpiConfig->combinedTransform_,\n+\t\t\t\t\t\t\t&sensorFormat);\n+\t} else {\n+\t\tsensorFormat = rpiConfig->sensorFormat_;\n+\t\tret = data->sensor_->setFormat(&sensorFormat,\n+\t\t\t\t\t       rpiConfig->combinedTransform_);\n+\t}\n \tif (ret)\n \t\treturn ret;\n \ndiff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.h b/src/libcamera/pipeline/rpi/common/pipeline_base.h\nindex a139c98a5a2b..0a795f4d2689 100644\n--- a/src/libcamera/pipeline/rpi/common/pipeline_base.h\n+++ b/src/libcamera/pipeline/rpi/common/pipeline_base.h\n@@ -42,6 +42,7 @@ namespace RPi {\n /* Map of mbus codes to supported sizes reported by the sensor. */\n using SensorFormats = std::map<unsigned int, std::vector<Size>>;\n \n+class RPiCameraConfiguration;\n class CameraData : public Camera::Private\n {\n public:\n@@ -72,7 +73,8 @@ public:\n \t\tV4L2VideoDevice *dev;\n \t};\n \n-\tvirtual CameraConfiguration::Status platformValidate(std::vector<StreamParams> &rawStreams,\n+\tvirtual CameraConfiguration::Status platformValidate(RPiCameraConfiguration *rpiConfig,\n+\t\t\t\t\t\t\t     std::vector<StreamParams> &rawStreams,\n \t\t\t\t\t\t\t     std::vector<StreamParams> &outStreams) const = 0;\n \tvirtual int platformConfigure(const V4L2SubdeviceFormat &sensorFormat,\n \t\t\t\t      std::optional<BayerFormat::Packing> packing,\ndiff --git a/src/libcamera/pipeline/rpi/vc4/vc4.cpp b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\nindex 018cf4881d0e..bf864d4174b2 100644\n--- a/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n+++ b/src/libcamera/pipeline/rpi/vc4/vc4.cpp\n@@ -65,7 +65,8 @@ public:\n \t{\n \t}\n \n-\tCameraConfiguration::Status platformValidate(std::vector<StreamParams> &rawStreams,\n+\tCameraConfiguration::Status platformValidate(RPi::RPiCameraConfiguration *rpiConfig,\n+\t\t\t\t\t\t     std::vector<StreamParams> &rawStreams,\n \t\t\t\t\t\t     std::vector<StreamParams> &outStreams) const override;\n \n \tint platformPipelineConfigure(const std::unique_ptr<YamlObject> &root) override;\n@@ -394,7 +395,8 @@ int PipelineHandlerVc4::platformRegister(std::unique_ptr<RPi::CameraData> &camer\n \treturn 0;\n }\n \n-CameraConfiguration::Status Vc4CameraData::platformValidate(std::vector<StreamParams> &rawStreams,\n+CameraConfiguration::Status Vc4CameraData::platformValidate(RPi::RPiCameraConfiguration *rpiConfig,\n+\t\t\t\t\t\t\t    std::vector<StreamParams> &rawStreams,\n \t\t\t\t\t\t\t    std::vector<StreamParams> &outStreams) const\n {\n \tCameraConfiguration::Status status = CameraConfiguration::Status::Valid;\n@@ -405,9 +407,29 @@ CameraConfiguration::Status Vc4CameraData::platformValidate(std::vector<StreamPa\n \t\treturn CameraConfiguration::Status::Invalid;\n \t}\n \n-\tif (!rawStreams.empty())\n+\tif (!rawStreams.empty()) {\n \t\trawStreams[0].dev = unicam_[Unicam::Image].dev();\n \n+\t\t/* Adjust the RAW stream to match the requested sensor config. */\n+\t\tif (rpiConfig->sensorConfig) {\n+\t\t\tStreamConfiguration *rawStream = rawStreams[0].cfg;\n+\t\t\tBayerFormat rawBayer = BayerFormat::fromMbusCode(rpiConfig->sensorFormat_.mbus_code);\n+\n+\t\t\t/* Handle flips to make sure to match the RAW stream format. */\n+\t\t\tif (flipsAlterBayerOrder_)\n+\t\t\t\trawBayer = rawBayer.transform(rpiConfig->combinedTransform_);\n+\t\t\tPixelFormat rawFormat = rawBayer.toPixelFormat();\n+\n+\t\t\tif (rawStream->pixelFormat != rawFormat ||\n+\t\t\t    rawStream->size != rpiConfig->sensorConfig.outputSize) {\n+\t\t\t\trawStream->pixelFormat = rawFormat;\n+\t\t\t\trawStream->size = rpiConfig->sensorConfig.outputSize;\n+\n+\t\t\t\tstatus = CameraConfiguration::Adjusted;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n \t/*\n \t * For the two ISP outputs, one stream must be equal or smaller than the\n \t * other in all dimensions.\n@@ -417,6 +439,8 @@ CameraConfiguration::Status Vc4CameraData::platformValidate(std::vector<StreamPa\n \tfor (unsigned int i = 0; i < outStreams.size(); i++) {\n \t\tSize size;\n \n+\t\t/* \\todo Warn if upscaling: reduces image quality. */\n+\n \t\tsize.width = std::min(outStreams[i].cfg->size.width,\n \t\t\t\t      outStreams[0].cfg->size.width);\n \t\tsize.height = std::min(outStreams[i].cfg->size.height,\n",
    "prefixes": [
        "libcamera-devel",
        "v2",
        "4/4"
    ]
}