[libcamera-devel] [PATCH 1/2] android: camera_worker: Introduce CameraWorker

Jacopo Mondi jacopo at jmondi.org
Fri Oct 9 15:39:55 CEST 2020


The Android camera framework provides for each buffer part of a capture
request an acquisition fence the camera HAL is supposed to wait on
before using the buffer. As the libcamera HAL runs in the camera service
thread, it is not possible to perform a synchronous wait there.

Introduce a CameraWorker class that runs an internal thread to wait
on a set of fences before queueing a capture request to the
libcamera::Camera.

Fences completion is handled through a simple poll, similar in
implementation to the sync_wait() function provided by libdrm.

Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
---
 src/android/camera_worker.cpp | 88 +++++++++++++++++++++++++++++++++++
 src/android/camera_worker.h   | 73 +++++++++++++++++++++++++++++
 src/android/meson.build       |  1 +
 3 files changed, 162 insertions(+)
 create mode 100644 src/android/camera_worker.cpp
 create mode 100644 src/android/camera_worker.h

diff --git a/src/android/camera_worker.cpp b/src/android/camera_worker.cpp
new file mode 100644
index 000000000000..775473da9f6e
--- /dev/null
+++ b/src/android/camera_worker.cpp
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Google Inc.
+ *
+ * camera_worker.cpp - Process capture request on behalf of the Camera HAL
+ */
+
+#include "camera_worker.h"
+
+#include <errno.h>
+#include <sys/poll.h>
+
+#include "camera_device.h"
+
+using namespace libcamera;
+
+void CaptureRequest::addBuffer(Stream *stream, FrameBuffer *buffer, int fence)
+{
+	request_->addBuffer(stream, buffer);
+	acquireFences_.push_back(fence);
+}
+
+void CaptureRequest::queue(Camera *camera)
+{
+	camera->queueRequest(request_);
+}
+
+CameraWorker::CameraWorker(const std::shared_ptr<Camera> &camera)
+	: worker_(camera)
+{
+	worker_.moveToThread(&thread_);
+}
+
+void CameraWorker::start()
+{
+	thread_.start();
+}
+
+void CameraWorker::stop()
+{
+	thread_.exit();
+	thread_.wait();
+}
+
+void CameraWorker::queueRequest(std::unique_ptr<CaptureRequest> request)
+{
+	CaptureRequest *req = request.release();
+	worker_.invokeMethod(&Worker::processRequest, ConnectionTypeQueued, req);
+}
+
+int CameraWorker::Worker::waitFence(int fence)
+{
+	struct pollfd fds = { fence, POLLIN, 0 };
+	constexpr unsigned int timeoutMs = 300;
+	int ret;
+
+	do {
+		ret = poll(&fds, 1, timeoutMs);
+		if (ret == 0)
+			return -ETIME;
+
+		if (ret > 0) {
+			if (fds.revents & (POLLERR | POLLNVAL))
+				return -EINVAL;
+
+			return 0;
+		}
+	} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+	return ret;
+}
+
+void CameraWorker::Worker::processRequest(CaptureRequest *request)
+{
+	for (int fence : request->fences()) {
+		if (fence == -1)
+			continue;
+
+		int ret = waitFence(fence);
+		if (ret < 0)
+			return;
+
+		close(fence);
+	}
+
+	request->queue(camera_.get());
+	delete request;
+}
diff --git a/src/android/camera_worker.h b/src/android/camera_worker.h
new file mode 100644
index 000000000000..7e193513d6f4
--- /dev/null
+++ b/src/android/camera_worker.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Google Inc.
+ *
+ * camera_worker.h - Process capture request on behalf of the Camera HAL
+ */
+#ifndef __ANDROID_CAMERA_WORKER_H__
+#define __ANDROID_CAMERA_WORKER_H__
+
+#include <memory>
+
+#include <libcamera/buffer.h>
+#include <libcamera/camera.h>
+#include <libcamera/object.h>
+#include <libcamera/request.h>
+#include <libcamera/stream.h>
+
+#include "libcamera/internal/thread.h"
+
+class CameraDevice;
+
+struct CaptureRequest {
+	CaptureRequest(libcamera::Request *request)
+		: request_(request)
+	{
+	}
+
+	const std::vector<int> &fences() const { return acquireFences_; }
+
+	void addBuffer(libcamera::Stream *stream,
+		       libcamera::FrameBuffer *buffer, int fence);
+	void queue(libcamera::Camera *camera);
+
+private:
+	std::vector<int> acquireFences_;
+	libcamera::Request *request_;
+};
+
+class CameraWorker
+{
+public:
+	CameraWorker(const std::shared_ptr<libcamera::Camera> &camera);
+
+	void start();
+	void stop();
+
+	void queueRequest(std::unique_ptr<CaptureRequest> request);
+
+private:
+	class Worker : public libcamera::Object
+	{
+	public:
+		Worker(const std::shared_ptr<libcamera::Camera> &camera)
+			: camera_(camera)
+		{
+		}
+		~Worker()
+		{
+		}
+
+		void processRequest(CaptureRequest *request);
+
+	private:
+		int waitFence(int fence);
+
+		const std::shared_ptr<libcamera::Camera> camera_;
+	};
+
+	Worker worker_;
+	libcamera::Thread thread_;
+};
+
+#endif /* __ANDROID_CAMERA_WORKER_H__ */
diff --git a/src/android/meson.build b/src/android/meson.build
index 802bb89afe57..b2b2293cf62d 100644
--- a/src/android/meson.build
+++ b/src/android/meson.build
@@ -21,6 +21,7 @@ android_hal_sources = files([
     'camera_metadata.cpp',
     'camera_ops.cpp',
     'camera_stream.cpp',
+    'camera_worker.cpp',
     'jpeg/encoder_libjpeg.cpp',
     'jpeg/exif.cpp',
 ])
-- 
2.28.0



More information about the libcamera-devel mailing list