[PATCH v4 07/11] libcamera: simple: Consider raw output configurations
Milan Zamazal
mzamazal at redhat.com
Tue May 13 12:31:02 CEST 2025
Hi Barnabás,
thank you for review.
Barnabás Pőcze <barnabas.pocze at ideasonboard.com> writes:
> 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.
Or it could be a loop over the two variables. I don't have any real
preference, I can do whatever reviewers like.
>> +{
>> + /* 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?
It's probably some implicit assumption about the steps, whether correct
or not. Perhaps this and the followup \todo should be revised some day.
> 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