summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ipa/ipu3/ipu3.cpp74
-rw-r--r--src/ipa/ipu3/meson.build4
-rw-r--r--src/ipa/libipa/ipa_interface_wrapper.cpp287
-rw-r--r--src/ipa/libipa/ipa_interface_wrapper.h61
-rw-r--r--src/ipa/libipa/meson.build2
-rw-r--r--src/ipa/raspberrypi/raspberrypi.cpp180
-rw-r--r--src/ipa/rkisp1/meson.build2
-rw-r--r--src/ipa/rkisp1/rkisp1.cpp63
-rw-r--r--src/ipa/vimc/meson.build2
-rw-r--r--src/ipa/vimc/vimc.cpp39
-rw-r--r--src/libcamera/ipa_context_wrapper.cpp298
-rw-r--r--src/libcamera/ipa_interface.cpp644
-rw-r--r--src/libcamera/ipa_manager.cpp47
-rw-r--r--src/libcamera/ipa_module.cpp18
-rw-r--r--src/libcamera/ipa_proxy.cpp101
-rw-r--r--src/libcamera/meson.build1
-rw-r--r--src/libcamera/pipeline/ipu3/ipu3.cpp93
-rw-r--r--src/libcamera/pipeline/raspberrypi/raspberrypi.cpp257
-rw-r--r--src/libcamera/pipeline/raspberrypi/rpi_stream.cpp6
-rw-r--r--src/libcamera/pipeline/raspberrypi/rpi_stream.h5
-rw-r--r--src/libcamera/pipeline/rkisp1/rkisp1.cpp75
-rw-r--r--src/libcamera/pipeline/vimc/vimc.cpp10
-rw-r--r--src/libcamera/pipeline_handler.cpp8
-rw-r--r--src/libcamera/proxy/ipa_proxy_linux.cpp104
-rw-r--r--src/libcamera/proxy/ipa_proxy_thread.cpp175
-rw-r--r--src/libcamera/proxy/meson.build5
-rw-r--r--src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp90
-rw-r--r--src/libcamera/proxy/worker/meson.build4
28 files changed, 408 insertions, 2247 deletions
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index b11b03ef..fcd8889c 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -5,8 +5,6 @@
* ipu3.cpp - IPU3 Image Processing Algorithms
*/
-#include <libcamera/ipa/ipu3.h>
-
#include <stdint.h>
#include <sys/mman.h>
@@ -17,10 +15,9 @@
#include <libcamera/control_ids.h>
#include <libcamera/ipa/ipa_interface.h>
#include <libcamera/ipa/ipa_module_info.h>
+#include <libcamera/ipa/ipu3_ipa_interface.h>
#include <libcamera/request.h>
-#include <libipa/ipa_interface_wrapper.h>
-
#include "libcamera/internal/buffer.h"
#include "libcamera/internal/log.h"
@@ -28,25 +25,21 @@ namespace libcamera {
LOG_DEFINE_CATEGORY(IPAIPU3)
-class IPAIPU3 : public IPAInterface
+class IPAIPU3 : public ipa::ipu3::IPAIPU3Interface
{
public:
int init([[maybe_unused]] const IPASettings &settings) override
{
return 0;
}
- int start([[maybe_unused]] const IPAOperationData &data,
- [[maybe_unused]] IPAOperationData *result) override { return 0; }
+ int start() override { return 0; }
void stop() override {}
- void configure(const CameraSensorInfo &info,
- const std::map<unsigned int, IPAStream> &streamConfig,
- const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- const IPAOperationData &ipaConfig,
- IPAOperationData *response) override;
+ void configure(const std::map<uint32_t, ControlInfoMap> &entityControls) override;
+
void mapBuffers(const std::vector<IPABuffer> &buffers) override;
void unmapBuffers(const std::vector<unsigned int> &ids) override;
- void processEvent(const IPAOperationData &event) override;
+ void processEvent(const ipa::ipu3::IPU3Event &event) override;
private:
void processControls(unsigned int frame, const ControlList &controls);
@@ -69,11 +62,7 @@ private:
uint32_t maxGain_;
};
-void IPAIPU3::configure([[maybe_unused]] const CameraSensorInfo &info,
- [[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,
- const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- [[maybe_unused]] const IPAOperationData &ipaConfig,
- [[maybe_unused]] IPAOperationData *result)
+void IPAIPU3::configure(const std::map<uint32_t, ControlInfoMap> &entityControls)
{
if (entityControls.empty())
return;
@@ -123,19 +112,15 @@ void IPAIPU3::unmapBuffers(const std::vector<unsigned int> &ids)
}
}
-void IPAIPU3::processEvent(const IPAOperationData &event)
+void IPAIPU3::processEvent(const ipa::ipu3::IPU3Event &event)
{
- switch (event.operation) {
- case IPU3_IPA_EVENT_PROCESS_CONTROLS: {
- unsigned int frame = event.data[0];
- processControls(frame, event.controls[0]);
+ switch (event.op) {
+ case ipa::ipu3::EventProcessControls: {
+ processControls(event.frame, event.controls);
break;
}
- case IPU3_IPA_EVENT_STAT_READY: {
- unsigned int frame = event.data[0];
- unsigned int bufferId = event.data[1];
-
- auto it = buffers_.find(bufferId);
+ case ipa::ipu3::EventStatReady: {
+ auto it = buffers_.find(event.bufferId);
if (it == buffers_.end()) {
LOG(IPAIPU3, Error) << "Could not find stats buffer!";
return;
@@ -145,14 +130,11 @@ void IPAIPU3::processEvent(const IPAOperationData &event)
const ipu3_uapi_stats_3a *stats =
reinterpret_cast<ipu3_uapi_stats_3a *>(mem.data());
- parseStatistics(frame, stats);
+ parseStatistics(event.frame, stats);
break;
}
- case IPU3_IPA_EVENT_FILL_PARAMS: {
- unsigned int frame = event.data[0];
- unsigned int bufferId = event.data[1];
-
- auto it = buffers_.find(bufferId);
+ case ipa::ipu3::EventFillParams: {
+ auto it = buffers_.find(event.bufferId);
if (it == buffers_.end()) {
LOG(IPAIPU3, Error) << "Could not find param buffer!";
return;
@@ -162,11 +144,11 @@ void IPAIPU3::processEvent(const IPAOperationData &event)
ipu3_uapi_params *params =
reinterpret_cast<ipu3_uapi_params *>(mem.data());
- fillParams(frame, params);
+ fillParams(event.frame, params);
break;
}
default:
- LOG(IPAIPU3, Error) << "Unknown event " << event.operation;
+ LOG(IPAIPU3, Error) << "Unknown event " << event.op;
break;
}
}
@@ -184,8 +166,8 @@ void IPAIPU3::fillParams(unsigned int frame, ipu3_uapi_params *params)
/* \todo Fill in parameters buffer. */
- IPAOperationData op;
- op.operation = IPU3_IPA_ACTION_PARAM_FILLED;
+ ipa::ipu3::IPU3Action op;
+ op.op = ipa::ipu3::ActionParamFilled;
queueFrameAction.emit(frame, op);
@@ -201,22 +183,22 @@ void IPAIPU3::parseStatistics(unsigned int frame,
/* \todo React to statistics and update internal state machine. */
/* \todo Add meta-data information to ctrls. */
- IPAOperationData op;
- op.operation = IPU3_IPA_ACTION_METADATA_READY;
- op.controls.push_back(ctrls);
+ ipa::ipu3::IPU3Action op;
+ op.op = ipa::ipu3::ActionMetadataReady;
+ op.controls = ctrls;
queueFrameAction.emit(frame, op);
}
void IPAIPU3::setControls(unsigned int frame)
{
- IPAOperationData op;
- op.operation = IPU3_IPA_ACTION_SET_SENSOR_CONTROLS;
+ ipa::ipu3::IPU3Action op;
+ op.op = ipa::ipu3::ActionSetSensorControls;
ControlList ctrls(ctrls_);
ctrls.set(V4L2_CID_EXPOSURE, static_cast<int32_t>(exposure_));
ctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast<int32_t>(gain_));
- op.controls.push_back(ctrls);
+ op.controls = ctrls;
queueFrameAction.emit(frame, op);
}
@@ -233,9 +215,9 @@ const struct IPAModuleInfo ipaModuleInfo = {
"ipu3",
};
-struct ipa_context *ipaCreate()
+IPAInterface *ipaCreate()
{
- return new IPAInterfaceWrapper(std::make_unique<IPAIPU3>());
+ return new IPAIPU3();
}
}
diff --git a/src/ipa/ipu3/meson.build b/src/ipa/ipu3/meson.build
index d31594fc..a241f617 100644
--- a/src/ipa/ipu3/meson.build
+++ b/src/ipa/ipu3/meson.build
@@ -3,10 +3,10 @@
ipa_name = 'ipa_ipu3'
mod = shared_module(ipa_name,
- 'ipu3.cpp',
+ ['ipu3.cpp', libcamera_generated_ipa_headers],
name_prefix : '',
include_directories : [ipa_includes, libipa_includes],
- dependencies : [libatomic, libcamera_dep],
+ dependencies : libcamera_dep,
link_with : libipa,
install : true,
install_dir : ipa_install_dir)
diff --git a/src/ipa/libipa/ipa_interface_wrapper.cpp b/src/ipa/libipa/ipa_interface_wrapper.cpp
deleted file mode 100644
index 40628489..00000000
--- a/src/ipa/libipa/ipa_interface_wrapper.cpp
+++ /dev/null
@@ -1,287 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * ipa_interface_wrapper.cpp - Image Processing Algorithm interface wrapper
- */
-
-#include "ipa_interface_wrapper.h"
-
-#include <map>
-#include <string.h>
-#include <unistd.h>
-#include <vector>
-
-#include <libcamera/ipa/ipa_interface.h>
-
-#include "libcamera/internal/byte_stream_buffer.h"
-#include "libcamera/internal/camera_sensor.h"
-
-/**
- * \file ipa_interface_wrapper.h
- * \brief Image Processing Algorithm interface wrapper
- */
-
-namespace libcamera {
-
-/**
- * \class IPAInterfaceWrapper
- * \brief Wrap an IPAInterface and expose it as an ipa_context
- *
- * This class implements the ipa_context API based on a provided IPAInterface.
- * It helps IPAs that implement the IPAInterface API to provide the external
- * ipa_context API.
- *
- * To use the wrapper, an IPA module simple creates a new instance of its
- * IPAInterface implementation, and passes it to the constructor of the
- * IPAInterfaceWrapper. As IPAInterfaceWrapper inherits from ipa_context, the
- * constructed wrapper can then be directly returned from the IPA module's
- * ipaCreate() function.
- *
- * \code{.cpp}
- * class MyIPA : public IPAInterface
- * {
- * ...
- * };
- *
- * struct ipa_context *ipaCreate()
- * {
- * return new IPAInterfaceWrapper(std::make_unique<MyIPA>());
- * }
- * \endcode
- *
- * The wrapper takes ownership of the IPAInterface and will automatically
- * delete it when the wrapper is destroyed.
- */
-
-/**
- * \brief Construct an IPAInterfaceWrapper wrapping \a interface
- * \param[in] interface The interface to wrap
- */
-IPAInterfaceWrapper::IPAInterfaceWrapper(std::unique_ptr<IPAInterface> interface)
- : ipa_(std::move(interface)), callbacks_(nullptr), cb_ctx_(nullptr)
-{
- ops = &operations_;
-
- ipa_->queueFrameAction.connect(this, &IPAInterfaceWrapper::queueFrameAction);
-}
-
-void IPAInterfaceWrapper::destroy(struct ipa_context *_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- delete ctx;
-}
-
-void *IPAInterfaceWrapper::get_interface(struct ipa_context *_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- return ctx->ipa_.get();
-}
-
-void IPAInterfaceWrapper::init(struct ipa_context *_ctx,
- const struct ipa_settings *settings)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- IPASettings ipaSettings{
- .configurationFile = settings->configuration_file
- };
- ctx->ipa_->init(ipaSettings);
-}
-
-int IPAInterfaceWrapper::start(struct ipa_context *_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- /* \todo Translate the data and result. */
- IPAOperationData data = {};
- return ctx->ipa_->start(data, nullptr);
-}
-
-void IPAInterfaceWrapper::stop(struct ipa_context *_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- ctx->ipa_->stop();
-}
-
-void IPAInterfaceWrapper::register_callbacks(struct ipa_context *_ctx,
- const struct ipa_callback_ops *callbacks,
- void *cb_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- ctx->callbacks_ = callbacks;
- ctx->cb_ctx_ = cb_ctx;
-}
-
-void IPAInterfaceWrapper::configure(struct ipa_context *_ctx,
- const struct ipa_sensor_info *sensor_info,
- const struct ipa_stream *streams,
- unsigned int num_streams,
- const struct ipa_control_info_map *maps,
- unsigned int num_maps)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- ctx->serializer_.reset();
-
- /* Translate the IPA sensor info. */
- CameraSensorInfo sensorInfo{};
- sensorInfo.model = sensor_info->model;
- sensorInfo.bitsPerPixel = sensor_info->bits_per_pixel;
- sensorInfo.activeAreaSize = { sensor_info->active_area.width,
- sensor_info->active_area.height };
- sensorInfo.analogCrop = { sensor_info->analog_crop.left,
- sensor_info->analog_crop.top,
- sensor_info->analog_crop.width,
- sensor_info->analog_crop.height };
- sensorInfo.outputSize = { sensor_info->output_size.width,
- sensor_info->output_size.height };
- sensorInfo.pixelRate = sensor_info->pixel_rate;
- sensorInfo.lineLength = sensor_info->line_length;
-
- /* Translate the IPA stream configurations map. */
- std::map<unsigned int, IPAStream> ipaStreams;
-
- for (unsigned int i = 0; i < num_streams; ++i) {
- const struct ipa_stream &stream = streams[i];
-
- ipaStreams[stream.id] = {
- stream.pixel_format,
- Size(stream.width, stream.height),
- };
- }
-
- /* Translate the IPA entity controls map. */
- std::map<unsigned int, const ControlInfoMap &> entityControls;
- std::map<unsigned int, ControlInfoMap> infoMaps;
-
- for (unsigned int i = 0; i < num_maps; ++i) {
- const struct ipa_control_info_map &ipa_map = maps[i];
- ByteStreamBuffer byteStream(ipa_map.data, ipa_map.size);
- unsigned int id = ipa_map.id;
-
- infoMaps[id] = ctx->serializer_.deserialize<ControlInfoMap>(byteStream);
- entityControls.emplace(id, infoMaps[id]);
- }
-
- /* \todo Translate the ipaConfig and result. */
- IPAOperationData ipaConfig;
- ctx->ipa_->configure(sensorInfo, ipaStreams, entityControls, ipaConfig,
- nullptr);
-}
-
-void IPAInterfaceWrapper::map_buffers(struct ipa_context *_ctx,
- const struct ipa_buffer *_buffers,
- size_t num_buffers)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
- std::vector<IPABuffer> buffers(num_buffers);
-
- for (unsigned int i = 0; i < num_buffers; ++i) {
- const struct ipa_buffer &_buffer = _buffers[i];
- IPABuffer &buffer = buffers[i];
- std::vector<FrameBuffer::Plane> &planes = buffer.planes;
-
- buffer.id = _buffer.id;
-
- planes.resize(_buffer.num_planes);
- for (unsigned int j = 0; j < _buffer.num_planes; ++j) {
- planes[j].fd = FileDescriptor(_buffer.planes[j].dmabuf);
- planes[j].length = _buffer.planes[j].length;
- }
- }
-
- ctx->ipa_->mapBuffers(buffers);
-}
-
-void IPAInterfaceWrapper::unmap_buffers(struct ipa_context *_ctx,
- const unsigned int *_ids,
- size_t num_buffers)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
- std::vector<unsigned int> ids(_ids, _ids + num_buffers);
- ctx->ipa_->unmapBuffers(ids);
-}
-
-void IPAInterfaceWrapper::process_event(struct ipa_context *_ctx,
- const struct ipa_operation_data *data)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
- IPAOperationData opData;
-
- opData.operation = data->operation;
-
- opData.data.resize(data->num_data);
- memcpy(opData.data.data(), data->data,
- data->num_data * sizeof(*data->data));
-
- opData.controls.resize(data->num_lists);
- for (unsigned int i = 0; i < data->num_lists; ++i) {
- const struct ipa_control_list *c_list = &data->lists[i];
- ByteStreamBuffer byteStream(c_list->data, c_list->size);
- opData.controls[i] = ctx->serializer_.deserialize<ControlList>(byteStream);
- }
-
- ctx->ipa_->processEvent(opData);
-}
-
-void IPAInterfaceWrapper::queueFrameAction(unsigned int frame,
- const IPAOperationData &data)
-{
- if (!callbacks_)
- return;
-
- struct ipa_operation_data c_data;
- c_data.operation = data.operation;
- c_data.data = data.data.data();
- c_data.num_data = data.data.size();
-
- struct ipa_control_list control_lists[data.controls.size()];
- c_data.lists = control_lists;
- c_data.num_lists = data.controls.size();
-
- std::size_t listsSize = 0;
- for (const auto &list : data.controls)
- listsSize += serializer_.binarySize(list);
-
- std::vector<uint8_t> binaryData(listsSize);
- ByteStreamBuffer byteStreamBuffer(binaryData.data(), listsSize);
-
- unsigned int i = 0;
- for (const auto &list : data.controls) {
- struct ipa_control_list &c_list = control_lists[i];
- c_list.size = serializer_.binarySize(list);
-
- ByteStreamBuffer b = byteStreamBuffer.carveOut(c_list.size);
- serializer_.serialize(list, b);
-
- c_list.data = b.base();
- }
-
- callbacks_->queue_frame_action(cb_ctx_, frame, c_data);
-}
-
-#ifndef __DOXYGEN__
-/*
- * This construct confuses Doygen and makes it believe that all members of the
- * operations is a member of IPAInterfaceWrapper. It must thus be hidden.
- */
-const struct ipa_context_ops IPAInterfaceWrapper::operations_ = {
- .destroy = &IPAInterfaceWrapper::destroy,
- .get_interface = &IPAInterfaceWrapper::get_interface,
- .init = &IPAInterfaceWrapper::init,
- .start = &IPAInterfaceWrapper::start,
- .stop = &IPAInterfaceWrapper::stop,
- .register_callbacks = &IPAInterfaceWrapper::register_callbacks,
- .configure = &IPAInterfaceWrapper::configure,
- .map_buffers = &IPAInterfaceWrapper::map_buffers,
- .unmap_buffers = &IPAInterfaceWrapper::unmap_buffers,
- .process_event = &IPAInterfaceWrapper::process_event,
-};
-#endif
-
-} /* namespace libcamera */
diff --git a/src/ipa/libipa/ipa_interface_wrapper.h b/src/ipa/libipa/ipa_interface_wrapper.h
deleted file mode 100644
index a1c70159..00000000
--- a/src/ipa/libipa/ipa_interface_wrapper.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * ipa_interface_wrapper.h - Image Processing Algorithm interface wrapper
- */
-#ifndef __LIBCAMERA_IPA_INTERFACE_WRAPPER_H__
-#define __LIBCAMERA_IPA_INTERFACE_WRAPPER_H__
-
-#include <memory>
-
-#include <libcamera/ipa/ipa_interface.h>
-
-#include "libcamera/internal/control_serializer.h"
-
-namespace libcamera {
-
-class IPAInterfaceWrapper : public ipa_context
-{
-public:
- IPAInterfaceWrapper(std::unique_ptr<IPAInterface> interface);
-
-private:
- static void destroy(struct ipa_context *ctx);
- static void *get_interface(struct ipa_context *ctx);
- static void init(struct ipa_context *ctx,
- const struct ipa_settings *settings);
- static int start(struct ipa_context *ctx);
- static void stop(struct ipa_context *ctx);
- static void register_callbacks(struct ipa_context *ctx,
- const struct ipa_callback_ops *callbacks,
- void *cb_ctx);
- static void configure(struct ipa_context *ctx,
- const struct ipa_sensor_info *sensor_info,
- const struct ipa_stream *streams,
- unsigned int num_streams,
- const struct ipa_control_info_map *maps,
- unsigned int num_maps);
- static void map_buffers(struct ipa_context *ctx,
- const struct ipa_buffer *c_buffers,
- size_t num_buffers);
- static void unmap_buffers(struct ipa_context *ctx,
- const unsigned int *ids,
- size_t num_buffers);
- static void process_event(struct ipa_context *ctx,
- const struct ipa_operation_data *data);
-
- static const struct ipa_context_ops operations_;
-
- void queueFrameAction(unsigned int frame, const IPAOperationData &data);
-
- std::unique_ptr<IPAInterface> ipa_;
- const struct ipa_callback_ops *callbacks_;
- void *cb_ctx_;
-
- ControlSerializer serializer_;
-};
-
-} /* namespace libcamera */
-
-#endif /* __LIBCAMERA_IPA_INTERFACE_WRAPPER_H__ */
diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
index 22626405..b29ef0f4 100644
--- a/src/ipa/libipa/meson.build
+++ b/src/ipa/libipa/meson.build
@@ -1,11 +1,9 @@
# SPDX-License-Identifier: CC0-1.0
libipa_headers = files([
- 'ipa_interface_wrapper.h',
])
libipa_sources = files([
- 'ipa_interface_wrapper.cpp',
])
libipa_includes = include_directories('..')
diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
index ef8b19ba..81a3195c 100644
--- a/src/ipa/raspberrypi/raspberrypi.cpp
+++ b/src/ipa/raspberrypi/raspberrypi.cpp
@@ -20,11 +20,10 @@
#include <libcamera/ipa/ipa_interface.h>
#include <libcamera/ipa/ipa_module_info.h>
#include <libcamera/ipa/raspberrypi.h>
+#include <libcamera/ipa/raspberrypi_ipa_interface.h>
#include <libcamera/request.h>
#include <libcamera/span.h>
-#include <libipa/ipa_interface_wrapper.h>
-
#include "libcamera/internal/buffer.h"
#include "libcamera/internal/camera_sensor.h"
#include "libcamera/internal/log.h"
@@ -64,7 +63,7 @@ constexpr double defaultMaxFrameDuration = 1e6 / 0.01;
LOG_DEFINE_CATEGORY(IPARPI)
-class IPARPi : public IPAInterface
+class IPARPi : public ipa::rpi::IPARPiInterface
{
public:
IPARPi()
@@ -77,21 +76,24 @@ public:
~IPARPi()
{
if (lsTable_)
- munmap(lsTable_, RPi::MaxLsGridSize);
+ munmap(lsTable_, ipa::rpi::MaxLsGridSize);
}
int init(const IPASettings &settings) override;
- int start(const IPAOperationData &data, IPAOperationData *result) override;
+ void start(const ipa::rpi::StartControls &data,
+ ipa::rpi::StartControls *result) override;
void stop() override {}
void configure(const CameraSensorInfo &sensorInfo,
const std::map<unsigned int, IPAStream> &streamConfig,
- const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- const IPAOperationData &ipaConfig,
- IPAOperationData *response) override;
+ const std::map<unsigned int, ControlInfoMap> &entityControls,
+ const ipa::rpi::ConfigInput &data,
+ ipa::rpi::ConfigOutput *response, int32_t *ret) override;
void mapBuffers(const std::vector<IPABuffer> &buffers) override;
void unmapBuffers(const std::vector<unsigned int> &ids) override;
- void processEvent(const IPAOperationData &event) override;
+ void signalStatReady(const uint32_t bufferId) override;
+ void signalQueueRequest(const ControlList &controls) override;
+ void signalIspPrepare(const ipa::rpi::ISPConfig &data) override;
private:
void setMode(const CameraSensorInfo &sensorInfo);
@@ -166,15 +168,15 @@ int IPARPi::init(const IPASettings &settings)
return 0;
}
-int IPARPi::start(const IPAOperationData &data, IPAOperationData *result)
+void IPARPi::start(const ipa::rpi::StartControls &data,
+ ipa::rpi::StartControls *result)
{
RPiController::Metadata metadata;
ASSERT(result);
- result->operation = 0;
- if (data.operation & RPi::IPA_CONFIG_STARTUP_CTRLS) {
+ if (!data.controls.empty()) {
/* We have been given some controls to action before start. */
- queueRequest(data.controls[0]);
+ queueRequest(data.controls);
}
controller_.SwitchMode(mode_, &metadata);
@@ -189,8 +191,7 @@ int IPARPi::start(const IPAOperationData &data, IPAOperationData *result)
if (agcStatus.shutter_time != 0.0 && agcStatus.analogue_gain != 0.0) {
ControlList ctrls(sensorCtrls_);
applyAGC(&agcStatus, ctrls);
- result->controls.emplace_back(ctrls);
- result->operation |= RPi::IPA_RESULT_SENSOR_CTRLS;
+ result->controls = std::move(ctrls);
}
/*
@@ -237,12 +238,9 @@ int IPARPi::start(const IPAOperationData &data, IPAOperationData *result)
mistrustCount_ = helper_->MistrustFramesModeSwitch();
}
- result->data.push_back(dropFrame);
- result->operation |= RPi::IPA_RESULT_DROP_FRAMES;
+ result->dropFrameCount = dropFrame;
firstStart_ = false;
-
- return 0;
}
void IPARPi::setMode(const CameraSensorInfo &sensorInfo)
@@ -292,30 +290,30 @@ void IPARPi::setMode(const CameraSensorInfo &sensorInfo)
void IPARPi::configure(const CameraSensorInfo &sensorInfo,
[[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,
- const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- const IPAOperationData &ipaConfig,
- IPAOperationData *result)
+ const std::map<unsigned int, ControlInfoMap> &entityControls,
+ const ipa::rpi::ConfigInput &ipaConfig,
+ ipa::rpi::ConfigOutput *result, int32_t *ret)
{
if (entityControls.size() != 2) {
LOG(IPARPI, Error) << "No ISP or sensor controls found.";
- result->operation = RPi::IPA_RESULT_CONFIG_FAILED;
+ *ret = -1;
return;
}
- result->operation = 0;
+ result->params = 0;
sensorCtrls_ = entityControls.at(0);
ispCtrls_ = entityControls.at(1);
if (!validateSensorControls()) {
LOG(IPARPI, Error) << "Sensor control validation failed.";
- result->operation = RPi::IPA_RESULT_CONFIG_FAILED;
+ *ret = -1;
return;
}
if (!validateIspControls()) {
LOG(IPARPI, Error) << "ISP control validation failed.";
- result->operation = RPi::IPA_RESULT_CONFIG_FAILED;
+ *ret = -1;
return;
}
@@ -334,7 +332,7 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,
if (!helper_) {
LOG(IPARPI, Error) << "Could not create camera helper for "
<< cameraName;
- result->operation = RPi::IPA_RESULT_CONFIG_FAILED;
+ *ret = -1;
return;
}
@@ -346,35 +344,30 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,
helper_->GetDelays(exposureDelay, gainDelay);
sensorMetadata = helper_->SensorEmbeddedDataPresent();
- result->data.push_back(gainDelay);
- result->data.push_back(exposureDelay); /* For EXPOSURE ctrl */
- result->data.push_back(exposureDelay); /* For VBLANK ctrl */
- result->data.push_back(sensorMetadata);
-
- result->operation |= RPi::IPA_RESULT_SENSOR_PARAMS;
+ result->params |= ipa::rpi::ConfigStaggeredWrite;
+ result->sensorConfig.gainDelay = gainDelay;
+ result->sensorConfig.exposureDelay = exposureDelay;
+ result->sensorConfig.vblank = exposureDelay;
+ result->sensorConfig.sensorMetadata = sensorMetadata;
}
/* Re-assemble camera mode using the sensor info. */
setMode(sensorInfo);
- /*
- * The ipaConfig.data always gives us the user transform first. Note that
- * this will always make the LS table pointer (if present) element 1.
- */
- mode_.transform = static_cast<libcamera::Transform>(ipaConfig.data[0]);
+ mode_.transform = static_cast<libcamera::Transform>(ipaConfig.transform);
/* Store the lens shading table pointer and handle if available. */
- if (ipaConfig.operation & RPi::IPA_CONFIG_LS_TABLE) {
+ if (ipaConfig.lsTableHandle.isValid()) {
/* Remove any previous table, if there was one. */
if (lsTable_) {
- munmap(lsTable_, RPi::MaxLsGridSize);
+ munmap(lsTable_, ipa::rpi::MaxLsGridSize);
lsTable_ = nullptr;
}
- /* Map the LS table buffer into user space (now element 1). */
- lsTableHandle_ = FileDescriptor(ipaConfig.data[1]);
+ /* Map the LS table buffer into user space. */
+ lsTableHandle_ = std::move(ipaConfig.lsTableHandle);
if (lsTableHandle_.isValid()) {
- lsTable_ = mmap(nullptr, RPi::MaxLsGridSize, PROT_READ | PROT_WRITE,
+ lsTable_ = mmap(nullptr, ipa::rpi::MaxLsGridSize, PROT_READ | PROT_WRITE,
MAP_SHARED, lsTableHandle_.fd(), 0);
if (lsTable_ == MAP_FAILED) {
@@ -403,11 +396,12 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,
agcStatus.analogue_gain = DefaultAnalogueGain;
applyAGC(&agcStatus, ctrls);
- result->controls.emplace_back(ctrls);
- result->operation |= RPi::IPA_RESULT_SENSOR_CTRLS;
+ result->controls = std::move(ctrls);
}
lastMode_ = mode_;
+
+ *ret = 0;
}
void IPARPi::mapBuffers(const std::vector<IPABuffer> &buffers)
@@ -429,56 +423,35 @@ void IPARPi::unmapBuffers(const std::vector<unsigned int> &ids)
}
}
-void IPARPi::processEvent(const IPAOperationData &event)
+void IPARPi::signalStatReady(uint32_t bufferId)
{
- switch (event.operation) {
- case RPi::IPA_EVENT_SIGNAL_STAT_READY: {
- unsigned int bufferId = event.data[0];
-
- if (++checkCount_ != frameCount_) /* assert here? */
- LOG(IPARPI, Error) << "WARNING: Prepare/Process mismatch!!!";
- if (frameCount_ > mistrustCount_)
- processStats(bufferId);
-
- reportMetadata();
-
- IPAOperationData op;
- op.operation = RPi::IPA_ACTION_STATS_METADATA_COMPLETE;
- op.data = { bufferId & RPi::BufferMask::ID };
- op.controls = { libcameraMetadata_ };
- queueFrameAction.emit(0, op);
- break;
- }
+ if (++checkCount_ != frameCount_) /* assert here? */
+ LOG(IPARPI, Error) << "WARNING: Prepare/Process mismatch!!!";
+ if (frameCount_ > mistrustCount_)
+ processStats(bufferId);
- case RPi::IPA_EVENT_SIGNAL_ISP_PREPARE: {
- unsigned int embeddedbufferId = event.data[0];
- unsigned int bayerbufferId = event.data[1];
+ reportMetadata();
- /*
- * At start-up, or after a mode-switch, we may want to
- * avoid running the control algos for a few frames in case
- * they are "unreliable".
- */
- prepareISP(embeddedbufferId);
- frameCount_++;
-
- /* Ready to push the input buffer into the ISP. */
- IPAOperationData op;
- op.operation = RPi::IPA_ACTION_RUN_ISP;
- op.data = { bayerbufferId & RPi::BufferMask::ID };
- queueFrameAction.emit(0, op);
- break;
- }
+ statsMetadataComplete.emit(bufferId & ipa::rpi::MaskID, libcameraMetadata_);
+}
- case RPi::IPA_EVENT_QUEUE_REQUEST: {
- queueRequest(event.controls[0]);
- break;
- }
+void IPARPi::signalQueueRequest(const ControlList &controls)
+{
+ queueRequest(controls);
+}
- default:
- LOG(IPARPI, Error) << "Unknown event " << event.operation;
- break;
- }
+void IPARPi::signalIspPrepare(const ipa::rpi::ISPConfig &data)
+{
+ /*
+ * At start-up, or after a mode-switch, we may want to
+ * avoid running the control algos for a few frames in case
+ * they are "unreliable".
+ */
+ prepareISP(data.embeddedbufferId);
+ frameCount_++;
+
+ /* Ready to push the input buffer into the ISP. */
+ runIsp.emit(data.bayerbufferId & ipa::rpi::MaskID);
}
void IPARPi::reportMetadata()
@@ -933,10 +906,7 @@ void IPARPi::queueRequest(const ControlList &controls)
void IPARPi::returnEmbeddedBuffer(unsigned int bufferId)
{
- IPAOperationData op;
- op.operation = RPi::IPA_ACTION_EMBEDDED_COMPLETE;
- op.data = { bufferId & RPi::BufferMask::ID };
- queueFrameAction.emit(0, op);
+ embeddedComplete.emit(bufferId & ipa::rpi::MaskID);
}
void IPARPi::prepareISP(unsigned int bufferId)
@@ -997,12 +967,8 @@ void IPARPi::prepareISP(unsigned int bufferId)
if (dpcStatus)
applyDPC(dpcStatus, ctrls);
- if (!ctrls.empty()) {
- IPAOperationData op;
- op.operation = RPi::IPA_ACTION_V4L2_SET_ISP;
- op.controls.push_back(ctrls);
- queueFrameAction.emit(0, op);
- }
+ if (!ctrls.empty())
+ setIsp.emit(ctrls);
}
}
@@ -1059,10 +1025,7 @@ void IPARPi::processStats(unsigned int bufferId)
ControlList ctrls(sensorCtrls_);
applyAGC(&agcStatus, ctrls);
- IPAOperationData op;
- op.operation = RPi::IPA_ACTION_SET_DELAYED_CTRLS;
- op.controls.emplace_back(ctrls);
- queueFrameAction.emit(0, op);
+ setDelayedControls.emit(ctrls);
}
}
@@ -1301,13 +1264,14 @@ void IPARPi::applyLS(const struct AlscStatus *lsStatus, ControlList &ctrls)
.grid_width = w,
.grid_stride = w,
.grid_height = h,
- .dmabuf = lsTableHandle_.fd(),
+ /* .dmabuf will be filled in by pipeline handler. */
+ .dmabuf = 0,
.ref_transform = 0,
.corner_sampled = 1,
.gain_format = GAIN_FORMAT_U4P10
};
- if (!lsTable_ || w * h * 4 * sizeof(uint16_t) > RPi::MaxLsGridSize) {
+ if (!lsTable_ || w * h * 4 * sizeof(uint16_t) > ipa::rpi::MaxLsGridSize) {
LOG(IPARPI, Error) << "Do not have a correctly allocate lens shading table!";
return;
}
@@ -1378,9 +1342,9 @@ const struct IPAModuleInfo ipaModuleInfo = {
"raspberrypi",
};
-struct ipa_context *ipaCreate()
+IPAInterface *ipaCreate()
{
- return new IPAInterfaceWrapper(std::make_unique<IPARPi>());
+ return new IPARPi();
}
} /* extern "C" */
diff --git a/src/ipa/rkisp1/meson.build b/src/ipa/rkisp1/meson.build
index 95eb5393..1a1c7159 100644
--- a/src/ipa/rkisp1/meson.build
+++ b/src/ipa/rkisp1/meson.build
@@ -3,7 +3,7 @@
ipa_name = 'ipa_rkisp1'
mod = shared_module(ipa_name,
- 'rkisp1.cpp',
+ ['rkisp1.cpp', libcamera_generated_ipa_headers],
name_prefix : '',
include_directories : [ipa_includes, libipa_includes],
dependencies : libcamera_dep,
diff --git a/src/ipa/rkisp1/rkisp1.cpp b/src/ipa/rkisp1/rkisp1.cpp
index 39783abd..67bac986 100644
--- a/src/ipa/rkisp1/rkisp1.cpp
+++ b/src/ipa/rkisp1/rkisp1.cpp
@@ -19,36 +19,31 @@
#include <libcamera/control_ids.h>
#include <libcamera/ipa/ipa_interface.h>
#include <libcamera/ipa/ipa_module_info.h>
-#include <libcamera/ipa/rkisp1.h>
+#include <libcamera/ipa/rkisp1_ipa_interface.h>
#include <libcamera/request.h>
-#include <libipa/ipa_interface_wrapper.h>
-
#include "libcamera/internal/log.h"
namespace libcamera {
LOG_DEFINE_CATEGORY(IPARkISP1)
-class IPARkISP1 : public IPAInterface
+class IPARkISP1 : public ipa::rkisp1::IPARkISP1Interface
{
public:
int init([[maybe_unused]] const IPASettings &settings) override
{
return 0;
}
- int start([[maybe_unused]] const IPAOperationData &data,
- [[maybe_unused]] IPAOperationData *result) override { return 0; }
+ int start() override { return 0; }
void stop() override {}
void configure(const CameraSensorInfo &info,
- const std::map<unsigned int, IPAStream> &streamConfig,
- const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- const IPAOperationData &ipaConfig,
- IPAOperationData *response) override;
+ const std::map<uint32_t, IPAStream> &streamConfig,
+ const std::map<uint32_t, ControlInfoMap> &entityControls) override;
void mapBuffers(const std::vector<IPABuffer> &buffers) override;
void unmapBuffers(const std::vector<unsigned int> &ids) override;
- void processEvent(const IPAOperationData &event) override;
+ void processEvent(const ipa::rkisp1::RkISP1Event &event) override;
private:
void queueRequest(unsigned int frame, rkisp1_params_cfg *params,
@@ -81,10 +76,8 @@ private:
* before accessing them.
*/
void IPARkISP1::configure([[maybe_unused]] const CameraSensorInfo &info,
- [[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,
- const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- [[maybe_unused]] const IPAOperationData &ipaConfig,
- [[maybe_unused]] IPAOperationData *result)
+ [[maybe_unused]] const std::map<uint32_t, IPAStream> &streamConfig,
+ const std::map<uint32_t, ControlInfoMap> &entityControls)
{
if (entityControls.empty())
return;
@@ -160,12 +153,12 @@ void IPARkISP1::unmapBuffers(const std::vector<unsigned int> &ids)
}
}
-void IPARkISP1::processEvent(const IPAOperationData &event)
+void IPARkISP1::processEvent(const ipa::rkisp1::RkISP1Event &event)
{
- switch (event.operation) {
- case RKISP1_IPA_EVENT_SIGNAL_STAT_BUFFER: {
- unsigned int frame = event.data[0];
- unsigned int bufferId = event.data[1];
+ switch (event.op) {
+ case ipa::rkisp1::EventSignalStatBuffer: {
+ unsigned int frame = event.frame;
+ unsigned int bufferId = event.bufferId;
const rkisp1_stat_buffer *stats =
static_cast<rkisp1_stat_buffer *>(buffersMemory_[bufferId]);
@@ -173,18 +166,18 @@ void IPARkISP1::processEvent(const IPAOperationData &event)
updateStatistics(frame, stats);
break;
}
- case RKISP1_IPA_EVENT_QUEUE_REQUEST: {
- unsigned int frame = event.data[0];
- unsigned int bufferId = event.data[1];
+ case ipa::rkisp1::EventQueueRequest: {
+ unsigned int frame = event.frame;
+ unsigned int bufferId = event.bufferId;
rkisp1_params_cfg *params =
static_cast<rkisp1_params_cfg *>(buffersMemory_[bufferId]);
- queueRequest(frame, params, event.controls[0]);
+ queueRequest(frame, params, event.controls);
break;
}
default:
- LOG(IPARkISP1, Error) << "Unknown event " << event.operation;
+ LOG(IPARkISP1, Error) << "Unknown event " << event.op;
break;
}
}
@@ -204,8 +197,8 @@ void IPARkISP1::queueRequest(unsigned int frame, rkisp1_params_cfg *params,
params->module_en_update = RKISP1_CIF_ISP_MODULE_AEC;
}
- IPAOperationData op;
- op.operation = RKISP1_IPA_ACTION_PARAM_FILLED;
+ ipa::rkisp1::RkISP1Action op;
+ op.op = ipa::rkisp1::ActionParamFilled;
queueFrameAction.emit(frame, op);
}
@@ -257,13 +250,13 @@ void IPARkISP1::updateStatistics(unsigned int frame,
void IPARkISP1::setControls(unsigned int frame)
{
- IPAOperationData op;
- op.operation = RKISP1_IPA_ACTION_V4L2_SET;
+ ipa::rkisp1::RkISP1Action op;
+ op.op = ipa::rkisp1::ActionV4L2Set;
ControlList ctrls(ctrls_);
ctrls.set(V4L2_CID_EXPOSURE, static_cast<int32_t>(exposure_));
ctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast<int32_t>(gain_));
- op.controls.push_back(ctrls);
+ op.controls = ctrls;
queueFrameAction.emit(frame, op);
}
@@ -275,9 +268,9 @@ void IPARkISP1::metadataReady(unsigned int frame, unsigned int aeState)
if (aeState)
ctrls.set(controls::AeLocked, aeState == 2);
- IPAOperationData op;
- op.operation = RKISP1_IPA_ACTION_METADATA;
- op.controls.push_back(ctrls);
+ ipa::rkisp1::RkISP1Action op;
+ op.op = ipa::rkisp1::ActionMetadata;
+ op.controls = ctrls;
queueFrameAction.emit(frame, op);
}
@@ -294,9 +287,9 @@ const struct IPAModuleInfo ipaModuleInfo = {
"rkisp1",
};
-struct ipa_context *ipaCreate()
+IPAInterface *ipaCreate()
{
- return new IPAInterfaceWrapper(std::make_unique<IPARkISP1>());
+ return new IPARkISP1();
}
}
diff --git a/src/ipa/vimc/meson.build b/src/ipa/vimc/meson.build
index b1544c28..a35825ae 100644
--- a/src/ipa/vimc/meson.build
+++ b/src/ipa/vimc/meson.build
@@ -3,7 +3,7 @@
ipa_name = 'ipa_vimc'
mod = shared_module(ipa_name,
- 'vimc.cpp',
+ ['vimc.cpp', libcamera_generated_ipa_headers],
name_prefix : '',
include_directories : [ipa_includes, libipa_includes],
dependencies : libcamera_dep,
diff --git a/src/ipa/vimc/vimc.cpp b/src/ipa/vimc/vimc.cpp
index 074902ee..13681d88 100644
--- a/src/ipa/vimc/vimc.cpp
+++ b/src/ipa/vimc/vimc.cpp
@@ -5,7 +5,7 @@
* ipa_vimc.cpp - Vimc Image Processing Algorithm module
*/
-#include <libcamera/ipa/vimc.h>
+#include <libcamera/ipa/vimc_ipa_interface.h>
#include <fcntl.h>
#include <string.h>
@@ -17,8 +17,6 @@
#include <libcamera/ipa/ipa_interface.h>
#include <libcamera/ipa/ipa_module_info.h>
-#include <libipa/ipa_interface_wrapper.h>
-
#include "libcamera/internal/file.h"
#include "libcamera/internal/log.h"
@@ -26,7 +24,7 @@ namespace libcamera {
LOG_DEFINE_CATEGORY(IPAVimc)
-class IPAVimc : public IPAInterface
+class IPAVimc : public ipa::vimc::IPAVimcInterface
{
public:
IPAVimc();
@@ -34,22 +32,12 @@ public:
int init(const IPASettings &settings) override;
- int start(const IPAOperationData &data,
- IPAOperationData *result) override;
+ int start() override;
void stop() override;
- void configure([[maybe_unused]] const CameraSensorInfo &sensorInfo,
- [[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,
- [[maybe_unused]] const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- [[maybe_unused]] const IPAOperationData &ipaConfig,
- [[maybe_unused]] IPAOperationData *result) override {}
- void mapBuffers([[maybe_unused]] const std::vector<IPABuffer> &buffers) override {}
- void unmapBuffers([[maybe_unused]] const std::vector<unsigned int> &ids) override {}
- void processEvent([[maybe_unused]] const IPAOperationData &event) override {}
-
private:
void initTrace();
- void trace(enum IPAOperationCode operation);
+ void trace(enum ipa::vimc::IPAOperationCode operation);
int fd_;
};
@@ -68,7 +56,7 @@ IPAVimc::~IPAVimc()
int IPAVimc::init(const IPASettings &settings)
{
- trace(IPAOperationInit);
+ trace(ipa::vimc::IPAOperationInit);
LOG(IPAVimc, Debug)
<< "initializing vimc IPA with configuration file "
@@ -83,10 +71,9 @@ int IPAVimc::init(const IPASettings &settings)
return 0;
}
-int IPAVimc::start([[maybe_unused]] const IPAOperationData &data,
- [[maybe_unused]] IPAOperationData *result)
+int IPAVimc::start()
{
- trace(IPAOperationStart);
+ trace(ipa::vimc::IPAOperationStart);
LOG(IPAVimc, Debug) << "start vimc IPA!";
@@ -95,7 +82,7 @@ int IPAVimc::start([[maybe_unused]] const IPAOperationData &data,
void IPAVimc::stop()
{
- trace(IPAOperationStop);
+ trace(ipa::vimc::IPAOperationStop);
LOG(IPAVimc, Debug) << "stop vimc IPA!";
}
@@ -103,11 +90,11 @@ void IPAVimc::stop()
void IPAVimc::initTrace()
{
struct stat fifoStat;
- int ret = stat(VIMC_IPA_FIFO_PATH, &fifoStat);
+ int ret = stat(ipa::vimc::VimcIPAFIFOPath.c_str(), &fifoStat);
if (ret)
return;
- ret = ::open(VIMC_IPA_FIFO_PATH, O_WRONLY);
+ ret = ::open(ipa::vimc::VimcIPAFIFOPath.c_str(), O_WRONLY);
if (ret < 0) {
ret = errno;
LOG(IPAVimc, Error) << "Failed to open vimc IPA test FIFO: "
@@ -118,7 +105,7 @@ void IPAVimc::initTrace()
fd_ = ret;
}
-void IPAVimc::trace(enum IPAOperationCode operation)
+void IPAVimc::trace(enum ipa::vimc::IPAOperationCode operation)
{
if (fd_ < 0)
return;
@@ -143,9 +130,9 @@ const struct IPAModuleInfo ipaModuleInfo = {
"vimc",
};
-struct ipa_context *ipaCreate()
+IPAInterface *ipaCreate()
{
- return new IPAInterfaceWrapper(std::make_unique<IPAVimc>());
+ return new IPAVimc();
}
}
diff --git a/src/libcamera/ipa_context_wrapper.cpp b/src/libcamera/ipa_context_wrapper.cpp
deleted file mode 100644
index 19c44ad8..00000000
--- a/src/libcamera/ipa_context_wrapper.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * ipa_context_wrapper.cpp - Image Processing Algorithm context wrapper
- */
-
-#include "libcamera/internal/ipa_context_wrapper.h"
-
-#include <vector>
-
-#include <libcamera/controls.h>
-
-#include "libcamera/internal/byte_stream_buffer.h"
-#include "libcamera/internal/camera_sensor.h"
-#include "libcamera/internal/utils.h"
-
-/**
- * \file ipa_context_wrapper.h
- * \brief Image Processing Algorithm context wrapper
- */
-
-namespace libcamera {
-
-/**
- * \class IPAContextWrapper
- * \brief Wrap an ipa_context and expose it as an IPAInterface
- *
- * The IPAContextWrapper class wraps an ipa_context, provided by an IPA module, and
- * exposes an IPAInterface. This mechanism is used for IPAs that are not
- * isolated in a separate process to allow direct calls from pipeline handler
- * using the IPAInterface API instead of the lower-level ipa_context API.
- *
- * The IPAInterface methods are converted to the ipa_context API by translating
- * all C++ arguments into plain C structures or byte arrays that contain no
- * pointer, as required by the ipa_context API.
- */
-
-/**
- * \brief Construct an IPAContextWrapper instance that wraps the \a context
- * \param[in] context The IPA module context
- *
- * Ownership of the \a context is passed to the IPAContextWrapper. The context remains
- * valid for the whole lifetime of the wrapper and is destroyed automatically
- * with it.
- */
-IPAContextWrapper::IPAContextWrapper(struct ipa_context *context)
- : ctx_(context), intf_(nullptr)
-{
- if (!ctx_)
- return;
-
- bool forceCApi = !!utils::secure_getenv("LIBCAMERA_IPA_FORCE_C_API");
-
- if (!forceCApi && ctx_ && ctx_->ops->get_interface) {
- intf_ = reinterpret_cast<IPAInterface *>(ctx_->ops->get_interface(ctx_));
- intf_->queueFrameAction.connect(this, &IPAContextWrapper::doQueueFrameAction);
- return;
- }
-
- ctx_->ops->register_callbacks(ctx_, &IPAContextWrapper::callbacks_,
- this);
-}
-
-IPAContextWrapper::~IPAContextWrapper()
-{
- if (!ctx_)
- return;
-
- ctx_->ops->destroy(ctx_);
-}
-
-int IPAContextWrapper::init(const IPASettings &settings)
-{
- if (intf_)
- return intf_->init(settings);
-
- if (!ctx_)
- return 0;
-
- struct ipa_settings c_settings;
- c_settings.configuration_file = settings.configurationFile.c_str();
-
- ctx_->ops->init(ctx_, &c_settings);
-
- return 0;
-}
-
-int IPAContextWrapper::start(const IPAOperationData &data,
- IPAOperationData *result)
-{
- if (intf_)
- return intf_->start(data, result);
-
- if (!ctx_)
- return 0;
-
- return ctx_->ops->start(ctx_);
-}
-
-void IPAContextWrapper::stop()
-{
- if (intf_)
- return intf_->stop();
-
- if (!ctx_)
- return;
-
- ctx_->ops->stop(ctx_);
-}
-
-void IPAContextWrapper::configure(const CameraSensorInfo &sensorInfo,
- const std::map<unsigned int, IPAStream> &streamConfig,
- const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- const IPAOperationData &ipaConfig,
- IPAOperationData *result)
-{
- if (intf_)
- return intf_->configure(sensorInfo, streamConfig,
- entityControls, ipaConfig, result);
-
- if (!ctx_)
- return;
-
- serializer_.reset();
-
- /* Translate the camera sensor info. */
- struct ipa_sensor_info sensor_info = {};
- sensor_info.model = sensorInfo.model.c_str();
- sensor_info.bits_per_pixel = sensorInfo.bitsPerPixel;
- sensor_info.active_area.width = sensorInfo.activeAreaSize.width;
- sensor_info.active_area.height = sensorInfo.activeAreaSize.height;
- sensor_info.analog_crop.left = sensorInfo.analogCrop.x;
- sensor_info.analog_crop.top = sensorInfo.analogCrop.y;
- sensor_info.analog_crop.width = sensorInfo.analogCrop.width;
- sensor_info.analog_crop.height = sensorInfo.analogCrop.height;
- sensor_info.output_size.width = sensorInfo.outputSize.width;
- sensor_info.output_size.height = sensorInfo.outputSize.height;
- sensor_info.pixel_rate = sensorInfo.pixelRate;
- sensor_info.line_length = sensorInfo.lineLength;
-
- /* Translate the IPA stream configurations map. */
- struct ipa_stream c_streams[streamConfig.size()];
-
- unsigned int i = 0;
- for (const auto &stream : streamConfig) {
- struct ipa_stream *c_stream = &c_streams[i];
- unsigned int id = stream.first;
- const IPAStream &ipaStream = stream.second;
-
- c_stream->id = id;
- c_stream->pixel_format = ipaStream.pixelFormat;
- c_stream->width = ipaStream.size.width;
- c_stream->height = ipaStream.size.height;
-
- ++i;
- }
-
- /* Translate the IPA entity controls map. */
- struct ipa_control_info_map c_info_maps[entityControls.size()];
- std::vector<std::vector<uint8_t>> data(entityControls.size());
-
- i = 0;
- for (const auto &info : entityControls) {
- struct ipa_control_info_map &c_info_map = c_info_maps[i];
- unsigned int id = info.first;
- const ControlInfoMap &infoMap = info.second;
-
- size_t infoMapSize = serializer_.binarySize(infoMap);
- data[i].resize(infoMapSize);
- ByteStreamBuffer byteStream(data[i].data(), data[i].size());
- serializer_.serialize(infoMap, byteStream);
-
- c_info_map.id = id;
- c_info_map.data = byteStream.base();
- c_info_map.size = byteStream.size();
-
- ++i;
- }
-
- /* \todo Translate the ipaConfig and reponse */
- ctx_->ops->configure(ctx_, &sensor_info, c_streams, streamConfig.size(),
- c_info_maps, entityControls.size());
-}
-
-void IPAContextWrapper::mapBuffers(const std::vector<IPABuffer> &buffers)
-{
- if (intf_)
- return intf_->mapBuffers(buffers);
-
- if (!ctx_)
- return;
-
- struct ipa_buffer c_buffers[buffers.size()];
-
- for (unsigned int i = 0; i < buffers.size(); ++i) {
- struct ipa_buffer &c_buffer = c_buffers[i];
- const IPABuffer &buffer = buffers[i];
- const std::vector<FrameBuffer::Plane> &planes = buffer.planes;
-
- c_buffer.id = buffer.id;
- c_buffer.num_planes = planes.size();
-
- for (unsigned int j = 0; j < planes.size(); ++j) {
- const FrameBuffer::Plane &plane = planes[j];
- c_buffer.planes[j].dmabuf = plane.fd.fd();
- c_buffer.planes[j].length = plane.length;
- }
- }
-
- ctx_->ops->map_buffers(ctx_, c_buffers, buffers.size());
-}
-
-void IPAContextWrapper::unmapBuffers(const std::vector<unsigned int> &ids)
-{
- if (intf_)
- return intf_->unmapBuffers(ids);
-
- if (!ctx_)
- return;
-
- ctx_->ops->unmap_buffers(ctx_, ids.data(), ids.size());
-}
-
-void IPAContextWrapper::processEvent(const IPAOperationData &data)
-{
- if (intf_)
- return intf_->processEvent(data);
-
- if (!ctx_)
- return;
-
- struct ipa_operation_data c_data;
- c_data.operation = data.operation;
- c_data.data = data.data.data();
- c_data.num_data = data.data.size();
-
- struct ipa_control_list control_lists[data.controls.size()];
- c_data.lists = control_lists;
- c_data.num_lists = data.controls.size();
-
- std::size_t listsSize = 0;
- for (const auto &list : data.controls)
- listsSize += serializer_.binarySize(list);
-
- std::vector<uint8_t> binaryData(listsSize);
- ByteStreamBuffer byteStreamBuffer(binaryData.data(), listsSize);
-
- unsigned int i = 0;
- for (const auto &list : data.controls) {
- struct ipa_control_list &c_list = control_lists[i];
- c_list.size = serializer_.binarySize(list);
- ByteStreamBuffer b = byteStreamBuffer.carveOut(c_list.size);
-
- serializer_.serialize(list, b);
-
- c_list.data = b.base();
- }
-
- ctx_->ops->process_event(ctx_, &c_data);
-}
-
-void IPAContextWrapper::doQueueFrameAction(unsigned int frame,
- const IPAOperationData &data)
-{
- IPAInterface::queueFrameAction.emit(frame, data);
-}
-
-void IPAContextWrapper::queue_frame_action(void *ctx, unsigned int frame,
- struct ipa_operation_data &data)
-{
- IPAContextWrapper *_this = static_cast<IPAContextWrapper *>(ctx);
- IPAOperationData opData;
-
- opData.operation = data.operation;
- for (unsigned int i = 0; i < data.num_data; ++i)
- opData.data.push_back(data.data[i]);
-
- for (unsigned int i = 0; i < data.num_lists; ++i) {
- const struct ipa_control_list &c_list = data.lists[i];
- ByteStreamBuffer b(c_list.data, c_list.size);
- opData.controls.push_back(_this->serializer_.deserialize<ControlList>(b));
- }
-
- _this->doQueueFrameAction(frame, opData);
-}
-
-#ifndef __DOXYGEN__
-/*
- * This construct confuses Doxygen and makes it believe that all members of the
- * operations is a member of IPAContextWrapper. It must thus be hidden.
- */
-const struct ipa_callback_ops IPAContextWrapper::callbacks_ = {
- .queue_frame_action = &IPAContextWrapper::queue_frame_action,
-};
-#endif
-
-} /* namespace libcamera */
diff --git a/src/libcamera/ipa_interface.cpp b/src/libcamera/ipa_interface.cpp
index 5be6f787..c44581b2 100644
--- a/src/libcamera/ipa_interface.cpp
+++ b/src/libcamera/ipa_interface.cpp
@@ -15,371 +15,51 @@
* an Image Processing Algorithm (IPA) module. An IPA module is developed for a
* specific pipeline handler and each pipeline handler may be compatible with
* multiple IPA implementations, both open and closed source. To support this,
- * libcamera communicates with IPA modules through a standard plain C interface.
+ * libcamera communicates with IPA modules through a per-pipeline C++ interface.
*
- * IPA modules shall expose a public function named ipaCreate() with the
- * following prototype.
+ * IPA modules shall provide an ipaCreate() function exported as a public C
+ * symbol with the following prototype:
*
* \code{.c}
- * struct ipa_context *ipaCreate();
+ * IPAInterface *ipaCreate();
* \endcode
*
- * The ipaCreate() function creates an instance of an IPA context, which models
+ * The ipaCreate() function creates an instance of an IPA interface, which models
* a context of execution for the IPA. IPA modules shall support creating one
* context per camera, as required by their associated pipeline handler.
*
- * The IPA module context operations are defined in the struct ipa_context_ops.
- * They model a low-level interface to configure the IPA, notify it of events,
- * and receive IPA actions through callbacks. An IPA module stores a pointer to
- * the operations corresponding to its context in the ipa_context::ops field.
- * That pointer is immutable for the lifetime of the context, and may differ
- * between different contexts created by the same IPA module.
+ * The IPA module interface operations are defined in the mojom file
+ * corresponding to the pipeline handler, in
+ * include/libcamera/ipa/{pipeline_name}.mojom.
*
- * The IPA interface defines base data types and functions to exchange data. On
- * top of this, each pipeline handler is responsible for defining the set of
- * events and actions used to communicate with their IPA. These are collectively
- * referred to as IPA operations and define the pipeline handler-specific IPA
- * protocol. Each operation defines the data that it carries, and how that data
- * is encoded in the ipa_context_ops functions arguments.
+ * The IPA interface is specific to each pipeline handler. The pipeline handlers
+ * define a set of operations used to communicate with their IPA modules. The
+ * operations, along with the data structures they use, are collectively
+ * referred to as the IPA protocol.
+ *
+ * The IPA protocol is defined using the
+ * <a href="https://chromium.googlesource.com/chromium/src/+/master/mojo/public/tools/bindings/README.md">Mojo interface definition language</a>,
+ * in a Mojo module file stored in include/libcamera/ipa/{pipeline_name}.mojom.
+ * The Mojo module contains two Mojo interfaces: IPAInterface defines the
+ * operations exposed by the IPA and called by the pipeline handler, and
+ * IPAEventInterface defines the events generated by the IPA and received by the
+ * pipeline handler.
*
* \todo Add reference to how pipelines shall document their protocol.
*
* IPAs can be isolated in a separate process. This implies that arguments to
- * the IPA interface functions may need to be transferred over IPC. All
- * arguments use Plain Old Data types and are documented either in the form of C
- * data types, or as a textual description of byte arrays for types that can't
- * be expressed using C data types (such as arrays of mixed data types). IPA
- * modules can thus use the C API without calling into libcamera to access the
- * data passed to the IPA context operations.
+ * the IPA interface functions may need to be transferred over IPC. An IPA
+ * proxy is auto-generated based on the mojom file, which abstracts away the
+ * (de)serialization from the pipeline handler and the IPA implementation. Thus
+ * any C++ structure that is defined in the mojom file, or the C++ libcamera
+ * objects that are listed in core.mojom, can be used directly.
*
* Due to IPC, synchronous communication between pipeline handlers and IPAs can
- * be costly. For that reason, the interface operates asynchronously. This
- * implies that methods don't return a status, and that all methods may copy
- * their arguments.
- *
- * The IPAInterface class is a C++ representation of the ipa_context_ops, using
- * C++ data classes provided by libcamera. This is the API exposed to pipeline
- * handlers to communicate with IPA modules. IPA modules may use the
- * IPAInterface API internally if they want to benefit from the data and helper
- * classes offered by libcamera.
- *
- * When an IPA module is loaded directly into the libcamera process and uses
- * the IPAInterface API internally, short-circuiting the path to the
- * ipa_context_ops and back to IPAInterface is desirable. To support this, IPA
- * modules may implement the ipa_context_ops::get_interface function to return a
- * pointer to their internal IPAInterface.
- */
-
-/**
- * \struct ipa_context
- * \brief IPA module context of execution
- *
- * This structure models a context of execution for an IPA module. It is
- * instantiated by the IPA module ipaCreate() function. IPA modules allocate
- * context instances in an implementation-defined way, contexts shall thus be
- * destroyed using the ipa_operation::destroy function only.
- *
- * The ipa_context structure provides a pointer to the IPA context operations.
- * It shall otherwise be treated as a constant black-box cookie and passed
- * unmodified to the functions defined in struct ipa_context_ops.
- *
- * IPA modules are expected to extend struct ipa_context by inheriting from it,
- * either through structure embedding to model inheritance in plain C, or
- * through C++ class inheritance. A simple example of the latter is available
- * in the IPAContextWrapper class implementation.
- *
- * \var ipa_context::ops
- * \brief The IPA context operations
- */
-
-/**
- * \struct ipa_settings
- * \brief IPA initialization settings for the IPA context operations
- * \sa IPASettings
- *
- * \var ipa_settings::configuration_file
- * \brief The name of the IPA configuration file (may be null or point to an
- * empty string)
- */
-
-/**
- * \struct ipa_sensor_info
- * \brief Camera sensor information for the IPA context operations
- * \sa libcamera::CameraSensorInfo
- *
- * \var ipa_sensor_info::model
- * \brief The camera sensor model name
- * \todo Remove this field as soon as no IPA depends on it anymore
- *
- * \var ipa_sensor_info::bits_per_pixel
- * \brief The camera sensor image format bit depth
- * \sa libcamera::CameraSensorInfo::bitsPerPixel
- *
- * \var ipa_sensor_info::active_area.width
- * \brief The camera sensor pixel array active area width
- * \sa libcamera::CameraSensorInfo::activeAreaSize
- *
- * \var ipa_sensor_info::active_area.height
- * \brief The camera sensor pixel array active area height
- * \sa libcamera::CameraSensorInfo::activeAreaSize
- *
- * \var ipa_sensor_info::active_area
- * \brief The camera sensor pixel array active size
- * \sa libcamera::CameraSensorInfo::activeAreaSize
- *
- * \var ipa_sensor_info::analog_crop.left
- * \brief The left coordinate of the analog crop rectangle, relative to the
- * pixel array active area
- * \sa libcamera::CameraSensorInfo::analogCrop
- *
- * \var ipa_sensor_info::analog_crop.top
- * \brief The top coordinate of the analog crop rectangle, relative to the pixel
- * array active area
- * \sa libcamera::CameraSensorInfo::analogCrop
- *
- * \var ipa_sensor_info::analog_crop.width
- * \brief The horizontal size of the analog crop rectangle
- * \sa libcamera::CameraSensorInfo::analogCrop
- *
- * \var ipa_sensor_info::analog_crop.height
- * \brief The vertical size of the analog crop rectangle
- * \sa libcamera::CameraSensorInfo::analogCrop
- *
- * \var ipa_sensor_info::analog_crop
- * \brief The analog crop rectangle
- * \sa libcamera::CameraSensorInfo::analogCrop
- *
- * \var ipa_sensor_info::output_size.width
- * \brief The horizontal size of the output image
- * \sa libcamera::CameraSensorInfo::outputSize
- *
- * \var ipa_sensor_info::output_size.height
- * \brief The vertical size of the output image
- * \sa libcamera::CameraSensorInfo::outputSize
- *
- * \var ipa_sensor_info::output_size
- * \brief The size of the output image
- * \sa libcamera::CameraSensorInfo::outputSize
- *
- * \var ipa_sensor_info::pixel_rate
- * \brief The number of pixel produced in a second
- * \sa libcamera::CameraSensorInfo::pixelRate
- *
- * \var ipa_sensor_info::line_length
- * \brief The full line length, including blanking, in pixel units
- * \sa libcamera::CameraSensorInfo::lineLength
- */
-
-/**
- * \struct ipa_stream
- * \brief Stream information for the IPA context operations
- *
- * \var ipa_stream::id
- * \brief Identifier for the stream, defined by the IPA protocol
- *
- * \var ipa_stream::pixel_format
- * \brief The stream pixel format, as defined by the PixelFormat class
- *
- * \var ipa_stream::width
- * \brief The stream width in pixels
- *
- * \var ipa_stream::height
- * \brief The stream height in pixels
- */
-
-/**
- * \struct ipa_control_info_map
- * \brief ControlInfoMap description for the IPA context operations
- *
- * \var ipa_control_info_map::id
- * \brief Identifier for the ControlInfoMap, defined by the IPA protocol
- *
- * \var ipa_control_info_map::data
- * \brief Pointer to a control packet for the ControlInfoMap
- * \sa ipa_controls.h
- *
- * \var ipa_control_info_map::size
- * \brief The size of the control packet in bytes
- */
-
-/**
- * \struct ipa_buffer_plane
- * \brief A plane for an ipa_buffer
- *
- * \var ipa_buffer_plane::dmabuf
- * \brief The dmabuf file descriptor for the plane (-1 for unused planes)
- *
- * \var ipa_buffer_plane::length
- * \brief The plane length in bytes (0 for unused planes)
- */
-
-/**
- * \struct ipa_buffer
- * \brief Buffer information for the IPA context operations
- *
- * \var ipa_buffer::id
- * \brief The buffer unique ID (see \ref libcamera::IPABuffer::id)
- *
- * \var ipa_buffer::num_planes
- * \brief The number of used planes in the ipa_buffer::planes array
- *
- * \var ipa_buffer::planes
- * \brief The buffer planes (up to 3)
- */
-
-/**
- * \struct ipa_control_list
- * \brief ControlList description for the IPA context operations
- *
- * \var ipa_control_list::data
- * \brief Pointer to a control packet for the ControlList
- * \sa ipa_controls.h
- *
- * \var ipa_control_list::size
- * \brief The size of the control packet in bytes
- */
-
-/**
- * \struct ipa_operation_data
- * \brief IPA operation data for the IPA context operations
- * \sa libcamera::IPAOperationData
- *
- * \var ipa_operation_data::operation
- * \brief IPA protocol operation
- *
- * \var ipa_operation_data::data
- * \brief Pointer to the operation data array
- *
- * \var ipa_operation_data::num_data
- * \brief Number of entries in the ipa_operation_data::data array
- *
- * \var ipa_operation_data::lists
- * \brief Pointer to an array of ipa_control_list
- *
- * \var ipa_operation_data::num_lists
- * \brief Number of entries in the ipa_control_list array
- */
-
-/**
- * \struct ipa_callback_ops
- * \brief IPA context operations as a set of function pointers
- */
-
-/**
- * \var ipa_callback_ops::queue_frame_action
- * \brief Queue an action associated with a frame to the pipeline handler
- * \param[in] cb_ctx The callback context registered with
- * ipa_context_ops::register_callbacks
- * \param[in] frame The frame number
- *
- * \sa libcamera::IPAInterface::queueFrameAction
- */
-
-/**
- * \struct ipa_context_ops
- * \brief IPA context operations as a set of function pointers
- *
- * To allow for isolation of IPA modules in separate processes, the functions
- * defined in the ipa_context_ops structure return only data related to the
- * libcamera side of the operations. In particular, error related to the
- * libcamera side of the IPC may be returned. Data returned by the IPA,
- * including status information, shall be provided through callbacks from the
- * IPA to libcamera.
- */
-
-/**
- * \var ipa_context_ops::destroy
- * \brief Destroy the IPA context created by the module's ipaCreate() function
- * \param[in] ctx The IPA context
- */
-
-/**
- * \var ipa_context_ops::get_interface
- * \brief Retrieve the IPAInterface implemented by the ipa_context (optional)
- * \param[in] ctx The IPA context
- *
- * IPA modules may implement this function to expose their internal
- * IPAInterface, if any. When implemented, libcamera may at its sole discretion
- * call it and then bypass the ipa_context_ops API by calling the IPAInterface
- * methods directly. IPA modules shall still implement and support the full
- * ipa_context_ops API.
- */
-
-/**
- * \var ipa_context_ops::init
- * \brief Initialise the IPA context
- * \param[in] ctx The IPA context
- * \param[in] settings The IPA initialization settings
- *
- * \sa libcamera::IPAInterface::init()
- */
-
-/**
- * \var ipa_context_ops::start
- * \brief Start the IPA context
- *
- * \sa libcamera::IPAInterface::start()
- */
-
-/**
- * \var ipa_context_ops::stop
- * \brief Stop the IPA context
- *
- * \sa libcamera::IPAInterface::stop()
- */
-
-/**
- * \var ipa_context_ops::register_callbacks
- * \brief Register callback operation from the IPA to the pipeline handler
- * \param[in] ctx The IPA context
- * \param[in] callback The IPA callback operations
- * \param[in] cb_ctx The callback context, passed to all callback operations
- */
-
-/**
- * \var ipa_context_ops::configure
- * \brief Configure the IPA stream and sensor settings
- * \param[in] ctx The IPA context
- * \param[in] sensor_info Camera sensor information
- * \param[in] streams Configuration of all active streams
- * \param[in] num_streams The number of entries in the \a streams array
- * \param[in] maps Controls provided by the pipeline entities
- * \param[in] num_maps The number of entries in the \a maps array
- *
- * \sa libcamera::IPAInterface::configure()
- */
-
-/**
- * \var ipa_context_ops::map_buffers
- * \brief Map buffers shared between the pipeline handler and the IPA
- * \param[in] ctx The IPA context
- * \param[in] buffers The buffers to map
- * \param[in] num_buffers The number of entries in the \a buffers array
- *
- * The dmabuf file descriptors provided in \a buffers are borrowed from the
- * caller and are only guaranteed to be valid during the map_buffers() call.
- * Should the callee need to store a copy of the file descriptors, it shall
- * duplicate them first with ::%dup().
- *
- * \sa libcamera::IPAInterface::mapBuffers()
- */
-
-/**
- * \var ipa_context_ops::unmap_buffers
- * \brief Unmap buffers shared by the pipeline to the IPA
- * \param[in] ctx The IPA context
- * \param[in] ids The IDs of the buffers to unmap
- * \param[in] num_buffers The number of entries in the \a ids array
- *
- * \sa libcamera::IPAInterface::unmapBuffers()
- */
-
-/**
- * \var ipa_context_ops::process_event
- * \brief Process an event from the pipeline handler
- * \param[in] ctx The IPA context
- *
- * \sa libcamera::IPAInterface::processEvent()
+ * be costly. For that reason, functions that cannot afford the high cost
+ * should be marked as [async] in the mojom file, and they will operate
+ * asynchronously. This implies that these methods don't return a status, and
+ * that all methods may copy their arguments. Synchronous functions are still
+ * allowed, but should be used with caution.
*/
/**
@@ -387,128 +67,22 @@
* \brief Entry point to the IPA modules
*
* This function is the entry point to the IPA modules. It is implemented by
- * every IPA module, and called by libcamera to create a new IPA context.
+ * every IPA module, and called by libcamera to create a new IPA interface
+ * instance.
*
- * \return A newly created IPA context
+ * \return A newly created IPA interface instance
*/
namespace libcamera {
/**
- * \struct IPASettings
- * \brief IPA interface initialization settings
- *
- * The IPASettings structure stores data passed to the IPAInterface::init()
- * function. The data contains settings that don't depend on a particular camera
- * or pipeline configuration and are valid for the whole life time of the IPA
- * interface.
- */
-
-/**
- * \var IPASettings::configurationFile
- * \brief The name of the IPA configuration file
- *
- * This field may be an empty string if the IPA doesn't require a configuration
- * file.
- */
-
-/**
- * \struct IPAStream
- * \brief Stream configuration for the IPA interface
- *
- * The IPAStream structure stores stream configuration parameters needed by the
- * IPAInterface::configure() method. It mirrors the StreamConfiguration class
- * that is not suitable for this purpose due to not being serializable.
- */
-
-/**
- * \var IPAStream::pixelFormat
- * \brief The stream pixel format
- */
-
-/**
- * \var IPAStream::size
- * \brief The stream size in pixels
- */
-
-/**
- * \struct IPABuffer
- * \brief Buffer information for the IPA interface
- *
- * The IPABuffer structure associates buffer memory with a unique ID. It is
- * used to map buffers to the IPA with IPAInterface::mapBuffers(), after which
- * buffers will be identified by their ID in the IPA interface.
- */
-
-/**
- * \var IPABuffer::id
- * \brief The buffer unique ID
- *
- * Buffers mapped to the IPA are identified by numerical unique IDs. The IDs
- * are chosen by the pipeline handler to fulfil the following constraints:
- *
- * - IDs shall be positive integers different than zero
- * - IDs shall be unique among all mapped buffers
- *
- * When buffers are unmapped with IPAInterface::unmapBuffers() their IDs are
- * freed and may be reused for new buffer mappings.
- */
-
-/**
- * \var IPABuffer::planes
- * \brief The buffer planes description
- *
- * Stores the dmabuf handle and length for each plane of the buffer.
- */
-
-/**
- * \struct IPAOperationData
- * \brief Parameters for IPA operations
- *
- * The IPAOperationData structure carries parameters for the IPA operations
- * performed through the IPAInterface::processEvent() method and the
- * IPAInterface::queueFrameAction signal.
- */
-
-/**
- * \var IPAOperationData::operation
- * \brief IPA protocol operation
- *
- * The operation field describes which operation the receiver shall perform. It
- * defines, through the IPA protocol, how the other fields of the structure are
- * interpreted. The protocol freely assigns numerical values to operations.
- */
-
-/**
- * \var IPAOperationData::data
- * \brief Operation integer data
- *
- * The interpretation and position of different values in the array are defined
- * by the IPA protocol.
- */
-
-/**
- * \var IPAOperationData::controls
- * \brief Operation controls data
- *
- * The interpretation and position of different values in the array are defined
- * by the IPA protocol.
- */
-
-/**
* \class IPAInterface
* \brief C++ Interface for IPA implementation
*
- * This pure virtual class defines a C++ API corresponding to the ipa_context,
- * ipa_context_ops and ipa_callback_ops API. It is used by pipeline handlers to
- * interact with IPA modules, and may be used internally in IPA modules if
- * desired to benefit from the data and helper classes provided by libcamera.
- *
- * Functions defined in the ipa_context_ops structure are mapped to IPAInterface
- * methods, while functions defined in the ipa_callback_ops are mapped to
- * IPAInterface signals. As with the C API, the IPA C++ interface uses
- * serializable data types only. It reuses structures defined by the C API, or
- * defines corresponding classes using C++ containers when required.
+ * This pure virtual class defines a skeletal C++ API for IPA modules.
+ * Specializations of this class must be defined in a mojom file in
+ * include/libcamera/ipa/ (see the IPA Writers Guide for details
+ * on how to do so).
*
* Due to process isolation all arguments to the IPAInterface methods and
* signals may need to be transferred over IPC. The class thus uses serializable
@@ -516,147 +90,15 @@ namespace libcamera {
* mirror core libcamera structures when the latter are not suitable, such as
* IPAStream to carry StreamConfiguration data.
*
- * As for the functions defined in struct ipa_context_ops, the methods defined
- * by this class shall not return data from the IPA.
+ * Custom data structures may also be defined in the mojom file, in which case
+ * the (de)serialization will automatically be generated. If any other libcamera
+ * structures are to be used as parameters, then a (de)serializer for them must
+ * be implemented in IPADataSerializer.
*
- * The pipeline handler shall use the IPAManager to locate a compatible
+ * The pipeline handlers shall use the IPAManager to locate a compatible
* IPAInterface. The interface may then be used to interact with the IPA module.
- */
-
-/**
- * \fn IPAInterface::init()
- * \brief Initialise the IPAInterface
- * \param[in] settings The IPA initialization settings
- *
- * This function initializes the IPA interface. It shall be called before any
- * other function of the IPAInterface. The \a settings carry initialization
- * parameters that are valid for the whole life time of the IPA interface.
- */
-
-/**
- * \fn IPAInterface::start()
- * \brief Start the IPA
- * \param[in] data Protocol-specific data for the start operation
- * \param[out] result Result of the start operation
- *
- * This method informs the IPA module that the camera is about to be started.
- * The IPA module shall prepare any resources it needs to operate.
- *
- * The \a data and \a result parameters carry custom data passed by the
- * pipeline handler to the IPA and back. The pipeline handler may set the \a
- * result parameter to null if the IPA protocol doesn't need to pass a result
- * back through the start() function.
- *
- * \return 0 on success or a negative error code otherwise
- */
-
-/**
- * \fn IPAInterface::stop()
- * \brief Stop the IPA
- *
- * This method informs the IPA module that the camera is stopped. The IPA module
- * shall release resources prepared in start().
- */
-
-/**
- * \fn IPAInterface::configure()
- * \brief Configure the IPA stream and sensor settings
- * \param[in] sensorInfo Camera sensor information
- * \param[in] streamConfig Configuration of all active streams
- * \param[in] entityControls Controls provided by the pipeline entities
- * \param[in] ipaConfig Pipeline-handler-specific configuration data
- * \param[out] result Pipeline-handler-specific configuration result
- *
- * This method shall be called when the camera is started to inform the IPA of
- * the camera's streams and the sensor settings. The meaning of the numerical
- * keys in the \a streamConfig and \a entityControls maps is defined by the IPA
- * protocol.
- *
- * The \a sensorInfo conveys information about the camera sensor settings that
- * the pipeline handler has selected for the configuration. The IPA may use
- * that information to tune its algorithms.
- *
- * The \a ipaConfig and \a result parameters carry custom data passed by the
- * pipeline handler to the IPA and back. The pipeline handler may set the \a
- * result parameter to null if the IPA protocol doesn't need to pass a result
- * back through the configure() function.
- */
-
-/**
- * \fn IPAInterface::mapBuffers()
- * \brief Map buffers shared between the pipeline handler and the IPA
- * \param[in] buffers List of buffers to map
- *
- * This method informs the IPA module of memory buffers set up by the pipeline
- * handler that the IPA needs to access. It provides dmabuf file handles for
- * each buffer, and associates the buffers with unique numerical IDs.
- *
- * IPAs shall map the dmabuf file handles to their address space and keep a
- * cache of the mappings, indexed by the buffer numerical IDs. The IDs are used
- * in all other IPA interface methods to refer to buffers, including the
- * unmapBuffers() method.
- *
- * All buffers that the pipeline handler wishes to share with an IPA shall be
- * mapped with this method. Buffers may be mapped all at once with a single
- * call, or mapped and unmapped dynamically at runtime, depending on the IPA
- * protocol. Regardless of the protocol, all buffers mapped at a given time
- * shall have unique numerical IDs.
- *
- * The numerical IDs have no meaning defined by the IPA interface, and IPA
- * protocols shall not give them any specific meaning either. They should be
- * treated as opaque handles by IPAs, with the only exception that ID zero is
- * invalid.
- *
- * \sa unmapBuffers()
- *
- * \todo Provide a generic implementation of mapBuffers and unmapBuffers for
- * IPAs
- */
-
-/**
- * \fn IPAInterface::unmapBuffers()
- * \brief Unmap buffers shared by the pipeline to the IPA
- * \param[in] ids List of buffer IDs to unmap
- *
- * This method removes mappings set up with mapBuffers(). Buffers may be
- * unmapped all at once with a single call, or selectively at runtime, depending
- * on the IPA protocol. Numerical IDs of unmapped buffers may be reused when
- * mapping new buffers.
- *
- * \sa mapBuffers()
- */
-
-/**
- * \fn IPAInterface::processEvent()
- * \brief Process an event from the pipeline handler
- * \param[in] data IPA operation data
- *
- * This operation is used by pipeline handlers to inform the IPA module of
- * events that occurred during the on-going capture operation.
- *
- * The event notified by the pipeline handler with this method is handled by the
- * IPA, which interprets the operation parameters according to the separately
- * documented IPA protocol.
- */
-
-/**
- * \var IPAInterface::queueFrameAction
- * \brief Queue an action associated with a frame to the pipeline handler
- * \param[in] frame The frame number for the action
- * \param[in] data IPA operation data
- *
- * This signal is emitted when the IPA wishes to queue a FrameAction on the
- * pipeline. The pipeline is still responsible for the scheduling of the action
- * on its timeline.
- *
- * This signal is emitted by the IPA to queue an action to be executed by the
- * pipeline handler on a frame. The type of action is identified by the
- * \a data.operation field, as defined by the IPA protocol, and the rest of the
- * \a data is interpreted accordingly. The pipeline handler shall queue the
- * action and execute it as appropriate.
*
- * The signal is only emitted when the IPA is running, that is after start() and
- * before stop() have been called.
+ * \todo Figure out how to generate IPAInterface documentation.
*/
} /* namespace libcamera */
diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp
index ad05b9c9..93d02d94 100644
--- a/src/libcamera/ipa_manager.cpp
+++ b/src/libcamera/ipa_manager.cpp
@@ -245,6 +245,7 @@ unsigned int IPAManager::addDir(const char *libDir, unsigned int maxDepth)
}
/**
+ * \fn IPAManager::createIPA()
* \brief Create an IPA proxy that matches a given pipeline handler
* \param[in] pipe The pipeline handler that wants a matching IPA proxy
* \param[in] minVersion Minimum acceptable version of IPA module
@@ -253,52 +254,6 @@ unsigned int IPAManager::addDir(const char *libDir, unsigned int maxDepth)
* \return A newly created IPA proxy, or nullptr if no matching IPA module is
* found or if the IPA proxy fails to initialize
*/
-std::unique_ptr<IPAProxy> IPAManager::createIPA(PipelineHandler *pipe,
- uint32_t maxVersion,
- uint32_t minVersion)
-{
- IPAModule *m = nullptr;
-
- for (IPAModule *module : self_->modules_) {
- if (module->match(pipe, minVersion, maxVersion)) {
- m = module;
- break;
- }
- }
-
- if (!m)
- return nullptr;
-
- /*
- * Load and run the IPA module in a thread if it has a valid signature,
- * or isolate it in a separate process otherwise.
- *
- * \todo Implement a better proxy selection
- */
- const char *proxyName = self_->isSignatureValid(m)
- ? "IPAProxyThread" : "IPAProxyLinux";
- IPAProxyFactory *pf = nullptr;
-
- for (IPAProxyFactory *factory : IPAProxyFactory::factories()) {
- if (!strcmp(factory->name().c_str(), proxyName)) {
- pf = factory;
- break;
- }
- }
-
- if (!pf) {
- LOG(IPAManager, Error) << "Failed to get proxy factory";
- return nullptr;
- }
-
- std::unique_ptr<IPAProxy> proxy = pf->create(m);
- if (!proxy->isValid()) {
- LOG(IPAManager, Error) << "Failed to load proxy";
- return nullptr;
- }
-
- return proxy;
-}
bool IPAManager::isSignatureValid([[maybe_unused]] IPAModule *ipa) const
{
diff --git a/src/libcamera/ipa_module.cpp b/src/libcamera/ipa_module.cpp
index de512a7f..f53e529b 100644
--- a/src/libcamera/ipa_module.cpp
+++ b/src/libcamera/ipa_module.cpp
@@ -391,13 +391,13 @@ const std::string &IPAModule::path() const
/**
* \brief Load the IPA implementation factory from the shared object
*
- * The IPA module shared object implements an ipa_context object to be used
+ * The IPA module shared object implements an IPAInterface object to be used
* by pipeline handlers. This method loads the factory function from the
- * shared object. Later, createContext() can be called to instantiate the
- * ipa_context.
+ * shared object. Later, createInterface() can be called to instantiate the
+ * IPAInterface.
*
* This method only needs to be called successfully once, after which
- * createContext() can be called as many times as ipa_context instances are
+ * createInterface() can be called as many times as IPAInterface instances are
* needed.
*
* Calling this function on an invalid module (as returned by isValid()) is
@@ -439,20 +439,18 @@ bool IPAModule::load()
}
/**
- * \brief Instantiate an IPA context
+ * \brief Instantiate an IPA interface
*
* After loading the IPA module with load(), this method creates an instance of
- * the IPA module context. Ownership of the context is passed to the caller, and
- * the context shall be destroyed by calling the \ref ipa_context_ops::destroy
- * "ipa_context::ops::destroy()" function.
+ * the IPA module interface.
*
* Calling this function on a module that has not yet been loaded, or an
* invalid module (as returned by load() and isValid(), respectively) is
* an error.
*
- * \return The IPA context on success, or nullptr on error
+ * \return The IPA interface on success, or nullptr on error
*/
-struct ipa_context *IPAModule::createContext()
+IPAInterface *IPAModule::createInterface()
{
if (!valid_ || !loaded_)
return nullptr;
diff --git a/src/libcamera/ipa_proxy.cpp b/src/libcamera/ipa_proxy.cpp
index ff4d7fd1..29c0e9e0 100644
--- a/src/libcamera/ipa_proxy.cpp
+++ b/src/libcamera/ipa_proxy.cpp
@@ -30,17 +30,11 @@ LOG_DEFINE_CATEGORY(IPAProxy)
* \brief IPA Proxy
*
* Isolate IPA into separate process.
- *
- * Every subclass of proxy shall be registered with libcamera using
- * the REGISTER_IPA_PROXY() macro.
*/
/**
* \brief Construct an IPAProxy instance
* \param[in] ipam The IPA module
- *
- * IPAProxy instances shall be constructed through the IPAProxyFactory::create()
- * method implemented by the respective factories.
*/
IPAProxy::IPAProxy(IPAModule *ipam)
: valid_(false), ipam_(ipam)
@@ -146,16 +140,6 @@ std::string IPAProxy::configurationFile(const std::string &name) const
}
/**
- * \fn IPAProxy::stop()
- * \brief Stop the IPA proxy
- *
- * This function stops the IPA and releases all the resources acquired by the
- * proxy in start(). Calling stop() when the IPA proxy hasn't been started or
- * has already been stopped is valid, the proxy shall treat this as a no-op and
- * shall not forward the call to the IPA.
- */
-
-/**
* \brief Find a valid full path for a proxy worker for a given executable name
* \param[in] file File name of proxy worker executable
*
@@ -229,89 +213,4 @@ std::string IPAProxy::resolvePath(const std::string &file) const
* construction.
*/
-/**
- * \class IPAProxyFactory
- * \brief Registration of IPAProxy classes and creation of instances
- *
- * To facilitate discovery and instantiation of IPAProxy classes, the
- * IPAProxyFactory class maintains a registry of IPAProxy classes. Each
- * IPAProxy subclass shall register itself using the REGISTER_IPA_PROXY()
- * macro, which will create a corresponding instance of a IPAProxyFactory
- * subclass and register it with the static list of factories.
- */
-
-/**
- * \brief Construct a IPAProxy factory
- * \param[in] name Name of the IPAProxy class
- *
- * Creating an instance of the factory registers is with the global list of
- * factories, accessible through the factories() function.
- *
- * The factory \a name is used for debugging and IPAProxy matching purposes
- * and shall be unique.
- */
-IPAProxyFactory::IPAProxyFactory(const char *name)
- : name_(name)
-{
- registerType(this);
-}
-
-/**
- * \fn IPAProxyFactory::create()
- * \brief Create an instance of the IPAProxy corresponding to the factory
- * \param[in] ipam The IPA module
- *
- * This virtual function is implemented by the REGISTER_IPA_PROXY() macro.
- * It creates a IPAProxy instance that isolates an IPA interface designated
- * by the IPA module \a ipam.
- *
- * \return A pointer to a newly constructed instance of the IPAProxy subclass
- * corresponding to the factory
- */
-
-/**
- * \fn IPAProxyFactory::name()
- * \brief Retrieve the factory name
- * \return The factory name
- */
-
-/**
- * \brief Add a IPAProxy class to the registry
- * \param[in] factory Factory to use to construct the IPAProxy
- *
- * The caller is responsible to guarantee the uniqueness of the IPAProxy name.
- */
-void IPAProxyFactory::registerType(IPAProxyFactory *factory)
-{
- std::vector<IPAProxyFactory *> &factories = IPAProxyFactory::factories();
-
- factories.push_back(factory);
-
- LOG(IPAProxy, Debug)
- << "Registered proxy \"" << factory->name() << "\"";
-}
-
-/**
- * \brief Retrieve the list of all IPAProxy factories
- *
- * The static factories map is defined inside the function to ensure it gets
- * initialized on first use, without any dependency on link order.
- *
- * \return The list of pipeline handler factories
- */
-std::vector<IPAProxyFactory *> &IPAProxyFactory::factories()
-{
- static std::vector<IPAProxyFactory *> factories;
- return factories;
-}
-
-/**
- * \def REGISTER_IPA_PROXY
- * \brief Register a IPAProxy with the IPAProxy factory
- * \param[in] proxy Class name of IPAProxy derived class to register
- *
- * Register a proxy subclass with the factory and make it available to
- * isolate IPA modules.
- */
-
} /* namespace libcamera */
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 6b5d126b..4b5e33ce 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -24,7 +24,6 @@ libcamera_sources = files([
'formats.cpp',
'framebuffer_allocator.cpp',
'geometry.cpp',
- 'ipa_context_wrapper.cpp',
'ipa_controls.cpp',
'ipa_data_serializer.cpp',
'ipa_interface.cpp',
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 61f7bf43..3e6b88af 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -14,7 +14,8 @@
#include <libcamera/camera.h>
#include <libcamera/control_ids.h>
#include <libcamera/formats.h>
-#include <libcamera/ipa/ipu3.h>
+#include <libcamera/ipa/ipu3_ipa_interface.h>
+#include <libcamera/ipa/ipu3_ipa_proxy.h>
#include <libcamera/request.h>
#include <libcamera/stream.h>
@@ -77,8 +78,11 @@ public:
std::unique_ptr<DelayedControls> delayedCtrls_;
IPU3Frames frameInfos_;
+ std::unique_ptr<ipa::ipu3::IPAProxyIPU3> ipa_;
+
private:
- void queueFrameAction(unsigned int id, const IPAOperationData &op);
+ void queueFrameAction(unsigned int id,
+ const ipa::ipu3::IPU3Action &action);
};
class IPU3CameraConfiguration : public CameraConfiguration
@@ -609,18 +613,12 @@ int PipelineHandlerIPU3::allocateBuffers(Camera *camera)
for (const std::unique_ptr<FrameBuffer> &buffer : imgu->paramBuffers_) {
buffer->setCookie(ipaBufferId++);
- ipaBuffers_.push_back({
- .id = buffer->cookie(),
- .planes = buffer->planes()
- });
+ ipaBuffers_.emplace_back(buffer->cookie(), buffer->planes());
}
for (const std::unique_ptr<FrameBuffer> &buffer : imgu->statBuffers_) {
buffer->setCookie(ipaBufferId++);
- ipaBuffers_.push_back({
- .id = buffer->cookie(),
- .planes = buffer->planes()
- });
+ ipaBuffers_.emplace_back(buffer->cookie(), buffer->planes());
}
data->ipa_->mapBuffers(ipaBuffers_);
@@ -650,16 +648,10 @@ int PipelineHandlerIPU3::freeBuffers(Camera *camera)
int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] ControlList *controls)
{
+ std::map<uint32_t, ControlInfoMap> entityControls;
IPU3CameraData *data = cameraData(camera);
CIO2Device *cio2 = &data->cio2_;
ImgUDevice *imgu = data->imgu_;
-
- CameraSensorInfo sensorInfo = {};
- std::map<unsigned int, IPAStream> streamConfig;
- std::map<unsigned int, const ControlInfoMap &> entityControls;
- IPAOperationData ipaConfig;
- IPAOperationData result = {};
-
int ret;
/* Allocate buffers for internal pipeline usage. */
@@ -667,8 +659,7 @@ int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] ControlList *con
if (ret)
return ret;
- IPAOperationData ipaData = {};
- ret = data->ipa_->start(ipaData, nullptr);
+ ret = data->ipa_->start();
if (ret)
goto error;
@@ -684,24 +675,8 @@ int PipelineHandlerIPU3::start(Camera *camera, [[maybe_unused]] ControlList *con
if (ret)
goto error;
- /* Inform IPA of stream configuration and sensor controls. */
- ret = data->cio2_.sensor()->sensorInfo(&sensorInfo);
- if (ret)
- goto error;
-
- streamConfig[0] = {
- .pixelFormat = data->outStream_.configuration().pixelFormat,
- .size = data->outStream_.configuration().size,
- };
- streamConfig[1] = {
- .pixelFormat = data->vfStream_.configuration().pixelFormat,
- .size = data->vfStream_.configuration().size,
- };
-
entityControls.emplace(0, data->cio2_.sensor()->controls());
-
- data->ipa_->configure(sensorInfo, streamConfig, entityControls,
- ipaConfig, &result);
+ data->ipa_->configure(entityControls);
return 0;
@@ -751,11 +726,11 @@ int PipelineHandlerIPU3::queueRequestDevice(Camera *camera, Request *request)
info->rawBuffer = rawBuffer;
- IPAOperationData op;
- op.operation = IPU3_IPA_EVENT_PROCESS_CONTROLS;
- op.data = { info->id };
- op.controls = { request->controls() };
- data->ipa_->processEvent(op);
+ ipa::ipu3::IPU3Event ev;
+ ev.op = ipa::ipu3::EventProcessControls;
+ ev.frame = info->id;
+ ev.controls = request->controls();
+ data->ipa_->processEvent(ev);
return 0;
}
@@ -1048,7 +1023,7 @@ int PipelineHandlerIPU3::registerCameras()
int IPU3CameraData::loadIPA()
{
- ipa_ = IPAManager::createIPA(pipe_, 1, 1);
+ ipa_ = IPAManager::createIPA<ipa::ipu3::IPAProxyIPU3>(pipe_, 1, 1);
if (!ipa_)
return -ENOENT;
@@ -1060,15 +1035,15 @@ int IPU3CameraData::loadIPA()
}
void IPU3CameraData::queueFrameAction(unsigned int id,
- const IPAOperationData &action)
+ const ipa::ipu3::IPU3Action &action)
{
- switch (action.operation) {
- case IPU3_IPA_ACTION_SET_SENSOR_CONTROLS: {
- const ControlList &controls = action.controls[0];
+ switch (action.op) {
+ case ipa::ipu3::ActionSetSensorControls: {
+ const ControlList &controls = action.controls;
delayedCtrls_->push(controls);
break;
}
- case IPU3_IPA_ACTION_PARAM_FILLED: {
+ case ipa::ipu3::ActionParamFilled: {
IPU3Frames::Info *info = frameInfos_.find(id);
if (!info)
break;
@@ -1090,13 +1065,13 @@ void IPU3CameraData::queueFrameAction(unsigned int id,
break;
}
- case IPU3_IPA_ACTION_METADATA_READY: {
+ case ipa::ipu3::ActionMetadataReady: {
IPU3Frames::Info *info = frameInfos_.find(id);
if (!info)
break;
Request *request = info->request;
- request->metadata() = action.controls[0];
+ request->metadata() = action.controls;
info->metadataProcessed = true;
if (frameInfos_.tryComplete(info))
pipe_->completeRequest(request);
@@ -1104,7 +1079,7 @@ void IPU3CameraData::queueFrameAction(unsigned int id,
break;
}
default:
- LOG(IPU3, Error) << "Unknown action " << action.operation;
+ LOG(IPU3, Error) << "Unknown action " << action.op;
break;
}
}
@@ -1172,10 +1147,11 @@ void IPU3CameraData::cio2BufferReady(FrameBuffer *buffer)
if (request->findBuffer(&rawStream_))
pipe_->completeBuffer(request, buffer);
- IPAOperationData op;
- op.operation = IPU3_IPA_EVENT_FILL_PARAMS;
- op.data = { info->id, info->paramBuffer->cookie() };
- ipa_->processEvent(op);
+ ipa::ipu3::IPU3Event ev;
+ ev.op = ipa::ipu3::EventFillParams;
+ ev.frame = info->id;
+ ev.bufferId = info->paramBuffer->cookie();
+ ipa_->processEvent(ev);
}
void IPU3CameraData::paramBufferReady(FrameBuffer *buffer)
@@ -1202,10 +1178,11 @@ void IPU3CameraData::statBufferReady(FrameBuffer *buffer)
return;
}
- IPAOperationData op;
- op.operation = IPU3_IPA_EVENT_STAT_READY;
- op.data = { info->id, info->statBuffer->cookie() };
- ipa_->processEvent(op);
+ ipa::ipu3::IPU3Event ev;
+ ev.op = ipa::ipu3::EventStatReady;
+ ev.frame = info->id;
+ ev.bufferId = info->statBuffer->cookie();
+ ipa_->processEvent(ev);
}
REGISTER_PIPELINE_HANDLER(PipelineHandlerIPU3)
diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index e4764681..15aa600e 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -18,10 +18,13 @@
#include <libcamera/file_descriptor.h>
#include <libcamera/formats.h>
#include <libcamera/ipa/raspberrypi.h>
+#include <libcamera/ipa/raspberrypi_ipa_interface.h>
+#include <libcamera/ipa/raspberrypi_ipa_proxy.h>
#include <libcamera/logging.h>
#include <libcamera/property_ids.h>
#include <libcamera/request.h>
+#include <linux/bcm2835-isp.h>
#include <linux/videodev2.h>
#include "libcamera/internal/bayer_format.h"
@@ -146,7 +149,11 @@ public:
int loadIPA();
int configureIPA(const CameraConfiguration *config);
- void queueFrameAction(unsigned int frame, const IPAOperationData &action);
+ void statsMetadataComplete(uint32_t bufferId, const ControlList &controls);
+ void runIsp(uint32_t bufferId);
+ void embeddedComplete(uint32_t bufferId);
+ void setIsp(const ControlList &controls);
+ void setDelayedControls(const ControlList &controls);
/* bufferComplete signal handlers. */
void unicamBufferDequeue(FrameBuffer *buffer);
@@ -159,6 +166,8 @@ public:
void handleState();
void applyScalerCrop(const ControlList &controls);
+ std::unique_ptr<ipa::rpi::IPAProxyRPi> ipa_;
+
std::unique_ptr<CameraSensor> sensor_;
/* Array of Unicam and ISP device streams and associated buffers/streams. */
RPi::Device<Unicam, 2> unicam_;
@@ -751,7 +760,7 @@ int PipelineHandlerRPi::exportFrameBuffers([[maybe_unused]] Camera *camera, Stre
return ret;
}
-int PipelineHandlerRPi::start(Camera *camera, [[maybe_unused]] ControlList *controls)
+int PipelineHandlerRPi::start(Camera *camera, ControlList *controls)
{
RPiCameraData *data = cameraData(camera);
int ret;
@@ -769,30 +778,20 @@ int PipelineHandlerRPi::start(Camera *camera, [[maybe_unused]] ControlList *cont
data->applyScalerCrop(*controls);
/* Start the IPA. */
- IPAOperationData ipaData = {};
- IPAOperationData result = {};
- if (controls) {
- ipaData.operation = RPi::IPA_CONFIG_STARTUP_CTRLS;
- ipaData.controls.emplace_back(*controls);
- }
- ret = data->ipa_->start(ipaData, &result);
- if (ret) {
- LOG(RPI, Error)
- << "Failed to start IPA for " << camera->id();
- stop(camera);
- return ret;
- }
+ ipa::rpi::StartControls ipaData;
+ ipa::rpi::StartControls result;
+ if (controls)
+ ipaData.controls = *controls;
+ data->ipa_->start(ipaData, &result);
/* Apply any gain/exposure settings that the IPA may have passed back. */
- if (result.operation & RPi::IPA_RESULT_SENSOR_CTRLS) {
- ControlList &ctrls = result.controls[0];
+ if (!result.controls.empty()) {
+ ControlList &ctrls = result.controls;
data->unicam_[Unicam::Image].dev()->setControls(&ctrls);
}
- if (result.operation & RPi::IPA_RESULT_DROP_FRAMES) {
- /* Configure the number of dropped frames required on startup. */
- data->dropFrameCount_ = result.data[0];
- }
+ /* Configure the number of dropped frames required on startup. */
+ data->dropFrameCount_ = result.dropFrameCount;
/* We need to set the dropFrameCount_ before queueing buffers. */
ret = queueAllBuffers(camera);
@@ -1115,8 +1114,8 @@ int PipelineHandlerRPi::prepareBuffers(Camera *camera)
* Pass the stats and embedded data buffers to the IPA. No other
* buffers need to be passed.
*/
- mapBuffers(camera, data->isp_[Isp::Stats].getBuffers(), RPi::BufferMask::STATS);
- mapBuffers(camera, data->unicam_[Unicam::Embedded].getBuffers(), RPi::BufferMask::EMBEDDED_DATA);
+ mapBuffers(camera, data->isp_[Isp::Stats].getBuffers(), ipa::rpi::MaskStats);
+ mapBuffers(camera, data->unicam_[Unicam::Embedded].getBuffers(), ipa::rpi::MaskEmbeddedData);
return 0;
}
@@ -1133,8 +1132,8 @@ void PipelineHandlerRPi::mapBuffers(Camera *camera, const RPi::BufferMap &buffer
* handler and the IPA.
*/
for (auto const &it : buffers) {
- ipaBuffers.push_back({ .id = mask | it.first,
- .planes = it.second->planes() });
+ ipaBuffers.push_back(IPABuffer(mask | it.first,
+ it.second->planes()));
data->ipaBuffers_.insert(mask | it.first);
}
@@ -1165,15 +1164,18 @@ void RPiCameraData::frameStarted(uint32_t sequence)
int RPiCameraData::loadIPA()
{
- ipa_ = IPAManager::createIPA(pipe_, 1, 1);
+ ipa_ = IPAManager::createIPA<ipa::rpi::IPAProxyRPi>(pipe_, 1, 1);
+
if (!ipa_)
return -ENOENT;
- ipa_->queueFrameAction.connect(this, &RPiCameraData::queueFrameAction);
+ ipa_->statsMetadataComplete.connect(this, &RPiCameraData::statsMetadataComplete);
+ ipa_->runIsp.connect(this, &RPiCameraData::runIsp);
+ ipa_->embeddedComplete.connect(this, &RPiCameraData::embeddedComplete);
+ ipa_->setIsp.connect(this, &RPiCameraData::setIsp);
+ ipa_->setDelayedControls.connect(this, &RPiCameraData::setDelayedControls);
- IPASettings settings{
- .configurationFile = ipa_->configurationFile(sensor_->model() + ".json")
- };
+ IPASettings settings(ipa_->configurationFile(sensor_->model() + ".json"));
return ipa_->init(settings);
}
@@ -1185,8 +1187,8 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)
static_cast<const RPiCameraConfiguration *>(config);
std::map<unsigned int, IPAStream> streamConfig;
- std::map<unsigned int, const ControlInfoMap &> entityControls;
- IPAOperationData ipaConfig = {};
+ std::map<unsigned int, ControlInfoMap> entityControls;
+ ipa::rpi::ConfigInput ipaConfig;
/* Get the device format to pass to the IPA. */
V4L2DeviceFormat sensorFormat;
@@ -1195,10 +1197,9 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)
unsigned int i = 0;
for (auto const &stream : isp_) {
if (stream.isExternal()) {
- streamConfig[i++] = {
- .pixelFormat = stream.configuration().pixelFormat,
- .size = stream.configuration().size
- };
+ streamConfig[i++] = IPAStream(
+ stream.configuration().pixelFormat,
+ stream.configuration().size);
}
}
@@ -1206,17 +1207,20 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)
entityControls.emplace(1, isp_[Isp::Input].dev()->controls());
/* Always send the user transform to the IPA. */
- ipaConfig.data = { static_cast<unsigned int>(config->transform) };
+ ipaConfig.transform = static_cast<unsigned int>(config->transform);
/* Allocate the lens shading table via dmaHeap and pass to the IPA. */
if (!lsTable_.isValid()) {
- lsTable_ = dmaHeap_.alloc("ls_grid", RPi::MaxLsGridSize);
+ lsTable_ = dmaHeap_.alloc("ls_grid", ipa::rpi::MaxLsGridSize);
if (!lsTable_.isValid())
return -ENOMEM;
/* Allow the IPA to mmap the LS table via the file descriptor. */
- ipaConfig.operation = RPi::IPA_CONFIG_LS_TABLE;
- ipaConfig.data.push_back(static_cast<unsigned int>(lsTable_.fd()));
+ /*
+ * \todo Investigate if mapping the lens shading table buffer
+ * could be handled with mapBuffers().
+ */
+ ipaConfig.lsTableHandle = lsTable_;
}
/* We store the CameraSensorInfo for digital zoom calculations. */
@@ -1227,35 +1231,34 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)
}
/* Ready the IPA - it must know about the sensor resolution. */
- IPAOperationData result = {};
+ ipa::rpi::ConfigOutput result;
ipa_->configure(sensorInfo_, streamConfig, entityControls, ipaConfig,
- &result);
+ &result, &ret);
- if (result.operation & RPi::IPA_RESULT_CONFIG_FAILED) {
+ if (ret < 0) {
LOG(RPI, Error) << "IPA configuration failed!";
return -EPIPE;
}
- unsigned int resultIdx = 0;
- if (result.operation & RPi::IPA_RESULT_SENSOR_PARAMS) {
+ if (result.params & ipa::rpi::ConfigStaggeredWrite) {
/*
* Setup our delayed control writer with the sensor default
* gain and exposure delays.
*/
std::unordered_map<uint32_t, unsigned int> delays = {
- { V4L2_CID_ANALOGUE_GAIN, result.data[resultIdx++] },
- { V4L2_CID_EXPOSURE, result.data[resultIdx++] },
- { V4L2_CID_VBLANK, result.data[resultIdx++] }
+ { V4L2_CID_ANALOGUE_GAIN, result.sensorConfig.gainDelay },
+ { V4L2_CID_EXPOSURE, result.sensorConfig.exposureDelay },
+ { V4L2_CID_VBLANK, result.sensorConfig.vblank }
};
delayedCtrls_ = std::make_unique<DelayedControls>(unicam_[Unicam::Image].dev(), delays);
- sensorMetadata_ = result.data[resultIdx++];
+ sensorMetadata_ = result.sensorConfig.sensorMetadata;
}
- if (result.operation & RPi::IPA_RESULT_SENSOR_CTRLS) {
- ControlList &ctrls = result.controls[0];
+ if (!result.controls.empty()) {
+ ControlList &ctrls = result.controls;
unicam_[Unicam::Image].dev()->setControls(&ctrls);
}
@@ -1275,90 +1278,86 @@ int RPiCameraData::configureIPA(const CameraConfiguration *config)
return 0;
}
-void RPiCameraData::queueFrameAction([[maybe_unused]] unsigned int frame,
- const IPAOperationData &action)
+void RPiCameraData::statsMetadataComplete(uint32_t bufferId, const ControlList &controls)
{
+ if (state_ == State::Stopped)
+ handleState();
+
+ FrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(bufferId);
+
+ handleStreamBuffer(buffer, &isp_[Isp::Stats]);
+
+ /* Fill the Request metadata buffer with what the IPA has provided */
+ Request *request = requestQueue_.front();
+ request->metadata() = std::move(controls);
+
/*
- * The following actions can be handled when the pipeline handler is in
- * a stopped state.
+ * Also update the ScalerCrop in the metadata with what we actually
+ * used. But we must first rescale that from ISP (camera mode) pixels
+ * back into sensor native pixels.
+ *
+ * Sending this information on every frame may be helpful.
*/
- switch (action.operation) {
- case RPi::IPA_ACTION_SET_DELAYED_CTRLS: {
- const ControlList &controls = action.controls[0];
- if (!delayedCtrls_->push(controls))
- LOG(RPI, Error) << "Failed to set delayed controls";
- goto done;
+ if (updateScalerCrop_) {
+ updateScalerCrop_ = false;
+ scalerCrop_ = ispCrop_.scaledBy(sensorInfo_.analogCrop.size(),
+ sensorInfo_.outputSize);
+ scalerCrop_.translateBy(sensorInfo_.analogCrop.topLeft());
}
+ request->metadata().set(controls::ScalerCrop, scalerCrop_);
- case RPi::IPA_ACTION_V4L2_SET_ISP: {
- ControlList controls = action.controls[0];
- isp_[Isp::Input].dev()->setControls(&controls);
- goto done;
- }
- }
+ state_ = State::IpaComplete;
- if (state_ == State::Stopped)
- goto done;
+ handleState();
+}
- /*
- * The following actions must not be handled when the pipeline handler
- * is in a stopped state.
- */
- switch (action.operation) {
- case RPi::IPA_ACTION_STATS_METADATA_COMPLETE: {
- unsigned int bufferId = action.data[0];
- FrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(bufferId);
+void RPiCameraData::runIsp(uint32_t bufferId)
+{
+ if (state_ == State::Stopped)
+ handleState();
- handleStreamBuffer(buffer, &isp_[Isp::Stats]);
+ FrameBuffer *buffer = unicam_[Unicam::Image].getBuffers().at(bufferId);
- /* Fill the Request metadata buffer with what the IPA has provided */
- Request *request = requestQueue_.front();
- request->metadata() = std::move(action.controls[0]);
+ LOG(RPI, Debug) << "Input re-queue to ISP, buffer id " << bufferId
+ << ", timestamp: " << buffer->metadata().timestamp;
- /*
- * Also update the ScalerCrop in the metadata with what we actually
- * used. But we must first rescale that from ISP (camera mode) pixels
- * back into sensor native pixels.
- *
- * Sending this information on every frame may be helpful.
- */
- if (updateScalerCrop_) {
- updateScalerCrop_ = false;
- scalerCrop_ = ispCrop_.scaledBy(sensorInfo_.analogCrop.size(),
- sensorInfo_.outputSize);
- scalerCrop_.translateBy(sensorInfo_.analogCrop.topLeft());
- }
- request->metadata().set(controls::ScalerCrop, scalerCrop_);
+ isp_[Isp::Input].queueBuffer(buffer);
+ ispOutputCount_ = 0;
+ handleState();
+}
- state_ = State::IpaComplete;
- break;
- }
+void RPiCameraData::embeddedComplete(uint32_t bufferId)
+{
+ if (state_ == State::Stopped)
+ handleState();
- case RPi::IPA_ACTION_EMBEDDED_COMPLETE: {
- unsigned int bufferId = action.data[0];
- FrameBuffer *buffer = unicam_[Unicam::Embedded].getBuffers().at(bufferId);
- handleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);
- break;
- }
+ FrameBuffer *buffer = unicam_[Unicam::Embedded].getBuffers().at(bufferId);
+ handleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);
+ handleState();
+}
- case RPi::IPA_ACTION_RUN_ISP: {
- unsigned int bufferId = action.data[0];
- FrameBuffer *buffer = unicam_[Unicam::Image].getBuffers().at(bufferId);
+void RPiCameraData::setIsp(const ControlList &controls)
+{
+ ControlList ctrls = controls;
- LOG(RPI, Debug) << "Input re-queue to ISP, buffer id " << bufferId
- << ", timestamp: " << buffer->metadata().timestamp;
+ Span<const uint8_t> s =
+ ctrls.get(V4L2_CID_USER_BCM2835_ISP_LENS_SHADING).data();
+ bcm2835_isp_lens_shading ls =
+ *reinterpret_cast<const bcm2835_isp_lens_shading *>(s.data());
+ ls.dmabuf = lsTable_.fd();
- isp_[Isp::Input].queueBuffer(buffer);
- ispOutputCount_ = 0;
- break;
- }
+ ControlValue c(Span<const uint8_t>{ reinterpret_cast<uint8_t *>(&ls),
+ sizeof(ls) });
+ ctrls.set(V4L2_CID_USER_BCM2835_ISP_LENS_SHADING, c);
- default:
- LOG(RPI, Error) << "Unknown action " << action.operation;
- break;
- }
+ isp_[Isp::Input].dev()->setControls(&ctrls);
+ handleState();
+}
-done:
+void RPiCameraData::setDelayedControls(const ControlList &controls)
+{
+ if (!delayedCtrls_->push(controls))
+ LOG(RPI, Error) << "V4L2 staggered set failed";
handleState();
}
@@ -1456,10 +1455,7 @@ void RPiCameraData::ispOutputDequeue(FrameBuffer *buffer)
* application until after the IPA signals so.
*/
if (stream == &isp_[Isp::Stats]) {
- IPAOperationData op;
- op.operation = RPi::IPA_EVENT_SIGNAL_STAT_READY;
- op.data = { RPi::BufferMask::STATS | static_cast<unsigned int>(index) };
- ipa_->processEvent(op);
+ ipa_->signalStatReady(ipa::rpi::MaskStats | static_cast<unsigned int>(index));
} else {
/* Any other ISP output can be handed back to the application now. */
handleStreamBuffer(buffer, stream);
@@ -1563,7 +1559,7 @@ void RPiCameraData::handleExternalBuffer(FrameBuffer *buffer, RPi::Stream *strea
{
unsigned int id = stream->getBufferId(buffer);
- if (!(id & RPi::BufferMask::EXTERNAL_BUFFER))
+ if (!(id & ipa::rpi::MaskExternalBuffer))
return;
/* Stop the Stream object from tracking the buffer. */
@@ -1663,7 +1659,6 @@ void RPiCameraData::applyScalerCrop(const ControlList &controls)
void RPiCameraData::tryRunPipeline()
{
FrameBuffer *bayerBuffer, *embeddedBuffer;
- IPAOperationData op;
/* If any of our request or buffer queues are empty, we cannot proceed. */
if (state_ != State::Idle || requestQueue_.empty() ||
@@ -1684,9 +1679,7 @@ void RPiCameraData::tryRunPipeline()
* queue the ISP output buffer listed in the request to start the HW
* pipeline.
*/
- op.operation = RPi::IPA_EVENT_QUEUE_REQUEST;
- op.controls = { request->controls() };
- ipa_->processEvent(op);
+ ipa_->signalQueueRequest(request->controls());
/* Set our state to say the pipeline is active. */
state_ = State::Busy;
@@ -1694,14 +1687,14 @@ void RPiCameraData::tryRunPipeline()
unsigned int bayerId = unicam_[Unicam::Image].getBufferId(bayerBuffer);
unsigned int embeddedId = unicam_[Unicam::Embedded].getBufferId(embeddedBuffer);
- LOG(RPI, Debug) << "Signalling RPi::IPA_EVENT_SIGNAL_ISP_PREPARE:"
+ LOG(RPI, Debug) << "Signalling signalIspPrepare:"
<< " Bayer buffer id: " << bayerId
<< " Embedded buffer id: " << embeddedId;
- op.operation = RPi::IPA_EVENT_SIGNAL_ISP_PREPARE;
- op.data = { RPi::BufferMask::EMBEDDED_DATA | embeddedId,
- RPi::BufferMask::BAYER_DATA | bayerId };
- ipa_->processEvent(op);
+ ipa::rpi::ISPConfig ispPrepare;
+ ispPrepare.embeddedbufferId = ipa::rpi::MaskEmbeddedData | embeddedId;
+ ispPrepare.bayerbufferId = ipa::rpi::MaskBayerData | bayerId;
+ ipa_->signalIspPrepare(ispPrepare);
}
bool RPiCameraData::findMatchingBuffers(FrameBuffer *&bayerBuffer, FrameBuffer *&embeddedBuffer)
diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
index 3a5dadab..496dd36f 100644
--- a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
+++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
@@ -6,6 +6,8 @@
*/
#include "rpi_stream.h"
+#include <libcamera/ipa/raspberrypi_ipa_interface.h>
+
#include "libcamera/internal/log.h"
namespace libcamera {
@@ -70,7 +72,7 @@ int Stream::getBufferId(FrameBuffer *buffer) const
void Stream::setExternalBuffer(FrameBuffer *buffer)
{
- bufferMap_.emplace(RPi::BufferMask::EXTERNAL_BUFFER | id_.get(), buffer);
+ bufferMap_.emplace(ipa::rpi::MaskExternalBuffer | id_.get(), buffer);
}
void Stream::removeExternalBuffer(FrameBuffer *buffer)
@@ -78,7 +80,7 @@ void Stream::removeExternalBuffer(FrameBuffer *buffer)
int id = getBufferId(buffer);
/* Ensure we have this buffer in the stream, and it is marked external. */
- ASSERT(id != -1 && (id & RPi::BufferMask::EXTERNAL_BUFFER));
+ ASSERT(id != -1 && (id & ipa::rpi::MaskExternalBuffer));
bufferMap_.erase(id);
}
diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
index 0b502f64..701110d0 100644
--- a/src/libcamera/pipeline/raspberrypi/rpi_stream.h
+++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
@@ -13,6 +13,7 @@
#include <vector>
#include <libcamera/ipa/raspberrypi.h>
+#include <libcamera/ipa/raspberrypi_ipa_interface.h>
#include <libcamera/stream.h>
#include "libcamera/internal/v4l2_videodevice.h"
@@ -31,13 +32,13 @@ class Stream : public libcamera::Stream
{
public:
Stream()
- : id_(RPi::BufferMask::ID)
+ : id_(ipa::rpi::MaskID)
{
}
Stream(const char *name, MediaEntity *dev, bool importOnly = false)
: external_(false), importOnly_(importOnly), name_(name),
- dev_(std::make_unique<V4L2VideoDevice>(dev)), id_(RPi::BufferMask::ID)
+ dev_(std::make_unique<V4L2VideoDevice>(dev)), id_(ipa::rpi::MaskID)
{
}
diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
index 7cb89eb0..a794501a 100644
--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp
+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp
@@ -18,7 +18,9 @@
#include <libcamera/camera.h>
#include <libcamera/control_ids.h>
#include <libcamera/formats.h>
-#include <libcamera/ipa/rkisp1.h>
+#include <libcamera/ipa/core_ipa_interface.h>
+#include <libcamera/ipa/rkisp1_ipa_interface.h>
+#include <libcamera/ipa/rkisp1_ipa_proxy.h>
#include <libcamera/request.h>
#include <libcamera/stream.h>
@@ -96,9 +98,11 @@ public:
RkISP1MainPath *mainPath_;
RkISP1SelfPath *selfPath_;
+ std::unique_ptr<ipa::rkisp1::IPAProxyRkISP1> ipa_;
+
private:
void queueFrameAction(unsigned int frame,
- const IPAOperationData &action);
+ const ipa::rkisp1::RkISP1Action &action);
void metadataReady(unsigned int frame, const ControlList &metadata);
};
@@ -298,7 +302,7 @@ RkISP1FrameInfo *RkISP1Frames::find(Request *request)
int RkISP1CameraData::loadIPA()
{
- ipa_ = IPAManager::createIPA(pipe_, 1, 1);
+ ipa_ = IPAManager::createIPA<ipa::rkisp1::IPAProxyRkISP1>(pipe_, 1, 1);
if (!ipa_)
return -ENOENT;
@@ -311,15 +315,15 @@ int RkISP1CameraData::loadIPA()
}
void RkISP1CameraData::queueFrameAction(unsigned int frame,
- const IPAOperationData &action)
+ const ipa::rkisp1::RkISP1Action &action)
{
- switch (action.operation) {
- case RKISP1_IPA_ACTION_V4L2_SET: {
- const ControlList &controls = action.controls[0];
+ switch (action.op) {
+ case ipa::rkisp1::ActionV4L2Set: {
+ const ControlList &controls = action.controls;
delayedCtrls_->push(controls);
break;
}
- case RKISP1_IPA_ACTION_PARAM_FILLED: {
+ case ipa::rkisp1::ActionParamFilled: {
PipelineHandlerRkISP1 *pipe = static_cast<PipelineHandlerRkISP1 *>(pipe_);
RkISP1FrameInfo *info = frameInfo_.find(frame);
if (!info)
@@ -336,11 +340,11 @@ void RkISP1CameraData::queueFrameAction(unsigned int frame,
break;
}
- case RKISP1_IPA_ACTION_METADATA:
- metadataReady(frame, action.controls[0]);
+ case ipa::rkisp1::ActionMetadata:
+ metadataReady(frame, action.controls);
break;
default:
- LOG(RkISP1, Error) << "Unknown action " << action.operation;
+ LOG(RkISP1, Error) << "Unknown action " << action.op;
break;
}
}
@@ -612,16 +616,12 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)
for (const StreamConfiguration &cfg : *config) {
if (cfg.stream() == &data->mainPathStream_) {
ret = mainPath_.configure(cfg, format);
- streamConfig[0] = {
- .pixelFormat = cfg.pixelFormat,
- .size = cfg.size,
- };
+ streamConfig[0] = IPAStream(cfg.pixelFormat,
+ cfg.size);
} else {
ret = selfPath_.configure(cfg, format);
- streamConfig[1] = {
- .pixelFormat = cfg.pixelFormat,
- .size = cfg.size,
- };
+ streamConfig[1] = IPAStream(cfg.pixelFormat,
+ cfg.size);
}
if (ret)
@@ -650,12 +650,10 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c)
ret = 0;
}
- std::map<unsigned int, const ControlInfoMap &> entityControls;
+ std::map<uint32_t, ControlInfoMap> entityControls;
entityControls.emplace(0, data->sensor_->controls());
- IPAOperationData ipaConfig;
- data->ipa_->configure(sensorInfo, streamConfig, entityControls,
- ipaConfig, nullptr);
+ data->ipa_->configure(sensorInfo, streamConfig, entityControls);
return 0;
}
@@ -695,15 +693,15 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera)
for (std::unique_ptr<FrameBuffer> &buffer : paramBuffers_) {
buffer->setCookie(ipaBufferId++);
- data->ipaBuffers_.push_back({ .id = buffer->cookie(),
- .planes = buffer->planes() });
+ data->ipaBuffers_.emplace_back(buffer->cookie(),
+ buffer->planes());
availableParamBuffers_.push(buffer.get());
}
for (std::unique_ptr<FrameBuffer> &buffer : statBuffers_) {
buffer->setCookie(ipaBufferId++);
- data->ipaBuffers_.push_back({ .id = buffer->cookie(),
- .planes = buffer->planes() });
+ data->ipaBuffers_.emplace_back(buffer->cookie(),
+ buffer->planes());
availableStatBuffers_.push(buffer.get());
}
@@ -757,8 +755,7 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] ControlList *c
if (ret)
return ret;
- IPAOperationData ipaData = {};
- ret = data->ipa_->start(ipaData, nullptr);
+ ret = data->ipa_->start();
if (ret) {
freeBuffers(camera);
LOG(RkISP1, Error)
@@ -853,11 +850,12 @@ int PipelineHandlerRkISP1::queueRequestDevice(Camera *camera, Request *request)
if (!info)
return -ENOENT;
- IPAOperationData op;
- op.operation = RKISP1_IPA_EVENT_QUEUE_REQUEST;
- op.data = { data->frame_, info->paramBuffer->cookie() };
- op.controls = { request->controls() };
- data->ipa_->processEvent(op);
+ ipa::rkisp1::RkISP1Event ev;
+ ev.op = ipa::rkisp1::EventQueueRequest;
+ ev.frame = data->frame_;
+ ev.bufferId = info->paramBuffer->cookie();
+ ev.controls = request->controls();
+ data->ipa_->processEvent(ev);
data->frame_++;
@@ -1088,10 +1086,11 @@ void PipelineHandlerRkISP1::statReady(FrameBuffer *buffer)
if (data->frame_ <= buffer->metadata().sequence)
data->frame_ = buffer->metadata().sequence + 1;
- IPAOperationData op;
- op.operation = RKISP1_IPA_EVENT_SIGNAL_STAT_BUFFER;
- op.data = { info->frame, info->statBuffer->cookie() };
- data->ipa_->processEvent(op);
+ ipa::rkisp1::RkISP1Event ev;
+ ev.op = ipa::rkisp1::EventSignalStatBuffer;
+ ev.frame = info->frame;
+ ev.bufferId = info->statBuffer->cookie();
+ data->ipa_->processEvent(ev);
}
REGISTER_PIPELINE_HANDLER(PipelineHandlerRkISP1)
diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp
index 36325ffb..78b47916 100644
--- a/src/libcamera/pipeline/vimc/vimc.cpp
+++ b/src/libcamera/pipeline/vimc/vimc.cpp
@@ -34,6 +34,9 @@
#include "libcamera/internal/v4l2_subdevice.h"
#include "libcamera/internal/v4l2_videodevice.h"
+#include <libcamera/ipa/vimc_ipa_interface.h>
+#include <libcamera/ipa/vimc_ipa_proxy.h>
+
namespace libcamera {
LOG_DEFINE_CATEGORY(VIMC)
@@ -56,6 +59,8 @@ public:
std::unique_ptr<V4L2VideoDevice> video_;
std::unique_ptr<V4L2VideoDevice> raw_;
Stream stream_;
+
+ std::unique_ptr<ipa::vimc::IPAProxyVimc> ipa_;
};
class VimcCameraConfiguration : public CameraConfiguration
@@ -311,8 +316,7 @@ int PipelineHandlerVimc::start(Camera *camera, [[maybe_unused]] ControlList *con
if (ret < 0)
return ret;
- IPAOperationData ipaData = {};
- ret = data->ipa_->start(ipaData, nullptr);
+ ret = data->ipa_->start();
if (ret) {
data->video_->releaseBuffers();
return ret;
@@ -418,7 +422,7 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator)
std::unique_ptr<VimcCameraData> data = std::make_unique<VimcCameraData>(this, media);
- data->ipa_ = IPAManager::createIPA(this, 0, 0);
+ data->ipa_ = IPAManager::createIPA<ipa::vimc::IPAProxyVimc>(this, 0, 0);
if (data->ipa_ != nullptr) {
std::string conf = data->ipa_->configurationFile("vimc.conf");
data->ipa_->init(IPASettings{ conf });
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index c2604d45..84d2555f 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -97,14 +97,6 @@ LOG_DEFINE_CATEGORY(Pipeline)
*/
/**
- * \var CameraData::ipa_
- * \brief The IPA module used by the camera
- *
- * Reference to the Image Processing Algorithms (IPA) operating on the camera's
- * stream(s). If no IPA exists for the camera, this field is set to nullptr.
- */
-
-/**
* \class PipelineHandler
* \brief Create and manage cameras based on a set of media devices
*
diff --git a/src/libcamera/proxy/ipa_proxy_linux.cpp b/src/libcamera/proxy/ipa_proxy_linux.cpp
deleted file mode 100644
index ea6f3e5e..00000000
--- a/src/libcamera/proxy/ipa_proxy_linux.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * ipa_proxy_linux.cpp - Default Image Processing Algorithm proxy for Linux
- */
-
-#include <vector>
-
-#include <libcamera/ipa/ipa_interface.h>
-#include <libcamera/ipa/ipa_module_info.h>
-
-#include "libcamera/internal/ipa_module.h"
-#include "libcamera/internal/ipa_proxy.h"
-#include "libcamera/internal/ipc_unixsocket.h"
-#include "libcamera/internal/log.h"
-#include "libcamera/internal/process.h"
-
-namespace libcamera {
-
-LOG_DECLARE_CATEGORY(IPAProxy)
-
-class IPAProxyLinux : public IPAProxy
-{
-public:
- IPAProxyLinux(IPAModule *ipam);
- ~IPAProxyLinux();
-
- int init([[maybe_unused]] const IPASettings &settings) override
- {
- return 0;
- }
- int start([[maybe_unused]] const IPAOperationData &data,
- [[maybe_unused]] IPAOperationData *result) override { return 0; }
- void stop() override {}
- void configure([[maybe_unused]] const CameraSensorInfo &sensorInfo,
- [[maybe_unused]] const std::map<unsigned int, IPAStream> &streamConfig,
- [[maybe_unused]] const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- [[maybe_unused]] const IPAOperationData &ipaConfig,
- [[maybe_unused]] IPAOperationData *result) override {}
- void mapBuffers([[maybe_unused]] const std::vector<IPABuffer> &buffers) override {}
- void unmapBuffers([[maybe_unused]] const std::vector<unsigned int> &ids) override {}
- void processEvent([[maybe_unused]] const IPAOperationData &event) override {}
-
-private:
- void readyRead(IPCUnixSocket *ipc);
-
- Process *proc_;
-
- IPCUnixSocket *socket_;
-};
-
-IPAProxyLinux::IPAProxyLinux(IPAModule *ipam)
- : IPAProxy(ipam), proc_(nullptr), socket_(nullptr)
-{
- LOG(IPAProxy, Debug)
- << "initializing dummy proxy: loading IPA from "
- << ipam->path();
-
- std::vector<int> fds;
- std::vector<std::string> args;
- args.push_back(ipam->path());
- const std::string path = resolvePath("ipa_proxy_linux");
- if (path.empty()) {
- LOG(IPAProxy, Error)
- << "Failed to get proxy worker path";
- return;
- }
-
- socket_ = new IPCUnixSocket();
- int fd = socket_->create();
- if (fd < 0) {
- LOG(IPAProxy, Error)
- << "Failed to create socket";
- return;
- }
- socket_->readyRead.connect(this, &IPAProxyLinux::readyRead);
- args.push_back(std::to_string(fd));
- fds.push_back(fd);
-
- proc_ = new Process();
- int ret = proc_->start(path, args, fds);
- if (ret) {
- LOG(IPAProxy, Error)
- << "Failed to start proxy worker process";
- return;
- }
-
- valid_ = true;
-}
-
-IPAProxyLinux::~IPAProxyLinux()
-{
- delete proc_;
- delete socket_;
-}
-
-void IPAProxyLinux::readyRead([[maybe_unused]] IPCUnixSocket *ipc)
-{
-}
-
-REGISTER_IPA_PROXY(IPAProxyLinux)
-
-} /* namespace libcamera */
diff --git a/src/libcamera/proxy/ipa_proxy_thread.cpp b/src/libcamera/proxy/ipa_proxy_thread.cpp
deleted file mode 100644
index a5fda2c8..00000000
--- a/src/libcamera/proxy/ipa_proxy_thread.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2020, Google Inc.
- *
- * ipa_proxy_thread.cpp - Proxy running an Image Processing Algorithm in a thread
- */
-
-#include <memory>
-
-#include <libcamera/ipa/ipa_interface.h>
-#include <libcamera/ipa/ipa_module_info.h>
-
-#include "libcamera/internal/ipa_context_wrapper.h"
-#include "libcamera/internal/ipa_module.h"
-#include "libcamera/internal/ipa_proxy.h"
-#include "libcamera/internal/log.h"
-#include "libcamera/internal/thread.h"
-
-namespace libcamera {
-
-LOG_DECLARE_CATEGORY(IPAProxy)
-
-class IPAProxyThread : public IPAProxy, public Object
-{
-public:
- IPAProxyThread(IPAModule *ipam);
-
- int init(const IPASettings &settings) override;
- int start(const IPAOperationData &data,
- IPAOperationData *result) override;
- void stop() override;
-
- void configure(const CameraSensorInfo &sensorInfo,
- const std::map<unsigned int, IPAStream> &streamConfig,
- const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- const IPAOperationData &ipaConfig,
- IPAOperationData *result) override;
- void mapBuffers(const std::vector<IPABuffer> &buffers) override;
- void unmapBuffers(const std::vector<unsigned int> &ids) override;
- void processEvent(const IPAOperationData &event) override;
-
-private:
- void queueFrameAction(unsigned int frame, const IPAOperationData &data);
-
- /* Helper class to invoke processEvent() in another thread. */
- class ThreadProxy : public Object
- {
- public:
- void setIPA(IPAInterface *ipa)
- {
- ipa_ = ipa;
- }
-
- int start(const IPAOperationData &data, IPAOperationData *result)
- {
- return ipa_->start(data, result);
- }
-
- void stop()
- {
- ipa_->stop();
- }
-
- void processEvent(const IPAOperationData &event)
- {
- ipa_->processEvent(event);
- }
-
- private:
- IPAInterface *ipa_;
- };
-
- bool running_;
- Thread thread_;
- ThreadProxy proxy_;
- std::unique_ptr<IPAInterface> ipa_;
-};
-
-IPAProxyThread::IPAProxyThread(IPAModule *ipam)
- : IPAProxy(ipam), running_(false)
-{
- if (!ipam->load())
- return;
-
- struct ipa_context *ctx = ipam->createContext();
- if (!ctx) {
- LOG(IPAProxy, Error)
- << "Failed to create IPA context for " << ipam->path();
- return;
- }
-
- ipa_ = std::make_unique<IPAContextWrapper>(ctx);
- proxy_.setIPA(ipa_.get());
-
- /*
- * Proxy the queueFrameAction signal to dispatch it in the caller's
- * thread.
- */
- ipa_->queueFrameAction.connect(this, &IPAProxyThread::queueFrameAction);
-
- valid_ = true;
-}
-
-int IPAProxyThread::init(const IPASettings &settings)
-{
- int ret = ipa_->init(settings);
- if (ret)
- return ret;
-
- proxy_.moveToThread(&thread_);
-
- return 0;
-}
-
-int IPAProxyThread::start(const IPAOperationData &data,
- IPAOperationData *result)
-{
- running_ = true;
- thread_.start();
-
- return proxy_.invokeMethod(&ThreadProxy::start, ConnectionTypeBlocking,
- data, result);
-}
-
-void IPAProxyThread::stop()
-{
- if (!running_)
- return;
-
- running_ = false;
-
- proxy_.invokeMethod(&ThreadProxy::stop, ConnectionTypeBlocking);
-
- thread_.exit();
- thread_.wait();
-}
-
-void IPAProxyThread::configure(const CameraSensorInfo &sensorInfo,
- const std::map<unsigned int, IPAStream> &streamConfig,
- const std::map<unsigned int, const ControlInfoMap &> &entityControls,
- const IPAOperationData &ipaConfig,
- IPAOperationData *result)
-{
- ipa_->configure(sensorInfo, streamConfig, entityControls, ipaConfig,
- result);
-}
-
-void IPAProxyThread::mapBuffers(const std::vector<IPABuffer> &buffers)
-{
- ipa_->mapBuffers(buffers);
-}
-
-void IPAProxyThread::unmapBuffers(const std::vector<unsigned int> &ids)
-{
- ipa_->unmapBuffers(ids);
-}
-
-void IPAProxyThread::processEvent(const IPAOperationData &event)
-{
- if (!running_)
- return;
-
- /* Dispatch the processEvent() call to the thread. */
- proxy_.invokeMethod(&ThreadProxy::processEvent, ConnectionTypeQueued,
- event);
-}
-
-void IPAProxyThread::queueFrameAction(unsigned int frame, const IPAOperationData &data)
-{
- IPAInterface::queueFrameAction.emit(frame, data);
-}
-
-REGISTER_IPA_PROXY(IPAProxyThread)
-
-} /* namespace libcamera */
diff --git a/src/libcamera/proxy/meson.build b/src/libcamera/proxy/meson.build
index 5c4365e7..00ae5a8f 100644
--- a/src/libcamera/proxy/meson.build
+++ b/src/libcamera/proxy/meson.build
@@ -1,10 +1,5 @@
# SPDX-License-Identifier: CC0-1.0
-libcamera_sources += files([
- 'ipa_proxy_linux.cpp',
- 'ipa_proxy_thread.cpp',
-])
-
# generate {pipeline}_ipa_proxy.cpp
foreach mojom : ipa_mojoms
proxy = custom_target(mojom['name'] + '_proxy_cpp',
diff --git a/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp b/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp
deleted file mode 100644
index bdbac988..00000000
--- a/src/libcamera/proxy/worker/ipa_proxy_linux_worker.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * ipa_proxy_linux_worker.cpp - Default Image Processing Algorithm proxy worker for Linux
- */
-
-#include <iostream>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <libcamera/ipa/ipa_interface.h>
-#include <libcamera/logging.h>
-
-#include "libcamera/internal/event_dispatcher.h"
-#include "libcamera/internal/ipa_module.h"
-#include "libcamera/internal/ipc_unixsocket.h"
-#include "libcamera/internal/log.h"
-#include "libcamera/internal/thread.h"
-
-using namespace libcamera;
-
-LOG_DEFINE_CATEGORY(IPAProxyLinuxWorker)
-
-void readyRead(IPCUnixSocket *ipc)
-{
- IPCUnixSocket::Payload message;
- int ret;
-
- ret = ipc->receive(&message);
- if (ret) {
- LOG(IPAProxyLinuxWorker, Error)
- << "Receive message failed: " << ret;
- return;
- }
-
- LOG(IPAProxyLinuxWorker, Debug) << "Received a message!";
-}
-
-int main(int argc, char **argv)
-{
- /* Uncomment this for debugging. */
-#if 0
- std::string logPath = "/tmp/libcamera.worker." +
- std::to_string(getpid()) + ".log";
- logSetFile(logPath.c_str());
-#endif
-
- if (argc < 3) {
- LOG(IPAProxyLinuxWorker, Debug)
- << "Tried to start worker with no args";
- return EXIT_FAILURE;
- }
-
- int fd = std::stoi(argv[2]);
- LOG(IPAProxyLinuxWorker, Debug)
- << "Starting worker for IPA module " << argv[1]
- << " with IPC fd = " << fd;
-
- std::unique_ptr<IPAModule> ipam = std::make_unique<IPAModule>(argv[1]);
- if (!ipam->isValid() || !ipam->load()) {
- LOG(IPAProxyLinuxWorker, Error)
- << "IPAModule " << argv[1] << " should be valid but isn't";
- return EXIT_FAILURE;
- }
-
- IPCUnixSocket socket;
- if (socket.bind(fd) < 0) {
- LOG(IPAProxyLinuxWorker, Error) << "IPC socket binding failed";
- return EXIT_FAILURE;
- }
- socket.readyRead.connect(&readyRead);
-
- struct ipa_context *ipac = ipam->createContext();
- if (!ipac) {
- LOG(IPAProxyLinuxWorker, Error) << "Failed to create IPA context";
- return EXIT_FAILURE;
- }
-
- LOG(IPAProxyLinuxWorker, Debug) << "Proxy worker successfully started";
-
- /* \todo upgrade listening loop */
- EventDispatcher *dispatcher = Thread::current()->eventDispatcher();
- while (1)
- dispatcher->processEvents();
-
- ipac->ops->destroy(ipac);
-
- return 0;
-}
diff --git a/src/libcamera/proxy/worker/meson.build b/src/libcamera/proxy/worker/meson.build
index 0fd26fd8..3796103e 100644
--- a/src/libcamera/proxy/worker/meson.build
+++ b/src/libcamera/proxy/worker/meson.build
@@ -1,9 +1,5 @@
# SPDX-License-Identifier: CC0-1.0
-ipa_proxy_sources = [
- ['ipa_proxy_linux', 'ipa_proxy_linux_worker.cpp']
-]
-
proxy_install_dir = join_paths(get_option('libexecdir'), 'libcamera')
# generate {pipeline}_ipa_proxy_worker.cpp