From patchwork Wed Feb 6 06:08:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 540 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 86BFB61031 for ; Wed, 6 Feb 2019 07:08:29 +0100 (CET) Received: from pendragon.ideasonboard.com (d51A4137F.access.telenet.be [81.164.19.127]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3262441 for ; Wed, 6 Feb 2019 07:08:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1549433309; bh=EZ0uI2hILy2K6NEikaRZG1CpzfbRdZLF5+lgdsyEO6Q=; h=From:To:Subject:Date:In-Reply-To:References:From; b=MOvCcGmLTjTceq1g18AoWf0yPrgTd9qhFCHtsD6RsfqenzcXZq+k8CsznZhhQBDR6 iO1ec4R3bojvSCn4e6nULfCuZInvo/4DQ3aH2LvX5TDtOLZD2glqcEh273DG9KM5yx 0IlsJsjSAOq8xeMuAU3uSFCVq9V9QKePlFQm1tXI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 6 Feb 2019 08:08:16 +0200 Message-Id: <20190206060818.13907-26-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20190206060818.13907-1-laurent.pinchart@ideasonboard.com> References: <20190206060818.13907-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 25/27] cam: Add capture operation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 06 Feb 2019 06:08:30 -0000 From: Niklas Söderlund Add an option to capture frames from a camera and keep it running until the user terminates by sending SIGINT. Signed-off-by: Niklas Söderlund Signed-off-by: Jacopo Mondi Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart --- src/cam/main.cpp | 141 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 111 insertions(+), 30 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 06f9e6e16e87..ec5040e19935 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -5,6 +5,7 @@ * main.cpp - cam - The libcamera swiss army knife */ +#include #include #include #include @@ -18,16 +19,17 @@ using namespace libcamera; OptionsParser::Options options; +std::shared_ptr camera; +EventLoop *loop; enum { OptCamera = 'c', + OptCapture = 'C', OptFormat = 'f', OptHelp = 'h', OptList = 'l', }; -EventLoop *loop; - void signalHandler(int signal) { std::cout << "Exiting" << std::endl; @@ -48,6 +50,8 @@ static int parseOptions(int argc, char *argv[]) parser.addOption(OptCamera, OptionString, "Specify which camera to operate on", "camera", ArgumentRequired, "camera"); + parser.addOption(OptCapture, OptionNone, + "Capture until interrupted by user", "capture"); parser.addOption(OptFormat, &formatKeyValue, "Set format of the camera's first stream", "format"); parser.addOption(OptHelp, OptionNone, "Display this help message", @@ -66,30 +70,25 @@ static int parseOptions(int argc, char *argv[]) return 0; } -bool configureStreams(Camera *camera, std::vector &streams) +static bool configureStreams(Camera *camera, std::vector &streams) { KeyValueParser::Options format = options[OptFormat]; - - if (streams.size() != 1) { - std::cout << "Camera has " << streams.size() - << " streams, I only know how to work with 1" - << std::endl; - return false; - } Stream *id = streams.front(); std::map config = camera->streamConfiguration(streams); - if (format.isSet("width")) - config[id].width = format["width"]; + if (options.isSet(OptFormat)) { + if (format.isSet("width")) + config[id].width = format["width"]; - if (format.isSet("height")) - config[id].height = format["height"]; + if (format.isSet("height")) + config[id].height = format["height"]; - /* TODO: Translate 4CC string to ID. */ - if (format.isSet("pixelformat")) - config[id].pixelFormat = format["pixelformat"]; + /* TODO: Translate 4CC string to ID. */ + if (format.isSet("pixelformat")) + config[id].pixelFormat = format["pixelformat"]; + } if (camera->configureStreams(config)) return false; @@ -97,6 +96,89 @@ bool configureStreams(Camera *camera, std::vector &streams) return true; } +static void requestComplete(Request *request, const std::map &buffers) +{ + static uint64_t last = 0; + + Buffer *buffer = buffers.begin()->second; + + double fps = buffer->timestamp() - last; + fps = last && fps ? 1000000000.0 / fps : 0.0; + last = buffer->timestamp(); + + std::cout << "seq: " << std::setw(6) << std::setfill('0') << buffer->sequence() + << " buf: " << buffer->index() + << " bytesused: " << buffer->bytesused() + << " timestamp: " << buffer->timestamp() + << " fps: " << std::fixed << std::setprecision(2) << fps + << std::endl; + + request = camera->createRequest(); + if (!request) { + std::cerr << "Can't create request" << std::endl; + return; + } + + request->setBuffers(buffers); + camera->queueRequest(request); +} + +static int capture() +{ + int ret; + + std::vector streams = camera->streams(); + + ret = configureStreams(camera.get(), streams); + if (ret < 0) { + std::cout << "Failed to configure camera" << std::endl; + return ret; + } + + Stream *stream = streams.front(); + + ret = camera->allocateBuffers(); + if (ret) { + std::cerr << "Failed to allocate buffers" + << std::endl; + return ret; + } + + camera->requestCompleted.connect(requestComplete); + + BufferPool &pool = stream->bufferPool(); + + for (Buffer &buffer : pool.buffers()) { + Request *request = camera->createRequest(); + if (!request) { + std::cerr << "Can't create request" << std::endl; + return -ENOMEM; + } + + std::map map; + map[stream] = &buffer; + ret = request->setBuffers(map); + if (ret < 0) { + std::cerr << "Can't set buffers for request" << std::endl; + return ret; + } + + ret = camera->queueRequest(request); + if (ret < 0) { + std::cerr << "Can't queue request" << std::endl; + return ret; + } + } + + std::cout << "Capture until user interrupts by SIGINT" << std::endl; + camera->start(); + + ret = loop->exec(); + + camera->stop(); + return ret; +} + int main(int argc, char **argv) { int ret; @@ -106,8 +188,6 @@ int main(int argc, char **argv) return EXIT_FAILURE; CameraManager *cm = CameraManager::instance(); - std::shared_ptr camera; - std::vector streams; ret = cm->start(); if (ret) { @@ -136,7 +216,13 @@ int main(int argc, char **argv) goto out; } - streams = camera->streams(); + const std::vector &streams = camera->streams(); + if (streams.size() != 1) { + std::cout << "Camera has " << streams.size() + << " streams, only 1 is supported" + << std::endl; + goto out; + } if (camera->acquire()) { std::cout << "Failed to acquire camera" << std::endl; @@ -146,22 +232,17 @@ int main(int argc, char **argv) std::cout << "Using camera " << camera->name() << std::endl; } - if (options.isSet(OptFormat)) { + if (options.isSet(OptCapture)) { if (!camera) { - std::cout << "Can't configure stream, no camera selected" + std::cout << "Can't capture without a camera" << std::endl; - goto out_camera; + ret = EXIT_FAILURE; + goto out; } - if (!configureStreams(camera.get(), streams)) { - std::cout << "Failed to configure camera" << std::endl; - goto out_camera; - } + capture(); } - ret = loop->exec(); - -out_camera: if (camera) { camera->release(); camera.reset();