diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h
index 29fa0bbaf670..ed98a284de16 100644
--- a/include/libcamera/internal/v4l2_videodevice.h
+++ b/include/libcamera/internal/v4l2_videodevice.h
@@ -14,6 +14,7 @@
 #include <ostream>
 #include <stdint.h>
 #include <string>
+#include <unordered_set>
 #include <vector>
 
 #include <linux/videodev2.h>
@@ -242,6 +243,8 @@ private:
 		Stopped,
 	};
 
+	int initFormats();
+
 	int getFormatMeta(V4L2DeviceFormat *format);
 	int trySetFormatMeta(V4L2DeviceFormat *format, bool set);
 
@@ -268,6 +271,7 @@ private:
 	V4L2Capability caps_;
 	V4L2DeviceFormat format_;
 	const PixelFormatInfo *formatInfo_;
+	std::unordered_set<V4L2PixelFormat> pixelFormats_;
 
 	enum v4l2_buf_type bufferType_;
 	enum v4l2_memory memoryType_;
diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
index 2ca22f485d45..b80ee1cdbcca 100644
--- a/src/libcamera/v4l2_videodevice.cpp
+++ b/src/libcamera/v4l2_videodevice.cpp
@@ -633,13 +633,9 @@ int V4L2VideoDevice::open()
 		<< "Opened device " << caps_.bus_info() << ": "
 		<< caps_.driver() << ": " << caps_.card();
 
-	ret = getFormat(&format_);
-	if (ret) {
-		LOG(V4L2, Error) << "Failed to get format";
+	ret = initFormats();
+	if (ret)
 		return ret;
-	}
-
-	formatInfo_ = &PixelFormatInfo::info(format_.fourcc);
 
 	return 0;
 }
@@ -726,7 +722,24 @@ int V4L2VideoDevice::open(SharedFD handle, enum v4l2_buf_type type)
 		<< "Opened device " << caps_.bus_info() << ": "
 		<< caps_.driver() << ": " << caps_.card();
 
-	ret = getFormat(&format_);
+	ret = initFormats();
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int V4L2VideoDevice::initFormats()
+{
+	const std::vector<V4L2PixelFormat> &deviceFormats = enumPixelformats(0);
+	if (deviceFormats.empty()) {
+		LOG(V4L2, Error) << "Failed to initialize device formats";
+		return -EINVAL;
+	}
+
+	pixelFormats_ = { deviceFormats.begin(), deviceFormats.end() };
+
+	int ret = getFormat(&format_);
 	if (ret) {
 		LOG(V4L2, Error) << "Failed to get format";
 		return ret;
@@ -1990,17 +2003,37 @@ V4L2VideoDevice::fromEntityName(const MediaDevice *media,
 }
 
 /**
- * \brief Convert \a PixelFormat to its corresponding V4L2 FourCC
+ * \brief Convert \a PixelFormat to a V4L2PixelFormat supported by the device
  * \param[in] pixelFormat The PixelFormat to convert
  *
- * The V4L2 format variant the function returns the contiguous version
- * unconditionally.
+ * Convert \a pixelformat to a V4L2 FourCC that is known to be supported by
+ * the video device.
  *
- * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat
+ * A V4L2VideoDevice may support different V4L2 pixel formats that map the same
+ * PixelFormat. This is the case of the contiguous and non-contiguous variants
+ * of multiplanar formats, and with the V4L2 MJPEG and JPEG pixel formats.
+ * Converting a PixelFormat to a V4L2PixelFormat may thus have multiple answers.
+ *
+ * This function converts the \a pixelFormat using the list of V4L2 pixel
+ * formats that the V4L2VideoDevice supports. This guarantees that the returned
+ * V4L2PixelFormat will be valid for the device. If multiple matches are still
+ * possible, contiguous variants are preferred. If the \a pixelFormat is not
+ * supported by the device, the function returns an invalid V4L2PixelFormat.
+ *
+ * \return The V4L2PixelFormat corresponding to \a pixelFormat if supported by
+ * the device, or an invalid V4L2PixelFormat otherwise
  */
 V4L2PixelFormat V4L2VideoDevice::toV4L2PixelFormat(const PixelFormat &pixelFormat) const
 {
-	return V4L2PixelFormat::fromPixelFormat(pixelFormat)[0];
+	const std::vector<V4L2PixelFormat> &v4l2PixelFormats =
+		V4L2PixelFormat::fromPixelFormat(pixelFormat);
+
+	for (const V4L2PixelFormat &v4l2Format : v4l2PixelFormats) {
+		if (pixelFormats_.count(v4l2Format))
+			return v4l2Format;
+	}
+
+	return {};
 }
 
 /**
