@@ -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_;
@@ -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 {};
}
/**