[PATCH v13 6/7] libcamera: virtual: Read config and register cameras based on the config
Cheng-Hao Yang
chenghaoyang at chromium.org
Mon Sep 30 08:35:09 CEST 2024
Hi Barnabás,
On Fri, Sep 27, 2024 at 4:25 AM Barnabás Pőcze <pobrn at protonmail.com> wrote:
>
> Hi
>
>
> 2024. szeptember 26., csütörtök 18:29 keltezéssel, Harvey Yang <chenghaoyang at chromium.org> írta:
>
> > This patch introduces the configuration file for Virtual Pipeline
> > Handler. The config file is written in yaml, and the format is
> > documented in `README.md`.
> >
> > The config file will define the camera with IDs, supported formats and
> > image sources, etc. In the default config file, only Test Patterns are
> > used. Developers can use real images loading if desired.
> >
> > Signed-off-by: Konami Shu <konamiz at google.com>
> > Co-developed-by: Harvey Yang <chenghaoyang at chromium.org>
> > Co-developed-by: Yunke Cao <yunkec at chromium.org>
> > Co-developed-by: Tomasz Figa <tfiga at chromium.org>
> > ---
> > [...]
> > +int Parser::parseFrameGenerator(const YamlObject &cameraConfigData, VirtualCameraData *data)
> > +{
> > + const std::string testPatternKey = "test_pattern";
> > + const std::string framesKey = "frames";
> > + if (cameraConfigData.contains(testPatternKey)) {
> > + if (cameraConfigData.contains(framesKey)) {
> > + LOG(Virtual, Error) << "A camera should use either "
> > + << testPatternKey << " or " << framesKey;
> > + return -EINVAL;
> > + }
> > +
> > + auto testPattern = cameraConfigData[testPatternKey].get<std::string>("");
> > +
> > + if (testPattern == "bars") {
> > + data->config_.frame = TestPattern::ColorBars;
> > + } else if (testPattern == "lines") {
> > + data->config_.frame = TestPattern::DiagonalLines;
> > + } else {
> > + LOG(Virtual, Debug) << "Test pattern: " << testPattern
> > + << " is not supported";
> > + return -EINVAL;
> > + }
> > +
> > + return 0;
> > + }
> > +
> > + const YamlObject &frames = cameraConfigData[framesKey];
> > +
> > + /* When there is no frames provided in the config file, use color bar test pattern */
> > + if (!frames) {
> > + data->config_.frame = TestPattern::ColorBars;
> > + return 0;
> > + }
> > +
> > + if (!frames.isDictionary()) {
> > + LOG(Virtual, Error) << "'frames' is not a dictionary.";
> > + return -EINVAL;
> > + }
> > +
> > + auto path = frames["path"].get<std::string>();
> > +
> > + if (!path) {
> > + LOG(Virtual, Error) << "Test pattern or path should be specified.";
> > + return -EINVAL;
> > + } else if (auto ext = std::filesystem::path(*path).extension();
> > + ext == ".jpg" || ext == ".jpeg") {
> > + data->config_.frame = ImageFrames{ *path, std::nullopt };
> > + } else if (std::filesystem::is_directory(std::filesystem::symlink_status(*path))) {
> > + using std::filesystem::directory_iterator;
> > + unsigned int numOfFiles = std::distance(directory_iterator(*path), directory_iterator{});
> > + if (numOfFiles == 0) {
> > + LOG(Virtual, Error) << "Empty directory";
> > + return -EINVAL;
> > + }
> > + data->config_.frame = ImageFrames{ *path, numOfFiles };
> > + } else {
> > + LOG(Virtual, Error) << "Frame: " << *path << " is not supported";
> > + return -EINVAL;
> > + }
> > [...]
>
> I wanted to reflect a bit on this part. I think the `ImageFrames` type can be made
> more easily understandable as follows:
>
> struct ImageFrames {
> std::vector<std::filesystem::path> files;
> };
>
> and then the above part would become something like this:
>
> if (!path) {
> LOG(Virtual, Error) << "Test pattern or path should be specified.";
> return -EINVAL;
> }
>
> std::vector<std::filesystem::path> files;
>
> switch (std::filesystem::symlink_status(*path).type()) {
> case std::filesystem::file_type::regular:
> files.push_back(*path);
> break;
> case std::filesystem::file_type::directory:
> for (const auto& dentry : std::filesystem::directory_iterator { *path })
> if (dentry.is_regular_file())
> files.push_back(dentry.path());
> std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) {
> return ::strverscmp(a.c_str(), b.c_str()) < 0;
> });
> if (files.empty()) {
> LOG(Virtual, Error) << "Directory has no files: " << *path;
> return -EINVAL;
> }
> break;
> default:
> LOG(Virtual, Error) << "Frame: " << *path << " is not supported";
> return -EINVAL;
> }
>
> data->config_.frame = ImageFrames { std::move(files) };
>
> So there would simply be a list of files. I think this is simple, and does not
> need any special code for the "single file" scenario when using an `ImageFrames`
> object.
>
> Note, that the files in the dictionary are sorted using `strverscmp()`, so
> frame-99 should be placed before frame-100, as one would expect.
Yeah this makes sense to me. IIUC, It also allows other file names, instead
of using numbers as the index though.
>
> Also notice that there is no extension checking anymore, as I don't believe
> that to be too useful since it does not guarantee anything, and only jpeg files
> are supported, so whether or not the file can be read will be found out when
> the program tries to load them.
Yeah that's true. Mentioning it in README.md should be enough.
>
> Any thoughts?
Mostly adopted.
Thanks!
Harvey
>
>
> Regards,
> Barnabás Pőcze
More information about the libcamera-devel
mailing list