[libcamera-devel] [RFC 2/2] libcamera: Modify streamConfiguration()

Jacopo Mondi jacopo at jmondi.org
Mon Apr 1 12:14:10 CEST 2019


Modify streamConfiguration() along the whole library stack:
- streamConfiguration receives a list of required stream configurations
- the camera, with support of the pipeline handler, associates one
stream to each requested configuration
- application modifies the received configuration and provide it to
configureStreams()

Implement stream matching in the IPU3 pipeline handler and modify the
camera application use the new API and capture from output and
viewfinder with different resolutions.

Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
---
 include/libcamera/camera.h               |  2 +-
 src/cam/main.cpp                         | 48 +++++++-------
 src/libcamera/camera.cpp                 | 30 ++++-----
 src/libcamera/include/pipeline_handler.h |  3 +-
 src/libcamera/pipeline/ipu3/ipu3.cpp     | 82 ++++++++++++++++--------
 src/libcamera/pipeline/uvcvideo.cpp      |  4 +-
 src/libcamera/pipeline/vimc.cpp          |  4 +-
 src/libcamera/pipeline_handler.cpp       | 23 ++++---
 8 files changed, 118 insertions(+), 78 deletions(-)

diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h
index bfd574a25070..01e0188468c1 100644
--- a/include/libcamera/camera.h
+++ b/include/libcamera/camera.h
@@ -44,7 +44,7 @@ public:
 
 	const std::set<Stream *> &streams() const;
 	std::map<Stream *, StreamConfiguration>
-	streamConfiguration(std::set<Stream *> &streams);
+	streamConfiguration(std::list<StreamConfiguration> &configs);
 	int configureStreams(std::map<Stream *, StreamConfiguration> &config);
 
 	int allocateBuffers();
diff --git a/src/cam/main.cpp b/src/cam/main.cpp
index 4608c2bc6f3c..fd94629e0726 100644
--- a/src/cam/main.cpp
+++ b/src/cam/main.cpp
@@ -5,6 +5,7 @@
  * main.cpp - cam - The libcamera swiss army knife
  */
 
+#include <list>
 #include <iomanip>
 #include <iostream>
 #include <map>
@@ -90,39 +91,42 @@ static int configureStreams(Camera *camera, std::set<Stream *> &streams,
 			    std::map<Stream *, StreamConfiguration> &config)
 {
 	KeyValueParser::Options format = options[OptFormat];
-	auto it = streams.begin();
-	Stream *output = *it;
-	Stream *viewfinder = *(++it);
-
-	std::map<Stream *, StreamConfiguration> defaultConfig =
-		camera->streamConfiguration(streams);
+	std::list<StreamConfiguration> streamConfs;
 
+	StreamConfiguration outputConfig = {};
 	if (options.isSet(OptFormat)) {
 		if (format.isSet("width"))
-			defaultConfig[output].width = format["width"];
+			outputConfig.width = format["width"];
 
 		if (format.isSet("height"))
-			defaultConfig[output].height = format["height"];
+			outputConfig.height = format["height"];
 
 		/* TODO: Translate 4CC string to ID. */
 		if (format.isSet("pixelformat"))
-			defaultConfig[output].pixelFormat = format["pixelformat"];
+			outputConfig.pixelFormat = format["pixelformat"];
 	}
+	outputConfig.hints.push_front(STILL_CAPTURE);
+	streamConfs.push_back(outputConfig);
 
-	/* Configure the secondary output stream. */
-	defaultConfig[viewfinder].width = 640;
-	defaultConfig[viewfinder].height = 480;
+	StreamConfiguration vfConfig = {};
+	vfConfig.hints.push_front(VIEWFINDER);
+	streamConfs.push_back(vfConfig);
 
-	/*
-	 * HACK: Select which stream to capture: use output if required,
-	 * use viewfinder if required or if no option has been specified
-	 * from the command line.
-	 */
-	if (options.isSet(OptOutput))
-		config[output] = defaultConfig[output];
-	if (options.isSet(OptViefinder) ||
-	    (!options.isSet(OptViefinder) && !options.isSet(OptOutput)))
-		config[viewfinder] = defaultConfig[viewfinder];
+	config = camera->streamConfiguration(streamConfs);
+	if (config.empty()) {
+		std::cout << "Cannot configure the requested streams"
+			  << std::endl;
+		return -EINVAL;
+	}
+
+	for (auto &map : config) {
+		StreamConfiguration *c = &map.second;
+
+		if (c->supports(VIEWFINDER)) {
+			c->width = 640;
+			c->height = 480;
+		}
+	}
 
 	return camera->configureStreams(config);
 }
diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
index 99eb0e6876f0..f2ae3d3e2d9a 100644
--- a/src/libcamera/camera.cpp
+++ b/src/libcamera/camera.cpp
@@ -346,32 +346,30 @@ const std::set<Stream *> &Camera::streams() const
 
 /**
  * \brief Retrieve a group of stream configurations
- * \param[in] streams A map of stream IDs and configurations to setup
+ * \param[in] configs A set of requested stream configurations
  *
- * Retrieve the camera's configuration for a specified group of streams. The
- * caller can specifies which of the camera's streams to retrieve configuration
- * from by populating \a streams.
- *
- * The easiest way to populate the array of streams to fetch configuration from
- * is to first retrieve the camera's full array of stream with streams() and
- * then potentially trim it down to only contain the streams the caller
- * are interested in.
+ * Retrieve a list of streams and associated default configurations in the
+ * camera. The caller specifies the properties a stream shall satisfy by
+ * populating \a config and the camera associates each supplied configuration
+ * with a stream that matches the requested properties. The requested
+ * per-stream configuration might be modified by the camera to report the
+ * stream default parameters. The callers of this function are free to adjust
+ * the default paramters and provide such configuration to the
+ * configureStreams() method.
  *
  * \return A map of successfully retrieved stream IDs and configurations or an
  * empty list on error.
  */
 std::map<Stream *, StreamConfiguration>
-Camera::streamConfiguration(std::set<Stream *> &streams)
+Camera::streamConfiguration(std::list<StreamConfiguration> &configs)
 {
-	if (disconnected_ || !streams.size())
+	if (disconnected_ || !configs.size())
 		return std::map<Stream *, StreamConfiguration>{};
 
-	for (Stream *stream : streams) {
-		if (streams_.find(stream) == streams_.end())
-			return std::map<Stream *, StreamConfiguration>{};
-	}
+	if (configs.size() > streams_.size())
+		return std::map<Stream *, StreamConfiguration>{};
 
-	return pipe_->streamConfiguration(this, streams);
+	return pipe_->streamConfiguration(this, configs);
 }
 
 /**
diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h
index 6cdadcbdc3ea..ff9f265fe880 100644
--- a/src/libcamera/include/pipeline_handler.h
+++ b/src/libcamera/include/pipeline_handler.h
@@ -56,7 +56,8 @@ public:
 	virtual bool match(DeviceEnumerator *enumerator) = 0;
 
 	virtual std::map<Stream *, StreamConfiguration>
-	streamConfiguration(Camera *camera, std::set<Stream *> &streams) = 0;
+	streamConfiguration(Camera *camera,
+			    std::list<StreamConfiguration> &config) = 0;
 	virtual int configureStreams(Camera *camera,
 				     std::map<Stream *, StreamConfiguration> &config) = 0;
 
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index 46479944a4da..52583b2beefd 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -197,7 +197,7 @@ public:
 
 	std::map<Stream *, StreamConfiguration>
 	streamConfiguration(Camera *camera,
-			    std::set<Stream *> &streams) override;
+			    std::list<StreamConfiguration> &confs) override;
 	int configureStreams(Camera *camera,
 			     std::map<Stream *, StreamConfiguration> &config) override;
 
@@ -318,36 +318,66 @@ PipelineHandlerIPU3::~PipelineHandlerIPU3()
 
 std::map<Stream *, StreamConfiguration>
 PipelineHandlerIPU3::streamConfiguration(Camera *camera,
-					 std::set<Stream *> &streams)
+					 std::list<StreamConfiguration> &confs)
 {
-	std::map<Stream *, StreamConfiguration> configs;
+	std::map<Stream *, StreamConfiguration> configs = {};
 	IPU3CameraData *data = cameraData(camera);
-	StreamConfiguration config = {};
+
+	std::list<Stream *> availableStreams;
+	availableStreams.push_front(&data->outStream_);
+	availableStreams.push_front(&data->vfStream_);
 
 	/*
-	 * FIXME: Soraka: the maximum resolution reported by both sensors
-	 * (2592x1944 for ov5670 and 4224x3136 for ov13858) are returned as
-	 * default configurations but they're not correctly processed by the
-	 * ImgU. Resolutions up tp 2560x1920 have been validated.
-	 *
-	 * \todo Clarify ImgU alignement requirements.
+	 * Try to match all the requested stream configurations with all
+	 * the streams available in the camera.
 	 */
-	config.width = 2560;
-	config.height = 1920;
-	config.pixelFormat = V4L2_PIX_FMT_NV12;
-	config.bufferCount = IPU3_BUFFER_COUNT;
-
-	configs[&data->outStream_] = config;
-	LOG(IPU3, Debug)
-		<< "Stream 'output' format set to " << config.width << "x"
-		<< config.height << "-0x" << std::hex << std::setfill('0')
-		<< std::setw(8) << config.pixelFormat;
-
-	configs[&data->vfStream_] = config;
-	LOG(IPU3, Debug)
-		<< "Stream 'viewfinder' format set to " << config.width << "x"
-		<< config.height << "-0x" << std::hex << std::setfill('0')
-		<< std::setw(8) << config.pixelFormat;
+	for (auto it = confs.begin(); it != confs.end(); ++it) {
+		StreamConfiguration &conf = *it;
+		auto sit = availableStreams.begin();
+
+		while (sit != availableStreams.end()) {
+			IPU3StreamProperties *props = &data->streamProps_[*sit];
+
+			if (!props->match(conf)) {
+				++sit;
+				continue;
+			}
+
+			/*
+			 * FIXME: Soraka: the maximum resolution reported by
+			 * both sensors (2592x1944 for ov5670 and 4224x3136 for
+			 * ov13858) are returned as default configurations but
+			 * they're not correctly processed by the ImgU.
+			 * Resolutions up tp 2560x1920 have been validated.
+			 *
+			 * \todo Clarify ImgU alignement requirements.
+			 */
+			conf.width = 2560;
+			conf.height = 1920;
+			conf.pixelFormat = V4L2_PIX_FMT_NV12;
+			conf.bufferCount = IPU3_BUFFER_COUNT;
+			configs[*sit] = conf;
+
+			LOG(IPU3, Debug)
+				<< "Stream " << props->name()
+				<< " format set to " << conf.width << "x"
+				<< conf.height << "-0x" << std::hex
+				<< std::setfill('0') << std::setw(8)
+				<< conf.pixelFormat;
+
+			/*
+			 * Once the stream has been assigned, remove it
+			 * from the list of available ones.
+			 */
+			availableStreams.erase(sit);
+			break;
+		}
+		if (sit == availableStreams.end()) {
+			LOG(IPU3, Error)
+				<< "Cannot satisfy the requested configuration";
+			return std::map<Stream *, StreamConfiguration> {};
+		}
+	}
 
 	return configs;
 }
diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp
index d571b8b4ea83..a88784b28189 100644
--- a/src/libcamera/pipeline/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo.cpp
@@ -28,7 +28,7 @@ public:
 
 	std::map<Stream *, StreamConfiguration>
 	streamConfiguration(Camera *camera,
-			    std::set<Stream *> &streams) override;
+			    std::list<StreamConfiguration> &confs) override;
 	int configureStreams(Camera *camera,
 			     std::map<Stream *, StreamConfiguration> &config) override;
 
@@ -86,7 +86,7 @@ PipelineHandlerUVC::~PipelineHandlerUVC()
 
 std::map<Stream *, StreamConfiguration>
 PipelineHandlerUVC::streamConfiguration(Camera *camera,
-					std::set<Stream *> &streams)
+					std::list<StreamConfiguration> &confs)
 {
 	UVCCameraData *data = cameraData(camera);
 
diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp
index e83416effad8..e36a58e70f8c 100644
--- a/src/libcamera/pipeline/vimc.cpp
+++ b/src/libcamera/pipeline/vimc.cpp
@@ -28,7 +28,7 @@ public:
 
 	std::map<Stream *, StreamConfiguration>
 	streamConfiguration(Camera *camera,
-			    std::set<Stream *> &streams) override;
+			    std::list<StreamConfiguration> &confs) override;
 	int configureStreams(Camera *camera,
 			     std::map<Stream *, StreamConfiguration> &config) override;
 
@@ -86,7 +86,7 @@ PipelineHandlerVimc::~PipelineHandlerVimc()
 
 std::map<Stream *, StreamConfiguration>
 PipelineHandlerVimc::streamConfiguration(Camera *camera,
-					 std::set<Stream *> &streams)
+					 std::list<StreamConfiguration> &confs)
 {
 	VimcCameraData *data = cameraData(camera);
 	std::map<Stream *, StreamConfiguration> configs;
diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp
index 82070d364c03..2dc78d7f0b5e 100644
--- a/src/libcamera/pipeline_handler.cpp
+++ b/src/libcamera/pipeline_handler.cpp
@@ -183,18 +183,25 @@ PipelineHandler::~PipelineHandler()
 
 /**
  * \fn PipelineHandler::streamConfiguration()
- * \brief Retrieve a group of stream configurations for a specified camera
+ * \brief Retrieve the streams matching a configurations for a specified camera
  * \param[in] camera The camera to fetch default configuration from
- * \param[in] streams An array of streams to fetch information about
+ * \param[in] config The list of requested stream configurations
  *
- * Retrieve the species camera's default configuration for a specified group of
- * streams. The caller shall populate the \a streams array with the streams it
- * wish to fetch the configuration from. The map of streams and configuration
- * returned can then be examined by the caller to learn about the defualt
- * parameters for the specified streams.
+ * For each provided stream configuration request, retrieve a stream in the
+ * camera that satisfies it and return it with an associated default
+ * configuration.
+ *
+ * The caller shall populate the \a config array with the stream configurations
+ * it wishes to have satisfied, specifying the requested sizes, formats and the
+ * stream's intended usage. The pipeline handler retrieves a stream that matches
+ * the characteristics reported in the configuration and associates it a default
+ * configuration in the returned map.
+ *
+ * The returned map can then be examined by the caller to learn about the
+ * defualt parameters for the returned streams.
  *
  * The intended companion to this is \a configureStreams() which can be used to
- * change the group of streams parameters.
+ * change each stream parameters and have them applied in the Camera.
  *
  * \return A map of successfully retrieved streams and configurations or an
  * empty map on error.
-- 
2.21.0



More information about the libcamera-devel mailing list