summaryrefslogtreecommitdiff
path: root/src/libcamera/ipa_context_wrapper.cpp
diff options
context:
space:
mode:
authorJacopo Mondi <jacopo@jmondi.org>2019-09-15 17:30:26 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2019-11-20 21:48:00 +0200
commit132d99bc8fac63d7473de6f62f7860b149f8e1c2 (patch)
treef6fbcb6ff234eaf3c44b71eed1c8215b736fc3c5 /src/libcamera/ipa_context_wrapper.cpp
parentbc9527de454670445a8d69b039e65c0e5c7a699e (diff)
ipa: Switch to the plain C API
Switch IPA communication to the plain C API. As the IPAInterface class is easier to use for pipeline handlers than a plain C API, retain it and add an IPAContextWrapper that translate between the C++ and the C APIs. On the IPA module side usage of IPAInterface may be desired for IPAs implemented in C++ that want to link to libcamera. For those IPAs, a new IPAInterfaceWrapper helper class is introduced to wrap the IPAInterface implemented internally by the IPA module into an ipa_context, ipa_context_ops and ipa_callback_ops. Signed-off-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Diffstat (limited to 'src/libcamera/ipa_context_wrapper.cpp')
-rw-r--r--src/libcamera/ipa_context_wrapper.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/libcamera/ipa_context_wrapper.cpp b/src/libcamera/ipa_context_wrapper.cpp
new file mode 100644
index 00000000..5b1f5972
--- /dev/null
+++ b/src/libcamera/ipa_context_wrapper.cpp
@@ -0,0 +1,221 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * ipa_context_wrapper.cpp - Image Processing Algorithm context wrapper
+ */
+
+#include "ipa_context_wrapper.h"
+
+#include <vector>
+
+#include <libcamera/controls.h>
+
+#include "byte_stream_buffer.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)
+{
+ if (!ctx_)
+ return;
+
+ ctx_->ops->register_callbacks(ctx_, &IPAContextWrapper::callbacks_,
+ this);
+}
+
+IPAContextWrapper::~IPAContextWrapper()
+{
+ if (!ctx_)
+ return;
+
+ ctx_->ops->destroy(ctx_);
+}
+
+int IPAContextWrapper::init()
+{
+ if (!ctx_)
+ return 0;
+
+ ctx_->ops->init(ctx_);
+
+ return 0;
+}
+
+void IPAContextWrapper::configure(const std::map<unsigned int, IPAStream> &streamConfig,
+ const std::map<unsigned int, const ControlInfoMap &> &entityControls)
+{
+ if (!ctx_)
+ return;
+
+ serializer_.reset();
+
+ /* 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;
+ }
+
+ ctx_->ops->configure(ctx_, c_streams, streamConfig.size(),
+ c_info_maps, entityControls.size());
+}
+
+void IPAContextWrapper::mapBuffers(const std::vector<IPABuffer> &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<Plane> &planes = buffer.memory.planes();
+
+ c_buffer.id = buffer.id;
+ c_buffer.num_planes = planes.size();
+
+ for (unsigned int j = 0; j < planes.size(); ++j) {
+ const Plane &plane = planes[j];
+ c_buffer.planes[j].dmabuf = plane.dmabuf();
+ 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 (!ctx_)
+ return;
+
+ ctx_->ops->unmap_buffers(ctx_, ids.data(), ids.size());
+}
+
+void IPAContextWrapper::processEvent(const IPAOperationData &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::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->queueFrameAction.emit(frame, opData);
+}
+
+#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_callback_ops IPAContextWrapper::callbacks_ = {
+ .queue_frame_action = &IPAContextWrapper::queue_frame_action,
+};
+#endif
+
+} /* namespace libcamera */