{"id":878,"url":"https://patchwork.libcamera.org/api/1.1/patches/878/?format=json","web_url":"https://patchwork.libcamera.org/patch/878/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20190403011235.12782-3-niklas.soderlund@ragnatech.se>","date":"2019-04-03T01:12:33","name":"[libcamera-devel,v2,2/4] cam: Add support to specify multiple stream configurations with roles","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"6083d03b2a68bb8a4af92e5c572057525db043f6","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/1.1/people/5/?format=json","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/878/mbox/","series":[{"id":233,"url":"https://patchwork.libcamera.org/api/1.1/series/233/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=233","date":"2019-04-03T01:12:31","name":"cam: Add support to specify multiple stream configurations with roles","version":2,"mbox":"https://patchwork.libcamera.org/series/233/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/878/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/878/checks/","tags":{},"headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net\n\t[195.74.38.229])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DD484610B3\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  3 Apr 2019 03:12:48 +0200 (CEST)","from bismarck.berto.se (unknown [89.233.230.99])\n\tby bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA\n\tid 966c20ae-55ad-11e9-8144-0050569116f7;\n\tWed, 03 Apr 2019 03:12:45 +0200 (CEST)"],"X-Halon-ID":"966c20ae-55ad-11e9-8144-0050569116f7","Authorized-sender":"niklas@soderlund.pp.se","From":"=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","To":"libcamera-devel@lists.libcamera.org","Date":"Wed,  3 Apr 2019 03:12:33 +0200","Message-Id":"<20190403011235.12782-3-niklas.soderlund@ragnatech.se>","X-Mailer":"git-send-email 2.21.0","In-Reply-To":"<20190403011235.12782-1-niklas.soderlund@ragnatech.se>","References":"<20190403011235.12782-1-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH v2 2/4] cam: Add support to specify\n\tmultiple stream configurations with roles","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Wed, 03 Apr 2019 01:12:49 -0000"},"content":"Extend the cam tool to allow configuring more than one stream. Add an\noptional parameter to the --stream option to specify a usage role for\nthe stream. The stream role is passed to libcamera to give it control\nover which streams to use.\n\nTo support multiple streams, creation of requests needs to be reworked\nto limit the number of requests to match the stream with the least\nnumber of buffers. This should be improved in the future as the tool and\nthe library evolve.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\n src/cam/main.cpp | 78 ++++++++++++++++++++++++++++++++++++++++--------\n 1 file changed, 66 insertions(+), 12 deletions(-)","diff":"diff --git a/src/cam/main.cpp b/src/cam/main.cpp\nindex 6bf5e5926704d6e9..b47bda21cbb7f220 100644\n--- a/src/cam/main.cpp\n+++ b/src/cam/main.cpp\n@@ -5,8 +5,10 @@\n  * main.cpp - cam - The libcamera swiss army knife\n  */\n \n+#include <algorithm>\n #include <iomanip>\n #include <iostream>\n+#include <limits.h>\n #include <map>\n #include <signal.h>\n #include <string.h>\n@@ -42,6 +44,9 @@ void signalHandler(int signal)\n static int parseOptions(int argc, char *argv[])\n {\n \tKeyValueParser streamKeyValue;\n+\tstreamKeyValue.addOption(\"role\", OptionString,\n+\t\t\t\t \"Role for the stream (viewfinder, video, still)\",\n+\t\t\t\t ArgumentRequired);\n \tstreamKeyValue.addOption(\"width\", OptionInteger, \"Width in pixels\",\n \t\t\t\t ArgumentRequired);\n \tstreamKeyValue.addOption(\"height\", OptionInteger, \"Height in pixels\",\n@@ -61,7 +66,7 @@ static int parseOptions(int argc, char *argv[])\n \t\t\t \"The default file name is 'frame-#.bin'.\",\n \t\t\t \"file\", ArgumentOptional, \"filename\");\n \tparser.addOption(OptStream, &streamKeyValue,\n-\t\t\t \"Set configuration of a camera stream\", \"stream\");\n+\t\t\t \"Set configuration of a camera stream\", \"stream\", true);\n \tparser.addOption(OptHelp, OptionNone, \"Display this help message\",\n \t\t\t \"help\");\n \tparser.addOption(OptList, OptionNone, \"List all cameras\", \"list\");\n@@ -80,12 +85,51 @@ static int parseOptions(int argc, char *argv[])\n \n static int prepareCameraConfig(std::map<Stream *, StreamConfiguration> *config)\n {\n-\tstd::set<Stream *> streams = camera->streams();\n-\t*config = camera->streamConfiguration({ Stream::VideoRecording() });\n-\tStream *stream = config->begin()->first;\n+\tstd::vector<StreamRole> roles;\n \n-\tif (options.isSet(OptStream)) {\n-\t\tKeyValueParser::Options conf = options[OptStream];\n+\t/* If no configuration is provided assume a single video stream. */\n+\tif (!options.isSet(OptStream)) {\n+\t\t*config = camera->streamConfiguration({ Stream::VideoRecording() });\n+\t\treturn 0;\n+\t}\n+\n+\tconst std::vector<OptionValue> &streamopts =\n+\t\toptions[OptStream].toArray();\n+\n+\t/* Use roles and get a default configuration. */\n+\tfor (auto const &value : streamopts) {\n+\t\tKeyValueParser::Options conf = value.toKeyValues();\n+\n+\t\tif (!conf.isSet(\"role\")) {\n+\t\t\troles.push_back(Stream::VideoRecording());\n+\t\t} else if (conf[\"role\"].toString() == \"viewfinder\") {\n+\t\t\troles.push_back(Stream::Viewfinder(conf[\"width\"],\n+\t\t\t\t\t\t\t   conf[\"height\"]));\n+\t\t} else if (conf[\"role\"].toString() == \"video\") {\n+\t\t\troles.push_back(Stream::VideoRecording());\n+\t\t} else if (conf[\"role\"].toString() == \"still\") {\n+\t\t\troles.push_back(Stream::StillCapture());\n+\t\t} else {\n+\t\t\tstd::cerr << \"Unknown stream role \"\n+\t\t\t\t  << conf[\"role\"].toString() << std::endl;\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\t*config = camera->streamConfiguration(roles);\n+\n+\tif (config->size() != streamopts.size()) {\n+\t\tstd::cerr << \"Failed to get default stream configuration\"\n+\t\t\t  << std::endl;\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Apply configuration explicitly requested. */\n+\tstd::map<Stream *, StreamConfiguration>::iterator it = config->begin();\n+\tfor (auto const &value : streamopts) {\n+\t\tKeyValueParser::Options conf = value.toKeyValues();\n+\t\tStream *stream = it->first;\n+\t\tit++;\n \n \t\tif (conf.isSet(\"width\"))\n \t\t\t(*config)[stream].width = conf[\"width\"];\n@@ -137,7 +181,6 @@ static void requestComplete(Request *request, const std::map<Stream *, Buffer *>\n static int capture()\n {\n \tstd::map<Stream *, StreamConfiguration> config;\n-\tstd::vector<Request *> requests;\n \tint ret;\n \n \tret = prepareCameraConfig(&config);\n@@ -152,8 +195,6 @@ static int capture()\n \t\treturn ret;\n \t}\n \n-\tStream *stream = config.begin()->first;\n-\n \tret = camera->allocateBuffers();\n \tif (ret) {\n \t\tstd::cerr << \"Failed to allocate buffers\"\n@@ -163,9 +204,18 @@ static int capture()\n \n \tcamera->requestCompleted.connect(requestComplete);\n \n-\tBufferPool &pool = stream->bufferPool();\n+\t/* Figure out which stream s the lower number of buffers. */\n+\tunsigned int nbuffers = UINT_MAX;\n+\tfor (auto const &it : config)\n+\t\tnbuffers = std::min(nbuffers, it.first->bufferPool().count());\n \n-\tfor (Buffer &buffer : pool.buffers()) {\n+\t/*\n+\t * TODO: make cam tool smarter to support still capture by for\n+\t * example pushing a button. For now run all streams all the time.\n+\t */\n+\n+\tstd::vector<Request *> requests;\n+\tfor (unsigned int i = 0; i < nbuffers; i++) {\n \t\tRequest *request = camera->createRequest();\n \t\tif (!request) {\n \t\t\tstd::cerr << \"Can't create request\" << std::endl;\n@@ -174,7 +224,11 @@ static int capture()\n \t\t}\n \n \t\tstd::map<Stream *, Buffer *> map;\n-\t\tmap[stream] = &buffer;\n+\t\tfor (auto const &it : config) {\n+\t\t\tStream *stream = it.first;\n+\t\t\tmap[stream] = &stream->bufferPool().buffers()[i];\n+\t\t}\n+\n \t\tret = request->setBuffers(map);\n \t\tif (ret < 0) {\n \t\t\tstd::cerr << \"Can't set buffers for request\" << std::endl;\n","prefixes":["libcamera-devel","v2","2/4"]}