Patch Detail
Show a patch.
GET /api/patches/14683/?format=api
{ "id": 14683, "url": "https://patchwork.libcamera.org/api/patches/14683/?format=api", "web_url": "https://patchwork.libcamera.org/patch/14683/", "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": "<20211122123427.808484-3-naush@raspberrypi.com>", "date": "2021-11-22T12:34:27", "name": "[libcamera-devel,v2,2/2] pipeline: raspberrypi: Allow registration of multiple cameras", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "2ec6bae20d5ef99ce4c2fe68a3c70bf5b2861b36", "submitter": { "id": 34, "url": "https://patchwork.libcamera.org/api/people/34/?format=api", "name": "Naushir Patuck", "email": "naush@raspberrypi.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/14683/mbox/", "series": [ { "id": 2740, "url": "https://patchwork.libcamera.org/api/series/2740/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=2740", "date": "2021-11-22T12:34:25", "name": "Raspberry Pi: Multi-camera changes", "version": 2, "mbox": "https://patchwork.libcamera.org/series/2740/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/14683/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/14683/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 E38F9C324F\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 22 Nov 2021 12:34:37 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7393C60394;\n\tMon, 22 Nov 2021 13:34:37 +0100 (CET)", "from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com\n\t[IPv6:2a00:1450:4864:20::42c])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 247936033C\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 22 Nov 2021 13:34:34 +0100 (CET)", "by mail-wr1-x42c.google.com with SMTP id n29so32355005wra.11\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 22 Nov 2021 04:34:34 -0800 (PST)", "from naush-laptop.pitowers.org\n\t([2a00:1098:3142:14:eb05:dcc9:77a0:2542])\n\tby smtp.gmail.com with ESMTPSA id\n\th7sm8482231wrt.64.2021.11.22.04.34.32\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tMon, 22 Nov 2021 04:34:33 -0800 (PST)" ], "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=\"jwlM1CNF\"; 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=SzHLwUjZud8JGLrthbyJvqLPt1vhtBbowMVa1Z2XZqs=;\n\tb=jwlM1CNFPO63j8MsRTjU1+Pj0jOns6Eom52TjD6njSHeWEbQdPALsiYF3h2rbG3R0A\n\tIMWuRkNWz/Amj//DjYh5duNnHJjdqfm3iunvW0PSakCL4Cc+FJ3+ace5OJxCohwf7vmN\n\tbEs5u04anaRAyqLaW2Q/wV5FZStg+CD6fOwh2WL/67mUN3XASmnbaOplSBsimAHn+RRt\n\ta8rNCetL72rS8QMpVZY+7nTEPYbuTsBFm4uVFFmCZqMlIPJgGaUinmGa8wdB0+93C2kw\n\toSBRHWZxoNB0fqtGB09aXNJz2aoxo5IfD0BYFZWQOCZn6hNmQA4jcp69uLgUKXSpvh33\n\tPQBg==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20210112;\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=SzHLwUjZud8JGLrthbyJvqLPt1vhtBbowMVa1Z2XZqs=;\n\tb=FN1Gh7I7FPjxogzrwdeZgajT2p8sBA6VSIeEl630iHcJk+BTps4A4AmfVijzsY4i3j\n\tbK7t5U91I/84VVQFtPindbzc15QzZU1KpMGfr0WXOfgeUOVJn75Q33uUZrzA1nMFf9Q3\n\tc7APVAMGs5QHi2rr72InfEdgLxjSsUj2xwRzKMl4uRNWHdiK2VOabtPhtt8l/ul+068v\n\tQ5nkd91zl4ZvAbsToAVJOrmm5tTMepo7kfBUiPBpCriTpermJ5MPOoPlHN37Kw1nwqz4\n\tkIi7D2qd9QD/9ZpU9Yx3T2zYgwwcnc6JnDvcM1jmLnpSk2OZy8zXR+JtVHGRqGzN+Pml\n\tQXlQ==", "X-Gm-Message-State": "AOAM531dZoe3H50qBgPPHDckxCid6Pp5tcCgha/0/s85muHsXS28csxN\n\tG4HS4LgsbFU6y/2QYYQsTJfcOtP3DNpbYnbT", "X-Google-Smtp-Source": "ABdhPJz7BSm8BuGpeWWnsECACFC8R3tqR3a4Z4jKEetpqzb4q3+Crva7wu9H+N28PEGx7gI6u7tVLw==", "X-Received": "by 2002:a5d:6d8b:: with SMTP id\n\tl11mr16776085wrs.232.1637584473597; \n\tMon, 22 Nov 2021 04:34:33 -0800 (PST)", "From": "Naushir Patuck <naush@raspberrypi.com>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Mon, 22 Nov 2021 12:34:27 +0000", "Message-Id": "<20211122123427.808484-3-naush@raspberrypi.com>", "X-Mailer": "git-send-email 2.25.1", "In-Reply-To": "<20211122123427.808484-1-naush@raspberrypi.com>", "References": "<20211122123427.808484-1-naush@raspberrypi.com>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v2 2/2] pipeline: raspberrypi: Allow\n\tregistration of multiple cameras", "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>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Expand the pipeline handler camera registration to correctly handle multiple\ncameras attached to the platform. For example, Raspberry Pi Compute Module\nplatforms have two camera connectors, and this change would allow the user to\nselect either of the two cameras to run.\n\nThere are associated kernel driver changes for both Unicam and the ISP needed\nto correctly advertise multiple media devices and nodes for multi-camera usage:\n\nhttps://github.com/raspberrypi/linux/pull/4140\nhttps://github.com/raspberrypi/linux/pull/4709\n\nHowever, this change is backward compatible with kernel builds that do not have\nthese changes for standard single camera usage.\n\nSigned-off-by: Naushir Patuck <naush@raspberrypi.com>\n---\n .../pipeline/raspberrypi/raspberrypi.cpp | 113 ++++++++++++------\n 1 file changed, 74 insertions(+), 39 deletions(-)", "diff": "diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\nindex 9aa7e9eef5e7..3f9e15514ed9 100644\n--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n@@ -311,14 +311,11 @@ private:\n \t\treturn static_cast<RPiCameraData *>(camera->_d());\n \t}\n \n-\tbool registerCameras();\n+\tint registerCameras(MediaDevice *unicam, MediaDevice *isp, const std::string &deviceId);\n \tint queueAllBuffers(Camera *camera);\n \tint prepareBuffers(Camera *camera);\n \tvoid freeBuffers(Camera *camera);\n \tvoid mapBuffers(Camera *camera, const RPi::BufferMap &buffers, unsigned int mask);\n-\n-\tMediaDevice *unicam_;\n-\tMediaDevice *isp_;\n };\n \n RPiCameraConfiguration::RPiCameraConfiguration(const RPiCameraData *data)\n@@ -509,7 +506,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()\n }\n \n PipelineHandlerRPi::PipelineHandlerRPi(CameraManager *manager)\n-\t: PipelineHandler(manager), unicam_(nullptr), isp_(nullptr)\n+\t: PipelineHandler(manager)\n {\n }\n \n@@ -993,49 +990,85 @@ int PipelineHandlerRPi::queueRequestDevice(Camera *camera, Request *request)\n \n bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator)\n {\n-\tDeviceMatch unicam(\"unicam\");\n-\tDeviceMatch isp(\"bcm2835-isp\");\n+\tMediaDevice *unicamDevice, *ispDevice;\n+\tstd::string deviceId;\n \n-\tunicam.add(\"unicam-image\");\n+\t/*\n+\t * String of indexes to append to the entity names when searching for\n+\t * the Unican media devices. The first string is empty (un-indexed) to\n+\t * to maintain backward compatability with old versions of the Unicam\n+\t * kernel driver that did not advertise instance indexes.\n+\t */\n+\tfor (const std::string &id : { \"\", \"0\", \"1\" }) {\n+\t\tDeviceMatch unicam(\"unicam\");\n+\t\tunicam.add(\"unicam\" + id + \"-image\");\n+\t\tunicamDevice = acquireMediaDevice(enumerator, unicam);\n \n-\tisp.add(\"bcm2835-isp0-output0\"); /* Input */\n-\tisp.add(\"bcm2835-isp0-capture1\"); /* Output 0 */\n-\tisp.add(\"bcm2835-isp0-capture2\"); /* Output 1 */\n-\tisp.add(\"bcm2835-isp0-capture3\"); /* Stats */\n+\t\tif (unicamDevice) {\n+\t\t\tdeviceId = id == \"1\" ? \"1\" : \"0\";\n+\t\t\tbreak;\n+\t\t}\n+\t}\n \n-\tunicam_ = acquireMediaDevice(enumerator, unicam);\n-\tif (!unicam_)\n+\tif (!unicamDevice) {\n+\t\tLOG(RPI, Debug) << \"Unable to acquire a Unicam instance\";\n \t\treturn false;\n+\t}\n \n-\tisp_ = acquireMediaDevice(enumerator, isp);\n-\tif (!isp_)\n+\tDeviceMatch isp(\"bcm2835-isp\");\n+\tisp.add(\"bcm2835-isp\" + deviceId + \"-output0\"); /* Input */\n+\tisp.add(\"bcm2835-isp\" + deviceId + \"-capture1\"); /* Output 0 */\n+\tisp.add(\"bcm2835-isp\" + deviceId + \"-capture2\"); /* Output 1 */\n+\tisp.add(\"bcm2835-isp\" + deviceId + \"-capture3\"); /* Stats */\n+\tispDevice = acquireMediaDevice(enumerator, isp);\n+\n+\tif (!ispDevice) {\n+\t\tLOG(RPI, Error) << \"Unable to acquire ISP instance \" << deviceId;\n \t\treturn false;\n+\t}\n+\n+\tint ret = registerCameras(unicamDevice, ispDevice, deviceId);\n+\tif (ret) {\n+\t\tLOG(RPI, Error) << \"Failed to register camera: \" << ret;\n+\t\treturn false;\n+\t}\n \n-\treturn registerCameras();\n+\treturn true;\n }\n \n-bool PipelineHandlerRPi::registerCameras()\n+int PipelineHandlerRPi::registerCameras(MediaDevice *unicam, MediaDevice *isp,\n+\t\t\t\t\tconst std::string &deviceId)\n {\n \tstd::unique_ptr<RPiCameraData> data = std::make_unique<RPiCameraData>(this);\n+\n \tif (!data->dmaHeap_.isValid())\n-\t\treturn false;\n+\t\treturn -ENOMEM;\n+\n+\tMediaEntity *unicamImage = unicam->getEntityByName(\"unicam\" + deviceId + \"-image\");\n+\tMediaEntity *ispOutput0 = isp->getEntityByName(\"bcm2835-isp\" + deviceId + \"-output0\");\n+\tMediaEntity *ispCapture1 = isp->getEntityByName(\"bcm2835-isp\" + deviceId + \"-capture1\");\n+\tMediaEntity *ispCapture2 = isp->getEntityByName(\"bcm2835-isp\" + deviceId + \"-capture2\");\n+\tMediaEntity *ispCapture3 = isp->getEntityByName(\"bcm2835-isp\" + deviceId + \"-capture3\");\n+\n+\tif (!unicamImage || !ispOutput0 || !ispCapture1 || !ispCapture2 || !ispCapture3)\n+\t\treturn -ENOENT;\n \n \t/* Locate and open the unicam video streams. */\n-\tdata->unicam_[Unicam::Image] = RPi::Stream(\"Unicam Image\", unicam_->getEntityByName(\"unicam-image\"));\n+\tdata->unicam_[Unicam::Image] = RPi::Stream(\"Unicam Image\", unicamImage);\n \n \t/* An embedded data node will not be present if the sensor does not support it. */\n-\tMediaEntity *embeddedEntity = unicam_->getEntityByName(\"unicam-embedded\");\n-\tif (embeddedEntity) {\n-\t\tdata->unicam_[Unicam::Embedded] = RPi::Stream(\"Unicam Embedded\", embeddedEntity);\n+\tMediaEntity *unicamEmbedded = unicam->getEntityByName(\"unicam\" + deviceId + \"-embedded\");\n+\tif (unicamEmbedded) {\n+\t\tdata->unicam_[Unicam::Embedded] = RPi::Stream(\"Unicam Embedded\", unicamEmbedded);\n \t\tdata->unicam_[Unicam::Embedded].dev()->bufferReady.connect(data.get(),\n \t\t\t\t\t\t\t\t\t &RPiCameraData::unicamBufferDequeue);\n \t}\n \n \t/* Tag the ISP input stream as an import stream. */\n-\tdata->isp_[Isp::Input] = RPi::Stream(\"ISP Input\", isp_->getEntityByName(\"bcm2835-isp0-output0\"), true);\n-\tdata->isp_[Isp::Output0] = RPi::Stream(\"ISP Output0\", isp_->getEntityByName(\"bcm2835-isp0-capture1\"));\n-\tdata->isp_[Isp::Output1] = RPi::Stream(\"ISP Output1\", isp_->getEntityByName(\"bcm2835-isp0-capture2\"));\n-\tdata->isp_[Isp::Stats] = RPi::Stream(\"ISP Stats\", isp_->getEntityByName(\"bcm2835-isp0-capture3\"));\n+\tdata->isp_[Isp::Input] = RPi::Stream(\"ISP Input\", ispOutput0, true);\n+\tdata->isp_[Isp::Output0] = RPi::Stream(\"ISP Output0\", ispCapture1);\n+\tdata->isp_[Isp::Output1] = RPi::Stream(\"ISP Output1\", ispCapture2);\n+\tdata->isp_[Isp::Stats] = RPi::Stream(\"ISP Stats\", ispCapture3);\n \n \t/* Wire up all the buffer connections. */\n \tdata->unicam_[Unicam::Image].dev()->frameStart.connect(data.get(), &RPiCameraData::frameStarted);\n@@ -1046,7 +1079,7 @@ bool PipelineHandlerRPi::registerCameras()\n \tdata->isp_[Isp::Stats].dev()->bufferReady.connect(data.get(), &RPiCameraData::ispOutputDequeue);\n \n \t/* Identify the sensor. */\n-\tfor (MediaEntity *entity : unicam_->entities()) {\n+\tfor (MediaEntity *entity : unicam->entities()) {\n \t\tif (entity->function() == MEDIA_ENT_F_CAM_SENSOR) {\n \t\t\tdata->sensor_ = std::make_unique<CameraSensor>(entity);\n \t\t\tbreak;\n@@ -1054,23 +1087,23 @@ bool PipelineHandlerRPi::registerCameras()\n \t}\n \n \tif (!data->sensor_)\n-\t\treturn false;\n+\t\treturn -EINVAL;\n \n \tif (data->sensor_->init())\n-\t\treturn false;\n+\t\treturn -EINVAL;\n \n \tdata->sensorFormats_ = populateSensorFormats(data->sensor_);\n \n \tipa::RPi::SensorConfig sensorConfig;\n \tif (data->loadIPA(&sensorConfig)) {\n \t\tLOG(RPI, Error) << \"Failed to load a suitable IPA library\";\n-\t\treturn false;\n+\t\treturn -EINVAL;\n \t}\n \n-\tif (sensorConfig.sensorMetadata ^ !!embeddedEntity) {\n+\tif (sensorConfig.sensorMetadata ^ !!unicamEmbedded) {\n \t\tLOG(RPI, Warning) << \"Mismatch between Unicam and CamHelper for embedded data usage!\";\n \t\tsensorConfig.sensorMetadata = false;\n-\t\tif (embeddedEntity)\n+\t\tif (unicamEmbedded)\n \t\t\tdata->unicam_[Unicam::Embedded].dev()->bufferReady.disconnect();\n \t}\n \n@@ -1091,12 +1124,12 @@ bool PipelineHandlerRPi::registerCameras()\n \n \tfor (auto stream : data->streams_) {\n \t\tif (stream->dev()->open())\n-\t\t\treturn false;\n+\t\t\tcontinue;\n \t}\n \n \tif (!data->unicam_[Unicam::Image].dev()->caps().hasMediaController()) {\n \t\tLOG(RPI, Error) << \"Unicam driver does not use the MediaController, please update your kernel!\";\n-\t\treturn false;\n+\t\treturn -EINVAL;\n \t}\n \n \t/*\n@@ -1158,7 +1191,7 @@ bool PipelineHandlerRPi::registerCameras()\n \n \tif (!bayerFormat.isValid()) {\n \t\tLOG(RPI, Error) << \"No Bayer format found\";\n-\t\treturn false;\n+\t\treturn -EINVAL;\n \t}\n \tdata->nativeBayerOrder_ = bayerFormat.order;\n \n@@ -1173,12 +1206,14 @@ bool PipelineHandlerRPi::registerCameras()\n \tstreams.insert(&data->isp_[Isp::Output1]);\n \n \t/* Create and register the camera. */\n-\tconst std::string &id = data->sensor_->id();\n+\tconst std::string &cameraId = data->sensor_->id();\n \tstd::shared_ptr<Camera> camera =\n-\t\tCamera::create(std::move(data), id, streams);\n+\t\tCamera::create(std::move(data), cameraId, streams);\n \tregisterCamera(std::move(camera));\n \n-\treturn true;\n+\tLOG(RPI, Info) << \"Registered camera \" << cameraId\n+\t\t << \" to instance \\\"\" << deviceId << \"\\\"\";\n+\treturn 0;\n }\n \n int PipelineHandlerRPi::queueAllBuffers(Camera *camera)\n", "prefixes": [ "libcamera-devel", "v2", "2/2" ] }