{"id":11363,"url":"https://patchwork.libcamera.org/api/1.1/patches/11363/?format=json","web_url":"https://patchwork.libcamera.org/patch/11363/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20210222113227.395737-1-jacopo@jmondi.org>","date":"2021-02-22T11:32:27","name":"[libcamera-devel,v5] libcamera: ipu3: Add rotation to ipu3 pipeline","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"bfea4e7c5734eabb586cddda477bfdff35049649","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/1.1/people/3/?format=json","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/11363/mbox/","series":[{"id":1719,"url":"https://patchwork.libcamera.org/api/1.1/series/1719/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=1719","date":"2021-02-22T11:32:27","name":"[libcamera-devel,v5] libcamera: ipu3: Add rotation to ipu3 pipeline","version":5,"mbox":"https://patchwork.libcamera.org/series/1719/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/11363/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/11363/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 95C11BD1F1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 22 Feb 2021 11:32:09 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 241EE68A04;\n\tMon, 22 Feb 2021 12:32:09 +0100 (CET)","from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net\n\t[217.70.183.195])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5450D637DA\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 22 Feb 2021 12:32:07 +0100 (CET)","from uno.lan (93-34-118-233.ip49.fastwebnet.it [93.34.118.233])\n\t(Authenticated sender: jacopo@jmondi.org)\n\tby relay3-d.mail.gandi.net (Postfix) with ESMTPSA id 70DB360002;\n\tMon, 22 Feb 2021 11:32:06 +0000 (UTC)"],"X-Originating-IP":"93.34.118.233","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"libcamera-devel@lists.libcamera.org","Date":"Mon, 22 Feb 2021 12:32:27 +0100","Message-Id":"<20210222113227.395737-1-jacopo@jmondi.org>","X-Mailer":"git-send-email 2.30.0","MIME-Version":"1.0","Subject":"[libcamera-devel] [PATCH v5] libcamera: ipu3: Add rotation to ipu3\n\tpipeline","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>","Content-Type":"text/plain; charset=\"utf-8\"","Content-Transfer-Encoding":"base64","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"From: Fabian Wüthrich <me@fabwu.ch>\n\nUse the same transformation logic as in the raspberry pipeline to\nimplement rotations in the ipu3 pipeline.\n\nTested on a Surface Book 2 with an experimental driver for OV5693.\n\nSigned-off-by: Fabian Wüthrich <me@fabwu.ch>\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\nSigned-off-by: Jacopo Mondi <jacopo@jmondi.org>\n---\n\nI have re-based and re-worked this slightly\n\n- Rebased on master\n- Remove snake_case variables\n- Move H/V flip setting from the end of configure() to just before\n  the part where bail out if the request contains only raw streams, so that\n  transform can be applied on RAW images as well\n- Minor style changes such as breaking lines more often\n\nFabian, could you re-ack this, and maybe if you have a setup to do so re-test ?\nI'll push it with your ack!\n\nThanks\n   j\n\n---\n src/libcamera/pipeline/ipu3/ipu3.cpp | 87 +++++++++++++++++++++++++++-\n 1 file changed, 85 insertions(+), 2 deletions(-)\n\n--\n2.30.0","diff":"diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\nindex b8a655ce0b68..0561a4610007 100644\n--- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n@@ -16,6 +16,7 @@\n #include <libcamera/formats.h>\n #include <libcamera/ipa/ipu3_ipa_interface.h>\n #include <libcamera/ipa/ipu3_ipa_proxy.h>\n+#include <libcamera/property_ids.h>\n #include <libcamera/request.h>\n #include <libcamera/stream.h>\n\n@@ -75,6 +76,9 @@ public:\n\n \tuint32_t exposureTime_;\n \tRectangle cropRegion_;\n+\tbool supportsFlips_;\n+\tTransform rotationTransform_;\n+\n \tstd::unique_ptr<DelayedControls> delayedCtrls_;\n \tIPU3Frames frameInfos_;\n\n@@ -95,6 +99,9 @@ public:\n \tconst StreamConfiguration &cio2Format() const { return cio2Configuration_; }\n \tconst ImgUDevice::PipeConfig imguConfig() const { return pipeConfig_; }\n\n+\t/* Cache the combinedTransform_ that will be applied to the sensor */\n+\tTransform combinedTransform_;\n+\n private:\n \t/*\n \t * The IPU3CameraData instance is guaranteed to be valid as long as the\n@@ -167,11 +174,49 @@ CameraConfiguration::Status IPU3CameraConfiguration::validate()\n \tif (config_.empty())\n \t\treturn Invalid;\n\n-\tif (transform != Transform::Identity) {\n-\t\ttransform = Transform::Identity;\n+\tTransform combined = transform * data_->rotationTransform_;\n+\n+\t/*\n+\t * We combine the platform and user transform, but must \"adjust away\"\n+\t * any combined result that includes a transposition, as we can't do\n+\t * those. In this case, flipping only the transpose bit is helpful to\n+\t * applications - they either get the transform they requested, or have\n+\t * to do a simple transpose themselves (they don't have to worry about\n+\t * the other possible cases).\n+\t */\n+\tif (!!(combined & Transform::Transpose)) {\n+\t\t/*\n+\t\t * Flipping the transpose bit in \"transform\" flips it in the\n+\t\t * combined result too (as it's the last thing that happens),\n+\t\t * which is of course clearing it.\n+\t\t */\n+\t\ttransform ^= Transform::Transpose;\n+\t\tcombined &= ~Transform::Transpose;\n+\t\tstatus = Adjusted;\n+\t}\n+\n+\t/*\n+\t * We also check if the sensor doesn't do h/vflips at all, in which\n+\t * case we clear them, and the application will have to do everything.\n+\t */\n+\tif (!data_->supportsFlips_ && !!combined) {\n+\t\t/*\n+\t\t * If the sensor can do no transforms, then combined must be\n+\t\t * changed to the identity. The only user transform that gives\n+\t\t * rise to this is the inverse of the rotation. (Recall that\n+\t\t * combined = transform * rotationTransform.)\n+\t\t */\n+\t\ttransform = -data_->rotationTransform_;\n+\t\tcombined = Transform::Identity;\n \t\tstatus = Adjusted;\n \t}\n\n+\t/*\n+\t * Store the final combined transform that configure() will need to\n+\t * apply to the sensor to save us working it out again.\n+\t */\n+\tcombinedTransform_ = combined;\n+\n \t/* Cap the number of entries to the available streams. */\n \tif (config_.size() > IPU3_MAX_STREAMS) {\n \t\tconfig_.resize(IPU3_MAX_STREAMS);\n@@ -503,6 +548,24 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)\n \tcio2->sensor()->sensorInfo(&sensorInfo);\n \tdata->cropRegion_ = sensorInfo.analogCrop;\n\n+\t/*\n+\t * Configure the H/V flip controls based on the combination of\n+\t * the sensor and user transform.\n+\t */\n+\tif (data->supportsFlips_) {\n+\t\tControlList sensorCtrls(cio2->sensor()->controls());\n+\t\tsensorCtrls.set(V4L2_CID_HFLIP,\n+\t\t\t\tstatic_cast<int32_t>(!!(config->combinedTransform_\n+\t\t\t\t\t\t\t& Transform::HFlip)));\n+\t\tsensorCtrls.set(V4L2_CID_VFLIP,\n+\t\t\t\tstatic_cast<int32_t>(!!(config->combinedTransform_\n+\t\t\t\t\t\t        & Transform::VFlip)));\n+\n+\t\tret = cio2->sensor()->setControls(&sensorCtrls);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\n \t/*\n \t * If the ImgU gets configured, its driver seems to expect that\n \t * buffers will be queued to its outputs, as otherwise the next\n@@ -980,6 +1043,26 @@ int PipelineHandlerIPU3::registerCameras()\n \t\tdata->cio2_.frameStart().connect(data->delayedCtrls_.get(),\n \t\t\t\t\t\t &DelayedControls::applyControls);\n\n+\t\t/* Convert the sensor rotation to a transformation */\n+\t\tint32_t rotation = 0;\n+\t\tif (data->properties_.contains(properties::Rotation))\n+\t\t\trotation = data->properties_.get(properties::Rotation);\n+\t\telse\n+\t\t\tLOG(IPU3, Warning) << \"Rotation control not exposed by \"\n+\t\t\t\t\t   << cio2->sensor()->id()\n+\t\t\t\t\t   << \". Assume rotation 0\";\n+\n+\t\tbool success;\n+\t\tdata->rotationTransform_ = transformFromRotation(rotation, &success);\n+\t\tif (!success)\n+\t\t\tLOG(IPU3, Warning) << \"Invalid rotation of \" << rotation\n+\t\t\t\t\t   << \" degrees: ignoring\";\n+\n+\t\tControlList ctrls = cio2->sensor()->getControls({ V4L2_CID_HFLIP });\n+\t\tif (!ctrls.empty())\n+\t\t\t/* We assume it will support vflips too... */\n+\t\t\tdata->supportsFlips_ = true;\n+\n \t\t/**\n \t\t * \\todo Dynamically assign ImgU and output devices to each\n \t\t * stream and camera; as of now, limit support to two cameras\n","prefixes":["libcamera-devel","v5"]}