cam: Use libevent to implement event loop

To prepare for removal of the EventDispatcher from the libcamera public
API, switch to libevent to handle the event loop.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
Laurent Pinchart 2020-10-25 14:40:50 +02:00
parent a27057fc50
commit 7d35c771c0
5 changed files with 55 additions and 26 deletions

View file

@ -78,6 +78,9 @@ for documentation: [optional]
for gstreamer: [optional] for gstreamer: [optional]
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
for cam: [optional]
libevent-dev
for qcam: [optional] for qcam: [optional]
qtbase5-dev libqt5core5a libqt5gui5 libqt5widgets5 qttools5-dev-tools libtiff-dev qtbase5-dev libqt5core5a libqt5gui5 libqt5widgets5 qttools5-dev-tools libtiff-dev

View file

@ -5,19 +5,34 @@
* event_loop.cpp - cam - Event loop * event_loop.cpp - cam - Event loop
*/ */
#include <libcamera/event_dispatcher.h>
#include "event_loop.h" #include "event_loop.h"
using namespace libcamera; #include <assert.h>
#include <event2/event.h>
#include <event2/thread.h>
EventLoop::EventLoop(EventDispatcher *dispatcher) EventLoop *EventLoop::instance_ = nullptr;
: dispatcher_(dispatcher)
EventLoop::EventLoop()
{ {
assert(!instance_);
evthread_use_pthreads();
event_ = event_base_new();
instance_ = this;
} }
EventLoop::~EventLoop() EventLoop::~EventLoop()
{ {
instance_ = nullptr;
event_base_free(event_);
libevent_global_shutdown();
}
EventLoop *EventLoop::instance()
{
return instance_;
} }
int EventLoop::exec() int EventLoop::exec()
@ -26,7 +41,7 @@ int EventLoop::exec()
exit_.store(false, std::memory_order_release); exit_.store(false, std::memory_order_release);
while (!exit_.load(std::memory_order_acquire)) while (!exit_.load(std::memory_order_acquire))
dispatcher_->processEvents(); event_base_loop(event_, EVLOOP_NO_EXIT_ON_EMPTY);
return exitCode_; return exitCode_;
} }
@ -35,5 +50,10 @@ void EventLoop::exit(int code)
{ {
exitCode_ = code; exitCode_ = code;
exit_.store(true, std::memory_order_release); exit_.store(true, std::memory_order_release);
dispatcher_->interrupt(); interrupt();
}
void EventLoop::interrupt()
{
event_base_loopbreak(event_);
} }

View file

@ -9,26 +9,27 @@
#include <atomic> #include <atomic>
#include <libcamera/event_notifier.h> struct event_base;
namespace libcamera {
class EventDispatcher;
}
class EventLoop class EventLoop
{ {
public: public:
EventLoop(libcamera::EventDispatcher *dispatcher); EventLoop();
~EventLoop(); ~EventLoop();
static EventLoop *instance();
int exec(); int exec();
void exit(int code = 0); void exit(int code = 0);
private: private:
libcamera::EventDispatcher *dispatcher_; static EventLoop *instance_;
struct event_base *event_;
std::atomic<bool> exit_; std::atomic<bool> exit_;
int exitCode_; int exitCode_;
void interrupt();
}; };
#endif /* __CAM_EVENT_LOOP_H__ */ #endif /* __CAM_EVENT_LOOP_H__ */

View file

@ -52,7 +52,7 @@ private:
CameraManager *cm_; CameraManager *cm_;
std::shared_ptr<Camera> camera_; std::shared_ptr<Camera> camera_;
std::unique_ptr<libcamera::CameraConfiguration> config_; std::unique_ptr<libcamera::CameraConfiguration> config_;
EventLoop *loop_; EventLoop loop_;
bool strictFormats_; bool strictFormats_;
}; };
@ -60,7 +60,7 @@ private:
CamApp *CamApp::app_ = nullptr; CamApp *CamApp::app_ = nullptr;
CamApp::CamApp() CamApp::CamApp()
: cm_(nullptr), camera_(nullptr), config_(nullptr), loop_(nullptr), : cm_(nullptr), camera_(nullptr), config_(nullptr),
strictFormats_(false) strictFormats_(false)
{ {
CamApp::app_ = this; CamApp::app_ = this;
@ -134,16 +134,11 @@ int CamApp::init(int argc, char **argv)
std::cout << "Monitoring new hotplug and unplug events" << std::endl; std::cout << "Monitoring new hotplug and unplug events" << std::endl;
} }
loop_ = new EventLoop(cm_->eventDispatcher());
return 0; return 0;
} }
void CamApp::cleanup() void CamApp::cleanup()
{ {
delete loop_;
loop_ = nullptr;
if (camera_) { if (camera_) {
camera_->release(); camera_->release();
camera_.reset(); camera_.reset();
@ -166,8 +161,7 @@ int CamApp::exec()
void CamApp::quit() void CamApp::quit()
{ {
if (loop_) loop_.exit();
loop_->exit();
} }
int CamApp::parseOptions(int argc, char *argv[]) int CamApp::parseOptions(int argc, char *argv[])
@ -366,13 +360,13 @@ int CamApp::run()
} }
if (options_.isSet(OptCapture)) { if (options_.isSet(OptCapture)) {
Capture capture(camera_, config_.get(), loop_); Capture capture(camera_, config_.get(), &loop_);
return capture.run(options_); return capture.run(options_);
} }
if (options_.isSet(OptMonitor)) { if (options_.isSet(OptMonitor)) {
std::cout << "Press Ctrl-C to interrupt" << std::endl; std::cout << "Press Ctrl-C to interrupt" << std::endl;
ret = loop_->exec(); ret = loop_.exec();
if (ret) if (ret)
std::cout << "Failed to run monitor loop" << std::endl; std::cout << "Failed to run monitor loop" << std::endl;
} }

View file

@ -1,5 +1,12 @@
# SPDX-License-Identifier: CC0-1.0 # SPDX-License-Identifier: CC0-1.0
libevent = dependency('libevent_pthreads', required : false)
if not libevent.found()
warning('libevent_pthreads not found, \'cam\' application will not be compiled')
subdir_done()
endif
cam_sources = files([ cam_sources = files([
'buffer_writer.cpp', 'buffer_writer.cpp',
'capture.cpp', 'capture.cpp',
@ -10,5 +17,9 @@ cam_sources = files([
]) ])
cam = executable('cam', cam_sources, cam = executable('cam', cam_sources,
dependencies : [ libatomic, libcamera_dep ], dependencies : [
libatomic,
libcamera_dep,
libevent,
],
install : true) install : true)