diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libcamera/ipa_interface.cpp | 3 | ||||
-rw-r--r-- | src/libcamera/ipa_manager.cpp | 48 | ||||
-rw-r--r-- | src/libcamera/proxy/ipa_proxy_thread.cpp | 162 | ||||
-rw-r--r-- | src/libcamera/proxy/meson.build | 1 |
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', ]) |