diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h
index bc1c6a4d10c7..2a380c0e61cd 100644
--- a/src/libcamera/include/v4l2_videodevice.h
+++ b/src/libcamera/include/v4l2_videodevice.h
@@ -149,10 +149,33 @@ private:
 	unsigned int missCounter_;
 };
 
+class V4L2PixelFormat
+{
+public:
+	V4L2PixelFormat()
+		: fourcc_(0)
+	{
+	}
+
+	V4L2PixelFormat(uint32_t fourcc)
+		: fourcc_(fourcc)
+	{
+	}
+
+	bool isValid() const { return fourcc_ != 0; }
+	uint32_t fourcc() const { return fourcc_; }
+	operator uint32_t() const { return fourcc_; }
+
+	std::string toString() const;
+
+private:
+	uint32_t fourcc_;
+};
+
 class V4L2DeviceFormat
 {
 public:
-	uint32_t fourcc;
+	V4L2PixelFormat fourcc;
 	Size size;
 
 	struct {
@@ -184,7 +207,7 @@ public:
 
 	int getFormat(V4L2DeviceFormat *format);
 	int setFormat(V4L2DeviceFormat *format);
-	ImageFormats formats();
+	std::map<V4L2PixelFormat, std::vector<SizeRange>> formats();
 
 	int setCrop(Rectangle *rect);
 	int setCompose(Rectangle *rect);
@@ -205,10 +228,10 @@ public:
 	static V4L2VideoDevice *fromEntityName(const MediaDevice *media,
 					       const std::string &entity);
 
-	static PixelFormat toPixelFormat(uint32_t v4l2Fourcc);
-	uint32_t toV4L2Fourcc(const PixelFormat &pixelFormat);
-	static uint32_t toV4L2Fourcc(const PixelFormat &pixelFormat,
-				     bool multiplanar);
+	static PixelFormat toPixelFormat(V4L2PixelFormat v4l2Fourcc);
+	V4L2PixelFormat toV4L2Fourcc(const PixelFormat &pixelFormat);
+	static V4L2PixelFormat toV4L2Fourcc(const PixelFormat &pixelFormat,
+					    bool multiplanar);
 
 protected:
 	std::string logPrefix() const;
@@ -223,8 +246,8 @@ private:
 	int getFormatSingleplane(V4L2DeviceFormat *format);
 	int setFormatSingleplane(V4L2DeviceFormat *format);
 
-	std::vector<unsigned int> enumPixelformats();
-	std::vector<SizeRange> enumSizes(unsigned int pixelFormat);
+	std::vector<V4L2PixelFormat> enumPixelformats();
+	std::vector<SizeRange> enumSizes(V4L2PixelFormat pixelFormat);
 
 	int setSelection(unsigned int target, Rectangle *rect);
 
diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp
index 731149755728..67750fbc7c0c 100644
--- a/src/libcamera/pipeline/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo.cpp
@@ -154,8 +154,8 @@ CameraConfiguration *PipelineHandlerUVC::generateConfiguration(Camera *camera,
 	if (roles.empty())
 		return config;
 
-	std::map<unsigned int, std::vector<SizeRange>> v4l2Formats =
-		data->video_->formats().data();
+	std::map<V4L2PixelFormat, std::vector<SizeRange>> 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 56251a465807..1c60014caa6f 100644
--- a/src/libcamera/v4l2_videodevice.cpp
+++ b/src/libcamera/v4l2_videodevice.cpp
@@ -278,6 +278,65 @@ bool V4L2BufferCache::Entry::operator==(const FrameBuffer &buffer) const
 	return true;
 }
 
+/**
+ * \class V4L2PixelFormat
+ * \brief V4L2 pixel format FourCC wrapper
+ *
+ * The V4L2PixelFormat class describes the pixel format of a V4L2 buffer. It
+ * wraps the V4L2 numerical FourCC, and shall be used in all APIs that deal with
+ * V4L2 pixel formats. Its purpose is to prevent unintentional confusion of
+ * V4L2 and DRM FourCCs in code by catching implicit conversion attempts at
+ * compile time.
+ */
+
+/**
+ * \fn V4L2PixelFormat::V4L2PixelFormat()
+ * \brief Construct a V4L2PixelFormat with an invalid format
+ *
+ * V4L2PixelFormat instances constructed with the default constructor are
+ * invalid, calling the isValid() function returns false.
+ */
+
+/**
+ * \fn V4L2PixelFormat::V4L2PixelFormat(uint32_t fourcc)
+ * \brief Construct a V4L2PixelFormat from a FourCC value
+ * \param[in] fourcc The pixel format FourCC numerical value
+ */
+
+/**
+ * \fn bool V4L2PixelFormat::isValid() const
+ * \brief Check if the pixel format is valid
+ *
+ * V4L2PixelFormat instances constructed with the default constructor are
+ * invalid. Instances constructed with a FourCC defined in the V4L2 API are
+ * valid. The behaviour is undefined otherwise.
+ *
+ * \return True if the pixel format is valid, false otherwise
+ */
+
+/**
+ * \fn uint32_t V4L2PixelFormat::fourcc() const
+ * \brief Retrieve the pixel format FourCC numerical value
+ * \return The pixel format FourCC numerical value
+ */
+
+/**
+ * \fn V4L2PixelFormat::operator uint32_t() const
+ * \brief Convert to the pixel format FourCC numerical value
+ * \return The pixel format FourCC numerical value
+ */
+
+/**
+ * \brief Assemble and return a string describing the pixel format
+ * \return A string describing the pixel format
+ */
+std::string V4L2PixelFormat::toString() const
+{
+	char str[11];
+	snprintf(str, 11, "0x%08x", fourcc_);
+	return str;
+}
+
 /**
  * \class V4L2DeviceFormat
  * \brief The V4L2 video device image format and sizes
@@ -386,7 +445,7 @@ bool V4L2BufferCache::Entry::operator==(const FrameBuffer &buffer) const
 const std::string V4L2DeviceFormat::toString() const
 {
 	std::stringstream ss;
-	ss << size.toString() << "-" << utils::hex(fourcc);
+	ss << size.toString() << "-" << fourcc.toString();
 	return ss.str();
 }
 
@@ -901,29 +960,31 @@ int V4L2VideoDevice::setFormatSingleplane(V4L2DeviceFormat *format)
  *
  * \return A list of the supported video device formats
  */
-ImageFormats V4L2VideoDevice::formats()
+std::map<V4L2PixelFormat, std::vector<SizeRange>> V4L2VideoDevice::formats()
 {
-	ImageFormats formats;
+	std::map<V4L2PixelFormat, std::vector<SizeRange>> formats;
 
-	for (unsigned int pixelformat : enumPixelformats()) {
-		std::vector<SizeRange> sizes = enumSizes(pixelformat);
+	for (V4L2PixelFormat pixelFormat : enumPixelformats()) {
+		std::vector<SizeRange> sizes = enumSizes(pixelFormat);
 		if (sizes.empty())
 			return {};
 
-		if (formats.addFormat(pixelformat, sizes)) {
+		if (formats.find(pixelFormat) != formats.end()) {
 			LOG(V4L2, Error)
 				<< "Could not add sizes for pixel format "
-				<< pixelformat;
+				<< pixelFormat;
 			return {};
 		}
+
+		formats.emplace(pixelFormat, sizes);
 	}
 
 	return formats;
 }
 
-std::vector<unsigned int> V4L2VideoDevice::enumPixelformats()
+std::vector<V4L2PixelFormat> V4L2VideoDevice::enumPixelformats()
 {
-	std::vector<unsigned int> formats;
+	std::vector<V4L2PixelFormat> formats;
 	int ret;
 
 	for (unsigned int index = 0; ; index++) {
@@ -948,7 +1009,7 @@ std::vector<unsigned int> V4L2VideoDevice::enumPixelformats()
 	return formats;
 }
 
-std::vector<SizeRange> V4L2VideoDevice::enumSizes(unsigned int pixelFormat)
+std::vector<SizeRange> V4L2VideoDevice::enumSizes(V4L2PixelFormat pixelFormat)
 {
 	std::vector<SizeRange> sizes;
 	int ret;
@@ -1563,7 +1624,7 @@ V4L2VideoDevice *V4L2VideoDevice::fromEntityName(const MediaDevice *media,
  * \param[in] v4l2Fourcc The V4L2 pixel format (V4L2_PIX_FORMAT_*)
  * \return The PixelFormat corresponding to \a v4l2Fourcc
  */
-PixelFormat V4L2VideoDevice::toPixelFormat(uint32_t v4l2Fourcc)
+PixelFormat V4L2VideoDevice::toPixelFormat(V4L2PixelFormat v4l2Fourcc)
 {
 	switch (v4l2Fourcc) {
 	/* RGB formats. */
@@ -1612,7 +1673,7 @@ PixelFormat V4L2VideoDevice::toPixelFormat(uint32_t v4l2Fourcc)
 		libcamera::_log(__FILE__, __LINE__, _LOG_CATEGORY(V4L2)(),
 				LogError).stream()
 			<< "Unsupported V4L2 pixel format "
-			<< utils::hex(v4l2Fourcc);
+			<< v4l2Fourcc.toString();
 		return PixelFormat();
 	}
 }
@@ -1628,7 +1689,7 @@ PixelFormat V4L2VideoDevice::toPixelFormat(uint32_t v4l2Fourcc)
  *
  * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat
  */
-uint32_t V4L2VideoDevice::toV4L2Fourcc(const PixelFormat &pixelFormat)
+V4L2PixelFormat V4L2VideoDevice::toV4L2Fourcc(const PixelFormat &pixelFormat)
 {
 	return V4L2VideoDevice::toV4L2Fourcc(pixelFormat, caps_.isMultiplanar());
 }
@@ -1646,8 +1707,8 @@ uint32_t V4L2VideoDevice::toV4L2Fourcc(const PixelFormat &pixelFormat)
  *
  * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat
  */
-uint32_t V4L2VideoDevice::toV4L2Fourcc(const PixelFormat &pixelFormat,
-				       bool multiplanar)
+V4L2PixelFormat V4L2VideoDevice::toV4L2Fourcc(const PixelFormat &pixelFormat,
+					      bool multiplanar)
 {
 	switch (pixelFormat) {
 	/* RGB formats. */
