{"id":2913,"url":"https://patchwork.libcamera.org/api/1.1/patches/2913/?format=json","web_url":"https://patchwork.libcamera.org/patch/2913/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20200228032913.497826-4-niklas.soderlund@ragnatech.se>","date":"2020-02-28T03:29:10","name":"[libcamera-devel,RFC,3/6] libcamera: PixelFormat: Turn into a class","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"179d95d85419f61e280980af63ce7f5eadad1e97","submitter":{"id":5,"url":"https://patchwork.libcamera.org/api/1.1/people/5/?format=json","name":"Niklas Söderlund","email":"niklas.soderlund@ragnatech.se"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/2913/mbox/","series":[{"id":694,"url":"https://patchwork.libcamera.org/api/1.1/series/694/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=694","date":"2020-02-28T03:29:07","name":"libcamera: PixelFormat: Turn into a class","version":1,"mbox":"https://patchwork.libcamera.org/series/694/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/2913/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/2913/checks/","tags":{},"headers":{"Return-Path":"<niklas.soderlund@ragnatech.se>","Received":["from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net\n\t[195.74.38.229])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 414246271F\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 28 Feb 2020 04:29:39 +0100 (CET)","from bismarck.berto.se (p4fca2392.dip0.t-ipconnect.de\n\t[79.202.35.146]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA\n\tid 8bdcdf91-59da-11ea-9f85-005056917a89;\n\tFri, 28 Feb 2020 04:29:37 +0100 (CET)"],"X-Halon-ID":"8bdcdf91-59da-11ea-9f85-005056917a89","Authorized-sender":"niklas@soderlund.pp.se","From":"=?utf-8?q?Niklas_S=C3=B6derlund?= <niklas.soderlund@ragnatech.se>","To":"libcamera-devel@lists.libcamera.org","Date":"Fri, 28 Feb 2020 04:29:10 +0100","Message-Id":"<20200228032913.497826-4-niklas.soderlund@ragnatech.se>","X-Mailer":"git-send-email 2.25.1","In-Reply-To":"<20200228032913.497826-1-niklas.soderlund@ragnatech.se>","References":"<20200228032913.497826-1-niklas.soderlund@ragnatech.se>","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [RFC 3/6] libcamera: PixelFormat: Turn into a\n\tclass","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Fri, 28 Feb 2020 03:29:39 -0000"},"content":"Create a class to represent the pixel formats. This is done to prepare\nto add support for modifiers for the formats. One bonus with this change\nit that it's allows it to make it impossible for other then designated\nclasses (V4L2VideoDevice and V4L2CameraProxy) to create PixelFormat\ninstances from a V4L2 fourcc limiting the risk of users of the class to\nmix the two fourcc namespaces unintentionally.\n\nThe patch is unfortunately quiet large as it have to touch a lot of\ndifferent ares of the code to simultaneously switch to the new class\nbased PixelFormat implementation.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\n include/libcamera/pixelformats.h         |  40 +++++++-\n src/cam/main.cpp                         |   4 +-\n src/libcamera/formats.cpp                |   3 +\n src/libcamera/pipeline/ipu3/ipu3.cpp     |   6 +-\n src/libcamera/pipeline/rkisp1/rkisp1.cpp |  22 ++--\n src/libcamera/pipeline/uvcvideo.cpp      |   4 +-\n src/libcamera/pipeline/vimc.cpp          |  12 +--\n src/libcamera/pixelformats.cpp           | 124 +++++++++++++++++++++++\n src/libcamera/stream.cpp                 |   6 +-\n src/libcamera/v4l2_videodevice.cpp       | 101 +-----------------\n src/qcam/format_converter.cpp            |   2 +-\n src/qcam/viewfinder.cpp                  |   2 +-\n src/v4l2/v4l2_camera_proxy.cpp           |  49 ++++-----\n test/stream/stream_formats.cpp           |  33 +++---\n 14 files changed, 236 insertions(+), 172 deletions(-)","diff":"diff --git a/include/libcamera/pixelformats.h b/include/libcamera/pixelformats.h\nindex 6e25b8d8b76e5961..f0951e983192d5e8 100644\n--- a/include/libcamera/pixelformats.h\n+++ b/include/libcamera/pixelformats.h\n@@ -7,11 +7,49 @@\n #ifndef __LIBCAMERA_PIXEL_FORMATS_H__\n #define __LIBCAMERA_PIXEL_FORMATS_H__\n \n+#include <set>\n #include <stdint.h>\n+#include <string>\n+\n+/* Needs to be forward declared in the global namespace. */\n+class V4L2CameraProxy;\n \n namespace libcamera {\n \n-using PixelFormat = uint32_t;\n+struct PixelFormatEntry;\n+\n+class PixelFormat\n+{\n+public:\n+\tPixelFormat();\n+\tPixelFormat(const PixelFormat &other);\n+\texplicit PixelFormat(uint32_t drm_fourcc, const std::set<uint32_t> &drm_modifiers);\n+\n+\tPixelFormat &operator=(const PixelFormat &other);\n+\n+\tbool operator==(const PixelFormat &other) const;\n+\tbool operator!=(const PixelFormat &other) const;\n+\tbool operator<(const PixelFormat &other) const;\n+\n+\tuint32_t v4l2() const;\n+\tuint32_t fourcc() const;\n+\tconst std::set<uint32_t> &modifiers() const;\n+\n+protected:\n+\t/* Needed so V4L2VideoDevice can create PixelFormat from V4L2 fourcc. */\n+\tfriend class V4L2VideoDevice;\n+\n+\t/* Needed so V4L2CameraProxy can create PixelFormat from V4L2 fourcc. */\n+\tfriend V4L2CameraProxy;\n+\n+\texplicit PixelFormat(uint32_t v4l2_fourcc);\n+\n+private:\n+\tconst PixelFormatEntry *fromDRM(uint32_t drm_fourcc, const std::set<uint32_t> &drm_modifiers) const;\n+\tconst PixelFormatEntry *fromV4L2(uint32_t v4l2_fourcc) const;\n+\n+\tconst PixelFormatEntry *format_;\n+};\n \n } /* namespace libcamera */\n \ndiff --git a/src/cam/main.cpp b/src/cam/main.cpp\nindex ad4be55fc114fe22..c8ef79daea37d8b6 100644\n--- a/src/cam/main.cpp\n+++ b/src/cam/main.cpp\n@@ -249,7 +249,7 @@ int CamApp::prepareConfig()\n \n \t\t\t/* TODO: Translate 4CC string to ID. */\n \t\t\tif (opt.isSet(\"pixelformat\"))\n-\t\t\t\tcfg.pixelFormat = opt[\"pixelformat\"];\n+\t\t\t\tcfg.pixelFormat = PixelFormat(opt[\"pixelformat\"], {});\n \t\t}\n \t}\n \n@@ -283,7 +283,7 @@ int CamApp::infoConfiguration()\n \t\tconst StreamFormats &formats = cfg.formats();\n \t\tfor (PixelFormat pixelformat : formats.pixelformats()) {\n \t\t\tstd::cout << \" * Pixelformat: 0x\" << std::hex\n-\t\t\t\t  << std::setw(8) << pixelformat << \" \"\n+\t\t\t\t  << std::setw(8) << pixelformat.fourcc() << \" \"\n \t\t\t\t  << formats.range(pixelformat).toString()\n \t\t\t\t  << std::endl;\n \ndiff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp\nindex 98817deee2b54c84..e3a89121e3c60151 100644\n--- a/src/libcamera/formats.cpp\n+++ b/src/libcamera/formats.cpp\n@@ -9,6 +9,8 @@\n \n #include <errno.h>\n \n+#include <libcamera/pixelformats.h>\n+\n /**\n  * \\file formats.h\n  * \\brief Types and helper methods to handle libcamera image formats\n@@ -110,5 +112,6 @@ const std::map<T, std::vector<SizeRange>> &ImageFormats<T>::data() const\n }\n \n template class ImageFormats<unsigned int>;\n+template class ImageFormats<PixelFormat>;\n \n } /* namespace libcamera */\ndiff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\nindex 33f97b340716abd0..71ac0ae33921f548 100644\n--- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n@@ -247,7 +247,7 @@ IPU3CameraConfiguration::IPU3CameraConfiguration(Camera *camera,\n void IPU3CameraConfiguration::adjustStream(StreamConfiguration &cfg, bool scale)\n {\n \t/* The only pixel format the driver supports is NV12. */\n-\tcfg.pixelFormat = DRM_FORMAT_NV12;\n+\tcfg.pixelFormat = PixelFormat(DRM_FORMAT_NV12, {});\n \n \tif (scale) {\n \t\t/*\n@@ -402,7 +402,7 @@ CameraConfiguration *PipelineHandlerIPU3::generateConfiguration(Camera *camera,\n \t\tStreamConfiguration cfg = {};\n \t\tIPU3Stream *stream = nullptr;\n \n-\t\tcfg.pixelFormat = DRM_FORMAT_NV12;\n+\t\tcfg.pixelFormat = PixelFormat(DRM_FORMAT_NV12, {});\n \n \t\tswitch (role) {\n \t\tcase StreamRole::StillCapture:\n@@ -1142,7 +1142,7 @@ int ImgUDevice::configureOutput(ImgUOutput *output,\n \t\treturn 0;\n \n \tV4L2DeviceFormat outputFormat = {};\n-\toutputFormat.fourcc = dev->toV4L2Fourcc(DRM_FORMAT_NV12);\n+\toutputFormat.fourcc = PixelFormat(DRM_FORMAT_NV12, {}).v4l2();\n \toutputFormat.size = cfg.size;\n \toutputFormat.planesCount = 2;\n \ndiff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\nindex 13433b216747cb8b..323fa3596c6ee242 100644\n--- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n+++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp\n@@ -433,14 +433,14 @@ RkISP1CameraConfiguration::RkISP1CameraConfiguration(Camera *camera,\n \n CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n {\n-\tstatic const std::array<unsigned int, 8> formats{\n-\t\tDRM_FORMAT_YUYV,\n-\t\tDRM_FORMAT_YVYU,\n-\t\tDRM_FORMAT_VYUY,\n-\t\tDRM_FORMAT_NV16,\n-\t\tDRM_FORMAT_NV61,\n-\t\tDRM_FORMAT_NV21,\n-\t\tDRM_FORMAT_NV12,\n+\tstatic const std::array<PixelFormat, 8> formats{\n+\t\tPixelFormat(DRM_FORMAT_YUYV, {}),\n+\t\tPixelFormat(DRM_FORMAT_YVYU, {}),\n+\t\tPixelFormat(DRM_FORMAT_VYUY, {}),\n+\t\tPixelFormat(DRM_FORMAT_NV16, {}),\n+\t\tPixelFormat(DRM_FORMAT_NV61, {}),\n+\t\tPixelFormat(DRM_FORMAT_NV21, {}),\n+\t\tPixelFormat(DRM_FORMAT_NV12, {}),\n \t\t/* \\todo Add support for 8-bit greyscale to DRM formats */\n \t};\n \n@@ -462,7 +462,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate()\n \tif (std::find(formats.begin(), formats.end(), cfg.pixelFormat) ==\n \t    formats.end()) {\n \t\tLOG(RkISP1, Debug) << \"Adjusting format to NV12\";\n-\t\tcfg.pixelFormat = DRM_FORMAT_NV12,\n+\t\tcfg.pixelFormat = PixelFormat(DRM_FORMAT_NV12, {});\n \t\tstatus = Adjusted;\n \t}\n \n@@ -541,7 +541,7 @@ CameraConfiguration *PipelineHandlerRkISP1::generateConfiguration(Camera *camera\n \t\treturn config;\n \n \tStreamConfiguration cfg{};\n-\tcfg.pixelFormat = DRM_FORMAT_NV12;\n+\tcfg.pixelFormat = PixelFormat(DRM_FORMAT_NV12, {});\n \tcfg.size = data->sensor_->resolution();\n \n \tconfig->addConfiguration(cfg);\n@@ -796,7 +796,7 @@ int PipelineHandlerRkISP1::start(Camera *camera)\n \t/* Inform IPA of stream configuration and sensor controls. */\n \tstd::map<unsigned int, IPAStream> streamConfig;\n \tstreamConfig[0] = {\n-\t\t.pixelFormat = data->stream_.configuration().pixelFormat,\n+\t\t.pixelFormat = data->stream_.configuration().pixelFormat.fourcc(),\n \t\t.size = data->stream_.configuration().size,\n \t};\n \ndiff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp\nindex 8efd188e75a3d135..5f3e52f691aaeae4 100644\n--- a/src/libcamera/pipeline/uvcvideo.cpp\n+++ b/src/libcamera/pipeline/uvcvideo.cpp\n@@ -115,8 +115,8 @@ CameraConfiguration::Status UVCCameraConfiguration::validate()\n \tif (iter == pixelFormats.end()) {\n \t\tcfg.pixelFormat = pixelFormats.front();\n \t\tLOG(UVC, Debug)\n-\t\t\t<< \"Adjusting pixel format from \" << pixelFormat\n-\t\t\t<< \" to \" << cfg.pixelFormat;\n+\t\t\t<< \"Adjusting pixel format from \" << pixelFormat.fourcc()\n+\t\t\t<< \" to \" << cfg.pixelFormat.fourcc();\n \t\tstatus = Adjusted;\n \t}\n \ndiff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp\nindex 9fbe33c626e327d4..a591c424919b0783 100644\n--- a/src/libcamera/pipeline/vimc.cpp\n+++ b/src/libcamera/pipeline/vimc.cpp\n@@ -106,10 +106,10 @@ private:\n \n namespace {\n \n-constexpr std::array<unsigned int, 3> pixelformats{\n-\tDRM_FORMAT_RGB888,\n-\tDRM_FORMAT_BGR888,\n-\tDRM_FORMAT_BGRA8888,\n+static const std::array<PixelFormat, 3> pixelformats{\n+\tPixelFormat(DRM_FORMAT_RGB888, {}),\n+\tPixelFormat(DRM_FORMAT_BGR888, {}),\n+\tPixelFormat(DRM_FORMAT_BGRA8888, {}),\n };\n \n } /* namespace */\n@@ -138,7 +138,7 @@ CameraConfiguration::Status VimcCameraConfiguration::validate()\n \tif (std::find(pixelformats.begin(), pixelformats.end(), cfg.pixelFormat) ==\n \t    pixelformats.end()) {\n \t\tLOG(VIMC, Debug) << \"Adjusting format to RGB24\";\n-\t\tcfg.pixelFormat = DRM_FORMAT_BGR888;\n+\t\tcfg.pixelFormat = PixelFormat(DRM_FORMAT_BGR888, {});\n \t\tstatus = Adjusted;\n \t}\n \n@@ -187,7 +187,7 @@ CameraConfiguration *PipelineHandlerVimc::generateConfiguration(Camera *camera,\n \n \tStreamConfiguration cfg(formats.data());\n \n-\tcfg.pixelFormat = DRM_FORMAT_BGR888;\n+\tcfg.pixelFormat = PixelFormat(DRM_FORMAT_BGR888, {});\n \tcfg.size = { 1920, 1080 };\n \tcfg.bufferCount = 4;\n \ndiff --git a/src/libcamera/pixelformats.cpp b/src/libcamera/pixelformats.cpp\nindex c03335400b709d9b..b2aacbc39b9ca16a 100644\n--- a/src/libcamera/pixelformats.cpp\n+++ b/src/libcamera/pixelformats.cpp\n@@ -7,6 +7,13 @@\n \n #include <libcamera/pixelformats.h>\n \n+#include <vector>\n+\n+#include <linux/drm_fourcc.h>\n+#include <linux/videodev2.h>\n+\n+#include \"log.h\"\n+\n /**\n  * \\file pixelformats.h\n  * \\brief libcamera pixel formats\n@@ -14,6 +21,8 @@\n \n namespace libcamera {\n \n+LOG_DEFINE_CATEGORY(PixelFormats)\n+\n /**\n  * \\typedef PixelFormat\n  * \\brief libcamera image pixel format\n@@ -25,4 +34,119 @@ namespace libcamera {\n  * \\todo Add support for format modifiers\n  */\n \n+struct PixelFormatEntry {\n+\tuint32_t v4l2;\n+\tuint32_t drm;\n+\tstd::set<uint32_t> modifiers;\n+};\n+\n+static const std::vector<PixelFormatEntry> pixelFormats = {\n+\t/* Invalid format, important to be first in list. */\n+\t{ .v4l2 = 0,\t\t\t.drm = DRM_FORMAT_INVALID,\t.modifiers = {} },\n+\t/* RGB formats. */\n+\t{ .v4l2 = V4L2_PIX_FMT_RGB24,\t.drm = DRM_FORMAT_BGR888,\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_BGR24,\t.drm = DRM_FORMAT_RGB888,\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_ARGB32,\t.drm = DRM_FORMAT_BGRA8888,\t.modifiers = {} },\n+\t/* YUV packed formats. */\n+\t{ .v4l2 = V4L2_PIX_FMT_YUYV,\t.drm = DRM_FORMAT_YUYV,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_YVYU,\t.drm = DRM_FORMAT_YVYU,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_UYVY,\t.drm = DRM_FORMAT_UYVY,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_VYUY,\t.drm = DRM_FORMAT_VYUY,\t\t.modifiers = {} },\n+\t/* YUY planar formats. */\n+\t{ .v4l2 = V4L2_PIX_FMT_NV16,\t.drm = DRM_FORMAT_NV16,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_NV16M,\t.drm = DRM_FORMAT_NV16,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_NV61,\t.drm = DRM_FORMAT_NV61,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_NV61M,\t.drm = DRM_FORMAT_NV61,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_NV12,\t.drm = DRM_FORMAT_NV12,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_NV12M,\t.drm = DRM_FORMAT_NV12,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_NV21,\t.drm = DRM_FORMAT_NV21,\t\t.modifiers = {} },\n+\t{ .v4l2 = V4L2_PIX_FMT_NV21M,\t.drm = DRM_FORMAT_NV21,\t\t.modifiers = {} },\n+\t/* Compressed formats. */\n+\t{ .v4l2 = V4L2_PIX_FMT_MJPEG,\t.drm = DRM_FORMAT_MJPEG,\t.modifiers = {} },\n+};\n+\n+PixelFormat::PixelFormat()\n+\t: format_(&pixelFormats[0])\n+{\n+}\n+\n+PixelFormat::PixelFormat(const PixelFormat &other)\n+\t: format_(other.format_)\n+{\n+}\n+\n+PixelFormat::PixelFormat(uint32_t drm_fourcc, const std::set<uint32_t> &drm_modifiers)\n+\t: format_(fromDRM(drm_fourcc, drm_modifiers))\n+{\n+}\n+\n+PixelFormat::PixelFormat(uint32_t v4l2_fourcc)\n+\t: format_(fromV4L2(v4l2_fourcc))\n+{\n+}\n+\n+PixelFormat &PixelFormat::operator=(const PixelFormat &other)\n+{\n+\tformat_ = other.format_;\n+\n+\treturn *this;\n+}\n+\n+bool PixelFormat::operator==(const PixelFormat &other) const\n+{\n+\treturn format_ == other.format_;\n+}\n+\n+bool PixelFormat::operator!=(const PixelFormat &other) const\n+{\n+\treturn format_ != other.format_;\n+}\n+\n+bool PixelFormat::operator<(const PixelFormat &other) const\n+{\n+\treturn format_ > other.format_;\n+}\n+\n+uint32_t PixelFormat::v4l2() const\n+{\n+\treturn format_->v4l2;\n+}\n+\n+uint32_t PixelFormat::fourcc() const\n+{\n+\treturn format_->drm;\n+}\n+\n+const std::set<uint32_t> &PixelFormat::modifiers() const\n+{\n+\treturn format_->modifiers;\n+}\n+\n+const PixelFormatEntry *PixelFormat::fromDRM(uint32_t drm_fourcc, const std::set<uint32_t> &drm_modifiers) const\n+{\n+\tfor (const PixelFormatEntry &entry : pixelFormats)\n+\t\tif (entry.drm == drm_fourcc &&\n+\t\t    entry.modifiers == drm_modifiers)\n+\t\t\treturn &entry;\n+\n+\tLOG(PixelFormats, Error)\n+\t\t<< \"Unsupported DRM pixel format \"\n+\t\t<< utils::hex(drm_fourcc);\n+\n+\treturn &pixelFormats[0];\n+}\n+\n+const PixelFormatEntry *PixelFormat::fromV4L2(uint32_t v4l2_fourcc) const\n+{\n+\tfor (const PixelFormatEntry &entry : pixelFormats)\n+\t\tif (entry.v4l2 == v4l2_fourcc)\n+\t\t\treturn &entry;\n+\n+\tLOG(PixelFormats, Error)\n+\t\t<< \"Unsupported V4L2 pixel format \"\n+\t\t<< utils::hex(v4l2_fourcc);\n+\n+\treturn &pixelFormats[0];\n+}\n+\n } /* namespace libcamera */\ndiff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp\nindex 13789e9eb344f95c..dbce550ca8d0b7b1 100644\n--- a/src/libcamera/stream.cpp\n+++ b/src/libcamera/stream.cpp\n@@ -279,7 +279,7 @@ SizeRange StreamFormats::range(PixelFormat pixelformat) const\n  * handlers provied StreamFormats.\n  */\n StreamConfiguration::StreamConfiguration()\n-\t: pixelFormat(0), stream_(nullptr)\n+\t: pixelFormat(), stream_(nullptr)\n {\n }\n \n@@ -287,7 +287,7 @@ StreamConfiguration::StreamConfiguration()\n  * \\brief Construct a configuration with stream formats\n  */\n StreamConfiguration::StreamConfiguration(const StreamFormats &formats)\n-\t: pixelFormat(0), stream_(nullptr), formats_(formats)\n+\t: pixelFormat(), stream_(nullptr), formats_(formats)\n {\n }\n \n@@ -348,7 +348,7 @@ StreamConfiguration::StreamConfiguration(const StreamFormats &formats)\n std::string StreamConfiguration::toString() const\n {\n \tstd::stringstream ss;\n-\tss << size.toString() << \"-\" << utils::hex(pixelFormat);\n+\tss << size.toString() << \"-\" << utils::hex(pixelFormat.fourcc());\n \treturn ss.str();\n }\n \ndiff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\nindex f84bd00570afa38c..e9d3e60198e140a0 100644\n--- a/src/libcamera/v4l2_videodevice.cpp\n+++ b/src/libcamera/v4l2_videodevice.cpp\n@@ -846,7 +846,7 @@ ImageFormats<PixelFormat> V4L2VideoDevice::formats()\n \t\tif (sizes.empty())\n \t\t\treturn {};\n \n-\t\tif (formats.addFormat(pixelformat, sizes)) {\n+\t\tif (formats.addFormat(PixelFormat(pixelformat), sizes)) {\n \t\t\tLOG(V4L2, Error)\n \t\t\t\t<< \"Could not add sizes for pixel format \"\n \t\t\t\t<< pixelformat;\n@@ -1417,56 +1417,7 @@ V4L2VideoDevice *V4L2VideoDevice::fromEntityName(const MediaDevice *media,\n  */\n PixelFormat V4L2VideoDevice::toPixelFormat(uint32_t v4l2Fourcc)\n {\n-\tswitch (v4l2Fourcc) {\n-\t/* RGB formats. */\n-\tcase V4L2_PIX_FMT_RGB24:\n-\t\treturn DRM_FORMAT_BGR888;\n-\tcase V4L2_PIX_FMT_BGR24:\n-\t\treturn DRM_FORMAT_RGB888;\n-\tcase V4L2_PIX_FMT_ARGB32:\n-\t\treturn DRM_FORMAT_BGRA8888;\n-\n-\t/* YUV packed formats. */\n-\tcase V4L2_PIX_FMT_YUYV:\n-\t\treturn DRM_FORMAT_YUYV;\n-\tcase V4L2_PIX_FMT_YVYU:\n-\t\treturn DRM_FORMAT_YVYU;\n-\tcase V4L2_PIX_FMT_UYVY:\n-\t\treturn DRM_FORMAT_UYVY;\n-\tcase V4L2_PIX_FMT_VYUY:\n-\t\treturn DRM_FORMAT_VYUY;\n-\n-\t/* YUY planar formats. */\n-\tcase V4L2_PIX_FMT_NV16:\n-\tcase V4L2_PIX_FMT_NV16M:\n-\t\treturn DRM_FORMAT_NV16;\n-\tcase V4L2_PIX_FMT_NV61:\n-\tcase V4L2_PIX_FMT_NV61M:\n-\t\treturn DRM_FORMAT_NV61;\n-\tcase V4L2_PIX_FMT_NV12:\n-\tcase V4L2_PIX_FMT_NV12M:\n-\t\treturn DRM_FORMAT_NV12;\n-\tcase V4L2_PIX_FMT_NV21:\n-\tcase V4L2_PIX_FMT_NV21M:\n-\t\treturn DRM_FORMAT_NV21;\n-\n-\t/* Compressed formats. */\n-\tcase V4L2_PIX_FMT_MJPEG:\n-\t\treturn DRM_FORMAT_MJPEG;\n-\n-\t/* V4L2 formats not yet supported by DRM. */\n-\tcase V4L2_PIX_FMT_GREY:\n-\tdefault:\n-\t\t/*\n-\t\t * \\todo We can't use LOG() in a static method of a Loggable\n-\t\t * class. Until we fix the logger, work around it.\n-\t\t */\n-\t\tlibcamera::_log(__FILE__, __LINE__, _LOG_CATEGORY(V4L2)(),\n-\t\t\t\tLogError).stream()\n-\t\t\t<< \"Unsupported V4L2 pixel format \"\n-\t\t\t<< utils::hex(v4l2Fourcc);\n-\t\treturn 0;\n-\t}\n+\treturn PixelFormat(v4l2Fourcc);\n }\n \n /**\n@@ -1500,53 +1451,7 @@ uint32_t V4L2VideoDevice::toV4L2Fourcc(PixelFormat pixelFormat)\n  */\n uint32_t V4L2VideoDevice::toV4L2Fourcc(PixelFormat pixelFormat, bool multiplanar)\n {\n-\tswitch (pixelFormat) {\n-\t/* RGB formats. */\n-\tcase DRM_FORMAT_BGR888:\n-\t\treturn V4L2_PIX_FMT_RGB24;\n-\tcase DRM_FORMAT_RGB888:\n-\t\treturn V4L2_PIX_FMT_BGR24;\n-\tcase DRM_FORMAT_BGRA8888:\n-\t\treturn V4L2_PIX_FMT_ARGB32;\n-\n-\t/* YUV packed formats. */\n-\tcase DRM_FORMAT_YUYV:\n-\t\treturn V4L2_PIX_FMT_YUYV;\n-\tcase DRM_FORMAT_YVYU:\n-\t\treturn V4L2_PIX_FMT_YVYU;\n-\tcase DRM_FORMAT_UYVY:\n-\t\treturn V4L2_PIX_FMT_UYVY;\n-\tcase DRM_FORMAT_VYUY:\n-\t\treturn V4L2_PIX_FMT_VYUY;\n-\n-\t/*\n-\t * YUY planar formats.\n-\t * \\todo Add support for non-contiguous memory planes\n-\t * \\todo Select the format variant not only based on \\a multiplanar but\n-\t * also take into account the formats supported by the device.\n-\t */\n-\tcase DRM_FORMAT_NV16:\n-\t\treturn V4L2_PIX_FMT_NV16;\n-\tcase DRM_FORMAT_NV61:\n-\t\treturn V4L2_PIX_FMT_NV61;\n-\tcase DRM_FORMAT_NV12:\n-\t\treturn V4L2_PIX_FMT_NV12;\n-\tcase DRM_FORMAT_NV21:\n-\t\treturn V4L2_PIX_FMT_NV21;\n-\n-\t/* Compressed formats. */\n-\tcase DRM_FORMAT_MJPEG:\n-\t\treturn V4L2_PIX_FMT_MJPEG;\n-\t}\n-\n-\t/*\n-\t * \\todo We can't use LOG() in a static method of a Loggable\n-\t * class. Until we fix the logger, work around it.\n-\t */\n-\tlibcamera::_log(__FILE__, __LINE__, _LOG_CATEGORY(V4L2)(), LogError).stream()\n-\t\t<< \"Unsupported V4L2 pixel format \"\n-\t\t<< utils::hex(pixelFormat);\n-\treturn 0;\n+\treturn pixelFormat.v4l2();\n }\n \n /**\ndiff --git a/src/qcam/format_converter.cpp b/src/qcam/format_converter.cpp\nindex 368cb43fbf17ae4d..c071ea9b4022750c 100644\n--- a/src/qcam/format_converter.cpp\n+++ b/src/qcam/format_converter.cpp\n@@ -30,7 +30,7 @@\n int FormatConverter::configure(libcamera::PixelFormat format, unsigned int width,\n \t\t\t       unsigned int height)\n {\n-\tswitch (format) {\n+\tswitch (format.fourcc()) {\n \tcase DRM_FORMAT_NV12:\n \t\tformatFamily_ = NV;\n \t\thorzSubSample_ = 2;\ndiff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp\nindex 0ebb8edd49efd1b1..d86c97dab8374d5e 100644\n--- a/src/qcam/viewfinder.cpp\n+++ b/src/qcam/viewfinder.cpp\n@@ -14,7 +14,7 @@\n #include \"viewfinder.h\"\n \n ViewFinder::ViewFinder(QWidget *parent)\n-\t: QWidget(parent), format_(0), width_(0), height_(0), image_(nullptr)\n+\t: QWidget(parent), format_(), width_(0), height_(0), image_(nullptr)\n {\n }\n \ndiff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\nindex 622520479be01f58..e9d7bfd8ee243b78 100644\n--- a/src/v4l2/v4l2_camera_proxy.cpp\n+++ b/src/v4l2/v4l2_camera_proxy.cpp\n@@ -525,7 +525,6 @@ struct PixelFormatPlaneInfo {\n };\n \n struct PixelFormatInfo {\n-\tPixelFormat format;\n \tuint32_t v4l2Format;\n \tunsigned int numPlanes;\n \tstd::array<PixelFormatPlaneInfo, 3> planes;\n@@ -533,24 +532,24 @@ struct PixelFormatInfo {\n \n namespace {\n \n-constexpr std::array<PixelFormatInfo, 13> pixelFormatInfo = {{\n+static const std::array<PixelFormatInfo, 13> pixelFormatInfo = { {\n \t/* RGB formats. */\n-\t{ DRM_FORMAT_RGB888,\tV4L2_PIX_FMT_BGR24,\t1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_BGR888,\tV4L2_PIX_FMT_RGB24,\t1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_BGRA8888,\tV4L2_PIX_FMT_ARGB32,\t1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_BGR24,\t1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_RGB24,\t1, {{ { 24, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_ARGB32,\t1, {{ { 32, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n \t/* YUV packed formats. */\n-\t{ DRM_FORMAT_UYVY,\tV4L2_PIX_FMT_UYVY,\t1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_VYUY,\tV4L2_PIX_FMT_VYUY,\t1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_YUYV,\tV4L2_PIX_FMT_YUYV,\t1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_YVYU,\tV4L2_PIX_FMT_YVYU,\t1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_UYVY,\t1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_VYUY,\t1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_YUYV,\t1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_YVYU,\t1, {{ { 16, 1, 1 }, {  0, 0, 0 }, {  0, 0, 0 } }} },\n \t/* YUY planar formats. */\n-\t{ DRM_FORMAT_NV12,\tV4L2_PIX_FMT_NV12,\t2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_NV21,\tV4L2_PIX_FMT_NV21,\t2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_NV16,\tV4L2_PIX_FMT_NV16,\t2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_NV61,\tV4L2_PIX_FMT_NV61,\t2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_NV24,\tV4L2_PIX_FMT_NV24,\t2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },\n-\t{ DRM_FORMAT_NV42,\tV4L2_PIX_FMT_NV42,\t2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },\n-}};\n+\t{ V4L2_PIX_FMT_NV12,\t2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_NV21,\t2, {{ {  8, 1, 1 }, { 16, 2, 2 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_NV16,\t2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_NV61,\t2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_NV24,\t2, {{ {  8, 1, 1 }, { 16, 2, 1 }, {  0, 0, 0 } }} },\n+\t{ V4L2_PIX_FMT_NV42,\t2, {{ {  8, 1, 1 }, { 16, 1, 1 }, {  0, 0, 0 } }} },\n+} };\n \n } /* namespace */\n \n@@ -588,24 +587,10 @@ unsigned int V4L2CameraProxy::imageSize(uint32_t format, unsigned int width,\n \n PixelFormat V4L2CameraProxy::v4l2ToDrm(uint32_t format)\n {\n-\tauto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),\n-\t\t\t\t [format](const PixelFormatInfo &info) {\n-\t\t\t\t\t return info.v4l2Format == format;\n-\t\t\t\t });\n-\tif (info == pixelFormatInfo.end())\n-\t\treturn format;\n-\n-\treturn info->format;\n+\treturn PixelFormat(format);\n }\n \n uint32_t V4L2CameraProxy::drmToV4L2(PixelFormat format)\n {\n-\tauto info = std::find_if(pixelFormatInfo.begin(), pixelFormatInfo.end(),\n-\t\t\t\t [format](const PixelFormatInfo &info) {\n-\t\t\t\t\t return info.format == format;\n-\t\t\t\t });\n-\tif (info == pixelFormatInfo.end())\n-\t\treturn format;\n-\n-\treturn info->v4l2Format;\n+\treturn format.v4l2();\n }\ndiff --git a/test/stream/stream_formats.cpp b/test/stream/stream_formats.cpp\nindex a391f5cd087d3872..a904d681c1691889 100644\n--- a/test/stream/stream_formats.cpp\n+++ b/test/stream/stream_formats.cpp\n@@ -7,6 +7,8 @@\n \n #include <iostream>\n \n+#include <linux/drm_fourcc.h>\n+\n #include <libcamera/geometry.h>\n #include <libcamera/stream.h>\n \n@@ -53,42 +55,49 @@ protected:\n \n \tint run()\n \t{\n+\t\tstd::vector<PixelFormat> pixelFormats = {\n+\t\t\tPixelFormat(DRM_FORMAT_YUYV, {}),\n+\t\t\tPixelFormat(DRM_FORMAT_YVYU, {}),\n+\t\t\tPixelFormat(DRM_FORMAT_UYVY, {}),\n+\t\t\tPixelFormat(DRM_FORMAT_VYUY, {}),\n+\t\t};\n+\n \t\t/* Test discrete sizes */\n \t\tStreamFormats discrete({\n-\t\t\t{ 1, { SizeRange(100, 100), SizeRange(200, 200) } },\n-\t\t\t{ 2, { SizeRange(300, 300), SizeRange(400, 400) } },\n+\t\t\t{ pixelFormats[0], { SizeRange(100, 100), SizeRange(200, 200) } },\n+\t\t\t{ pixelFormats[1], { SizeRange(300, 300), SizeRange(400, 400) } },\n \t\t});\n \n-\t\tif (testSizes(\"discrete 1\", discrete.sizes(1),\n+\t\tif (testSizes(\"discrete 1\", discrete.sizes(pixelFormats[0]),\n \t\t\t      { Size(100, 100), Size(200, 200) }))\n \t\t\treturn TestFail;\n-\t\tif (testSizes(\"discrete 2\", discrete.sizes(2),\n+\t\tif (testSizes(\"discrete 2\", discrete.sizes(pixelFormats[1]),\n \t\t\t      { Size(300, 300), Size(400, 400) }))\n \t\t\treturn TestFail;\n \n \t\t/* Test range sizes */\n \t\tStreamFormats range({\n-\t\t\t{ 1, { SizeRange(640, 480, 640, 480) } },\n-\t\t\t{ 2, { SizeRange(640, 480, 800, 600, 8, 8) } },\n-\t\t\t{ 3, { SizeRange(640, 480, 800, 600, 16, 16) } },\n-\t\t\t{ 4, { SizeRange(128, 128, 4096, 4096, 128, 128) } },\n+\t\t\t{ pixelFormats[0], { SizeRange(640, 480, 640, 480) } },\n+\t\t\t{ pixelFormats[1], { SizeRange(640, 480, 800, 600, 8, 8) } },\n+\t\t\t{ pixelFormats[2], { SizeRange(640, 480, 800, 600, 16, 16) } },\n+\t\t\t{ pixelFormats[3], { SizeRange(128, 128, 4096, 4096, 128, 128) } },\n \t\t});\n \n-\t\tif (testSizes(\"range 1\", range.sizes(1), { Size(640, 480) }))\n+\t\tif (testSizes(\"range 1\", range.sizes(pixelFormats[0]), { Size(640, 480) }))\n \t\t\treturn TestFail;\n \n-\t\tif (testSizes(\"range 2\", range.sizes(2), {\n+\t\tif (testSizes(\"range 2\", range.sizes(pixelFormats[1]), {\n \t\t\t      Size(640, 480), Size(720, 480),\n \t\t\t      Size(720, 576), Size(768, 480),\n \t\t\t      Size(800, 600) }))\n \t\t\treturn TestFail;\n \n-\t\tif (testSizes(\"range 3\", range.sizes(3), {\n+\t\tif (testSizes(\"range 3\", range.sizes(pixelFormats[2]), {\n \t\t\t      Size(640, 480), Size(720, 480),\n \t\t\t      Size(720, 576), Size(768, 480) }))\n \t\t\treturn TestFail;\n \n-\t\tif (testSizes(\"range 4\", range.sizes(4), {\n+\t\tif (testSizes(\"range 4\", range.sizes(pixelFormats[3]), {\n \t\t\t      Size(1024, 768), Size(1280, 1024),\n \t\t\t      Size(2048, 1152), Size(2048, 1536),\n \t\t\t      Size(2560, 2048), Size(3200, 2048), }))\n","prefixes":["libcamera-devel","RFC","3/6"]}