[libcamera-devel] [PATCH 2/4] cam: Add support to specify multiple stream configurations with hints

Niklas Söderlund niklas.soderlund at ragnatech.se
Tue Apr 2 02:54:04 CEST 2019


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 <niklas.soderlund at ragnatech.se>
---
 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 <iomanip>
 #include <iostream>
+#include <limits.h>
 #include <map>
 #include <signal.h>
 #include <string.h>
@@ -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<Stream *, StreamConfiguration> *config)
 {
-	std::set<Stream *> streams = camera->streams();
-	*config = camera->streamConfiguration({ Video() });
-	Stream *stream = config->begin()->first;
+	std::vector<StreamHint> 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<Stream *, StreamConfiguration>::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<Stream *, Buffer *>
 static int capture()
 {
 	std::map<Stream *, StreamConfiguration> config;
-	std::vector<Request *> 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<Request *> 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<Stream *, Buffer *> 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;
-- 
2.21.0



More information about the libcamera-devel mailing list