Message ID | 20191028110208.15751-7-laurent.pinchart@ideasonboard.com |
---|---|
State | Accepted |
Commit | 2a8bf04227811b29bc94b942e78f1567afd8874b |
Headers | show |
Series |
|
Related | show |
Hi Jacopo, On 28/10/2019 11:02, Laurent Pinchart wrote: > From: Jacopo Mondi <jacopo@jmondi.org> > > In preparation for switching PixelFormat to DRM pixel formats, add > helper methods to the V4L2VideoDevice class to translate between DRM > pixel formats and V4L2 pixel formats. > > More work is needed to properly suppor the V4L2 multi-planar (NV[0-9]*M) s/suppor/support/ > formats. > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org> > Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > --- > src/libcamera/include/v4l2_videodevice.h | 5 + > src/libcamera/v4l2_videodevice.cpp | 141 +++++++++++++++++++++++ > 2 files changed, 146 insertions(+) > > diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h > index 4b8cf9394eb9..fdf11b3a6ec9 100644 > --- a/src/libcamera/include/v4l2_videodevice.h > +++ b/src/libcamera/include/v4l2_videodevice.h > @@ -13,6 +13,7 @@ > #include <linux/videodev2.h> > > #include <libcamera/geometry.h> > +#include <libcamera/pixelformats.h> Hrm, seeing this makes me think the include file should be "libcamera/pixelformat.h" > #include <libcamera/signal.h> Because we don't call this libcamera/signals.h :D > > #include "formats.h" > @@ -155,6 +156,10 @@ public: > static V4L2VideoDevice *fromEntityName(const MediaDevice *media, > const std::string &entity); > > + static PixelFormat toPixelFormat(uint32_t v4l2Fourcc); > + uint32_t toV4L2Fourcc(PixelFormat pixelFormat); > + static uint32_t toV4L2Fourcc(PixelFormat pixelFormat, bool multiplanar); > + > protected: > std::string logPrefix() const; > > diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp > index 208ab54199b1..3f2dc2799796 100644 > --- a/src/libcamera/v4l2_videodevice.cpp > +++ b/src/libcamera/v4l2_videodevice.cpp > @@ -17,6 +17,8 @@ > #include <unistd.h> > #include <vector> > > +#include <linux/drm_fourcc.h> > + > #include <libcamera/buffer.h> > #include <libcamera/event_notifier.h> > > @@ -1234,6 +1236,145 @@ V4L2VideoDevice *V4L2VideoDevice::fromEntityName(const MediaDevice *media, > return new V4L2VideoDevice(mediaEntity); > } > > +/** > + * \brief Convert a \a v4l2Fourcc to the corresponding PixelFormat > + * \param[in] v4l2Fourcc The V4L2 pixel format (V4L2_PIX_FORMAT_*) > + * \return The PixelFormat corresponding to \a v4l2Fourcc > + */ > +PixelFormat V4L2VideoDevice::toPixelFormat(uint32_t v4l2Fourcc) > +{ > + switch (v4l2Fourcc) { > + /* RGB formats. */ > + case V4L2_PIX_FMT_RGB24: > + return DRM_FORMAT_BGR888; > + case V4L2_PIX_FMT_BGR24: > + return DRM_FORMAT_RGB888; > + case V4L2_PIX_FMT_ARGB32: > + return DRM_FORMAT_BGRA8888; > + > + /* YUV packed formats. */ > + case V4L2_PIX_FMT_YUYV: > + return DRM_FORMAT_YUYV; > + case V4L2_PIX_FMT_YVYU: > + return DRM_FORMAT_YVYU; > + case V4L2_PIX_FMT_UYVY: > + return DRM_FORMAT_UYVY; > + case V4L2_PIX_FMT_VYUY: > + return DRM_FORMAT_VYUY; > + > + /* YUY planar formats. */ > + case V4L2_PIX_FMT_NV16: > + case V4L2_PIX_FMT_NV16M: > + return DRM_FORMAT_NV16; > + case V4L2_PIX_FMT_NV61: > + case V4L2_PIX_FMT_NV61M: > + return DRM_FORMAT_NV61; > + case V4L2_PIX_FMT_NV12: > + case V4L2_PIX_FMT_NV12M: > + return DRM_FORMAT_NV12; > + case V4L2_PIX_FMT_NV21: > + case V4L2_PIX_FMT_NV21M: > + return DRM_FORMAT_NV21; > + > + /* Compressed formats. */ > + case V4L2_PIX_FMT_MJPEG: > + return DRM_FORMAT_MJPEG; > + > + /* V4L2 formats not yet supported by DRM. */ > + case V4L2_PIX_FMT_GREY: > + default: > + /* > + * \todo We can't use LOG() in a static method of a Loggable > + * class. Until we fix the logger, work around it. > + */ > + libcamera::_log(__FILE__, __LINE__, _LOG_CATEGORY(V4L2)(), > + LogError).stream() > + << "Unsupported V4L2 pixel format " > + << utils::hex(v4l2Fourcc); > + return 0; > + } > +} I wonder if these would be more manageable as a table of entries in a map, with a lookup - but I bet there's not much performance benefits either way, and it's only ever going to be a (relatively) small table. Perhaps a future optimisation maybe ... > + > +/** > + * \brief Convert \a PixelFormat to its corresponding V4L2 FourCC > + * \param[in] pixelFormat The PixelFormat to convert > + * > + * For multiplanar formats, the V4L2 format variant (contiguous or > + * non-contiguous planes) is selected automatically based on the capabilities > + * of the video device. If the video device supports the V4L2 multiplanar API, > + * non-contiguous formats are preferred. I think that's fine for now. We might have issues later if a device uses planar formats even though it supports MPLANE, but I can't think of a reason why that would happen at the moment, so lets go with this. > + * > + * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat > + */ > +uint32_t V4L2VideoDevice::toV4L2Fourcc(PixelFormat pixelFormat) > +{ > + return V4L2VideoDevice::toV4L2Fourcc(pixelFormat, caps_.isMultiplanar()); > +} > + > +/** > + * \brief Convert \a pixelFormat to its corresponding V4L2 FourCC > + * \param[in] pixelFormat The PixelFormat to convert > + * \param[in] multiplanar V4L2 Multiplanar API support flag > + * > + * Multiple V4L2 formats may exist for one PixelFormat when the format uses > + * multiple planes, as V4L2 defines separate 4CCs for contiguous and separate > + * planes formats. Set the \a multiplanar parameter to false to select a format > + * with contiguous planes, or to true to select a format with non-contiguous > + * planes. > + * > + * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat > + */ > +uint32_t V4L2VideoDevice::toV4L2Fourcc(PixelFormat pixelFormat, bool multiplanar) > +{ > + switch (pixelFormat) { > + /* RGB formats. */ > + case DRM_FORMAT_BGR888: > + return V4L2_PIX_FMT_RGB24; > + case DRM_FORMAT_RGB888: > + return V4L2_PIX_FMT_BGR24; > + case DRM_FORMAT_BGRA8888: > + return V4L2_PIX_FMT_ARGB32; > + > + /* YUV packed formats. */ > + case DRM_FORMAT_YUYV: > + return V4L2_PIX_FMT_YUYV; > + case DRM_FORMAT_YVYU: > + return V4L2_PIX_FMT_YVYU; > + case DRM_FORMAT_UYVY: > + return V4L2_PIX_FMT_UYVY; > + case DRM_FORMAT_VYUY: > + return V4L2_PIX_FMT_VYUY; > + > + /* > + * YUY planar formats. > + * \todo Add support for non-contiguous memory planes > + * \todo Select the format variant not only based on \a multiplanar but > + * also take into account the formats supported by the device. > + */ > + case DRM_FORMAT_NV16: > + return V4L2_PIX_FMT_NV16; > + case DRM_FORMAT_NV61: > + return V4L2_PIX_FMT_NV61; > + case DRM_FORMAT_NV12: > + return V4L2_PIX_FMT_NV12; > + case DRM_FORMAT_NV21: > + return V4L2_PIX_FMT_NV21; > + > + /* Compressed formats. */ > + case DRM_FORMAT_MJPEG: > + return V4L2_PIX_FMT_MJPEG; > + } > + > + /* > + * \todo We can't use LOG() in a static method of a Loggable > + * class. Until we fix the logger, work around it. > + */ > + libcamera::_log(__FILE__, __LINE__, _LOG_CATEGORY(V4L2)(), LogError).stream() > + << "Unsupported V4L2 pixel format " > + << utils::hex(pixelFormat); > + return 0; > +} > + > /** > * \class V4L2M2MDevice > * \brief Memory-to-Memory video device >
diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h index 4b8cf9394eb9..fdf11b3a6ec9 100644 --- a/src/libcamera/include/v4l2_videodevice.h +++ b/src/libcamera/include/v4l2_videodevice.h @@ -13,6 +13,7 @@ #include <linux/videodev2.h> #include <libcamera/geometry.h> +#include <libcamera/pixelformats.h> #include <libcamera/signal.h> #include "formats.h" @@ -155,6 +156,10 @@ public: static V4L2VideoDevice *fromEntityName(const MediaDevice *media, const std::string &entity); + static PixelFormat toPixelFormat(uint32_t v4l2Fourcc); + uint32_t toV4L2Fourcc(PixelFormat pixelFormat); + static uint32_t toV4L2Fourcc(PixelFormat pixelFormat, bool multiplanar); + protected: std::string logPrefix() const; diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 208ab54199b1..3f2dc2799796 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -17,6 +17,8 @@ #include <unistd.h> #include <vector> +#include <linux/drm_fourcc.h> + #include <libcamera/buffer.h> #include <libcamera/event_notifier.h> @@ -1234,6 +1236,145 @@ V4L2VideoDevice *V4L2VideoDevice::fromEntityName(const MediaDevice *media, return new V4L2VideoDevice(mediaEntity); } +/** + * \brief Convert a \a v4l2Fourcc to the corresponding PixelFormat + * \param[in] v4l2Fourcc The V4L2 pixel format (V4L2_PIX_FORMAT_*) + * \return The PixelFormat corresponding to \a v4l2Fourcc + */ +PixelFormat V4L2VideoDevice::toPixelFormat(uint32_t v4l2Fourcc) +{ + switch (v4l2Fourcc) { + /* RGB formats. */ + case V4L2_PIX_FMT_RGB24: + return DRM_FORMAT_BGR888; + case V4L2_PIX_FMT_BGR24: + return DRM_FORMAT_RGB888; + case V4L2_PIX_FMT_ARGB32: + return DRM_FORMAT_BGRA8888; + + /* YUV packed formats. */ + case V4L2_PIX_FMT_YUYV: + return DRM_FORMAT_YUYV; + case V4L2_PIX_FMT_YVYU: + return DRM_FORMAT_YVYU; + case V4L2_PIX_FMT_UYVY: + return DRM_FORMAT_UYVY; + case V4L2_PIX_FMT_VYUY: + return DRM_FORMAT_VYUY; + + /* YUY planar formats. */ + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV16M: + return DRM_FORMAT_NV16; + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV61M: + return DRM_FORMAT_NV61; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV12M: + return DRM_FORMAT_NV12; + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV21M: + return DRM_FORMAT_NV21; + + /* Compressed formats. */ + case V4L2_PIX_FMT_MJPEG: + return DRM_FORMAT_MJPEG; + + /* V4L2 formats not yet supported by DRM. */ + case V4L2_PIX_FMT_GREY: + default: + /* + * \todo We can't use LOG() in a static method of a Loggable + * class. Until we fix the logger, work around it. + */ + libcamera::_log(__FILE__, __LINE__, _LOG_CATEGORY(V4L2)(), + LogError).stream() + << "Unsupported V4L2 pixel format " + << utils::hex(v4l2Fourcc); + return 0; + } +} + +/** + * \brief Convert \a PixelFormat to its corresponding V4L2 FourCC + * \param[in] pixelFormat The PixelFormat to convert + * + * For multiplanar formats, the V4L2 format variant (contiguous or + * non-contiguous planes) is selected automatically based on the capabilities + * of the video device. If the video device supports the V4L2 multiplanar API, + * non-contiguous formats are preferred. + * + * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat + */ +uint32_t V4L2VideoDevice::toV4L2Fourcc(PixelFormat pixelFormat) +{ + return V4L2VideoDevice::toV4L2Fourcc(pixelFormat, caps_.isMultiplanar()); +} + +/** + * \brief Convert \a pixelFormat to its corresponding V4L2 FourCC + * \param[in] pixelFormat The PixelFormat to convert + * \param[in] multiplanar V4L2 Multiplanar API support flag + * + * Multiple V4L2 formats may exist for one PixelFormat when the format uses + * multiple planes, as V4L2 defines separate 4CCs for contiguous and separate + * planes formats. Set the \a multiplanar parameter to false to select a format + * with contiguous planes, or to true to select a format with non-contiguous + * planes. + * + * \return The V4L2_PIX_FMT_* pixel format code corresponding to \a pixelFormat + */ +uint32_t V4L2VideoDevice::toV4L2Fourcc(PixelFormat pixelFormat, bool multiplanar) +{ + switch (pixelFormat) { + /* RGB formats. */ + case DRM_FORMAT_BGR888: + return V4L2_PIX_FMT_RGB24; + case DRM_FORMAT_RGB888: + return V4L2_PIX_FMT_BGR24; + case DRM_FORMAT_BGRA8888: + return V4L2_PIX_FMT_ARGB32; + + /* YUV packed formats. */ + case DRM_FORMAT_YUYV: + return V4L2_PIX_FMT_YUYV; + case DRM_FORMAT_YVYU: + return V4L2_PIX_FMT_YVYU; + case DRM_FORMAT_UYVY: + return V4L2_PIX_FMT_UYVY; + case DRM_FORMAT_VYUY: + return V4L2_PIX_FMT_VYUY; + + /* + * YUY planar formats. + * \todo Add support for non-contiguous memory planes + * \todo Select the format variant not only based on \a multiplanar but + * also take into account the formats supported by the device. + */ + case DRM_FORMAT_NV16: + return V4L2_PIX_FMT_NV16; + case DRM_FORMAT_NV61: + return V4L2_PIX_FMT_NV61; + case DRM_FORMAT_NV12: + return V4L2_PIX_FMT_NV12; + case DRM_FORMAT_NV21: + return V4L2_PIX_FMT_NV21; + + /* Compressed formats. */ + case DRM_FORMAT_MJPEG: + return V4L2_PIX_FMT_MJPEG; + } + + /* + * \todo We can't use LOG() in a static method of a Loggable + * class. Until we fix the logger, work around it. + */ + libcamera::_log(__FILE__, __LINE__, _LOG_CATEGORY(V4L2)(), LogError).stream() + << "Unsupported V4L2 pixel format " + << utils::hex(pixelFormat); + return 0; +} + /** * \class V4L2M2MDevice * \brief Memory-to-Memory video device