Message ID | 20190527001543.13593-12-niklas.soderlund@ragnatech.se |
---|---|
State | Superseded |
Headers | show |
Series |
|
Related | show |
Hi Niklas, On 27/05/2019 01:15, Niklas Söderlund wrote: > Add a StreamFormats which describes all the formats a stream can > support. The object does not collect any formation itself but can > simplify users interaction with formats as it's able to translate a > stream format range into discrete list and a discrete list to a range. > > Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> > --- > include/libcamera/stream.h | 16 +++ > src/libcamera/stream.cpp | 216 +++++++++++++++++++++++++++++++++++++ > 2 files changed, 232 insertions(+) > > diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h > index e38c0e7e827d5888..48daf5ac23f55d85 100644 > --- a/include/libcamera/stream.h > +++ b/include/libcamera/stream.h > @@ -7,6 +7,7 @@ > #ifndef __LIBCAMERA_STREAM_H__ > #define __LIBCAMERA_STREAM_H__ > > +#include <map> > #include <string> > #include <vector> > > @@ -18,6 +19,21 @@ namespace libcamera { > class Camera; > class Stream; > > +class StreamFormats > +{ > +public: > + StreamFormats(); > + StreamFormats(const std::map<unsigned int, std::vector<SizeRange>> &formats); > + > + std::vector<unsigned int> pixelformats() const; > + std::vector<Size> sizes(unsigned int pixelformat) const; > + > + SizeRange range(unsigned int pixelformat) const; > + > +private: > + std::map<unsigned int, std::vector<SizeRange>> formats_; > +}; > + > struct StreamConfiguration { > StreamConfiguration() > : stream_(nullptr) > diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp > index eecd37160150d55c..a2931902fda2baa5 100644 > --- a/src/libcamera/stream.cpp > +++ b/src/libcamera/stream.cpp > @@ -7,6 +7,7 @@ > > #include <libcamera/stream.h> > > +#include <algorithm> > #include <iomanip> > #include <sstream> > > @@ -36,6 +37,221 @@ namespace libcamera { > > LOG_DEFINE_CATEGORY(Stream) > > +/** > + * \class StreamFormats > + * \brief Hold information about supported stream formats > + * > + * The StreamFormats class holds information about pixel formats and frame /about pixel formats/about the pixel formats/ > + * sizes a stream supports. The class groups size information by the pixel > + * format which can produce it. There are two ways to examine the size > + * information, as a range or as a list of discrete sizes. > + * > + * When sizes are viewed as a range it describes the minimum and maximum width > + * and height values. There is a possibility to supplement the range description > + * with a horizontal och vertical stepping size. The stepping size describes the /och/and/ ? > + * step size in pixel from the minimum with/height. /in pixel/in pixels/ > + * > + * When sizes is viewed as a list of discrete sizes it describes exact dimensions When sizes are viewed... ... they describe exact ... > + * which can be selected and used. > + * > + * Pipeline handlers can create StreamFormats describing each pixel format using > + * either a range or a list of discrete sizes. The StreamFormats class attempts /of discrete/of discrete/ <remove extra space> > + * to translates between the two different ways to view them. The translations /translates/translate/ > + * are performed as: > + * > + * - If a pixel format is described as a list of discrete sizes a range is ... of discrete sizes then a range .... > + * created by taking the minim and maximum width/height in the list. /minim/minimum/ > + * The stepping information is not recreated and set to 1. ... and is set to 1. > + * > + * - If a pixel format is described as a range a list of discrete sizes which ... as a range then a list of ... > + * fits inside that range are selected from a list of common sizes. The > + * stepping information is taken into consideration when generating the > + * sizes. > + * > + * Applications examining sizes as a range with stepping values of 1 should be > + * aware that the range could be generated form a list of discrete sizes and /form/from/ > + * there could be big gaps in the range to what the stream can support. ... there could be a large quantity of possible Size combinations which may not be supported by the Stream. Could we set the stepping size to '-1' or '0' or something here to identify that the range is really only specifying the maximum, and minimum width/height ? > + * > + * All sizes retrieved from StreamFormats should be treated as advisory and no > + * size should be considered to be supported until its been verified using > + * CameraConfiguration::validate(). > + */ > + > +/** > + * \brief Construct a empty StreamFormats object > + */ > +StreamFormats::StreamFormats() > +{ > +} > + > +/** > + * \brief Construct a StreamFormats object > + * \param[in] formats A map of pixel formats to a sizes description > + */ > +StreamFormats::StreamFormats(const std::map<unsigned int, std::vector<SizeRange>> &formats) > + : formats_(formats) > +{ > +} > + > +/** > + * \brief Retrieve the list of pixel formats supported > + * \returns List of pixel formats > + */ > +std::vector<unsigned int> StreamFormats::pixelformats() const > +{ > + std::vector<unsigned int> formats; > + > + for (auto const &it : formats_) > + formats.push_back(it.first); > + > + return formats; > +} > + > +/** > + * \brief Retrieve the list of frame sizes > + * \param[in] pixelformat Pixel format to retrieve sizes for > + * \returns List description of frame sizes > + */ > +std::vector<Size> StreamFormats::sizes(unsigned int pixelformat) const > +{ > + /* > + * Sizes to try and extract from ranges. > + * \todo Verify list of resolutions are good, current list compiled > + * from v4l2 documentation and source code as well as lists of > + * common frame sizes. > + */ > + static const std::vector<Size> rangeDiscreteSizes = { > + Size(160, 120), > + Size(240, 160), > + Size(320, 240), > + Size(400, 240), > + Size(480, 320), > + Size(640, 360), > + Size(640, 480), > + Size(720, 480), > + Size(720, 576), > + Size(768, 480), > + Size(800, 600), > + Size(854, 480), > + Size(960, 540), > + Size(960, 640), > + Size(1024, 576), > + Size(1024, 600), > + Size(1024, 768), > + Size(1152, 864), > + Size(1280, 1024), > + Size(1280, 1080), > + Size(1280, 720), > + Size(1280, 800), > + Size(1360, 768), > + Size(1366, 768), > + Size(1400, 1050), > + Size(1440, 900), > + Size(1536, 864), > + Size(1600, 1200), > + Size(1600, 900), > + Size(1680, 1050), > + Size(1920, 1080), > + Size(1920, 1200), > + Size(2048, 1080), > + Size(2048, 1152), > + Size(2048, 1536), > + Size(2160, 1080), > + Size(2560, 1080), > + Size(2560, 1440), > + Size(2560, 1600), > + Size(2560, 2048), > + Size(2960, 1440), > + Size(3200, 1800), > + Size(3200, 2048), > + Size(3200, 2400), > + Size(3440, 1440), > + Size(3840, 1080), > + Size(3840, 1600), > + Size(3840, 2160), > + Size(3840, 2400), > + Size(4096, 2160), > + Size(5120, 2160), > + Size(5120, 2880), > + Size(7680, 4320), I still wonder if we could generate this data table in a better form. For a start, perhaps it might be worth grouping common Sizes to a single line to form a table based on their ratios? That would show what ratios are included maybe? (perhaps we could generate each ratio from a single width or height instead?) /* 4:3 16:9 16:10 */ Size(1600, 1200), Size(1600, 900), Size(1680, 1050), Size(1920, 1080), Size(1920, 1200), /* 2:1 2:1 ish again? 4:3 */ Size(2048, 1080), Size(2048, 1152), Size(2048, 1536), If you did look at doing this, I'd move the table outside of the function so that it's indent is reduced. > + }; > + std::vector<Size> sizes; > + > + /* Make sure pixel format exists. */ > + auto const &it = formats_.find(pixelformat); > + if (it == formats_.end()) > + return {}; > + > + /* Try create list of discrete sizes. */ > + const std::vector<SizeRange> &ranges = it->second; > + bool discrete = true; > + for (const SizeRange &range : ranges) { > + if (range.min != range.max) { > + discrete = false; > + break; > + } > + sizes.emplace_back(range.min.width, range.min.height); > + } > + > + /* If discrete not possible generate from range. */ > + if (!discrete) { > + if (ranges.size() != 1) { > + LOG(Stream, Error) << "Range format is ambiguous"; > + return {}; > + } > + > + const SizeRange &limit = ranges.front(); > + sizes.clear(); > + > + for (const Size &size : rangeDiscreteSizes) { > + if (size.width < limit.min.width || > + size.width > limit.max.width || > + size.height < limit.min.height || > + size.height > limit.max.height || > + (size.width - limit.min.width) % limit.vStep || > + (size.height - limit.min.height) % limit.hStep) > + continue; > + > + sizes.push_back(size); > + } > + } > + > + std::sort(sizes.begin(), sizes.end()); > + > + return sizes; > +} > + > +/** > + * \brief Retrieve a frame size range > + * \param[in] pixelformat Pixel format to retrieve range for > + * \returns Range description of frame size > + */ > +SizeRange StreamFormats::range(unsigned int pixelformat) const > +{ > + auto const it = formats_.find(pixelformat); > + if (it == formats_.end()) > + return {}; > + > + const SizeRange &first = it->second.front(); > + if (it->second.size() == 1) > + return first; There's a lot of mixing of 'first' and 'second' here which is a bit awkward for comprehension.... > + > + LOG(Stream, Debug) << "Building range from discret"; /discret/discrete/ > + > + SizeRange range(first.min.width, first.min.height, > + first.max.width, first.max.height); > + > + for (const SizeRange &limit : it->second) { > + if (limit.min < range.min) > + range.min = limit.min; > + > + if (limit.max > range.max) > + range.max = limit.max; > + } > + > + return range; > +} > + > /** > * \struct StreamConfiguration > * \brief Configuration parameters for a stream >
Hi Niklas, On Wed, May 29, 2019 at 11:22:51PM +0100, Kieran Bingham wrote: > On 27/05/2019 01:15, Niklas Söderlund wrote: > > Add a StreamFormats which describes all the formats a stream can s/StreamFormats/StreamFormats class/ > > support. The object does not collect any formation itself but can > > simplify users interaction with formats as it's able to translate a s/users interaction/user interactions/ > > stream format range into discrete list and a discrete list to a range. > > > > Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> > > --- > > include/libcamera/stream.h | 16 +++ > > src/libcamera/stream.cpp | 216 +++++++++++++++++++++++++++++++++++++ > > 2 files changed, 232 insertions(+) > > > > diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h > > index e38c0e7e827d5888..48daf5ac23f55d85 100644 > > --- a/include/libcamera/stream.h > > +++ b/include/libcamera/stream.h > > @@ -7,6 +7,7 @@ > > #ifndef __LIBCAMERA_STREAM_H__ > > #define __LIBCAMERA_STREAM_H__ > > > > +#include <map> > > #include <string> > > #include <vector> > > > > @@ -18,6 +19,21 @@ namespace libcamera { > > class Camera; > > class Stream; > > > > +class StreamFormats > > +{ > > +public: > > + StreamFormats(); > > + StreamFormats(const std::map<unsigned int, std::vector<SizeRange>> &formats); > > + > > + std::vector<unsigned int> pixelformats() const; For efficiency reasons, do you think it would make sense to cache the pixel formats vector the first time it is computed and return a const reference to the cached copy ? Or do you expect applications to typically retrieve the pixel formats once only ? > > + std::vector<Size> sizes(unsigned int pixelformat) const; Same question for the sizes and ranges. > > + > > + SizeRange range(unsigned int pixelformat) const; > > + > > +private: > > + std::map<unsigned int, std::vector<SizeRange>> formats_; > > +}; > > + > > struct StreamConfiguration { > > StreamConfiguration() > > : stream_(nullptr) > > diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp > > index eecd37160150d55c..a2931902fda2baa5 100644 > > --- a/src/libcamera/stream.cpp > > +++ b/src/libcamera/stream.cpp > > @@ -7,6 +7,7 @@ > > > > #include <libcamera/stream.h> > > > > +#include <algorithm> > > #include <iomanip> > > #include <sstream> > > > > @@ -36,6 +37,221 @@ namespace libcamera { > > > > LOG_DEFINE_CATEGORY(Stream) > > > > +/** > > + * \class StreamFormats > > + * \brief Hold information about supported stream formats > > + * > > + * The StreamFormats class holds information about pixel formats and frame > > /about pixel formats/about the pixel formats/ > > > + * sizes a stream supports. The class groups size information by the pixel > > + * format which can produce it. There are two ways to examine the size > > + * information, as a range or as a list of discrete sizes. > > + * I would start a new paragraph before the lest sentence, and remove this blank line, as the last sentence and the text beflow are related. > > + * When sizes are viewed as a range it describes the minimum and maximum width > > + * and height values. There is a possibility to supplement the range description > > + * with a horizontal och vertical stepping size. The stepping size describes the > > /och/and/ ? > > > > + * step size in pixel from the minimum with/height. > > /in pixel/in pixels/ > > > + * > > + * When sizes is viewed as a list of discrete sizes it describes exact dimensions > > When sizes are viewed... ... they describe exact ... > > > + * which can be selected and used. > > + * > > + * Pipeline handlers can create StreamFormats describing each pixel format using > > + * either a range or a list of discrete sizes. The StreamFormats class attempts > > /of discrete/of discrete/ <remove extra space> > > > + * to translates between the two different ways to view them. The translations > > /translates/translate/ > > > + * are performed as: > > + * > > + * - If a pixel format is described as a list of discrete sizes a range is > > ... of discrete sizes then a range .... > > > + * created by taking the minim and maximum width/height in the list. > > /minim/minimum/ > > > + * The stepping information is not recreated and set to 1. > > ... and is set to 1. > > > > + * > > + * - If a pixel format is described as a range a list of discrete sizes which > > ... as a range then a list of ... > > > + * fits inside that range are selected from a list of common sizes. The > > + * stepping information is taken into consideration when generating the > > + * sizes. > > + * > > + * Applications examining sizes as a range with stepping values of 1 should be > > + * aware that the range could be generated form a list of discrete sizes and > > /form/from/ > > > + * there could be big gaps in the range to what the stream can support. > > ... there could be a large quantity of possible Size combinations which > may not be supported by the Stream. > > > Could we set the stepping size to '-1' or '0' or something here to > identify that the range is really only specifying the maximum, and > minimum width/height ? I think it would be indeed be useful for an application to determine if the range is continuous, or just exposes the minimum and maximum with the stream only supported discrete resolutions. Setting the step to 0 would be one way of doing so. It should then be clearly documented. We should also evaluate the impact on applications, and find a better API if it gets too awkward or error-prone to use. > > + * > > + * All sizes retrieved from StreamFormats should be treated as advisory and no > > + * size should be considered to be supported until its been verified using > > + * CameraConfiguration::validate(). s/should/shall/g We should also take care of not returning sizes that are not supported. I think the current implementation is good enough for now, if a pipeline handler has requirements more complex than a continuous range with a step, it should likely provide a list of discrete sizes explicitly. However, we may want to revisit this later, possibly to add a helper for pipeline handlers that can handle more complex constraints. When we will do so it may make sense to move the logic that constructs the sizes based on the standard discrete sizes to a separate function, outside of the StreamFormats class. > > + */ > > + > > +/** > > + * \brief Construct a empty StreamFormats object > > + */ > > +StreamFormats::StreamFormats() > > +{ > > +} > > + > > +/** > > + * \brief Construct a StreamFormats object > > + * \param[in] formats A map of pixel formats to a sizes description > > + */ > > +StreamFormats::StreamFormats(const std::map<unsigned int, std::vector<SizeRange>> &formats) > > + : formats_(formats) > > +{ > > +} > > + > > +/** > > + * \brief Retrieve the list of pixel formats supported s/pixel formats supported/supported pixel formats/ > > + * \returns List of pixel formats The list of supported pixel formats > > + */ > > +std::vector<unsigned int> StreamFormats::pixelformats() const > > +{ > > + std::vector<unsigned int> formats; > > + > > + for (auto const &it : formats_) > > + formats.push_back(it.first); > > + > > + return formats; > > +} > > + > > +/** > > + * \brief Retrieve the list of frame sizes > > + * \param[in] pixelformat Pixel format to retrieve sizes for > > + * \returns List description of frame sizes > > + */ It would be useful to extend the documentation to explain that sizes are computed (and how) if the device supports a continuous range. > > +std::vector<Size> StreamFormats::sizes(unsigned int pixelformat) const > > +{ > > + /* > > + * Sizes to try and extract from ranges. > > + * \todo Verify list of resolutions are good, current list compiled > > + * from v4l2 documentation and source code as well as lists of > > + * common frame sizes. > > + */ > > + static const std::vector<Size> rangeDiscreteSizes = { > > + Size(160, 120), > > + Size(240, 160), > > + Size(320, 240), > > + Size(400, 240), > > + Size(480, 320), > > + Size(640, 360), > > + Size(640, 480), > > + Size(720, 480), > > + Size(720, 576), > > + Size(768, 480), > > + Size(800, 600), > > + Size(854, 480), > > + Size(960, 540), > > + Size(960, 640), > > + Size(1024, 576), > > + Size(1024, 600), > > + Size(1024, 768), > > + Size(1152, 864), > > + Size(1280, 1024), > > + Size(1280, 1080), > > + Size(1280, 720), > > + Size(1280, 800), > > + Size(1360, 768), > > + Size(1366, 768), > > + Size(1400, 1050), > > + Size(1440, 900), > > + Size(1536, 864), > > + Size(1600, 1200), > > + Size(1600, 900), > > + Size(1680, 1050), > > + Size(1920, 1080), > > + Size(1920, 1200), > > + Size(2048, 1080), > > + Size(2048, 1152), > > + Size(2048, 1536), > > + Size(2160, 1080), > > + Size(2560, 1080), > > + Size(2560, 1440), > > + Size(2560, 1600), > > + Size(2560, 2048), > > + Size(2960, 1440), > > + Size(3200, 1800), > > + Size(3200, 2048), > > + Size(3200, 2400), > > + Size(3440, 1440), > > + Size(3840, 1080), > > + Size(3840, 1600), > > + Size(3840, 2160), > > + Size(3840, 2400), > > + Size(4096, 2160), > > + Size(5120, 2160), > > + Size(5120, 2880), > > + Size(7680, 4320), > > I still wonder if we could generate this data table in a better form. > > For a start, perhaps it might be worth grouping common Sizes to a single > line to form a table based on their ratios? That would show what ratios > are included maybe? > > (perhaps we could generate each ratio from a single width or height > instead?) > > /* 4:3 16:9 16:10 */ > > Size(1600, 1200), Size(1600, 900), Size(1680, 1050), > Size(1920, 1080), Size(1920, 1200), > > /* 2:1 2:1 ish again? 4:3 */ > Size(2048, 1080), Size(2048, 1152), Size(2048, 1536), > > > If you did look at doing this, I'd move the table outside of the > function so that it's indent is reduced. > > > + }; > > + std::vector<Size> sizes; > > + > > + /* Make sure pixel format exists. */ > > + auto const &it = formats_.find(pixelformat); > > + if (it == formats_.end()) > > + return {}; > > + > > + /* Try create list of discrete sizes. */ s/create/creating a/ > > + const std::vector<SizeRange> &ranges = it->second; > > + bool discrete = true; > > + for (const SizeRange &range : ranges) { > > + if (range.min != range.max) { > > + discrete = false; > > + break; > > + } > > + sizes.emplace_back(range.min.width, range.min.height); sizes.emplace_back(range.min); > > + } > > + > > + /* If discrete not possible generate from range. */ > > + if (!discrete) { > > + if (ranges.size() != 1) { > > + LOG(Stream, Error) << "Range format is ambiguous"; > > + return {}; > > + } > > + > > + const SizeRange &limit = ranges.front(); > > + sizes.clear(); > > + > > + for (const Size &size : rangeDiscreteSizes) { > > + if (size.width < limit.min.width || > > + size.width > limit.max.width || > > + size.height < limit.min.height || > > + size.height > limit.max.height || Would it make sense to add a bool SizeRange::contains(const Size &size) method ? > > + (size.width - limit.min.width) % limit.vStep || > > + (size.height - limit.min.height) % limit.hStep) > > + continue; > > + > > + sizes.push_back(size); > > + } > > + } > > + > > + std::sort(sizes.begin(), sizes.end()); > > + > > + return sizes; > > +} > > + > > +/** > > + * \brief Retrieve a frame size range > > + * \param[in] pixelformat Pixel format to retrieve range for > > + * \returns Range description of frame size It would be useful to extend the documentation to explain what the range represents and how it can be used (in particular that not all sizes within the range are necessarily supported by the stream). > > + */ > > +SizeRange StreamFormats::range(unsigned int pixelformat) const > > +{ > > + auto const it = formats_.find(pixelformat); > > + if (it == formats_.end()) > > + return {}; > > + > > + const SizeRange &first = it->second.front(); > > + if (it->second.size() == 1) > > + return first; > > There's a lot of mixing of 'first' and 'second' here which is a bit > awkward for comprehension.... You could write it as const std::vector<SizeRange> &ranges = it->second; if (ranges.size() == 1) return ranges[0]; > > + > > + LOG(Stream, Debug) << "Building range from discret"; > > /discret/discrete/ > > > + > > + SizeRange range(first.min.width, first.min.height, > > + first.max.width, first.max.height); Feel free to add a SizeRange(const Size &min, const Size &max) constructor if you think it would be useful. You can also initialise range to (UINT_MAX, UINT_MAX, 0, 0). > > + > > + for (const SizeRange &limit : it->second) { > > + if (limit.min < range.min) > > + range.min = limit.min; > > + > > + if (limit.max > range.max) > > + range.max = limit.max; > > + } > > + > > + return range; > > +} > > + > > /** > > * \struct StreamConfiguration > > * \brief Configuration parameters for a stream
diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index e38c0e7e827d5888..48daf5ac23f55d85 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -7,6 +7,7 @@ #ifndef __LIBCAMERA_STREAM_H__ #define __LIBCAMERA_STREAM_H__ +#include <map> #include <string> #include <vector> @@ -18,6 +19,21 @@ namespace libcamera { class Camera; class Stream; +class StreamFormats +{ +public: + StreamFormats(); + StreamFormats(const std::map<unsigned int, std::vector<SizeRange>> &formats); + + std::vector<unsigned int> pixelformats() const; + std::vector<Size> sizes(unsigned int pixelformat) const; + + SizeRange range(unsigned int pixelformat) const; + +private: + std::map<unsigned int, std::vector<SizeRange>> formats_; +}; + struct StreamConfiguration { StreamConfiguration() : stream_(nullptr) diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index eecd37160150d55c..a2931902fda2baa5 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -7,6 +7,7 @@ #include <libcamera/stream.h> +#include <algorithm> #include <iomanip> #include <sstream> @@ -36,6 +37,221 @@ namespace libcamera { LOG_DEFINE_CATEGORY(Stream) +/** + * \class StreamFormats + * \brief Hold information about supported stream formats + * + * The StreamFormats class holds information about pixel formats and frame + * sizes a stream supports. The class groups size information by the pixel + * format which can produce it. There are two ways to examine the size + * information, as a range or as a list of discrete sizes. + * + * When sizes are viewed as a range it describes the minimum and maximum width + * and height values. There is a possibility to supplement the range description + * with a horizontal och vertical stepping size. The stepping size describes the + * step size in pixel from the minimum with/height. + * + * When sizes is viewed as a list of discrete sizes it describes exact dimensions + * which can be selected and used. + * + * Pipeline handlers can create StreamFormats describing each pixel format using + * either a range or a list of discrete sizes. The StreamFormats class attempts + * to translates between the two different ways to view them. The translations + * are performed as: + * + * - If a pixel format is described as a list of discrete sizes a range is + * created by taking the minim and maximum width/height in the list. + * The stepping information is not recreated and set to 1. + * + * - If a pixel format is described as a range a list of discrete sizes which + * fits inside that range are selected from a list of common sizes. The + * stepping information is taken into consideration when generating the + * sizes. + * + * Applications examining sizes as a range with stepping values of 1 should be + * aware that the range could be generated form a list of discrete sizes and + * there could be big gaps in the range to what the stream can support. + * + * All sizes retrieved from StreamFormats should be treated as advisory and no + * size should be considered to be supported until its been verified using + * CameraConfiguration::validate(). + */ + +/** + * \brief Construct a empty StreamFormats object + */ +StreamFormats::StreamFormats() +{ +} + +/** + * \brief Construct a StreamFormats object + * \param[in] formats A map of pixel formats to a sizes description + */ +StreamFormats::StreamFormats(const std::map<unsigned int, std::vector<SizeRange>> &formats) + : formats_(formats) +{ +} + +/** + * \brief Retrieve the list of pixel formats supported + * \returns List of pixel formats + */ +std::vector<unsigned int> StreamFormats::pixelformats() const +{ + std::vector<unsigned int> formats; + + for (auto const &it : formats_) + formats.push_back(it.first); + + return formats; +} + +/** + * \brief Retrieve the list of frame sizes + * \param[in] pixelformat Pixel format to retrieve sizes for + * \returns List description of frame sizes + */ +std::vector<Size> StreamFormats::sizes(unsigned int pixelformat) const +{ + /* + * Sizes to try and extract from ranges. + * \todo Verify list of resolutions are good, current list compiled + * from v4l2 documentation and source code as well as lists of + * common frame sizes. + */ + static const std::vector<Size> rangeDiscreteSizes = { + Size(160, 120), + Size(240, 160), + Size(320, 240), + Size(400, 240), + Size(480, 320), + Size(640, 360), + Size(640, 480), + Size(720, 480), + Size(720, 576), + Size(768, 480), + Size(800, 600), + Size(854, 480), + Size(960, 540), + Size(960, 640), + Size(1024, 576), + Size(1024, 600), + Size(1024, 768), + Size(1152, 864), + Size(1280, 1024), + Size(1280, 1080), + Size(1280, 720), + Size(1280, 800), + Size(1360, 768), + Size(1366, 768), + Size(1400, 1050), + Size(1440, 900), + Size(1536, 864), + Size(1600, 1200), + Size(1600, 900), + Size(1680, 1050), + Size(1920, 1080), + Size(1920, 1200), + Size(2048, 1080), + Size(2048, 1152), + Size(2048, 1536), + Size(2160, 1080), + Size(2560, 1080), + Size(2560, 1440), + Size(2560, 1600), + Size(2560, 2048), + Size(2960, 1440), + Size(3200, 1800), + Size(3200, 2048), + Size(3200, 2400), + Size(3440, 1440), + Size(3840, 1080), + Size(3840, 1600), + Size(3840, 2160), + Size(3840, 2400), + Size(4096, 2160), + Size(5120, 2160), + Size(5120, 2880), + Size(7680, 4320), + }; + std::vector<Size> sizes; + + /* Make sure pixel format exists. */ + auto const &it = formats_.find(pixelformat); + if (it == formats_.end()) + return {}; + + /* Try create list of discrete sizes. */ + const std::vector<SizeRange> &ranges = it->second; + bool discrete = true; + for (const SizeRange &range : ranges) { + if (range.min != range.max) { + discrete = false; + break; + } + sizes.emplace_back(range.min.width, range.min.height); + } + + /* If discrete not possible generate from range. */ + if (!discrete) { + if (ranges.size() != 1) { + LOG(Stream, Error) << "Range format is ambiguous"; + return {}; + } + + const SizeRange &limit = ranges.front(); + sizes.clear(); + + for (const Size &size : rangeDiscreteSizes) { + if (size.width < limit.min.width || + size.width > limit.max.width || + size.height < limit.min.height || + size.height > limit.max.height || + (size.width - limit.min.width) % limit.vStep || + (size.height - limit.min.height) % limit.hStep) + continue; + + sizes.push_back(size); + } + } + + std::sort(sizes.begin(), sizes.end()); + + return sizes; +} + +/** + * \brief Retrieve a frame size range + * \param[in] pixelformat Pixel format to retrieve range for + * \returns Range description of frame size + */ +SizeRange StreamFormats::range(unsigned int pixelformat) const +{ + auto const it = formats_.find(pixelformat); + if (it == formats_.end()) + return {}; + + const SizeRange &first = it->second.front(); + if (it->second.size() == 1) + return first; + + LOG(Stream, Debug) << "Building range from discret"; + + SizeRange range(first.min.width, first.min.height, + first.max.width, first.max.height); + + for (const SizeRange &limit : it->second) { + if (limit.min < range.min) + range.min = limit.min; + + if (limit.max > range.max) + range.max = limit.max; + } + + return range; +} + /** * \struct StreamConfiguration * \brief Configuration parameters for a stream
Add a StreamFormats which describes all the formats a stream can support. The object does not collect any formation itself but can simplify users interaction with formats as it's able to translate a stream format range into discrete list and a discrete list to a range. Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> --- include/libcamera/stream.h | 16 +++ src/libcamera/stream.cpp | 216 +++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+)