[PATCH v4 07/11] libcamera: simple: Consider raw output configurations

Barnabás Pőcze barnabas.pocze at ideasonboard.com
Fri May 9 17:46:22 CEST 2025


Hi

2025. 04. 07. 10:56 keltezéssel, Milan Zamazal írta:
> When generating simple pipeline configuration, raw output configurations
> are generated but later filtered out.  Let's include processed and/or
> raw output configurations depending on the requested stream roles.
> 
> Raw and processed formats are handled separately.  The intention is that
> in case both raw and processed formats are requested then the raw
> formats should be left intact to the extent possible and not be
> influenced by the processed formats (implying that raw parameters
> compatible with the processed output requirements must be requested by
> the application).
> 
> Raw output configurations are identified by colorSpace being set to
> ColorSpace::Raw.
> 
> This is another preparatory patch without making raw outputs working.
> 
> Signed-off-by: Milan Zamazal <mzamazal at redhat.com>
> ---
>   src/libcamera/pipeline/simple/simple.cpp | 73 ++++++++++++++++--------
>   1 file changed, 48 insertions(+), 25 deletions(-)
> 
> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
> index bf9d75f4..6b65d79f 100644
> --- a/src/libcamera/pipeline/simple/simple.cpp
> +++ b/src/libcamera/pipeline/simple/simple.cpp
> @@ -439,6 +439,8 @@ private:
>   	const MediaPad *acquirePipeline(SimpleCameraData *data);
>   	void releasePipeline(SimpleCameraData *data);
>   
> +	void setUpFormatSizes(std::map<PixelFormat, std::vector<SizeRange>> &formats);
> +
>   	std::map<const MediaEntity *, EntityData> entities_;
>   
>   	MediaDevice *converter_;
> @@ -1321,35 +1323,28 @@ SimplePipelineHandler::generateConfiguration(Camera *camera, Span<const StreamRo
>   			data->processedRequested_ = true;
>   		}
>   
> -	/* Create the formats map. */
> -	std::map<PixelFormat, std::vector<SizeRange>> formats;
> +	/* Create the formats maps. */
> +	std::map<PixelFormat, std::vector<SizeRange>> processedFormats;
> +	std::map<PixelFormat, std::vector<SizeRange>> rawFormats;
>   
>   	for (const SimpleCameraData::Configuration &cfg : data->configs_)
> -		if (!cfg.raw)
> -			for (PixelFormat format : cfg.outputFormats)
> -				formats[format].push_back(cfg.outputSizes);
> +		for (PixelFormat format : cfg.outputFormats)
> +			(cfg.raw ? rawFormats : processedFormats)[format].push_back(cfg.outputSizes);
>   
> -	/* Sort the sizes and merge any consecutive overlapping ranges. */
> -	for (auto &[format, sizes] : formats) {
> -		std::sort(sizes.begin(), sizes.end(),
> -			  [](SizeRange &a, SizeRange &b) {
> -				  return a.min < b.min;
> -			  });
> -
> -		auto cur = sizes.begin();
> -		auto next = cur;
> -
> -		while (++next != sizes.end()) {
> -			if (cur->max.width >= next->min.width &&
> -			    cur->max.height >= next->min.height)
> -				cur->max = next->max;
> -			else if (++cur != next)
> -				*cur = *next;
> -		}
> -
> -		sizes.erase(++cur, sizes.end());
> +	if (data->processedRequested_ && processedFormats.empty()) {
> +		LOG(SimplePipeline, Error)
> +			<< "Processed stream requsted but no corresponding output configuration found";
> +		return nullptr;
> +	}
> +	if (data->rawRequested_ && rawFormats.empty()) {
> +		LOG(SimplePipeline, Error)
> +			<< "Raw stream requsted but no corresponding output configuration found";
> +		return nullptr;
>   	}
>   
> +	setUpFormatSizes(processedFormats);
> +	setUpFormatSizes(rawFormats);
> +
>   	/*
>   	 * Create the stream configurations. Take the first entry in the formats
>   	 * map as the default, for lack of a better option.
> @@ -1357,11 +1352,13 @@ SimplePipelineHandler::generateConfiguration(Camera *camera, Span<const StreamRo
>   	 * \todo Implement a better way to pick the default format
>   	 */
>   	for (StreamRole role : roles) {
> +		bool raw = (role == StreamRole::Raw);
> +		auto formats = (raw ? rawFormats : processedFormats);
>   		StreamConfiguration cfg{ StreamFormats{ formats } };
>   		cfg.pixelFormat = formats.begin()->first;
>   		cfg.size = formats.begin()->second[0].max;
>   
> -		if (role == StreamRole::Raw)
> +		if (raw)
>   			cfg.colorSpace = ColorSpace::Raw;
>   		else if (data->swIsp_)
>   			cfg.colorSpace = ColorSpace::Srgb;
> @@ -1374,6 +1371,32 @@ SimplePipelineHandler::generateConfiguration(Camera *camera, Span<const StreamRo
>   	return config;
>   }
>   
> +void SimplePipelineHandler::setUpFormatSizes(
> +	std::map<PixelFormat, std::vector<SizeRange>> &formats)

Does this need to be a member? If not, could it be moved into an anonymous
namespace in this file? Or since this is only used in a function, maybe
just save it into a lambda there for now.


> +{
> +	/* Sort the sizes and merge any consecutive overlapping ranges. */

I see that this has been copied unchanged, but I don't understand how this could
be correct. It does not seem to account for `SizeRange::{h,v}Step` at all.
What am I missing something?


Regards,
Barnabás Pőcze

> +
> +	for (auto &[format, sizes] : formats) {
> +		std::sort(sizes.begin(), sizes.end(),
> +			  [](SizeRange &a, SizeRange &b) {
> +				  return a.min < b.min;
> +			  });
> +
> +		auto cur = sizes.begin();
> +		auto next = cur;
> +
> +		while (++next != sizes.end()) {
> +			if (cur->max.width >= next->min.width &&
> +			    cur->max.height >= next->min.height)
> +				cur->max = next->max;
> +			else if (++cur != next)
> +				*cur = *next;
> +		}
> +
> +		sizes.erase(++cur, sizes.end());
> +	}
> +}
> +
>   int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
>   {
>   	SimpleCameraConfiguration *config =



More information about the libcamera-devel mailing list