Message ID | 20250711175345.90318-5-mzamazal@redhat.com |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
Hi Milan On Fri, Jul 11, 2025 at 07:53:37PM +0200, Milan Zamazal wrote: > Let's handle both processed and/or raw output configurations, depending > on the requested stream roles. In addition to the already handled > processed formats and sizes, this patch adds handling of raw formats and > sizes, which correspond to the capture formats and sizes. > > 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). > > Accompanying checks for invalid role specifications are introduced. > > This is another preparatory patch without making raw outputs working. > > Signed-off-by: Milan Zamazal <mzamazal@redhat.com> > --- > src/libcamera/pipeline/simple/simple.cpp | 80 +++++++++++++++++------- > 1 file changed, 57 insertions(+), 23 deletions(-) > > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp > index 87b26d4a2..37abaa0e0 100644 > --- a/src/libcamera/pipeline/simple/simple.cpp > +++ b/src/libcamera/pipeline/simple/simple.cpp > @@ -1310,35 +1310,67 @@ SimplePipelineHandler::generateConfiguration(Camera *camera, Span<const StreamRo > if (roles.empty()) > return config; > > - /* Create the formats map. */ > - std::map<PixelFormat, std::vector<SizeRange>> formats; > + bool processedRequested = false; > + bool rawRequested = false; > + for (const auto &role : roles) > + if (role == StreamRole::Raw) { > + if (rawRequested) { > + LOG(SimplePipeline, Error) > + << "Can't capture multiple raw streams"; > + return nullptr; > + } > + rawRequested = true; > + } else { > + processedRequested = true; > + } > + > + /* 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_) { You can simply try to iterate over data->formats_ data->formats_ contain both raw and processed formats already, so we can populate the local formats map from that. > + rawFormats[cfg.captureFormat].push_back(cfg.captureSize); > for (PixelFormat format : cfg.outputFormats) > - formats[format].push_back(cfg.outputSizes); > + 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 (processedRequested && processedFormats.empty()) { > + LOG(SimplePipeline, Error) > + << "Processed stream requsted but no corresponding output configuration found"; > + return nullptr; > + } > + if (rawRequested && rawFormats.empty()) { > + LOG(SimplePipeline, Error) > + << "Raw stream requsted but no corresponding output configuration found"; > + return nullptr; > } You can simply keep one formats map locally. No need to split between the raw and processed. Depending on the role requested, you can simply pick appropriate configurations from the formats map. > > + auto setUpFormatSizes = [](std::map<PixelFormat, std::vector<SizeRange>> &formats) { > + /* 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()); > + } > + }; > + 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. > @@ -1346,11 +1378,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); > + const 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) { > /* Enforce raw colour space for raw roles. */ > cfg.colorSpace = ColorSpace::Raw; > } else if (data->swIsp_) { What I have done is the following: for (StreamRole role : roles) { StreamConfiguration cfg{ StreamFormats{ formats } }; switch (role) { case StreamRole::Raw: for (auto &[format, sizes] : formats) { if (!isFormatRaw(format)) continue; cfg.pixelFormat = format; cfg.size = sizes.back().max; cfg.colorSpace = ColorSpace::Raw; break; } break; default: for (auto &[format, sizes] : formats) { if (isFormatRaw(format)) continue; cfg.pixelFormat = format; cfg.size = sizes[0].max; } } config->addConfiguration(cfg); } I have `formats` which contain both the RAW and processed formats (populated from data->formats_). Hence in this loop, I simply pick up the first entry - which would satisfy the role. > -- > 2.50.1 >
Hi Umang, Umang Jain <uajain@igalia.com> writes: > Hi Milan > > On Fri, Jul 11, 2025 at 07:53:37PM +0200, Milan Zamazal wrote: >> Let's handle both processed and/or raw output configurations, depending >> on the requested stream roles. In addition to the already handled >> processed formats and sizes, this patch adds handling of raw formats and >> sizes, which correspond to the capture formats and sizes. >> >> 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). >> >> Accompanying checks for invalid role specifications are introduced. >> >> This is another preparatory patch without making raw outputs working. >> >> Signed-off-by: Milan Zamazal <mzamazal@redhat.com> >> --- >> src/libcamera/pipeline/simple/simple.cpp | 80 +++++++++++++++++------- >> 1 file changed, 57 insertions(+), 23 deletions(-) >> >> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp >> index 87b26d4a2..37abaa0e0 100644 >> --- a/src/libcamera/pipeline/simple/simple.cpp >> +++ b/src/libcamera/pipeline/simple/simple.cpp >> @@ -1310,35 +1310,67 @@ SimplePipelineHandler::generateConfiguration(Camera *camera, Span<const StreamRo >> if (roles.empty()) >> return config; >> >> - /* Create the formats map. */ >> - std::map<PixelFormat, std::vector<SizeRange>> formats; >> + bool processedRequested = false; >> + bool rawRequested = false; >> + for (const auto &role : roles) >> + if (role == StreamRole::Raw) { >> + if (rawRequested) { >> + LOG(SimplePipeline, Error) >> + << "Can't capture multiple raw streams"; >> + return nullptr; >> + } >> + rawRequested = true; >> + } else { >> + processedRequested = true; >> + } >> + >> + /* 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_) { > > You can simply try to iterate over data->formats_ > data->formats_ contain both raw and processed formats already, so we can > populate the local formats map from that. > >> + rawFormats[cfg.captureFormat].push_back(cfg.captureSize); >> for (PixelFormat format : cfg.outputFormats) >> - formats[format].push_back(cfg.outputSizes); >> + 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 (processedRequested && processedFormats.empty()) { >> + LOG(SimplePipeline, Error) >> + << "Processed stream requsted but no corresponding output configuration found"; >> + return nullptr; >> + } >> + if (rawRequested && rawFormats.empty()) { >> + LOG(SimplePipeline, Error) >> + << "Raw stream requsted but no corresponding output configuration found"; >> + return nullptr; >> } > > You can simply keep one formats map locally. No need to split between > the raw and processed. Depending on the role requested, you can simply > pick appropriate configurations from the formats map. I'm not sure this is correct. I'd think that if a raw role is requested, it means an unprocessed input from the camera. Which may or may not be a format for which isFormatRaw returns true. And a processed output can, at least in theory, produce a format for which isFormatRaw returns true. >> >> + auto setUpFormatSizes = [](std::map<PixelFormat, std::vector<SizeRange>> &formats) { >> + /* 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()); >> + } >> + }; >> + 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. >> @@ -1346,11 +1378,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); >> + const 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) { >> /* Enforce raw colour space for raw roles. */ >> cfg.colorSpace = ColorSpace::Raw; >> } else if (data->swIsp_) { > > What I have done is the following: > > for (StreamRole role : roles) { > StreamConfiguration cfg{ StreamFormats{ formats } }; > > switch (role) { > case StreamRole::Raw: > for (auto &[format, sizes] : formats) { > if (!isFormatRaw(format)) > continue; > cfg.pixelFormat = format; > cfg.size = sizes.back().max; > cfg.colorSpace = ColorSpace::Raw; > break; > } > break; > default: > for (auto &[format, sizes] : formats) { > if (isFormatRaw(format)) > continue; > cfg.pixelFormat = format; > cfg.size = sizes[0].max; > } > } > > config->addConfiguration(cfg); > } > > I have `formats` which contain both the RAW and processed formats > (populated from data->formats_). Hence in this loop, I simply pick up > the first entry - which would satisfy the role. > >> -- >> 2.50.1 >>
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 87b26d4a2..37abaa0e0 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -1310,35 +1310,67 @@ SimplePipelineHandler::generateConfiguration(Camera *camera, Span<const StreamRo if (roles.empty()) return config; - /* Create the formats map. */ - std::map<PixelFormat, std::vector<SizeRange>> formats; + bool processedRequested = false; + bool rawRequested = false; + for (const auto &role : roles) + if (role == StreamRole::Raw) { + if (rawRequested) { + LOG(SimplePipeline, Error) + << "Can't capture multiple raw streams"; + return nullptr; + } + rawRequested = true; + } else { + processedRequested = true; + } + + /* 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_) { + rawFormats[cfg.captureFormat].push_back(cfg.captureSize); for (PixelFormat format : cfg.outputFormats) - formats[format].push_back(cfg.outputSizes); + 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 (processedRequested && processedFormats.empty()) { + LOG(SimplePipeline, Error) + << "Processed stream requsted but no corresponding output configuration found"; + return nullptr; + } + if (rawRequested && rawFormats.empty()) { + LOG(SimplePipeline, Error) + << "Raw stream requsted but no corresponding output configuration found"; + return nullptr; } + auto setUpFormatSizes = [](std::map<PixelFormat, std::vector<SizeRange>> &formats) { + /* 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()); + } + }; + 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. @@ -1346,11 +1378,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); + const 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) { /* Enforce raw colour space for raw roles. */ cfg.colorSpace = ColorSpace::Raw; } else if (data->swIsp_) {
Let's handle both processed and/or raw output configurations, depending on the requested stream roles. In addition to the already handled processed formats and sizes, this patch adds handling of raw formats and sizes, which correspond to the capture formats and sizes. 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). Accompanying checks for invalid role specifications are introduced. This is another preparatory patch without making raw outputs working. Signed-off-by: Milan Zamazal <mzamazal@redhat.com> --- src/libcamera/pipeline/simple/simple.cpp | 80 +++++++++++++++++------- 1 file changed, 57 insertions(+), 23 deletions(-)