[libcamera-devel,2/5] libcamera: v4l2_videodevice: Use ImageFormats

Message ID 20200529110335.620503-3-jacopo@jmondi.org
State Superseded
Headers show
Series
  • ImageFormats' not dead
Related show

Commit Message

Jacopo Mondi May 29, 2020, 11:03 a.m. UTC
ImageFormats was meant to be used not only for V4L2Subdevice but
for video devices as well. Since the introduction of of V4L2PixelFormat
the V4L2VideoDevice class and its users have been using a raw map to
enumerate and inspect the V4L2VideoDevice formats.

Use the ImageFormats<V4L2PixelFormat> specialization in place of a raw
map and update its usage in pipeline handlers.

Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
---
 include/libcamera/internal/v4l2_videodevice.h   |  2 +-
 .../pipeline/raspberrypi/raspberrypi.cpp        | 17 +++++++----------
 src/libcamera/pipeline/simple/simple.cpp        |  3 +--
 src/libcamera/pipeline/uvcvideo/uvcvideo.cpp    |  3 +--
 src/libcamera/v4l2_videodevice.cpp              |  4 ++--
 5 files changed, 12 insertions(+), 17 deletions(-)

Comments

Laurent Pinchart June 5, 2020, 11:27 p.m. UTC | #1
Hi Jacopo,

Thank you for the patch.

On Fri, May 29, 2020 at 01:03:32PM +0200, Jacopo Mondi wrote:
> ImageFormats was meant to be used not only for V4L2Subdevice but
> for video devices as well. Since the introduction of of V4L2PixelFormat
> the V4L2VideoDevice class and its users have been using a raw map to
> enumerate and inspect the V4L2VideoDevice formats.
> 
> Use the ImageFormats<V4L2PixelFormat> specialization in place of a raw
> map and update its usage in pipeline handlers.
> 
> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> ---
>  include/libcamera/internal/v4l2_videodevice.h   |  2 +-
>  .../pipeline/raspberrypi/raspberrypi.cpp        | 17 +++++++----------
>  src/libcamera/pipeline/simple/simple.cpp        |  3 +--
>  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp    |  3 +--
>  src/libcamera/v4l2_videodevice.cpp              |  4 ++--
>  5 files changed, 12 insertions(+), 17 deletions(-)
> 
> diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h
> index dc259523599c..de4745982e94 100644
> --- a/include/libcamera/internal/v4l2_videodevice.h
> +++ b/include/libcamera/internal/v4l2_videodevice.h
> @@ -187,7 +187,7 @@ public:
>  
>  	int getFormat(V4L2DeviceFormat *format);
>  	int setFormat(V4L2DeviceFormat *format);
> -	std::map<V4L2PixelFormat, std::vector<SizeRange>> formats(uint32_t code = 0);
> +	ImageFormats<V4L2PixelFormat> formats(uint32_t code = 0);
>  
>  	int setSelection(unsigned int target, Rectangle *rect);
>  
> diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> index e16a9c7f10d3..64364afb3f7e 100644
> --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> @@ -37,8 +37,6 @@ namespace libcamera {
>  
>  LOG_DEFINE_CATEGORY(RPI)
>  
> -using V4L2PixFmtMap = std::map<V4L2PixelFormat, std::vector<SizeRange>>;
> -
>  namespace {
>  
>  bool isRaw(PixelFormat &pixFmt)
> @@ -67,7 +65,7 @@ double scoreFormat(double desired, double actual)
>  	return score;
>  }
>  
> -V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
> +V4L2DeviceFormat findBestMode(ImageFormats<V4L2PixelFormat> &formatsMap, const Size &req)
>  {
>  	double bestScore = 9e9, score;
>  	V4L2DeviceFormat bestMode = {};
> @@ -79,12 +77,11 @@ V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
>  #define PENALTY_UNPACKED	 500.0
>  
>  	/* Calculate the closest/best mode from the user requested size. */
> -	for (const auto &iter : formatsMap) {
> -		V4L2PixelFormat v4l2Format = iter.first;
> +	for (const auto &v4l2Format : formatsMap.formats()) {

This will impact efficiency, as you will first create a temporary vector
calling formats(), with an additional but smaller impact when calling
size() below. Is this required ?

It's also a change that isn't described in the commit message, so I'd
split it to a separate patch if desired.

>  		PixelFormat pixelFormat = v4l2Format.toPixelFormat();
>  		const PixelFormatInfo &info = PixelFormatInfo::info(pixelFormat);
>  
> -		for (const SizeRange &sz : iter.second) {
> +		for (const SizeRange &sz : formatsMap.sizes(v4l2Format)) {
>  			double modeWidth = sz.contains(req) ? req.width : sz.max.width;
>  			double modeHeight = sz.contains(req) ? req.height : sz.max.height;
>  			double reqAr = static_cast<double>(req.width) / req.height;
> @@ -427,7 +424,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
>  			 * Calculate the best sensor mode we can use based on
>  			 * the user request.
>  			 */
> -			V4L2PixFmtMap fmts = data_->unicam_[Unicam::Image].dev()->formats();
> +			ImageFormats<V4L2PixelFormat> fmts = data_->unicam_[Unicam::Image].dev()->formats();
>  			V4L2DeviceFormat sensorFormat = findBestMode(fmts, cfg.size);
>  			PixelFormat sensorPixFormat = sensorFormat.fourcc.toPixelFormat();
>  			if (cfg.size != sensorFormat.size ||
> @@ -481,7 +478,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
>  		 *
>  		 */
>  		PixelFormat &cfgPixFmt = config_.at(outSize[i].first).pixelFormat;
> -		V4L2PixFmtMap fmts;
> +		ImageFormats<V4L2PixelFormat> fmts;
>  
>  		if (i == maxIndex)
>  			fmts = data_->isp_[Isp::Output0].dev()->formats();
> @@ -518,7 +515,7 @@ CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,
>  	RPiCameraData *data = cameraData(camera);
>  	CameraConfiguration *config = new RPiCameraConfiguration(data);
>  	V4L2DeviceFormat sensorFormat;
> -	V4L2PixFmtMap fmts;
> +	ImageFormats<V4L2PixelFormat> fmts;
>  
>  	if (roles.empty())
>  		return config;
> @@ -605,7 +602,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
>  	}
>  
>  	/* First calculate the best sensor mode we can use based on the user request. */
> -	V4L2PixFmtMap fmts = data->unicam_[Unicam::Image].dev()->formats();
> +	ImageFormats<V4L2PixelFormat> fmts = data->unicam_[Unicam::Image].dev()->formats();
>  	V4L2DeviceFormat sensorFormat = findBestMode(fmts, rawStream ? sensorSize : maxSize);
>  
>  	/*
> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
> index 1ec8d0f7de03..f3e03ba60196 100644
> --- a/src/libcamera/pipeline/simple/simple.cpp
> +++ b/src/libcamera/pipeline/simple/simple.cpp
> @@ -275,8 +275,7 @@ int SimpleCameraData::init()
>  			return ret;
>  		}
>  
> -		std::map<V4L2PixelFormat, std::vector<SizeRange>> videoFormats =
> -			video_->formats(format.mbus_code);
> +		ImageFormats<V4L2PixelFormat> videoFormats = video_->formats(format.mbus_code);
>  
>  		LOG(SimplePipeline, Debug)
>  			<< "Adding configuration for " << format.size.toString()
> diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> index a074909499f1..dbd835f5c5ef 100644
> --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> @@ -159,8 +159,7 @@ CameraConfiguration *PipelineHandlerUVC::generateConfiguration(Camera *camera,
>  	if (roles.empty())
>  		return config;
>  
> -	std::map<V4L2PixelFormat, std::vector<SizeRange>> v4l2Formats =
> -		data->video_->formats();
> +	ImageFormats<V4L2PixelFormat> v4l2Formats = data->video_->formats();
>  	std::map<PixelFormat, std::vector<SizeRange>> deviceFormats;
>  	std::transform(v4l2Formats.begin(), v4l2Formats.end(),
>  		       std::inserter(deviceFormats, deviceFormats.begin()),
> diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
> index 3614b2ed1cbc..ea952444e0ad 100644
> --- a/src/libcamera/v4l2_videodevice.cpp
> +++ b/src/libcamera/v4l2_videodevice.cpp
> @@ -925,9 +925,9 @@ int V4L2VideoDevice::setFormatSingleplane(V4L2DeviceFormat *format)
>   *
>   * \return A list of the supported video device formats
>   */
> -std::map<V4L2PixelFormat, std::vector<SizeRange>> V4L2VideoDevice::formats(uint32_t code)
> +ImageFormats<V4L2PixelFormat> V4L2VideoDevice::formats(uint32_t code)
>  {
> -	std::map<V4L2PixelFormat, std::vector<SizeRange>> formats;
> +	ImageFormats<V4L2PixelFormat> formats;
>  
>  	for (V4L2PixelFormat pixelFormat : enumPixelformats(code)) {
>  		std::vector<SizeRange> sizes = enumSizes(pixelFormat);
Jacopo Mondi June 8, 2020, 7:59 a.m. UTC | #2
Hi Laurent,

On Sat, Jun 06, 2020 at 02:27:14AM +0300, Laurent Pinchart wrote:
> Hi Jacopo,
>
> Thank you for the patch.
>
> On Fri, May 29, 2020 at 01:03:32PM +0200, Jacopo Mondi wrote:
> > ImageFormats was meant to be used not only for V4L2Subdevice but
> > for video devices as well. Since the introduction of of V4L2PixelFormat
> > the V4L2VideoDevice class and its users have been using a raw map to
> > enumerate and inspect the V4L2VideoDevice formats.
> >
> > Use the ImageFormats<V4L2PixelFormat> specialization in place of a raw
> > map and update its usage in pipeline handlers.
> >
> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>
> > ---
> >  include/libcamera/internal/v4l2_videodevice.h   |  2 +-
> >  .../pipeline/raspberrypi/raspberrypi.cpp        | 17 +++++++----------
> >  src/libcamera/pipeline/simple/simple.cpp        |  3 +--
> >  src/libcamera/pipeline/uvcvideo/uvcvideo.cpp    |  3 +--
> >  src/libcamera/v4l2_videodevice.cpp              |  4 ++--
> >  5 files changed, 12 insertions(+), 17 deletions(-)
> >
> > diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h
> > index dc259523599c..de4745982e94 100644
> > --- a/include/libcamera/internal/v4l2_videodevice.h
> > +++ b/include/libcamera/internal/v4l2_videodevice.h
> > @@ -187,7 +187,7 @@ public:
> >
> >  	int getFormat(V4L2DeviceFormat *format);
> >  	int setFormat(V4L2DeviceFormat *format);
> > -	std::map<V4L2PixelFormat, std::vector<SizeRange>> formats(uint32_t code = 0);
> > +	ImageFormats<V4L2PixelFormat> formats(uint32_t code = 0);
> >
> >  	int setSelection(unsigned int target, Rectangle *rect);
> >
> > diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > index e16a9c7f10d3..64364afb3f7e 100644
> > --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
> > @@ -37,8 +37,6 @@ namespace libcamera {
> >
> >  LOG_DEFINE_CATEGORY(RPI)
> >
> > -using V4L2PixFmtMap = std::map<V4L2PixelFormat, std::vector<SizeRange>>;
> > -
> >  namespace {
> >
> >  bool isRaw(PixelFormat &pixFmt)
> > @@ -67,7 +65,7 @@ double scoreFormat(double desired, double actual)
> >  	return score;
> >  }
> >
> > -V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
> > +V4L2DeviceFormat findBestMode(ImageFormats<V4L2PixelFormat> &formatsMap, const Size &req)
> >  {
> >  	double bestScore = 9e9, score;
> >  	V4L2DeviceFormat bestMode = {};
> > @@ -79,12 +77,11 @@ V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
> >  #define PENALTY_UNPACKED	 500.0
> >
> >  	/* Calculate the closest/best mode from the user requested size. */
> > -	for (const auto &iter : formatsMap) {
> > -		V4L2PixelFormat v4l2Format = iter.first;
> > +	for (const auto &v4l2Format : formatsMap.formats()) {
>
> This will impact efficiency, as you will first create a temporary vector
> calling formats(), with an additional but smaller impact when calling
> size() below. Is this required ?
>

No, it's for stylistic reasons mostly, and considering we'll usually
have no more than 2 or 3 formats to iterate on, I considered this a
negligible performance impact.

> It's also a change that isn't described in the commit message, so I'd
> split it to a separate patch if desired.

I can drop this if it's controversial.

Thanks
   j

>
> >  		PixelFormat pixelFormat = v4l2Format.toPixelFormat();
> >  		const PixelFormatInfo &info = PixelFormatInfo::info(pixelFormat);
> >
> > -		for (const SizeRange &sz : iter.second) {
> > +		for (const SizeRange &sz : formatsMap.sizes(v4l2Format)) {
> >  			double modeWidth = sz.contains(req) ? req.width : sz.max.width;
> >  			double modeHeight = sz.contains(req) ? req.height : sz.max.height;
> >  			double reqAr = static_cast<double>(req.width) / req.height;
> > @@ -427,7 +424,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
> >  			 * Calculate the best sensor mode we can use based on
> >  			 * the user request.
> >  			 */
> > -			V4L2PixFmtMap fmts = data_->unicam_[Unicam::Image].dev()->formats();
> > +			ImageFormats<V4L2PixelFormat> fmts = data_->unicam_[Unicam::Image].dev()->formats();
> >  			V4L2DeviceFormat sensorFormat = findBestMode(fmts, cfg.size);
> >  			PixelFormat sensorPixFormat = sensorFormat.fourcc.toPixelFormat();
> >  			if (cfg.size != sensorFormat.size ||
> > @@ -481,7 +478,7 @@ CameraConfiguration::Status RPiCameraConfiguration::validate()
> >  		 *
> >  		 */
> >  		PixelFormat &cfgPixFmt = config_.at(outSize[i].first).pixelFormat;
> > -		V4L2PixFmtMap fmts;
> > +		ImageFormats<V4L2PixelFormat> fmts;
> >
> >  		if (i == maxIndex)
> >  			fmts = data_->isp_[Isp::Output0].dev()->formats();
> > @@ -518,7 +515,7 @@ CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,
> >  	RPiCameraData *data = cameraData(camera);
> >  	CameraConfiguration *config = new RPiCameraConfiguration(data);
> >  	V4L2DeviceFormat sensorFormat;
> > -	V4L2PixFmtMap fmts;
> > +	ImageFormats<V4L2PixelFormat> fmts;
> >
> >  	if (roles.empty())
> >  		return config;
> > @@ -605,7 +602,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
> >  	}
> >
> >  	/* First calculate the best sensor mode we can use based on the user request. */
> > -	V4L2PixFmtMap fmts = data->unicam_[Unicam::Image].dev()->formats();
> > +	ImageFormats<V4L2PixelFormat> fmts = data->unicam_[Unicam::Image].dev()->formats();
> >  	V4L2DeviceFormat sensorFormat = findBestMode(fmts, rawStream ? sensorSize : maxSize);
> >
> >  	/*
> > diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
> > index 1ec8d0f7de03..f3e03ba60196 100644
> > --- a/src/libcamera/pipeline/simple/simple.cpp
> > +++ b/src/libcamera/pipeline/simple/simple.cpp
> > @@ -275,8 +275,7 @@ int SimpleCameraData::init()
> >  			return ret;
> >  		}
> >
> > -		std::map<V4L2PixelFormat, std::vector<SizeRange>> videoFormats =
> > -			video_->formats(format.mbus_code);
> > +		ImageFormats<V4L2PixelFormat> videoFormats = video_->formats(format.mbus_code);
> >
> >  		LOG(SimplePipeline, Debug)
> >  			<< "Adding configuration for " << format.size.toString()
> > diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> > index a074909499f1..dbd835f5c5ef 100644
> > --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> > +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
> > @@ -159,8 +159,7 @@ CameraConfiguration *PipelineHandlerUVC::generateConfiguration(Camera *camera,
> >  	if (roles.empty())
> >  		return config;
> >
> > -	std::map<V4L2PixelFormat, std::vector<SizeRange>> v4l2Formats =
> > -		data->video_->formats();
> > +	ImageFormats<V4L2PixelFormat> v4l2Formats = data->video_->formats();
> >  	std::map<PixelFormat, std::vector<SizeRange>> deviceFormats;
> >  	std::transform(v4l2Formats.begin(), v4l2Formats.end(),
> >  		       std::inserter(deviceFormats, deviceFormats.begin()),
> > diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
> > index 3614b2ed1cbc..ea952444e0ad 100644
> > --- a/src/libcamera/v4l2_videodevice.cpp
> > +++ b/src/libcamera/v4l2_videodevice.cpp
> > @@ -925,9 +925,9 @@ int V4L2VideoDevice::setFormatSingleplane(V4L2DeviceFormat *format)
> >   *
> >   * \return A list of the supported video device formats
> >   */
> > -std::map<V4L2PixelFormat, std::vector<SizeRange>> V4L2VideoDevice::formats(uint32_t code)
> > +ImageFormats<V4L2PixelFormat> V4L2VideoDevice::formats(uint32_t code)
> >  {
> > -	std::map<V4L2PixelFormat, std::vector<SizeRange>> formats;
> > +	ImageFormats<V4L2PixelFormat> formats;
> >
> >  	for (V4L2PixelFormat pixelFormat : enumPixelformats(code)) {
> >  		std::vector<SizeRange> sizes = enumSizes(pixelFormat);
>
> --
> Regards,
>
> Laurent Pinchart

Patch

diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h
index dc259523599c..de4745982e94 100644
--- a/include/libcamera/internal/v4l2_videodevice.h
+++ b/include/libcamera/internal/v4l2_videodevice.h
@@ -187,7 +187,7 @@  public:
 
 	int getFormat(V4L2DeviceFormat *format);
 	int setFormat(V4L2DeviceFormat *format);
-	std::map<V4L2PixelFormat, std::vector<SizeRange>> formats(uint32_t code = 0);
+	ImageFormats<V4L2PixelFormat> formats(uint32_t code = 0);
 
 	int setSelection(unsigned int target, Rectangle *rect);
 
diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
index e16a9c7f10d3..64364afb3f7e 100644
--- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
+++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp
@@ -37,8 +37,6 @@  namespace libcamera {
 
 LOG_DEFINE_CATEGORY(RPI)
 
-using V4L2PixFmtMap = std::map<V4L2PixelFormat, std::vector<SizeRange>>;
-
 namespace {
 
 bool isRaw(PixelFormat &pixFmt)
@@ -67,7 +65,7 @@  double scoreFormat(double desired, double actual)
 	return score;
 }
 
-V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
+V4L2DeviceFormat findBestMode(ImageFormats<V4L2PixelFormat> &formatsMap, const Size &req)
 {
 	double bestScore = 9e9, score;
 	V4L2DeviceFormat bestMode = {};
@@ -79,12 +77,11 @@  V4L2DeviceFormat findBestMode(V4L2PixFmtMap &formatsMap, const Size &req)
 #define PENALTY_UNPACKED	 500.0
 
 	/* Calculate the closest/best mode from the user requested size. */
-	for (const auto &iter : formatsMap) {
-		V4L2PixelFormat v4l2Format = iter.first;
+	for (const auto &v4l2Format : formatsMap.formats()) {
 		PixelFormat pixelFormat = v4l2Format.toPixelFormat();
 		const PixelFormatInfo &info = PixelFormatInfo::info(pixelFormat);
 
-		for (const SizeRange &sz : iter.second) {
+		for (const SizeRange &sz : formatsMap.sizes(v4l2Format)) {
 			double modeWidth = sz.contains(req) ? req.width : sz.max.width;
 			double modeHeight = sz.contains(req) ? req.height : sz.max.height;
 			double reqAr = static_cast<double>(req.width) / req.height;
@@ -427,7 +424,7 @@  CameraConfiguration::Status RPiCameraConfiguration::validate()
 			 * Calculate the best sensor mode we can use based on
 			 * the user request.
 			 */
-			V4L2PixFmtMap fmts = data_->unicam_[Unicam::Image].dev()->formats();
+			ImageFormats<V4L2PixelFormat> fmts = data_->unicam_[Unicam::Image].dev()->formats();
 			V4L2DeviceFormat sensorFormat = findBestMode(fmts, cfg.size);
 			PixelFormat sensorPixFormat = sensorFormat.fourcc.toPixelFormat();
 			if (cfg.size != sensorFormat.size ||
@@ -481,7 +478,7 @@  CameraConfiguration::Status RPiCameraConfiguration::validate()
 		 *
 		 */
 		PixelFormat &cfgPixFmt = config_.at(outSize[i].first).pixelFormat;
-		V4L2PixFmtMap fmts;
+		ImageFormats<V4L2PixelFormat> fmts;
 
 		if (i == maxIndex)
 			fmts = data_->isp_[Isp::Output0].dev()->formats();
@@ -518,7 +515,7 @@  CameraConfiguration *PipelineHandlerRPi::generateConfiguration(Camera *camera,
 	RPiCameraData *data = cameraData(camera);
 	CameraConfiguration *config = new RPiCameraConfiguration(data);
 	V4L2DeviceFormat sensorFormat;
-	V4L2PixFmtMap fmts;
+	ImageFormats<V4L2PixelFormat> fmts;
 
 	if (roles.empty())
 		return config;
@@ -605,7 +602,7 @@  int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config)
 	}
 
 	/* First calculate the best sensor mode we can use based on the user request. */
-	V4L2PixFmtMap fmts = data->unicam_[Unicam::Image].dev()->formats();
+	ImageFormats<V4L2PixelFormat> fmts = data->unicam_[Unicam::Image].dev()->formats();
 	V4L2DeviceFormat sensorFormat = findBestMode(fmts, rawStream ? sensorSize : maxSize);
 
 	/*
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 1ec8d0f7de03..f3e03ba60196 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -275,8 +275,7 @@  int SimpleCameraData::init()
 			return ret;
 		}
 
-		std::map<V4L2PixelFormat, std::vector<SizeRange>> videoFormats =
-			video_->formats(format.mbus_code);
+		ImageFormats<V4L2PixelFormat> videoFormats = video_->formats(format.mbus_code);
 
 		LOG(SimplePipeline, Debug)
 			<< "Adding configuration for " << format.size.toString()
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index a074909499f1..dbd835f5c5ef 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -159,8 +159,7 @@  CameraConfiguration *PipelineHandlerUVC::generateConfiguration(Camera *camera,
 	if (roles.empty())
 		return config;
 
-	std::map<V4L2PixelFormat, std::vector<SizeRange>> v4l2Formats =
-		data->video_->formats();
+	ImageFormats<V4L2PixelFormat> v4l2Formats = data->video_->formats();
 	std::map<PixelFormat, std::vector<SizeRange>> deviceFormats;
 	std::transform(v4l2Formats.begin(), v4l2Formats.end(),
 		       std::inserter(deviceFormats, deviceFormats.begin()),
diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
index 3614b2ed1cbc..ea952444e0ad 100644
--- a/src/libcamera/v4l2_videodevice.cpp
+++ b/src/libcamera/v4l2_videodevice.cpp
@@ -925,9 +925,9 @@  int V4L2VideoDevice::setFormatSingleplane(V4L2DeviceFormat *format)
  *
  * \return A list of the supported video device formats
  */
-std::map<V4L2PixelFormat, std::vector<SizeRange>> V4L2VideoDevice::formats(uint32_t code)
+ImageFormats<V4L2PixelFormat> V4L2VideoDevice::formats(uint32_t code)
 {
-	std::map<V4L2PixelFormat, std::vector<SizeRange>> formats;
+	ImageFormats<V4L2PixelFormat> formats;
 
 	for (V4L2PixelFormat pixelFormat : enumPixelformats(code)) {
 		std::vector<SizeRange> sizes = enumSizes(pixelFormat);