summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--event_loop.cpp99
-rw-r--r--event_loop.h45
-rw-r--r--meson.build2
-rw-r--r--simple-cam.cpp35
4 files changed, 168 insertions, 13 deletions
diff --git a/event_loop.cpp b/event_loop.cpp
new file mode 100644
index 0000000..7b6ea65
--- /dev/null
+++ b/event_loop.cpp
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020, Google Inc.
+ *
+ * event_loop.cpp - Event loop based on cam
+ */
+
+#include "event_loop.h"
+
+#include <assert.h>
+#include <event2/event.h>
+#include <event2/thread.h>
+
+EventLoop *EventLoop::instance_ = nullptr;
+
+EventLoop::EventLoop()
+{
+ assert(!instance_);
+
+ evthread_use_pthreads();
+ event_ = event_base_new();
+ instance_ = this;
+}
+
+EventLoop::~EventLoop()
+{
+ instance_ = nullptr;
+
+ event_base_free(event_);
+ libevent_global_shutdown();
+}
+
+int EventLoop::exec()
+{
+ exitCode_ = -1;
+ exit_.store(false, std::memory_order_release);
+
+ while (!exit_.load(std::memory_order_acquire)) {
+ dispatchCalls();
+ event_base_loop(event_, EVLOOP_NO_EXIT_ON_EMPTY);
+ }
+
+ return exitCode_;
+}
+
+void EventLoop::exit(int code)
+{
+ exitCode_ = code;
+ exit_.store(true, std::memory_order_release);
+ interrupt();
+}
+
+void EventLoop::interrupt()
+{
+ event_base_loopbreak(event_);
+}
+
+
+void EventLoop::timeoutTriggered(int fd, short event, void *arg)
+{
+ EventLoop *self = static_cast<EventLoop *>(arg);
+ self->exit();
+}
+
+void EventLoop::timeout(unsigned int sec)
+{
+ struct event *ev;
+ struct timeval tv;
+
+ tv.tv_sec = sec;
+ tv.tv_usec = 0;
+ ev = evtimer_new(event_, &timeoutTriggered, this);
+ evtimer_add(ev, &tv);
+}
+
+void EventLoop::callLater(const std::function<void()> &func)
+{
+ {
+ std::unique_lock<std::mutex> locker(lock_);
+ calls_.push_back(func);
+ }
+
+ interrupt();
+}
+
+void EventLoop::dispatchCalls()
+{
+ std::unique_lock<std::mutex> locker(lock_);
+
+ for (auto iter = calls_.begin(); iter != calls_.end(); ) {
+ std::function<void()> call = std::move(*iter);
+
+ iter = calls_.erase(iter);
+
+ locker.unlock();
+ call();
+ locker.lock();
+ }
+}
diff --git a/event_loop.h b/event_loop.h
new file mode 100644
index 0000000..003c3d8
--- /dev/null
+++ b/event_loop.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020, Google Inc.
+ *
+ * event_loop.h - Event loop based on cam's
+ */
+#ifndef __SIMPLE_CAM_EVENT_LOOP_H__
+#define __SIMPLE_CAM_EVENT_LOOP_H__
+
+#include <atomic>
+#include <functional>
+#include <list>
+#include <mutex>
+
+struct event_base;
+
+class EventLoop
+{
+public:
+ EventLoop();
+ ~EventLoop();
+
+ void exit(int code = 0);
+ int exec();
+
+ void timeout(unsigned int sec);
+ void callLater(const std::function<void()> &func);
+
+private:
+ static EventLoop *instance_;
+
+ static void timeoutTriggered(int fd, short event, void *arg);
+
+ struct event_base *event_;
+ std::atomic<bool> exit_;
+ int exitCode_;
+
+ std::list<std::function<void()>> calls_;
+ std::mutex lock_;
+
+ void interrupt();
+ void dispatchCalls();
+};
+
+#endif /* __SIMPLE_CAM_EVENT_LOOP_H__ */
diff --git a/meson.build b/meson.build
index c312f2c..4d580c2 100644
--- a/meson.build
+++ b/meson.build
@@ -8,12 +8,14 @@ project('simple-cam', 'c', 'cpp',
# simple-cam.cpp is the fully commented application
src_files = files([
'simple-cam.cpp',
+ 'event_loop.cpp',
])
# Point your PKG_CONFIG_PATH environment variable to the
# libcamera install path camera.pc file ($prefix/lib/pkgconfig/camera.pc)
libcamera_deps = [
dependency('camera', required : true),
+ dependency('libevent_pthreads'),
]
cpp_arguments = [ '-Wno-unused-parameter', ]
diff --git a/simple-cam.cpp b/simple-cam.cpp
index bfe30d7..6d1d84f 100644
--- a/simple-cam.cpp
+++ b/simple-cam.cpp
@@ -11,8 +11,13 @@
#include <libcamera/libcamera.h>
+#include "event_loop.h"
+
+#define TIMEOUT_SEC 3
+
using namespace libcamera;
std::shared_ptr<Camera> camera;
+EventLoop loop;
/*
* --------------------------------------------------------------------
@@ -21,13 +26,26 @@ std::shared_ptr<Camera> camera;
* For each Camera::requestCompleted Signal emitted from the Camera the
* connected Slot is invoked.
*
+ * The Slot is invoked in the CameraManager's thread, hence one should avoid
+ * any heavy processing here. The processing of the request shall be re-directed
+ * to the application's thread instead, so as not to block the CameraManager's
+ * thread for large amount of time.
+ *
* The Slot receives the Request as a parameter.
*/
+
+static void processRequest(Request *request);
+
static void requestComplete(Request *request)
{
if (request->status() == Request::RequestCancelled)
return;
+ loop.callLater(std::bind(&processRequest, request));
+}
+
+static void processRequest(Request *request)
+{
const Request::BufferMap &buffers = request->buffers();
for (auto bufferPair : buffers) {
@@ -320,20 +338,11 @@ int main()
*
* In order to dispatch events received from the video devices, such
* as buffer completions, an event loop has to be run.
- *
- * Libcamera provides its own default event dispatcher realized by
- * polling a set of file descriptors, but applications can integrate
- * their own even loop with the Libcamera EventDispatcher.
- *
- * Here, as an example, run the poll-based EventDispatcher for 3
- * seconds.
*/
- EventDispatcher *dispatcher = cm->eventDispatcher();
- Timer timer;
- timer.start(3000);
- while (timer.isRunning())
- dispatcher->processEvents();
-
+ loop.timeout(TIMEOUT_SEC);
+ int ret = loop.exec();
+ std::cout << "Capture ran for " << TIMEOUT_SEC << " seconds and "
+ << "stopped with exit status: " << ret << std::endl;
/*
* --------------------------------------------------------------------
* Clean Up