From patchwork Tue Apr 2 00:54:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 840 X-Patchwork-Delegate: niklas.soderlund@ragnatech.se Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 401AC60DB2 for ; Tue, 2 Apr 2019 02:54:35 +0200 (CEST) X-Halon-ID: e15b54bf-54e1-11e9-846a-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id e15b54bf-54e1-11e9-846a-005056917a89; Tue, 02 Apr 2019 02:54:33 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Tue, 2 Apr 2019 02:54:04 +0200 Message-Id: <20190402005406.25097-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190402005406.25097-1-niklas.soderlund@ragnatech.se> References: <20190402005406.25097-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 2/4] cam: Add support to specify multiple stream configurations with hints 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: Tue, 02 Apr 2019 00:54:35 -0000 Extend the cam tool to allow configuring more then one stream. Add an optional parameter to the --stream option to allow specifying a usage hint for the stream. The usage hint is passed to libcamera to allow it to make better decisions on which stream to use. To allow multiple streams to work creation of requests needs to be reworked to be limit the number of requests to match the stream with the leasts number of buffers. This should be improved in the future as the tool and the library evolves. Signed-off-by: Niklas Söderlund --- src/cam/main.cpp | 76 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index d3f1f341d44e7f98..1bf28ca8eb8c6da7 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -17,6 +18,8 @@ #include "event_loop.h" #include "options.h" +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + using namespace libcamera; OptionsParser::Options options; @@ -42,6 +45,9 @@ void signalHandler(int signal) static int parseOptions(int argc, char *argv[]) { KeyValueParser streamKeyValue; + streamKeyValue.addOption("hint", OptionString, + "Usage hint for the stream (viewfinder, video, still)", + ArgumentRequired); streamKeyValue.addOption("width", OptionInteger, "Width in pixels", ArgumentRequired); streamKeyValue.addOption("height", OptionInteger, "Height in pixels", @@ -61,7 +67,7 @@ static int parseOptions(int argc, char *argv[]) "The default file name is 'frame-#.bin'.", "file", ArgumentOptional, "filename"); parser.addOption(OptStream, &streamKeyValue, - "Set configuration of the camera's streams", "stream"); + "Set configuration of the camera's streams", "stream", true); parser.addOption(OptHelp, OptionNone, "Display this help message", "help"); parser.addOption(OptList, OptionNone, "List all cameras", "list"); @@ -80,12 +86,48 @@ static int parseOptions(int argc, char *argv[]) static int prepare_camera_config(std::map *config) { - std::set streams = camera->streams(); - *config = camera->streamConfiguration({ Video() }); - Stream *stream = config->begin()->first; + std::vector hints; - if (options.isSet(OptStream)) { - KeyValueParser::Options conf = options[OptStream]; + /* If no configuration is provided assume a single video stream. */ + if (!options.isSet(OptStream)) { + *config = camera->streamConfiguration({ Video() }); + return 0; + } + + /* Use hints and get a default configuration. */ + for (auto const &value : options[OptStream].toArray()) { + KeyValueParser::Options conf = value.toKeyValues(); + + if (!conf.isSet("hint")) + hints.push_back(Video()); + else if (conf["hint"].toString() == "viewfinder") + hints.push_back(Viewfinder(conf["width"], + conf["height"])); + else if (conf["hint"].toString() == "video") + hints.push_back(Video()); + else if (conf["hint"].toString() == "still") + hints.push_back(Still()); + else { + std::cerr << "Unknown stream hint " + << conf["hint"].toString() << std::endl; + return -EINVAL; + } + } + + *config = camera->streamConfiguration(hints); + + if (config->size() != options[OptStream].toArray().size()) { + std::cerr << "Failed to get default stream configuration" + << std::endl; + return -EINVAL; + } + + /* Apply configuration explicitly requested. */ + std::map::iterator it = config->begin(); + for (auto const &value : options[OptStream].toArray()) { + KeyValueParser::Options conf = value.toKeyValues(); + Stream *stream = it->first; + it++; if (conf.isSet("width")) (*config)[stream].width = conf["width"]; @@ -137,7 +179,6 @@ static void requestComplete(Request *request, const std::map static int capture() { std::map config; - std::vector requests; int ret; ret = prepare_camera_config(&config); @@ -152,8 +193,6 @@ static int capture() return ret; } - Stream *stream = config.begin()->first; - ret = camera->allocateBuffers(); if (ret) { std::cerr << "Failed to allocate buffers" @@ -163,9 +202,18 @@ static int capture() camera->requestCompleted.connect(requestComplete); - BufferPool &pool = stream->bufferPool(); + /* Figure out which stream have least number of buffers. */ + unsigned int nbuffers = UINT_MAX; + for (auto const &it : config) + nbuffers = MIN(nbuffers, it.first->bufferPool().count()); - for (Buffer &buffer : pool.buffers()) { + /* + * TODO: make cam tool smarter to support still capture by for + * example pushing a button. For now run all streams all the time. + */ + + std::vector requests; + for (unsigned int i = 0; i < nbuffers; i++) { Request *request = camera->createRequest(); if (!request) { std::cerr << "Can't create request" << std::endl; @@ -174,7 +222,11 @@ static int capture() } std::map map; - map[stream] = &buffer; + for (auto const &it : config) { + Stream *stream = it.first; + map[stream] = &stream->bufferPool().buffers()[i]; + } + ret = request->setBuffers(map); if (ret < 0) { std::cerr << "Can't set buffers for request" << std::endl;