{"id":10730,"url":"https://patchwork.libcamera.org/api/1.1/patches/10730/?format=json","web_url":"https://patchwork.libcamera.org/patch/10730/","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":"<20201224081613.41662-10-paul.elder@ideasonboard.com>","date":"2020-12-24T08:16:11","name":"[libcamera-devel,v6,09/11] libcamera: pipeline, ipa: raspberrypi: Use new data definition","commit_ref":null,"pull_url":null,"state":"changes-requested","archived":false,"hash":"b08adb9a5ab5675b26b2a601f5068466ca526bd0","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/1.1/people/17/?format=json","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"delegate":{"id":17,"url":"https://patchwork.libcamera.org/api/1.1/users/17/?format=json","username":"epaul","first_name":"Paul","last_name":"Elder","email":"paul.elder@ideasonboard.com"},"mbox":"https://patchwork.libcamera.org/patch/10730/mbox/","series":[{"id":1547,"url":"https://patchwork.libcamera.org/api/1.1/series/1547/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=1547","date":"2020-12-24T08:16:02","name":"IPA isolation: Part 2: Conversion and plumbing","version":6,"mbox":"https://patchwork.libcamera.org/series/1547/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/10730/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/10730/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 B8670C0F1A\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 24 Dec 2020 08:16:47 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 85D0F6200B;\n\tThu, 24 Dec 2020 09:16:47 +0100 (CET)","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 3620662005\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 24 Dec 2020 09:16:46 +0100 (CET)","from pyrite.rasen.tech (unknown\n\t[IPv6:2400:4051:61:600:2c71:1b79:d06d:5032])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id AECEAA1D;\n\tThu, 24 Dec 2020 09:16:44 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"dIuSS3CI\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1608797805;\n\tbh=JgllzIojnq28j1Y6xawxhiwSQYFqZJ5wSgdp9TSkaXM=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=dIuSS3CIkDusbKO/CXJCcvTUr2I26r1jkvoN0H1ObJciAxe/zYJHW/B5aha08RruS\n\t8vZBaJBvcxOjPrW/VTN+ZKK7knFCsZ2ShI5CA4nqOAPsNZoz6VC1r3dUhYCrfFUhnm\n\tT3o7ExWmToT9/qKXzEqpMhhetWBzKiP2Qll8gqpc=","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Thu, 24 Dec 2020 17:16:11 +0900","Message-Id":"<20201224081613.41662-10-paul.elder@ideasonboard.com>","X-Mailer":"git-send-email 2.27.0","In-Reply-To":"<20201224081613.41662-1-paul.elder@ideasonboard.com>","References":"<20201224081613.41662-1-paul.elder@ideasonboard.com>","MIME-Version":"1.0","Subject":"[libcamera-devel] [PATCH v6 09/11] libcamera: pipeline,\n\tipa: raspberrypi: Use new data definition","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":"Now that we can generate custom functions and data structures with mojo,\nswitch the raspberrypi pipeline handler and IPA to use the custom data\nstructures as defined in the mojom data definition file.\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\n\n---\nChanges in v6:\n- rebase on \"pipeline: ipa: raspberrypi: Handle failures during IPA\n  configuration\"\n- move the enums and consts to the mojom file\n  - use them with the namespace in the IPA and pipeline handler\n- no longer need to initialize the ControlInfoMap\n- fill in the LS table handle in the pipeline handler instead of passing\n  it from the IPA (which was passed to the IPA from the pipeline handler\n  in the first place)\n- use custom start()\n- no more postfix _ in generated struct fields\n\nChanges in v5:\n- minor fixes\n- use new struct names\n\nChanges in v4:\n- rename Controls to controls\n- use the renamed header (raspberrypi_ipa_interface.h)\n\nChanges in v3:\n- use ipa::rpi namespace\n- rebase on the RPi namespace patch series newly merged into master\n\nChanges in v2:\n- rebased on \"libcamera: pipeline: ipa: raspberrypi: Rework drop frame\n  signalling\"\n- use newly customized RPi IPA interface\n---\n include/libcamera/ipa/raspberrypi.h           |  11 -\n src/ipa/raspberrypi/raspberrypi.cpp           | 181 ++++++-------\n .../pipeline/raspberrypi/raspberrypi.cpp      | 244 +++++++++---------\n .../pipeline/raspberrypi/rpi_stream.cpp       |   6 +-\n .../pipeline/raspberrypi/rpi_stream.h         |   5 +-\n 5 files changed, 208 insertions(+), 239 deletions(-)","diff":"diff --git a/include/libcamera/ipa/raspberrypi.h b/include/libcamera/ipa/raspberrypi.h\nindex df30b4a2..70ecc5a8 100644\n--- a/include/libcamera/ipa/raspberrypi.h\n+++ b/include/libcamera/ipa/raspberrypi.h\n@@ -16,17 +16,6 @@ namespace libcamera {\n \n namespace RPi {\n \n-enum BufferMask {\n-\tID\t\t= 0x00ffff,\n-\tSTATS\t\t= 0x010000,\n-\tEMBEDDED_DATA\t= 0x020000,\n-\tBAYER_DATA\t= 0x040000,\n-\tEXTERNAL_BUFFER\t= 0x100000,\n-};\n-\n-/* Size of the LS grid allocation. */\n-static constexpr unsigned int MaxLsGridSize = 32 << 10;\n-\n /* List of controls handled by the Raspberry Pi IPA */\n static const ControlInfoMap Controls = {\n \t{ &controls::AeEnable, ControlInfo(false, true) },\ndiff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp\nindex 67f47c11..5acc25a0 100644\n--- a/src/ipa/raspberrypi/raspberrypi.cpp\n+++ b/src/ipa/raspberrypi/raspberrypi.cpp\n@@ -20,6 +20,7 @@\n #include <libcamera/ipa/ipa_interface.h>\n #include <libcamera/ipa/ipa_module_info.h>\n #include <libcamera/ipa/raspberrypi.h>\n+#include <libcamera/ipa/raspberrypi_ipa_interface.h>\n #include <libcamera/request.h>\n #include <libcamera/span.h>\n \n@@ -59,7 +60,7 @@ constexpr unsigned int DefaultExposureTime = 20000;\n \n LOG_DEFINE_CATEGORY(IPARPI)\n \n-class IPARPi : public IPAInterface\n+class IPARPi : public ipa::rpi::IPARPiInterface\n {\n public:\n \tIPARPi()\n@@ -72,21 +73,24 @@ public:\n \t~IPARPi()\n \t{\n \t\tif (lsTable_)\n-\t\t\tmunmap(lsTable_, RPi::MaxLsGridSize);\n+\t\t\tmunmap(lsTable_, ipa::rpi::MaxLsGridSize);\n \t}\n \n \tint init(const IPASettings &settings) override;\n-\tint start(const IPAOperationData &data, IPAOperationData *result) override;\n+\tvoid start(const ipa::rpi::StartControls &data,\n+\t\t   ipa::rpi::StartControls *result, int *ret) override;\n \tvoid stop() override {}\n \n \tvoid configure(const CameraSensorInfo &sensorInfo,\n \t\t       const std::map<unsigned int, IPAStream> &streamConfig,\n-\t\t       const std::map<unsigned int, const ControlInfoMap &> &entityControls,\n-\t\t       const IPAOperationData &ipaConfig,\n-\t\t       IPAOperationData *response) override;\n+\t\t       const std::map<unsigned int, ControlInfoMap> &entityControls,\n+\t\t       const ipa::rpi::ConfigInput &data,\n+\t\t       ipa::rpi::ConfigOutput *response) override;\n \tvoid mapBuffers(const std::vector<IPABuffer> &buffers) override;\n \tvoid unmapBuffers(const std::vector<unsigned int> &ids) override;\n-\tvoid processEvent(const IPAOperationData &event) override;\n+\tvoid signalStatReady(const uint32_t bufferId) override;\n+\tvoid signalQueueRequest(const ControlList &controls) override;\n+\tvoid signalIspPrepare(const ipa::rpi::ISPConfig &data) override;\n \n private:\n \tvoid setMode(const CameraSensorInfo &sensorInfo);\n@@ -156,15 +160,17 @@ int IPARPi::init(const IPASettings &settings)\n \treturn 0;\n }\n \n-int IPARPi::start(const IPAOperationData &data, IPAOperationData *result)\n+void IPARPi::start(const ipa::rpi::StartControls &data,\n+\t\t   ipa::rpi::StartControls *result, int *ret)\n {\n \tRPiController::Metadata metadata;\n \n+\tASSERT(ret);\n \tASSERT(result);\n-\tresult->operation = 0;\n-\tif (data.operation & RPi::IPA_CONFIG_STARTUP) {\n+\tresult->hasControls = false;\n+\tif (data.hasControls) {\n \t\t/* We have been given some controls to action before start. */\n-\t\tqueueRequest(data.controls[0]);\n+\t\tqueueRequest(data.controls);\n \t}\n \n \tcontroller_.SwitchMode(mode_, &metadata);\n@@ -179,8 +185,8 @@ int IPARPi::start(const IPAOperationData &data, IPAOperationData *result)\n \tif (agcStatus.shutter_time != 0.0 && agcStatus.analogue_gain != 0.0) {\n \t\tControlList ctrls(sensorCtrls_);\n \t\tapplyAGC(&agcStatus, ctrls);\n-\t\tresult->controls.emplace_back(ctrls);\n-\t\tresult->operation |= RPi::IPA_CONFIG_SENSOR;\n+\t\tresult->controls = std::move(ctrls);\n+\t\tresult->hasControls = true;\n \t}\n \n \t/*\n@@ -227,12 +233,11 @@ int IPARPi::start(const IPAOperationData &data, IPAOperationData *result)\n \t\tmistrustCount_ = helper_->MistrustFramesModeSwitch();\n \t}\n \n-\tresult->data.push_back(dropFrame);\n-\tresult->operation |= RPi::IPA_CONFIG_DROP_FRAMES;\n+\tresult->dropFrameCount = dropFrame;\n \n \tfirstStart_ = false;\n \n-\treturn 0;\n+\t*ret = 0;\n }\n \n void IPARPi::setMode(const CameraSensorInfo &sensorInfo)\n@@ -275,30 +280,30 @@ void IPARPi::setMode(const CameraSensorInfo &sensorInfo)\n \n void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n \t\t       [[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,\n-\t\t       const std::map<unsigned int, const ControlInfoMap &> &entityControls,\n-\t\t       const IPAOperationData &ipaConfig,\n-\t\t       IPAOperationData *result)\n+\t\t       const std::map<unsigned int, ControlInfoMap> &entityControls,\n+\t\t       const ipa::rpi::ConfigInput &ipaConfig,\n+\t\t       ipa::rpi::ConfigOutput *result)\n {\n \tif (entityControls.size() != 2) {\n \t\tLOG(IPARPI, Error) << \"No ISP or sensor controls found.\";\n-\t\tresult->operation = RPi::IPA_CONFIG_FAILED;\n+\t\tresult->op = ipa::rpi::ConfigFailed;\n \t\treturn;\n \t}\n \n-\tresult->operation = 0;\n+\tresult->op = 0;\n \n \tsensorCtrls_ = entityControls.at(0);\n \tispCtrls_ = entityControls.at(1);\n \n \tif (!validateSensorControls()) {\n \t\tLOG(IPARPI, Error) << \"Sensor control validation failed.\";\n-\t\tresult->operation = RPi::IPA_CONFIG_FAILED;\n+\t\tresult->op = ipa::rpi::ConfigFailed;\n \t\treturn;\n \t}\n \n \tif (!validateIspControls()) {\n \t\tLOG(IPARPI, Error) << \"ISP control validation failed.\";\n-\t\tresult->operation = RPi::IPA_CONFIG_FAILED;\n+\t\tresult->op = ipa::rpi::ConfigFailed;\n \t\treturn;\n \t}\n \n@@ -317,7 +322,7 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n \t\tif (!helper_) {\n \t\t\tLOG(IPARPI, Error) << \"Could not create camera helper for \"\n \t\t\t\t\t   << cameraName;\n-\t\t\tresult->operation = RPi::IPA_CONFIG_FAILED;\n+\t\t\tresult->op = ipa::rpi::ConfigFailed;\n \t\t\treturn;\n \t\t}\n \n@@ -329,34 +334,29 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n \t\thelper_->GetDelays(exposureDelay, gainDelay);\n \t\tsensorMetadata = helper_->SensorEmbeddedDataPresent();\n \n-\t\tresult->data.push_back(gainDelay);\n-\t\tresult->data.push_back(exposureDelay);\n-\t\tresult->data.push_back(sensorMetadata);\n-\n-\t\tresult->operation |= RPi::IPA_CONFIG_STAGGERED_WRITE;\n+\t\tresult->op |= ipa::rpi::ConfigStaggeredWrite;\n+\t\tresult->sensorConfig.gainDelay = gainDelay;\n+\t\tresult->sensorConfig.exposureDelay = exposureDelay;\n+\t\tresult->sensorConfig.sensorMetadata = sensorMetadata;\n \t}\n \n \t/* Re-assemble camera mode using the sensor info. */\n \tsetMode(sensorInfo);\n \n-\t/*\n-\t * The ipaConfig.data always gives us the user transform first. Note that\n-\t * this will always make the LS table pointer (if present) element 1.\n-\t */\n-\tmode_.transform = static_cast<libcamera::Transform>(ipaConfig.data[0]);\n+\tmode_.transform = static_cast<libcamera::Transform>(ipaConfig.transform);\n \n \t/* Store the lens shading table pointer and handle if available. */\n-\tif (ipaConfig.operation & RPi::IPA_CONFIG_LS_TABLE) {\n+\tif (ipaConfig.op & ipa::rpi::ConfigLsTable) {\n \t\t/* Remove any previous table, if there was one. */\n \t\tif (lsTable_) {\n-\t\t\tmunmap(lsTable_, RPi::MaxLsGridSize);\n+\t\t\tmunmap(lsTable_, ipa::rpi::MaxLsGridSize);\n \t\t\tlsTable_ = nullptr;\n \t\t}\n \n-\t\t/* Map the LS table buffer into user space (now element 1). */\n-\t\tlsTableHandle_ = FileDescriptor(ipaConfig.data[1]);\n+\t\t/* Map the LS table buffer into user space. */\n+\t\tlsTableHandle_ = FileDescriptor(ipaConfig.lsTableHandle);\n \t\tif (lsTableHandle_.isValid()) {\n-\t\t\tlsTable_ = mmap(nullptr, RPi::MaxLsGridSize, PROT_READ | PROT_WRITE,\n+\t\t\tlsTable_ = mmap(nullptr, ipa::rpi::MaxLsGridSize, PROT_READ | PROT_WRITE,\n \t\t\t\t\tMAP_SHARED, lsTableHandle_.fd(), 0);\n \n \t\t\tif (lsTable_ == MAP_FAILED) {\n@@ -382,8 +382,8 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,\n \t\tagcStatus.analogue_gain = DefaultAnalogueGain;\n \t\tapplyAGC(&agcStatus, ctrls);\n \n-\t\tresult->controls.emplace_back(ctrls);\n-\t\tresult->operation |= RPi::IPA_CONFIG_SENSOR;\n+\t\tresult->op |= ipa::rpi::ConfigSensor;\n+\t\tresult->controls = std::move(ctrls);\n \t}\n \n \tlastMode_ = mode_;\n@@ -408,56 +408,38 @@ void IPARPi::unmapBuffers(const std::vector<unsigned int> &ids)\n \t}\n }\n \n-void IPARPi::processEvent(const IPAOperationData &event)\n+void IPARPi::signalStatReady(const uint32_t bufferId)\n {\n-\tswitch (event.operation) {\n-\tcase RPi::IPA_EVENT_SIGNAL_STAT_READY: {\n-\t\tunsigned int bufferId = event.data[0];\n-\n-\t\tif (++checkCount_ != frameCount_) /* assert here? */\n-\t\t\tLOG(IPARPI, Error) << \"WARNING: Prepare/Process mismatch!!!\";\n-\t\tif (frameCount_ > mistrustCount_)\n-\t\t\tprocessStats(bufferId);\n-\n-\t\treportMetadata();\n-\n-\t\tIPAOperationData op;\n-\t\top.operation = RPi::IPA_ACTION_STATS_METADATA_COMPLETE;\n-\t\top.data = { bufferId & RPi::BufferMask::ID };\n-\t\top.controls = { libcameraMetadata_ };\n-\t\tqueueFrameAction.emit(0, op);\n-\t\tbreak;\n-\t}\n+\tif (++checkCount_ != frameCount_) /* assert here? */\n+\t\tLOG(IPARPI, Error) << \"WARNING: Prepare/Process mismatch!!!\";\n+\tif (frameCount_ > mistrustCount_)\n+\t\tprocessStats(bufferId);\n \n-\tcase RPi::IPA_EVENT_SIGNAL_ISP_PREPARE: {\n-\t\tunsigned int embeddedbufferId = event.data[0];\n-\t\tunsigned int bayerbufferId = event.data[1];\n+\treportMetadata();\n \n-\t\t/*\n-\t\t * At start-up, or after a mode-switch, we may want to\n-\t\t * avoid running the control algos for a few frames in case\n-\t\t * they are \"unreliable\".\n-\t\t */\n-\t\tprepareISP(embeddedbufferId);\n-\t\tframeCount_++;\n-\n-\t\t/* Ready to push the input buffer into the ISP. */\n-\t\tIPAOperationData op;\n-\t\top.operation = RPi::IPA_ACTION_RUN_ISP;\n-\t\top.data = { bayerbufferId & RPi::BufferMask::ID };\n-\t\tqueueFrameAction.emit(0, op);\n-\t\tbreak;\n-\t}\n+\tstatsMetadataComplete.emit(bufferId & ipa::rpi::MaskID, libcameraMetadata_);\n+}\n \n-\tcase RPi::IPA_EVENT_QUEUE_REQUEST: {\n-\t\tqueueRequest(event.controls[0]);\n-\t\tbreak;\n-\t}\n+void IPARPi::signalQueueRequest(const ControlList &controls)\n+{\n+\tqueueRequest(controls);\n+}\n \n-\tdefault:\n-\t\tLOG(IPARPI, Error) << \"Unknown event \" << event.operation;\n-\t\tbreak;\n-\t}\n+void IPARPi::signalIspPrepare(const ipa::rpi::ISPConfig &data)\n+{\n+\tunsigned int embeddedbufferId = data.embeddedbufferId;\n+\tunsigned int bayerbufferId = data.bayerbufferId;\n+\n+\t/*\n+\t * At start-up, or after a mode-switch, we may want to\n+\t * avoid running the control algos for a few frames in case\n+\t * they are \"unreliable\".\n+\t */\n+\tprepareISP(embeddedbufferId);\n+\tframeCount_++;\n+\n+\t/* Ready to push the input buffer into the ISP. */\n+\trunIsp.emit(bayerbufferId & ipa::rpi::MaskID);\n }\n \n void IPARPi::reportMetadata()\n@@ -815,10 +797,7 @@ void IPARPi::queueRequest(const ControlList &controls)\n \n void IPARPi::returnEmbeddedBuffer(unsigned int bufferId)\n {\n-\tIPAOperationData op;\n-\top.operation = RPi::IPA_ACTION_EMBEDDED_COMPLETE;\n-\top.data = { bufferId & RPi::BufferMask::ID };\n-\tqueueFrameAction.emit(0, op);\n+\tembeddedComplete.emit(bufferId & ipa::rpi::MaskID);\n }\n \n void IPARPi::prepareISP(unsigned int bufferId)\n@@ -879,12 +858,8 @@ void IPARPi::prepareISP(unsigned int bufferId)\n \t\tif (dpcStatus)\n \t\t\tapplyDPC(dpcStatus, ctrls);\n \n-\t\tif (!ctrls.empty()) {\n-\t\t\tIPAOperationData op;\n-\t\t\top.operation = RPi::IPA_ACTION_V4L2_SET_ISP;\n-\t\t\top.controls.push_back(ctrls);\n-\t\t\tqueueFrameAction.emit(0, op);\n-\t\t}\n+\t\tif (!ctrls.empty())\n+\t\t\tsetIsp.emit(ctrls);\n \t}\n }\n \n@@ -941,10 +916,7 @@ void IPARPi::processStats(unsigned int bufferId)\n \t\tControlList ctrls(sensorCtrls_);\n \t\tapplyAGC(&agcStatus, ctrls);\n \n-\t\tIPAOperationData op;\n-\t\top.operation = RPi::IPA_ACTION_V4L2_SET_STAGGERED;\n-\t\top.controls.emplace_back(ctrls);\n-\t\tqueueFrameAction.emit(0, op);\n+\t\tsetStaggered.emit(ctrls);\n \t}\n }\n \n@@ -1114,13 +1086,14 @@ void IPARPi::applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls)\n \t\t.grid_width = w,\n \t\t.grid_stride = w,\n \t\t.grid_height = h,\n-\t\t.dmabuf = lsTableHandle_.fd(),\n+\t\t/* .dmabuf will be filled in by pipeline handler. */\n+\t\t.dmabuf = 0,\n \t\t.ref_transform = 0,\n \t\t.corner_sampled = 1,\n \t\t.gain_format = GAIN_FORMAT_U4P10\n \t};\n \n-\tif (!lsTable_ || w * h * 4 * sizeof(uint16_t) > RPi::MaxLsGridSize) {\n+\tif (!lsTable_ || w * h * 4 * sizeof(uint16_t) > ipa::rpi::MaxLsGridSize) {\n \t\tLOG(IPARPI, Error) << \"Do not have a correctly allocate lens shading table!\";\n \t\treturn;\n \t}\n@@ -1191,9 +1164,9 @@ const struct IPAModuleInfo ipaModuleInfo = {\n \t\"raspberrypi\",\n };\n \n-struct ipa_context *ipaCreate()\n+IPAInterface *ipaCreate()\n {\n-\treturn new IPAInterfaceWrapper(std::make_unique<IPARPi>());\n+\treturn new IPARPi();\n }\n \n } /* extern \"C\" */\ndiff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\nindex 7a5f5881..4152ab69 100644\n--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp\n@@ -17,11 +17,15 @@\n #include <libcamera/control_ids.h>\n #include <libcamera/file_descriptor.h>\n #include <libcamera/formats.h>\n+#include <libcamera/ipa/core_ipa_interface.h>\n #include <libcamera/ipa/raspberrypi.h>\n+#include <libcamera/ipa/raspberrypi_ipa_interface.h>\n+#include <libcamera/ipa/raspberrypi_ipa_proxy.h>\n #include <libcamera/logging.h>\n #include <libcamera/property_ids.h>\n #include <libcamera/request.h>\n \n+#include <linux/bcm2835-isp.h>\n #include <linux/videodev2.h>\n \n #include \"libcamera/internal/bayer_format.h\"\n@@ -146,7 +150,11 @@ public:\n \tint loadIPA();\n \tint configureIPA(const CameraConfiguration *config);\n \n-\tvoid queueFrameAction(unsigned int frame, const IPAOperationData &action);\n+\tvoid statsMetadataComplete(uint32_t bufferId, const ControlList &controls);\n+\tvoid runIsp(uint32_t bufferId);\n+\tvoid embeddedComplete(uint32_t bufferId);\n+\tvoid setIsp(const ControlList &controls);\n+\tvoid setStaggered(const ControlList &controls);\n \n \t/* bufferComplete signal handlers. */\n \tvoid unicamBufferDequeue(FrameBuffer *buffer);\n@@ -159,6 +167,8 @@ public:\n \tvoid handleState();\n \tvoid applyScalerCrop(const ControlList &controls);\n \n+\tstd::unique_ptr<ipa::rpi::IPAProxyRPi> ipa_;\n+\n \tstd::unique_ptr<CameraSensor> sensor_;\n \t/* Array of Unicam and ISP device streams and associated buffers/streams. */\n \tRPi::Device<Unicam, 2> unicam_;\n@@ -733,7 +743,7 @@ int PipelineHandlerRPi::exportFrameBuffers([[maybe_unused]] Camera *camera, Stre\n \treturn ret;\n }\n \n-int PipelineHandlerRPi::start(Camera *camera, [[maybe_unused]] ControlList *controls)\n+int PipelineHandlerRPi::start(Camera *camera, ControlList *controls)\n {\n \tRPiCameraData *data = cameraData(camera);\n \tint ret;\n@@ -751,13 +761,13 @@ int PipelineHandlerRPi::start(Camera *camera, [[maybe_unused]] ControlList *cont\n \t\tdata->applyScalerCrop(*controls);\n \n \t/* Start the IPA. */\n-\tIPAOperationData ipaData = {};\n-\tIPAOperationData result = {};\n+\tipa::rpi::StartControls ipaData = {};\n+\tipa::rpi::StartControls result = {};\n \tif (controls) {\n-\t\tipaData.operation = RPi::IPA_CONFIG_STARTUP;\n-\t\tipaData.controls.emplace_back(*controls);\n+\t\tipaData.hasControls = true;\n+\t\tipaData.controls = std::move(*controls);\n \t}\n-\tret = data->ipa_->start(ipaData, &result);\n+\tdata->ipa_->start(ipaData, &result, &ret);\n \tif (ret) {\n \t\tLOG(RPI, Error)\n \t\t\t<< \"Failed to start IPA for \" << camera->id();\n@@ -767,15 +777,15 @@ int PipelineHandlerRPi::start(Camera *camera, [[maybe_unused]] ControlList *cont\n \n \t/* Apply any gain/exposure settings that the IPA may have passed back. */\n \tASSERT(data->staggeredCtrl_);\n-\tif (result.operation & RPi::IPA_CONFIG_SENSOR) {\n-\t\tconst ControlList &ctrls = result.controls[0];\n+\tif (result.hasControls) {\n+\t\tconst ControlList &ctrls = result.controls;\n \t\tif (!data->staggeredCtrl_.set(ctrls))\n \t\t\tLOG(RPI, Error) << \"V4L2 staggered set failed\";\n \t}\n \n-\tif (result.operation & RPi::IPA_CONFIG_DROP_FRAMES) {\n+\tif (result.dropFrameCount > 0) {\n \t\t/* Configure the number of dropped frames required on startup. */\n-\t\tdata->dropFrameCount_ = result.data[0];\n+\t\tdata->dropFrameCount_ = result.dropFrameCount;\n \t}\n \n \t/* We need to set the dropFrameCount_ before queueing buffers. */\n@@ -1102,8 +1112,8 @@ int PipelineHandlerRPi::prepareBuffers(Camera *camera)\n \t * Pass the stats and embedded data buffers to the IPA. No other\n \t * buffers need to be passed.\n \t */\n-\tmapBuffers(camera, data->isp_[Isp::Stats].getBuffers(), RPi::BufferMask::STATS);\n-\tmapBuffers(camera, data->unicam_[Unicam::Embedded].getBuffers(), RPi::BufferMask::EMBEDDED_DATA);\n+\tmapBuffers(camera, data->isp_[Isp::Stats].getBuffers(), ipa::rpi::MaskStats);\n+\tmapBuffers(camera, data->unicam_[Unicam::Embedded].getBuffers(), ipa::rpi::MaskEmbeddedData);\n \n \treturn 0;\n }\n@@ -1120,8 +1130,8 @@ void PipelineHandlerRPi::mapBuffers(Camera *camera, const RPi::BufferMap &buffer\n \t * handler and the IPA.\n \t */\n \tfor (auto const &it : buffers) {\n-\t\tipaBuffers.push_back({ .id = mask | it.first,\n-\t\t\t\t       .planes = it.second->planes() });\n+\t\tipaBuffers.push_back(IPABuffer(mask | it.first,\n+\t\t\t\t\t       it.second->planes()));\n \t\tdata->ipaBuffers_.insert(mask | it.first);\n \t}\n \n@@ -1152,15 +1162,18 @@ void RPiCameraData::frameStarted(uint32_t sequence)\n \n int RPiCameraData::loadIPA()\n {\n-\tipa_ = IPAManager::createIPA(pipe_, 1, 1);\n+\tipa_ = IPAManager::createIPA<ipa::rpi::IPAProxyRPi>(pipe_, 1, 1);\n+\n \tif (!ipa_)\n \t\treturn -ENOENT;\n \n-\tipa_->queueFrameAction.connect(this, &RPiCameraData::queueFrameAction);\n+\tipa_->statsMetadataComplete.connect(this, &RPiCameraData::statsMetadataComplete);\n+\tipa_->runIsp.connect(this, &RPiCameraData::runIsp);\n+\tipa_->embeddedComplete.connect(this, &RPiCameraData::embeddedComplete);\n+\tipa_->setIsp.connect(this, &RPiCameraData::setIsp);\n+\tipa_->setStaggered.connect(this, &RPiCameraData::setStaggered);\n \n-\tIPASettings settings{\n-\t\t.configurationFile = ipa_->configurationFile(sensor_->model() + \".json\")\n-\t};\n+\tIPASettings settings(ipa_->configurationFile(sensor_->model() + \".json\"));\n \n \treturn ipa_->init(settings);\n }\n@@ -1172,8 +1185,8 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \t\tstatic_cast<const RPiCameraConfiguration *>(config);\n \n \tstd::map<unsigned int, IPAStream> streamConfig;\n-\tstd::map<unsigned int, const ControlInfoMap &> entityControls;\n-\tIPAOperationData ipaConfig = {};\n+\tstd::map<unsigned int, ControlInfoMap> entityControls;\n+\tipa::rpi::ConfigInput ipaConfig;\n \n \t/* Get the device format to pass to the IPA. */\n \tV4L2DeviceFormat sensorFormat;\n@@ -1182,10 +1195,9 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \tunsigned int i = 0;\n \tfor (auto const &stream : isp_) {\n \t\tif (stream.isExternal()) {\n-\t\t\tstreamConfig[i++] = {\n-\t\t\t\t.pixelFormat = stream.configuration().pixelFormat,\n-\t\t\t\t.size = stream.configuration().size\n-\t\t\t};\n+\t\t\tstreamConfig[i++] = IPAStream(\n+\t\t\t\tstream.configuration().pixelFormat,\n+\t\t\t\tstream.configuration().size);\n \t\t}\n \t}\n \n@@ -1193,17 +1205,17 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \tentityControls.emplace(1, isp_[Isp::Input].dev()->controls());\n \n \t/* Always send the user transform to the IPA. */\n-\tipaConfig.data = { static_cast<unsigned int>(config->transform) };\n+\tipaConfig.transform = static_cast<unsigned int>(config->transform);\n \n \t/* Allocate the lens shading table via dmaHeap and pass to the IPA. */\n \tif (!lsTable_.isValid()) {\n-\t\tlsTable_ = dmaHeap_.alloc(\"ls_grid\", RPi::MaxLsGridSize);\n+\t\tlsTable_ = dmaHeap_.alloc(\"ls_grid\", ipa::rpi::MaxLsGridSize);\n \t\tif (!lsTable_.isValid())\n \t\t\treturn -ENOMEM;\n \n \t\t/* Allow the IPA to mmap the LS table via the file descriptor. */\n-\t\tipaConfig.operation = RPi::IPA_CONFIG_LS_TABLE;\n-\t\tipaConfig.data.push_back(static_cast<unsigned int>(lsTable_.fd()));\n+\t\tipaConfig.op |= ipa::rpi::ConfigLsTable;\n+\t\tipaConfig.lsTableHandle = lsTable_;\n \t}\n \n \t/* We store the CameraSensorInfo for digital zoom calculations. */\n@@ -1214,32 +1226,33 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \t}\n \n \t/* Ready the IPA - it must know about the sensor resolution. */\n-\tIPAOperationData result = {};\n+\tipa::rpi::ConfigOutput result = {};\n \n \tipa_->configure(sensorInfo_, streamConfig, entityControls, ipaConfig,\n \t\t\t&result);\n \n-\tif (result.operation & RPi::IPA_CONFIG_FAILED) {\n+\tif (result.op & ipa::rpi::ConfigFailed) {\n \t\tLOG(RPI, Error) << \"IPA configuration failed!\";\n \t\treturn -EPIPE;\n \t}\n \n-\tunsigned int resultIdx = 0;\n-\tif (result.operation & RPi::IPA_CONFIG_STAGGERED_WRITE) {\n+\tif (result.op & ipa::rpi::ConfigStaggeredWrite) {\n \t\t/*\n \t\t * Setup our staggered control writer with the sensor default\n \t\t * gain and exposure delays.\n \t\t */\n \t\tif (!staggeredCtrl_) {\n \t\t\tstaggeredCtrl_.init(unicam_[Unicam::Image].dev(),\n-\t\t\t\t\t    { { V4L2_CID_ANALOGUE_GAIN, result.data[resultIdx++] },\n-\t\t\t\t\t      { V4L2_CID_EXPOSURE, result.data[resultIdx++] } });\n-\t\t\tsensorMetadata_ = result.data[resultIdx++];\n+\t\t\t\t\t    { { V4L2_CID_ANALOGUE_GAIN,\n+\t\t\t\t\t\tresult.sensorConfig.gainDelay },\n+\t\t\t\t\t      { V4L2_CID_EXPOSURE,\n+\t\t\t\t\t\tresult.sensorConfig.exposureDelay } });\n+\t\t\tsensorMetadata_ = result.sensorConfig.sensorMetadata;\n \t\t}\n \t}\n \n-\tif (result.operation & RPi::IPA_CONFIG_SENSOR) {\n-\t\tconst ControlList &ctrls = result.controls[0];\n+\tif (result.op & ipa::rpi::ConfigSensor) {\n+\t\tconst ControlList &ctrls = result.controls;\n \t\tif (!staggeredCtrl_.set(ctrls))\n \t\t\tLOG(RPI, Error) << \"V4L2 staggered set failed\";\n \t}\n@@ -1260,90 +1273,87 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)\n \treturn 0;\n }\n \n-void RPiCameraData::queueFrameAction([[maybe_unused]] unsigned int frame,\n-\t\t\t\t     const IPAOperationData &action)\n+void RPiCameraData::statsMetadataComplete(uint32_t bufferId, const ControlList &controls)\n {\n+\tif (state_ == State::Stopped)\n+\t\thandleState();\n+\n+\tFrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(bufferId);\n+\n+\thandleStreamBuffer(buffer, &isp_[Isp::Stats]);\n+\n+\t/* Fill the Request metadata buffer with what the IPA has provided */\n+\tRequest *request = requestQueue_.front();\n+\trequest->metadata() = std::move(controls);\n+\n \t/*\n-\t * The following actions can be handled when the pipeline handler is in\n-\t * a stopped state.\n+\t * Also update the ScalerCrop in the metadata with what we actually\n+\t * used. But we must first rescale that from ISP (camera mode) pixels\n+\t * back into sensor native pixels.\n+\t *\n+\t * Sending this information on every frame may be helpful.\n \t */\n-\tswitch (action.operation) {\n-\tcase RPi::IPA_ACTION_V4L2_SET_STAGGERED: {\n-\t\tconst ControlList &controls = action.controls[0];\n-\t\tif (!staggeredCtrl_.set(controls))\n-\t\t\tLOG(RPI, Error) << \"V4L2 staggered set failed\";\n-\t\tgoto done;\n+\tif (updateScalerCrop_) {\n+\t\tupdateScalerCrop_ = false;\n+\t\tscalerCrop_ = ispCrop_.scaledBy(sensorInfo_.analogCrop.size(),\n+\t\t\t\t\t\tsensorInfo_.outputSize);\n+\t\tscalerCrop_.translateBy(sensorInfo_.analogCrop.topLeft());\n \t}\n+\trequest->metadata().set(controls::ScalerCrop, scalerCrop_);\n \n-\tcase RPi::IPA_ACTION_V4L2_SET_ISP: {\n-\t\tControlList controls = action.controls[0];\n-\t\tisp_[Isp::Input].dev()->setControls(&controls);\n-\t\tgoto done;\n-\t}\n-\t}\n+\tstate_ = State::IpaComplete;\n \n-\tif (state_ == State::Stopped)\n-\t\tgoto done;\n+\thandleState();\n+}\n \n-\t/*\n-\t * The following actions must not be handled when the pipeline handler\n-\t * is in a stopped state.\n-\t */\n-\tswitch (action.operation) {\n-\tcase RPi::IPA_ACTION_STATS_METADATA_COMPLETE: {\n-\t\tunsigned int bufferId = action.data[0];\n-\t\tFrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(bufferId);\n+void RPiCameraData::runIsp(uint32_t bufferId)\n+{\n+\tif (state_ == State::Stopped)\n+\t\thandleState();\n \n-\t\thandleStreamBuffer(buffer, &isp_[Isp::Stats]);\n+\tFrameBuffer *buffer = unicam_[Unicam::Image].getBuffers().at(bufferId);\n \n-\t\t/* Fill the Request metadata buffer with what the IPA has provided */\n-\t\tRequest *request = requestQueue_.front();\n-\t\trequest->metadata() = std::move(action.controls[0]);\n+\tLOG(RPI, Debug) << \"Input re-queue to ISP, buffer id \" << bufferId\n+\t\t\t<< \", timestamp: \" << buffer->metadata().timestamp;\n \n-\t\t/*\n-\t\t * Also update the ScalerCrop in the metadata with what we actually\n-\t\t * used. But we must first rescale that from ISP (camera mode) pixels\n-\t\t * back into sensor native pixels.\n-\t\t *\n-\t\t * Sending this information on every frame may be helpful.\n-\t\t */\n-\t\tif (updateScalerCrop_) {\n-\t\t\tupdateScalerCrop_ = false;\n-\t\t\tscalerCrop_ = ispCrop_.scaledBy(sensorInfo_.analogCrop.size(),\n-\t\t\t\t\t\t\tsensorInfo_.outputSize);\n-\t\t\tscalerCrop_.translateBy(sensorInfo_.analogCrop.topLeft());\n-\t\t}\n-\t\trequest->metadata().set(controls::ScalerCrop, scalerCrop_);\n+\tisp_[Isp::Input].queueBuffer(buffer);\n+\tispOutputCount_ = 0;\n+\thandleState();\n+}\n \n-\t\tstate_ = State::IpaComplete;\n-\t\tbreak;\n-\t}\n+void RPiCameraData::embeddedComplete(uint32_t bufferId)\n+{\n+\tif (state_ == State::Stopped)\n+\t\thandleState();\n \n-\tcase RPi::IPA_ACTION_EMBEDDED_COMPLETE: {\n-\t\tunsigned int bufferId = action.data[0];\n-\t\tFrameBuffer *buffer = unicam_[Unicam::Embedded].getBuffers().at(bufferId);\n-\t\thandleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);\n-\t\tbreak;\n-\t}\n+\tFrameBuffer *buffer = unicam_[Unicam::Embedded].getBuffers().at(bufferId);\n+\thandleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);\n+\thandleState();\n+}\n \n-\tcase RPi::IPA_ACTION_RUN_ISP: {\n-\t\tunsigned int bufferId = action.data[0];\n-\t\tFrameBuffer *buffer = unicam_[Unicam::Image].getBuffers().at(bufferId);\n+void RPiCameraData::setIsp(const ControlList &controls)\n+{\n+\tControlList ctrls = controls;\n \n-\t\tLOG(RPI, Debug) << \"Input re-queue to ISP, buffer id \" << bufferId\n-\t\t\t\t<< \", timestamp: \" << buffer->metadata().timestamp;\n+\tSpan<const uint8_t> s =\n+\t\tctrls.get(V4L2_CID_USER_BCM2835_ISP_LENS_SHADING).data();\n+\tconst bcm2835_isp_lens_shading *lsp =\n+\t\treinterpret_cast<const bcm2835_isp_lens_shading *>(s.data());\n+\tbcm2835_isp_lens_shading ls = *lsp;\n+\tls.dmabuf = lsTable_.fd();\n \n-\t\tisp_[Isp::Input].queueBuffer(buffer);\n-\t\tispOutputCount_ = 0;\n-\t\tbreak;\n-\t}\n+\tControlValue c(Span<const uint8_t>{ reinterpret_cast<uint8_t *>(&ls),\n+\t\t\t\t\t    sizeof(ls) });\n+\tctrls.set(V4L2_CID_USER_BCM2835_ISP_LENS_SHADING, c);\n \n-\tdefault:\n-\t\tLOG(RPI, Error) << \"Unknown action \" << action.operation;\n-\t\tbreak;\n-\t}\n+\tisp_[Isp::Input].dev()->setControls(&ctrls);\n+\thandleState();\n+}\n \n-done:\n+void RPiCameraData::setStaggered(const ControlList &controls)\n+{\n+\tif (!staggeredCtrl_.set(controls))\n+\t\tLOG(RPI, Error) << \"V4L2 staggered set failed\";\n \thandleState();\n }\n \n@@ -1445,10 +1455,7 @@ void RPiCameraData::ispOutputDequeue(FrameBuffer *buffer)\n \t * application until after the IPA signals so.\n \t */\n \tif (stream == &isp_[Isp::Stats]) {\n-\t\tIPAOperationData op;\n-\t\top.operation = RPi::IPA_EVENT_SIGNAL_STAT_READY;\n-\t\top.data = { RPi::BufferMask::STATS | static_cast<unsigned int>(index) };\n-\t\tipa_->processEvent(op);\n+\t\tipa_->signalStatReady(ipa::rpi::MaskStats | static_cast<unsigned int>(index));\n \t} else {\n \t\t/* Any other ISP output can be handed back to the application now. */\n \t\thandleStreamBuffer(buffer, stream);\n@@ -1552,7 +1559,7 @@ void RPiCameraData::handleExternalBuffer(FrameBuffer *buffer, RPi::Stream *strea\n {\n \tunsigned int id = stream->getBufferId(buffer);\n \n-\tif (!(id & RPi::BufferMask::EXTERNAL_BUFFER))\n+\tif (!(id & ipa::rpi::MaskExternalBuffer))\n \t\treturn;\n \n \t/* Stop the Stream object from tracking the buffer. */\n@@ -1652,7 +1659,6 @@ void RPiCameraData::applyScalerCrop(const ControlList &controls)\n void RPiCameraData::tryRunPipeline()\n {\n \tFrameBuffer *bayerBuffer, *embeddedBuffer;\n-\tIPAOperationData op;\n \n \t/* If any of our request or buffer queues are empty, we cannot proceed. */\n \tif (state_ != State::Idle || requestQueue_.empty() ||\n@@ -1673,9 +1679,7 @@ void RPiCameraData::tryRunPipeline()\n \t * queue the ISP output buffer listed in the request to start the HW\n \t * pipeline.\n \t */\n-\top.operation = RPi::IPA_EVENT_QUEUE_REQUEST;\n-\top.controls = { request->controls() };\n-\tipa_->processEvent(op);\n+\tipa_->signalQueueRequest(request->controls());\n \n \t/* Set our state to say the pipeline is active. */\n \tstate_ = State::Busy;\n@@ -1683,14 +1687,14 @@ void RPiCameraData::tryRunPipeline()\n \tunsigned int bayerId = unicam_[Unicam::Image].getBufferId(bayerBuffer);\n \tunsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);\n \n-\tLOG(RPI, Debug) << \"Signalling RPi::IPA_EVENT_SIGNAL_ISP_PREPARE:\"\n+\tLOG(RPI, Debug) << \"Signalling signalIspPrepare:\"\n \t\t\t<< \" Bayer buffer id: \" << bayerId\n \t\t\t<< \" Embedded buffer id: \" << embeddedId;\n \n-\top.operation = RPi::IPA_EVENT_SIGNAL_ISP_PREPARE;\n-\top.data = { RPi::BufferMask::EMBEDDED_DATA | embeddedId,\n-\t\t    RPi::BufferMask::BAYER_DATA | bayerId };\n-\tipa_->processEvent(op);\n+\tipa::rpi::ISPConfig ispPrepare;\n+\tispPrepare.embeddedbufferId = ipa::rpi::MaskEmbeddedData | embeddedId;\n+\tispPrepare.bayerbufferId = ipa::rpi::MaskBayerData | bayerId;\n+\tipa_->signalIspPrepare(ispPrepare);\n }\n \n bool RPiCameraData::findMatchingBuffers(FrameBuffer *&bayerBuffer, FrameBuffer *&embeddedBuffer)\ndiff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp\nindex 3a5dadab..496dd36f 100644\n--- a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp\n+++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp\n@@ -6,6 +6,8 @@\n  */\n #include \"rpi_stream.h\"\n \n+#include <libcamera/ipa/raspberrypi_ipa_interface.h>\n+\n #include \"libcamera/internal/log.h\"\n \n namespace libcamera {\n@@ -70,7 +72,7 @@ int Stream::getBufferId(FrameBuffer *buffer) const\n \n void Stream::setExternalBuffer(FrameBuffer *buffer)\n {\n-\tbufferMap_.emplace(RPi::BufferMask::EXTERNAL_BUFFER | id_.get(), buffer);\n+\tbufferMap_.emplace(ipa::rpi::MaskExternalBuffer | id_.get(), buffer);\n }\n \n void Stream::removeExternalBuffer(FrameBuffer *buffer)\n@@ -78,7 +80,7 @@ void Stream::removeExternalBuffer(FrameBuffer *buffer)\n \tint id = getBufferId(buffer);\n \n \t/* Ensure we have this buffer in the stream, and it is marked external. */\n-\tASSERT(id != -1 && (id & RPi::BufferMask::EXTERNAL_BUFFER));\n+\tASSERT(id != -1 && (id & ipa::rpi::MaskExternalBuffer));\n \tbufferMap_.erase(id);\n }\n \ndiff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h\nindex 0b502f64..701110d0 100644\n--- a/src/libcamera/pipeline/raspberrypi/rpi_stream.h\n+++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h\n@@ -13,6 +13,7 @@\n #include <vector>\n \n #include <libcamera/ipa/raspberrypi.h>\n+#include <libcamera/ipa/raspberrypi_ipa_interface.h>\n #include <libcamera/stream.h>\n \n #include \"libcamera/internal/v4l2_videodevice.h\"\n@@ -31,13 +32,13 @@ class Stream : public libcamera::Stream\n {\n public:\n \tStream()\n-\t\t: id_(RPi::BufferMask::ID)\n+\t\t: id_(ipa::rpi::MaskID)\n \t{\n \t}\n \n \tStream(const char *name, MediaEntity *dev, bool importOnly = false)\n \t\t: external_(false), importOnly_(importOnly), name_(name),\n-\t\t  dev_(std::make_unique<V4L2VideoDevice>(dev)), id_(RPi::BufferMask::ID)\n+\t\t  dev_(std::make_unique<V4L2VideoDevice>(dev)), id_(ipa::rpi::MaskID)\n \t{\n \t}\n \n","prefixes":["libcamera-devel","v6","09/11"]}