[libcamera-devel,v2,8/8] cam: Add --format option to configure a stream

Message ID 20190131234721.22606-9-laurent.pinchart@ideasonboard.com
State Accepted
Headers show
Series
  • cam: add --format option to configure a stream
Related show

Commit Message

Laurent Pinchart Jan. 31, 2019, 11:47 p.m. UTC
From: Niklas Söderlund <niklas.soderlund@ragnatech.se>

Add an option to configure the first stream of a camera from an argument
with options and parse the width, height and pixel format from that
list.

The pixel format is still specified as a integer which should correspond
to the kernels FOURCC identifiers. Going forward this should be turned
into a string representation and the cam parser should translate between
the two.

Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
Changes since v1:

- Don't rename OptCamera option
- Reword the format options help texts
- Use the new KeyValueParser integration
---
 src/cam/main.cpp | 103 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 91 insertions(+), 12 deletions(-)

Patch

diff --git a/src/cam/main.cpp b/src/cam/main.cpp
index 7934d0bf4132..02d9b86f546f 100644
--- a/src/cam/main.cpp
+++ b/src/cam/main.cpp
@@ -21,6 +21,7 @@  OptionsParser::Options options;
 
 enum {
 	OptCamera = 'c',
+	OptFormat = 'f',
 	OptHelp = 'h',
 	OptList = 'l',
 };
@@ -35,11 +36,20 @@  void signalHandler(int signal)
 
 static int parseOptions(int argc, char *argv[])
 {
-	OptionsParser parser;
+	KeyValueParser formatKeyValue;
+	formatKeyValue.addOption("width", OptionInteger, "Width in pixels",
+				 ArgumentRequired);
+	formatKeyValue.addOption("height", OptionInteger, "Height in pixels",
+				 ArgumentRequired);
+	formatKeyValue.addOption("pixelformat", OptionInteger, "Pixel format",
+				 ArgumentRequired);
 
+	OptionsParser parser;
 	parser.addOption(OptCamera, OptionString,
 			 "Specify which camera to operate on", "camera",
 			 ArgumentRequired, "camera");
+	parser.addOption(OptFormat, &formatKeyValue,
+			 "Set format of the camera's first stream", "format");
 	parser.addOption(OptHelp, OptionNone, "Display this help message",
 			 "help");
 	parser.addOption(OptList, OptionNone, "List all cameras", "list");
@@ -56,6 +66,47 @@  static int parseOptions(int argc, char *argv[])
 	return 0;
 }
 
+int str2uint(std::string str, unsigned int *dest)
+{
+	if (!dest || str == "" || !sscanf(str.c_str(), "%d", dest))
+		return -EINVAL;
+	return 0;
+}
+
+bool configureStreams(Camera *camera, std::vector<Stream *> &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<Stream *, StreamConfiguration> config =
+		camera->streamConfiguration(streams);
+
+	if (format.isSet("width"))
+		if (str2uint(format["width"], &config[id].width))
+			return false;
+
+	if (format.isSet("height"))
+		if (str2uint(format["height"], &config[id].height))
+			return false;
+
+	/* TODO: Translate 4CC string to ID. */
+	if (format.isSet("pixelformat"))
+		if (str2uint(format["pixelformat"], &config[id].pixelFormat))
+			return false;
+
+	if (camera->configureStreams(config))
+		return false;
+
+	return true;
+}
+
 int main(int argc, char **argv)
 {
 	int ret;
@@ -65,6 +116,8 @@  int main(int argc, char **argv)
 		return EXIT_FAILURE;
 
 	CameraManager *cm = CameraManager::instance();
+	std::shared_ptr<Camera> camera;
+	std::vector<Stream *> streams;
 
 	ret = cm->start();
 	if (ret) {
@@ -73,31 +126,57 @@  int main(int argc, char **argv)
 		return EXIT_FAILURE;
 	}
 
+	loop = new EventLoop(cm->eventDispatcher());
+
+	struct sigaction sa = {};
+	sa.sa_handler = &signalHandler;
+	sigaction(SIGINT, &sa, nullptr);
+
 	if (options.isSet(OptList)) {
 		std::cout << "Available cameras:" << std::endl;
-		for (const std::shared_ptr<Camera> &camera : cm->cameras())
-			std::cout << "- " << camera->name() << std::endl;
+		for (const std::shared_ptr<Camera> &cam : cm->cameras())
+			std::cout << "- " << cam->name() << std::endl;
 	}
 
 	if (options.isSet(OptCamera)) {
-		std::shared_ptr<Camera> cam = cm->get(options[OptCamera]);
-
-		if (cam) {
-			std::cout << "Using camera " << cam->name() << std::endl;
-		} else {
+		camera = cm->get(options[OptCamera]);
+		if (!camera) {
 			std::cout << "Camera " << options[OptCamera]
 				  << " not found" << std::endl;
+			goto out;
+		}
+
+		streams = camera->streams();
+
+		if (camera->acquire()) {
+			std::cout << "Failed to acquire camera" << std::endl;
+			goto out;
 		}
+
+		std::cout << "Using camera " << camera->name() << std::endl;
 	}
 
-	loop = new EventLoop(cm->eventDispatcher());
+	if (options.isSet(OptFormat)) {
+		if (!camera) {
+			std::cout << "Can't configure stream, no camera selected"
+				  << std::endl;
+			goto out_camera;
+		}
 
-	struct sigaction sa = {};
-	sa.sa_handler = &signalHandler;
-	sigaction(SIGINT, &sa, nullptr);
+		if (!configureStreams(camera.get(), streams)) {
+			std::cout << "Failed to configure camera" << std::endl;
+			goto out_camera;
+		}
+	}
 
 	ret = loop->exec();
 
+out_camera:
+	if (camera) {
+		camera->release();
+		camera.reset();
+	}
+out:
 	delete loop;
 
 	cm->stop();