From patchwork Tue Dec 1 17:43:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 10534 X-Patchwork-Delegate: kieran.bingham@ideasonboard.com Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E0AEEBE177 for ; Tue, 1 Dec 2020 17:43:33 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AB16063501; Tue, 1 Dec 2020 18:43:33 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=uajain.com header.i=@uajain.com header.b="jlpPDv5f"; dkim-atps=neutral Received: from mail.uajain.com (static.126.159.217.95.clients.your-server.de [95.217.159.126]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D227163460 for ; Tue, 1 Dec 2020 18:43:31 +0100 (CET) From: Umang Jain DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=uajain.com; s=mail; t=1606844611; bh=pNoQ0U/VmFqQ14vuFDziSpJb3Gj2Au/s+/uuIPwLXPo=; h=From:To:Cc:Subject:In-Reply-To:References; b=jlpPDv5fN34w3KaHw5m3vlU+x9LVKBa/1vdn5soFln5VXmPLPL7RkYMTrIeKrXyUi mfSE8G6jzfg9czvxBHgM8TeDi556ca/OZ+6I1WboVPpwJfbkhjDFdyldHtGO3k8Pku 8ZvFca+HHRjZiyAZWC+ZriMqK9tOJnvJtUjlLqH2OttRXAPv5TsgaHuvHbSzsW4nwA ti2kARJVeNoLi/K6Ylgv3O6uif/7gVS9f7eNrjZiA5WzaTrbCjYINyJ/kONUr2wCKf 6osqhtlUsNfzhEtyE8VsqW+6rRFbajOe6bOvQbpN/ntpZQVpMmA1bWn94BFbFCgIae 9vSR2ilpbljBg== To: libcamera-devel@lists.libcamera.org Date: Tue, 1 Dec 2020 23:13:14 +0530 Message-Id: <20201201174314.12774-5-email@uajain.com> In-Reply-To: <20201201174314.12774-1-email@uajain.com> References: <20201201174314.12774-1-email@uajain.com> Mime-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 4/4] simple-cam: Provide event-loop backed by libevent X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" libcamera moved its EventDispatcher and Timer API to its internal API, since providing an event loop to applications should not be the job of libcamera. Application utility like cam, were ported to use libevent, hence inspired from that, un-break simple-cam by using the similar implementation to replace the EventDispatcher and Timer functionality by libevent. Signed-off-by: Umang Jain --- meson.build | 1 + simple-cam.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 91 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index c312f2c..0eca0a1 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,7 @@ src_files = files([ # libcamera install path camera.pc file ($prefix/lib/pkgconfig/camera.pc) libcamera_deps = [ dependency('camera', required : true), + dependency('libevent_pthreads', required : true), ] cpp_arguments = [ '-Wno-unused-parameter', ] diff --git a/simple-cam.cpp b/simple-cam.cpp index 0e26895..dd785fc 100644 --- a/simple-cam.cpp +++ b/simple-cam.cpp @@ -8,12 +8,58 @@ #include #include #include +#include + +#include +#include #include +#define TIMEOUT_SEC 3 + using namespace libcamera; std::shared_ptr camera; +/* + * -------------------------------------------------------------------- + * Helper functions to interact and control the event loop. + * \todo Split event loop handling to a separate class and file. + */ +bool capture = true; +std::mutex lock; +std::list> calls_; +struct event_base *event; + +void interrupt() +{ + event_base_loopbreak(event); +} + +void callLater(const std::function &func) +{ + { + std::unique_lock locker(lock); + calls_.push_back(func); + } + + interrupt(); +} + +void dispatchCalls() +{ + std::unique_lock locker(lock); + + for (auto iter = calls_.begin(); iter != calls_.end(); ) { + std::function call = std::move(*iter); + + iter = calls_.erase(iter); + + locker.unlock(); + call(); + locker.lock(); + } +} + /* * -------------------------------------------------------------------- * Handle RequestComplete @@ -21,13 +67,26 @@ std::shared_ptr 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; + callLater(std::bind(&processRequest, request)); +} + +static void processRequest(Request *request) +{ const Request::BufferMap &buffers = request->buffers(); for (auto bufferPair : buffers) { @@ -60,6 +119,15 @@ static void requestComplete(Request *request) camera->queueRequest(request); } +void timeoutTriggered(int fd, short event, void *arg) +{ + capture = false; + interrupt(); + + std::cout << "Capture ran for " << TIMEOUT_SEC << " seconds, Exiting." + << std::endl; +} + int main() { /* @@ -321,18 +389,25 @@ 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. + * simple-cam uses a base event loop provided by libevent, which is run + * for TIMEOUT_SEC seconds after which, the event loop is interrupted + * via interrupt() and begins the cleanup. The interval for which the + * event loop is being run, completed requests are processed via + * requestComplete() handler. */ - EventDispatcher *dispatcher = cm->eventDispatcher(); - Timer timer; - timer.start(3000); - while (timer.isRunning()) - dispatcher->processEvents(); + struct event *ev; + struct timeval tv; + + tv.tv_sec = TIMEOUT_SEC; + tv.tv_usec = 0; + evthread_use_pthreads(); + event = event_base_new(); + ev = event_new(event, -1, EV_TIMEOUT, &timeoutTriggered, NULL); + event_add(ev, &tv); + while (capture) { + dispatchCalls(); + event_base_loop(event, EVLOOP_NO_EXIT_ON_EMPTY); + } /* * -------------------------------------------------------------------- @@ -341,6 +416,10 @@ int main() * Stop the Camera, release resources and stop the CameraManager. * Libcamera has now released all resources it owned. */ + event_free(ev); + event_base_free(event); + libevent_global_shutdown(); + camera->stop(); allocator->free(stream); delete allocator;