From patchwork Tue Apr 2 00:54:03 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: 838 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 BDDEB610BF for ; Tue, 2 Apr 2019 02:54:33 +0200 (CEST) X-Halon-ID: e10d5c06-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 e10d5c06-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:03 +0200 Message-Id: <20190402005406.25097-2-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 1/4] cam: Rename --format to --stream 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:34 -0000 More then format information needs to be configured for each stream to allow multiple streams to be configured. Rename the option and adapt all uses of it. There is no functional change except the rename. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/cam/main.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 0a248d042cfe772b..d3f1f341d44e7f98 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -28,9 +28,9 @@ enum { OptCamera = 'c', OptCapture = 'C', OptFile = 'F', - OptFormat = 'f', OptHelp = 'h', OptList = 'l', + OptStream = 's', }; void signalHandler(int signal) @@ -41,12 +41,12 @@ void signalHandler(int signal) static int parseOptions(int argc, char *argv[]) { - KeyValueParser formatKeyValue; - formatKeyValue.addOption("width", OptionInteger, "Width in pixels", + KeyValueParser streamKeyValue; + streamKeyValue.addOption("width", OptionInteger, "Width in pixels", ArgumentRequired); - formatKeyValue.addOption("height", OptionInteger, "Height in pixels", + streamKeyValue.addOption("height", OptionInteger, "Height in pixels", ArgumentRequired); - formatKeyValue.addOption("pixelformat", OptionInteger, "Pixel format", + streamKeyValue.addOption("pixelformat", OptionInteger, "Pixel format", ArgumentRequired); OptionsParser parser; @@ -60,8 +60,8 @@ static int parseOptions(int argc, char *argv[]) "The first '#' character in the file name is expanded to the frame sequence number.\n" "The default file name is 'frame-#.bin'.", "file", ArgumentOptional, "filename"); - parser.addOption(OptFormat, &formatKeyValue, - "Set format of the camera's first stream", "format"); + parser.addOption(OptStream, &streamKeyValue, + "Set configuration of the camera's streams", "stream"); parser.addOption(OptHelp, OptionNone, "Display this help message", "help"); parser.addOption(OptList, OptionNone, "List all cameras", "list"); @@ -84,18 +84,18 @@ static int prepare_camera_config(std::map *config *config = camera->streamConfiguration({ Video() }); Stream *stream = config->begin()->first; - if (options.isSet(OptFormat)) { - KeyValueParser::Options format = options[OptFormat]; + if (options.isSet(OptStream)) { + KeyValueParser::Options conf = options[OptStream]; - if (format.isSet("width")) - (*config)[stream].width = format["width"]; + if (conf.isSet("width")) + (*config)[stream].width = conf["width"]; - if (format.isSet("height")) - (*config)[stream].height = format["height"]; + if (conf.isSet("height")) + (*config)[stream].height = conf["height"]; /* TODO: Translate 4CC string to ID. */ - if (format.isSet("pixelformat")) - (*config)[stream].pixelFormat = format["pixelformat"]; + if (conf.isSet("pixelformat")) + (*config)[stream].pixelFormat = conf["pixelformat"]; } return 0; 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; From patchwork Tue Apr 2 00:54:05 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: 839 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 40F24610BF for ; Tue, 2 Apr 2019 02:54:35 +0200 (CEST) X-Halon-ID: e1ca9d7d-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 e1ca9d7d-54e1-11e9-846a-005056917a89; Tue, 02 Apr 2019 02:54:34 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Tue, 2 Apr 2019 02:54:05 +0200 Message-Id: <20190402005406.25097-4-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 3/4] cam: Extend request complete handler to deal with multiple streams 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 The completion handler needs to handle all buffers in the request. Solve this by iterating over all buffers in the completed and assign each stream a name as we encounter them. The buffer writer needs to be extended to learn about stream names so it can prefix the files it writes with it. Signed-off-by: Niklas Söderlund --- src/cam/buffer_writer.cpp | 4 ++-- src/cam/buffer_writer.h | 2 +- src/cam/main.cpp | 41 +++++++++++++++++++++++++++------------ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp index 2d2258b4cd1cbbc2..02a9610b8b3caa31 100644 --- a/src/cam/buffer_writer.cpp +++ b/src/cam/buffer_writer.cpp @@ -19,13 +19,13 @@ BufferWriter::BufferWriter(const std::string &pattern) { } -int BufferWriter::write(libcamera::Buffer *buffer) +int BufferWriter::write(libcamera::Buffer *buffer, const std::string &prefix) { std::string filename; size_t pos; int fd, ret = 0; - filename = pattern_; + filename = prefix + "-" + pattern_; pos = filename.find_first_of('#'); if (pos != std::string::npos) { std::stringstream ss; diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h index 9705773e0e397d45..ebc6c24cd8f8d43a 100644 --- a/src/cam/buffer_writer.h +++ b/src/cam/buffer_writer.h @@ -16,7 +16,7 @@ class BufferWriter public: BufferWriter(const std::string &pattern = "frame-#.bin"); - int write(libcamera::Buffer *buffer); + int write(libcamera::Buffer *buffer, const std::string &prefix); private: std::string pattern_; diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 1bf28ca8eb8c6da7..6aed4073f70d37a2 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -143,28 +143,45 @@ static int prepare_camera_config(std::map *config return 0; } +static std::string streamToName(const Stream *stream) +{ + static std::map names; + + if (names.find(stream) == names.end()) + names[stream] = std::string("stream") + std::to_string(names.size()); + + return names[stream]; +} + static void requestComplete(Request *request, const std::map &buffers) { static uint64_t last = 0; + double fps = 0.0; if (request->status() == Request::RequestCancelled) return; - Buffer *buffer = buffers.begin()->second; + for (auto const &it : buffers) { + Stream *stream = it.first; + Buffer *buffer = it.second; + std::string name = streamToName(stream); - double fps = buffer->timestamp() - last; - fps = last && fps ? 1000000000.0 / fps : 0.0; - last = buffer->timestamp(); + if (fps == 0.0) { + 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; + std::cout << name << " 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; - if (writer) - writer->write(buffer); + if (writer) + writer->write(buffer, name); + } request = camera->createRequest(); if (!request) { From patchwork Tue Apr 2 00:54:06 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: 841 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 B9A366110D for ; Tue, 2 Apr 2019 02:54:35 +0200 (CEST) X-Halon-ID: e233bb2b-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 e233bb2b-54e1-11e9-846a-005056917a89; Tue, 02 Apr 2019 02:54:35 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Tue, 2 Apr 2019 02:54:06 +0200 Message-Id: <20190402005406.25097-5-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 4/4] cam: Allow cameras with more then one stream 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:36 -0000 The libcamera API and the cam tool is now ready to make use of cameras with more then one stream. Remove the limitation in the tool which disallows cameras which provides more then one stream. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/cam/main.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 6aed4073f70d37a2..9fb29fc8995001f6 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -317,14 +317,6 @@ int main(int argc, char **argv) goto out; } - const std::set &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; goto out;