summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libcamera/ipa_interface.cpp3
-rw-r--r--src/libcamera/ipa_manager.cpp48
-rw-r--r--src/libcamera/proxy/ipa_proxy_thread.cpp162
-rw-r--r--src/libcamera/proxy/meson.build1
4 files changed, 187 insertions, 27 deletions
diff --git a/src/libcamera/ipa_interface.cpp b/src/libcamera/ipa_interface.cpp
index 0b785bdf..890d4340 100644
--- a/src/libcamera/ipa_interface.cpp
+++ b/src/libcamera/ipa_interface.cpp
@@ -528,6 +528,9 @@ namespace libcamera {
* \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.
*/
} /* namespace libcamera */
diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp
index bcaae356..6d23f470 100644
--- a/src/libcamera/ipa_manager.cpp
+++ b/src/libcamera/ipa_manager.cpp
@@ -12,7 +12,6 @@
#include <string.h>
#include <sys/types.h>
-#include "ipa_context_wrapper.h"
#include "ipa_module.h"
#include "ipa_proxy.h"
#include "log.h"
@@ -271,40 +270,35 @@ std::unique_ptr<IPAInterface> IPAManager::createIPA(PipelineHandler *pipe,
if (!m)
return nullptr;
- if (!m->isOpenSource()) {
- IPAProxyFactory *pf = nullptr;
- std::vector<IPAProxyFactory *> &factories = IPAProxyFactory::factories();
-
- for (IPAProxyFactory *factory : factories) {
- /* TODO: Better matching */
- if (!strcmp(factory->name().c_str(), "IPAProxyLinux")) {
- pf = factory;
- break;
- }
- }
-
- if (!pf) {
- LOG(IPAManager, Error) << "Failed to get proxy factory";
- return nullptr;
- }
+ /*
+ * Load and run the IPA module in a thread if it is open-source, or
+ * isolate it in a separate process otherwise.
+ *
+ * \todo Implement a better proxy selection
+ */
+ const char *proxyName = m->isOpenSource()
+ ? "IPAProxyThread" : "IPAProxyLinux";
+ IPAProxyFactory *pf = nullptr;
- std::unique_ptr<IPAProxy> proxy = pf->create(m);
- if (!proxy->isValid()) {
- LOG(IPAManager, Error) << "Failed to load proxy";
- return nullptr;
+ for (IPAProxyFactory *factory : IPAProxyFactory::factories()) {
+ if (!strcmp(factory->name().c_str(), proxyName)) {
+ pf = factory;
+ break;
}
-
- return proxy;
}
- if (!m->load())
+ if (!pf) {
+ LOG(IPAManager, Error) << "Failed to get proxy factory";
return nullptr;
+ }
- struct ipa_context *ctx = m->createContext();
- if (!ctx)
+ std::unique_ptr<IPAProxy> proxy = pf->create(m);
+ if (!proxy->isValid()) {
+ LOG(IPAManager, Error) << "Failed to load proxy";
return nullptr;
+ }
- return std::make_unique<IPAContextWrapper>(ctx);
+ return proxy;
}
} /* namespace libcamera */
diff --git a/src/libcamera/proxy/ipa_proxy_thread.cpp b/src/libcamera/proxy/ipa_proxy_thread.cpp
new file mode 100644
index 00000000..368ccca1
--- /dev/null
+++ b/src/libcamera/proxy/ipa_proxy_thread.cpp
@@ -0,0 +1,162 @@
+/* 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 <ipa/ipa_interface.h>
+#include <ipa/ipa_module_info.h>
+
+#include "ipa_context_wrapper.h"
+#include "ipa_module.h"
+#include "ipa_proxy.h"
+#include "log.h"
+#include "thread.h"
+
+namespace libcamera {
+
+LOG_DECLARE_CATEGORY(IPAProxy)
+
+class IPAProxyThread : public IPAProxy, public Object
+{
+public:
+ IPAProxyThread(IPAModule *ipam);
+
+ int init() override;
+ int start() override;
+ void stop() override;
+
+ void configure(const std::map<unsigned int, IPAStream> &streamConfig,
+ const std::map<unsigned int, const 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;
+
+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()
+ {
+ return ipa_->start();
+ }
+
+ 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)
+ : 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()
+{
+ int ret = ipa_->init();
+ if (ret)
+ return ret;
+
+ proxy_.moveToThread(&thread_);
+
+ return 0;
+}
+
+int IPAProxyThread::start()
+{
+ running_ = true;
+ thread_.start();
+
+ return proxy_.invokeMethod(&ThreadProxy::start, ConnectionTypeBlocking);
+}
+
+void IPAProxyThread::stop()
+{
+ running_ = false;
+
+ proxy_.invokeMethod(&ThreadProxy::stop, ConnectionTypeBlocking);
+
+ thread_.exit();
+ thread_.wait();
+}
+
+void IPAProxyThread::configure(const std::map<unsigned int, IPAStream> &streamConfig,
+ const std::map<unsigned int, const ControlInfoMap &> &entityControls)
+{
+ ipa_->configure(streamConfig, entityControls);
+}
+
+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 efc11323..6c00d5f3 100644
--- a/src/libcamera/proxy/meson.build
+++ b/src/libcamera/proxy/meson.build
@@ -1,3 +1,4 @@
libcamera_sources += files([
'ipa_proxy_linux.cpp',
+ 'ipa_proxy_thread.cpp',
])