Show a patch.

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

{
    "id": 9432,
    "url": "https://patchwork.libcamera.org/api/patches/9432/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/9432/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/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": "<20200829115429.30010-7-david.plowman@raspberrypi.com>",
    "date": "2020-08-29T11:54:27",
    "name": "[libcamera-devel,v5,6/8] libcamera: raspberrypi: Set camera flips correctly from user transform",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "1c90f7755992e8abd5f4fa1b13ca7a770d774998",
    "submitter": {
        "id": 42,
        "url": "https://patchwork.libcamera.org/api/people/42/?format=api",
        "name": "David Plowman",
        "email": "david.plowman@raspberrypi.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/9432/mbox/",
    "series": [
        {
            "id": 1252,
            "url": "https://patchwork.libcamera.org/api/series/1252/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1252",
            "date": "2020-08-29T11:54:21",
            "name": "2D transforms",
            "version": 5,
            "mbox": "https://patchwork.libcamera.org/series/1252/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/9432/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/9432/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 2CE7CBF019\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSat, 29 Aug 2020 11:54:43 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EDFC76293F;\n\tSat, 29 Aug 2020 13:54:42 +0200 (CEST)",
            "from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com\n\t[IPv6:2a00:1450:4864:20::42b])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BD93C62920\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 29 Aug 2020 13:54:39 +0200 (CEST)",
            "by mail-wr1-x42b.google.com with SMTP id b18so1552013wrs.7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSat, 29 Aug 2020 04:54:39 -0700 (PDT)",
            "from pi4-davidp.lan (plowpeople3.plus.com. [80.229.223.72])\n\tby smtp.gmail.com with ESMTPSA id\n\tv16sm3071523wmj.14.2020.08.29.04.54.38\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tSat, 29 Aug 2020 04:54:38 -0700 (PDT)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=raspberrypi.com header.i=@raspberrypi.com\n\theader.b=\"l4pIK0dQ\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=raspberrypi.com; s=google;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=zDr2YMtYWCg4u86sRPc68xnTPi105UzxUzv42mZx7uw=;\n\tb=l4pIK0dQ5OOYP6lifyWPIpOQCAr3S1cVqBxOvzhArCLB43ROPF1upMRR1uo0g8BY5N\n\teQisYiExZpB0YlbNIezjxIDn6CK+4ZclNktb0YSSq9XsFooNjUDFTqlFBKEN9gkFVqTY\n\tcndBcfs0eJB3MVXGvhDgnxhbSpQ7vwUNsmeyJ1qPf6Zg34wnv2mj3esGxvoWPNIf04Yy\n\tB6GfkCK2m0c49o9VLGUNB5SAnZD0KdaNh0tuHdfKsHRyJrTG74sgwtJzgluQobGa41MW\n\tiM0SjO2Lt2Q9RgcMJGuL61+xAxFmRBpN9b2qxu2zNUptA2Fr1mxKlWOlN4JxDieB4Sz5\n\tx39A==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=zDr2YMtYWCg4u86sRPc68xnTPi105UzxUzv42mZx7uw=;\n\tb=cp0cJyJDpo9iXXTGKwMkGqwFcf4Z+6MG10g4gUTjSrXEicXA7dvNevXvsoFiqF7ySl\n\tquncB3bpDyJFqwRzuJuFHa3JFfOPrt2cZxu7CTztFtJN9UsN+7wvuHzHluZLSnBvQvut\n\twC8/TFGezBxFsAKYWqW9xVImcFVL2sRRssmubRn90Ki6R1TItZyA+ZRNirugYixZ6cKF\n\tyTWpGpRfp8hYywklzM6X09Y4qSkml3rxmcK6PtlTFkZP2OEAs0yMy6voixwQMIXqj0DD\n\tKEDvuYsXGSf05GwwScrxLM8R23D/snOjNoqk5gQeuJozfCEBZlgSvswgRqMzlk8jRgBr\n\ta7kg==",
        "X-Gm-Message-State": "AOAM530OrenagWmg7XfEIxdvOtb5Pk92HSV3hymzMibtBmVS8VrM0q1c\n\tSdhwfido32GTFu5TE4n7Q6rrPUgZ1zfk/g==",
        "X-Google-Smtp-Source": "ABdhPJweY8ywZbVOribAyDsMtQj5rjI/4HeHkM5MREYB3GHV1SaQ26jaEHOc8ugrLicVItcpo1EuVA==",
        "X-Received": "by 2002:adf:ef0a:: with SMTP id\n\te10mr1414775wro.362.1598702079089; \n\tSat, 29 Aug 2020 04:54:39 -0700 (PDT)",
        "From": "David Plowman <david.plowman@raspberrypi.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Date": "Sat, 29 Aug 2020 12:54:27 +0100",
        "Message-Id": "<20200829115429.30010-7-david.plowman@raspberrypi.com>",
        "X-Mailer": "git-send-email 2.20.1",
        "In-Reply-To": "<20200829115429.30010-1-david.plowman@raspberrypi.com>",
        "References": "<20200829115429.30010-1-david.plowman@raspberrypi.com>",
        "MIME-Version": "1.0",
        "Subject": "[libcamera-devel] [PATCH v5 6/8] libcamera: raspberrypi: Set camera\n\tflips correctly from user transform",
        "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=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "The Raspberry Pi pipeline handler allows all transforms except those\ninvolving a transpose. The user transform is combined with any\ninherent rotation of the camera, and the camera's H and V flip bits\nare set accordingly.\n\nNote that the validate() method has to work out what the final Bayer\norder of any raw streams will be, before configure() actually applies\nthe transform to the sensor.\n\nSigned-off-by: David Plowman <david.plowman@raspberrypi.com>\n---\n .../pipeline/raspberrypi/raspberrypi.cpp      | 82 ++++++++++++++++---\n 1 file changed, 71 insertions(+), 11 deletions(-)",
    "diff": "diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\nindex c554532..333aa94 100644\n--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n@@ -294,7 +294,7 @@ public:\n \tvoid frameStarted(uint32_t sequence);\n \n \tint loadIPA();\n-\tint configureIPA();\n+\tint configureIPA(CameraConfiguration *config);\n \n \tvoid queueFrameAction(unsigned int frame, const IPAOperationData &action);\n \n@@ -400,8 +400,34 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n \tif (config_.empty())\n \t\treturn Invalid;\n \n-\tif (transform != Transform::Identity) {\n-\t\ttransform = Transform::Identity;\n+\t/*\n+\t * What if the platform has a non-90 degree rotation? We can't even\n+\t * \"adjust\" the configuration and carry on. Alternatively, raising an\n+\t * error means the platform can never run. Let's just print a warning\n+\t * and continue regardless; the rotation is effectively set to zero.\n+\t */\n+\tint32_t rotation = data_->sensor_->properties().get(properties::Rotation);\n+\tbool success;\n+\tTransform combined = transform * transformFromRotation(rotation, &success);\n+\tif (!success)\n+\t\tLOG(RPI, Warning) << \"Invalid rotation of \" << rotation\n+\t\t\t\t  << \" degrees - ignoring\";\n+\n+\t/*\n+\t * We combine the platform and user transform, but must \"adjust away\"\n+\t * any combined result that includes a transform, as we can't do those.\n+\t * 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\n+\t\t * combined result too (as it's the last thing that happens).\n+\t\t */\n+\t\ttransform ^= Transform::Transpose;\n+\t\tcombined ^= Transform::Transpose;\n \t\tstatus = Adjusted;\n \t}\n \n@@ -414,13 +440,42 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n \t\t\t * Calculate the best sensor mode we can use based on\n \t\t\t * the user request.\n \t\t\t */\n-\t\t\tV4L2VideoDevice::Formats fmts = data_->unicam_[Unicam::Image].dev()->formats();\n+\t\t\tV4L2VideoDevice *dev = data_->unicam_[Unicam::Image].dev();\n+\t\t\tV4L2VideoDevice::Formats fmts = dev->formats();\n \t\t\tV4L2DeviceFormat sensorFormat = findBestMode(fmts, cfg.size);\n-\t\t\tint ret = data_->unicam_[Unicam::Image].dev()->tryFormat(&sensorFormat);\n+\t\t\tint ret = dev->tryFormat(&sensorFormat);\n \t\t\tif (ret)\n \t\t\t\treturn Invalid;\n \n-\t\t\tPixelFormat sensorPixFormat = sensorFormat.fourcc.toPixelFormat();\n+\t\t\t/*\n+\t\t\t * Some sensors change their Bayer order when they are\n+\t\t\t * h-flipped or v-flipped, according to the transform.\n+\t\t\t * If the controls own up to \"modifying the layout\" we\n+\t\t\t * will assume that's what is going on and advertise\n+\t\t\t * the transformed Bayer order in the stream.\n+\t\t\t */\n+\t\t\tV4L2PixelFormat fourcc = sensorFormat.fourcc;\n+\n+\t\t\t/*\n+\t\t\t * The camera may already be transformed, so we must\n+\t\t\t * only transform the fourcc if the new transform is\n+\t\t\t * different.\n+\t\t\t */\n+\t\t\tControlList ctrls = dev->getControls({ V4L2_CID_HFLIP, V4L2_CID_VFLIP });\n+\n+\t\t\tconst struct v4l2_query_ext_ctrl *hflipCtrl = dev->queryControl(V4L2_CID_HFLIP);\n+\t\t\tif (hflipCtrl &&\n+\t\t\t    (hflipCtrl->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT) &&\n+\t\t\t    ctrls.get(V4L2_CID_HFLIP).get<int32_t>() != !!(combined & Transform::HFlip))\n+\t\t\t\tfourcc = fourcc.transform(Transform::HFlip);\n+\n+\t\t\tconst struct v4l2_query_ext_ctrl *vflipCtrl = dev->queryControl(V4L2_CID_VFLIP);\n+\t\t\tif (vflipCtrl &&\n+\t\t\t    (vflipCtrl->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT) &&\n+\t\t\t    ctrls.get(V4L2_CID_VFLIP).get<int32_t>() != !!(combined & Transform::VFlip))\n+\t\t\t\tfourcc = fourcc.transform(Transform::VFlip);\n+\n+\t\t\tPixelFormat sensorPixFormat = fourcc.toPixelFormat();\n \t\t\tif (cfg.size != sensorFormat.size ||\n \t\t\t    cfg.pixelFormat != sensorPixFormat) {\n \t\t\t\tcfg.size = sensorFormat.size;\n@@ -756,7 +811,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)\n \tcrop.y = (sensorFormat.size.height - crop.height) >> 1;\n \tdata->isp_[Isp::Input].dev()->setSelection(V4L2_SEL_TGT_CROP, &crop);\n \n-\tret = data->configureIPA();\n+\tret = data->configureIPA(config);\n \tif (ret)\n \t\tLOG(RPI, Error) << \"Failed to configure the IPA: \" << ret;\n \n@@ -1112,7 +1167,7 @@ int RPiCameraData::loadIPA()\n \treturn ipa_->init(settings);\n }\n \n-int RPiCameraData::configureIPA()\n+int RPiCameraData::configureIPA(CameraConfiguration *config)\n {\n \tstd::map<unsigned int, IPAStream> streamConfig;\n \tstd::map<unsigned int, const ControlInfoMap &> entityControls;\n@@ -1170,11 +1225,16 @@ int RPiCameraData::configureIPA()\n \t\t\tsensorMetadata_ = result.data[2];\n \t\t}\n \n-\t\t/* Configure the H/V flip controls based on the sensor rotation. */\n+\t\t/* \n+\t\t * Configure the H/V flip controls based on the sensor rotation\n+\t\t * and user transform.\n+\t\t */\n \t\tControlList ctrls(unicam_[Unicam::Image].dev()->controls());\n \t\tint32_t rotation = sensor_->properties().get(properties::Rotation);\n-\t\tctrls.set(V4L2_CID_HFLIP, static_cast<int32_t>(!!rotation));\n-\t\tctrls.set(V4L2_CID_VFLIP, static_cast<int32_t>(!!rotation));\n+\t\t/* The rotation angle was already checked in validate(). */\n+\t\tTransform combined = config->transform * transformFromRotation(rotation);\n+\t\tctrls.set(V4L2_CID_HFLIP, static_cast<int32_t>(!!(combined & Transform::HFlip)));\n+\t\tctrls.set(V4L2_CID_VFLIP, static_cast<int32_t>(!!(combined & Transform::VFlip)));\n \t\tunicam_[Unicam::Image].dev()->setControls(&ctrls);\n \t}\n \n",
    "prefixes": [
        "libcamera-devel",
        "v5",
        "6/8"
    ]
}