/* 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 #include #include #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 &streamConfig, const std::map &entityControls) override; void mapBuffers(const std::vector &buffers) override; void unmapBuffers(const std::vector &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 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(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 &streamConfig, const std::map &entityControls) { ipa_->configure(streamConfig, entityControls); } void IPAProxyThread::mapBuffers(const std::vector &buffers) { ipa_->mapBuffers(buffers); } void IPAProxyThread::unmapBuffers(const std::vector &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 */