summaryrefslogtreecommitdiff
path: root/src/libcamera/proxy/ipa_proxy_thread.cpp
blob: 1ebb9b6a6c9d76b70dc8fa1bba764195650a3af3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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)
	: 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()
{
	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 */