[libcamera-devel] [PATCH v2.1 1/7] libcamera: Define constants for pixel formats in the public API

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Jun 17 16:39:14 CEST 2020


libcamera uses pixel format FourCC and modifier values from DRM. This
requires inclusion of drm_fourcc.h, creating a dependency on a header
that is packaged differently between distributions, and causing possible
issues with third-party applications.

Define constants for the supported pixel formats in the new formats.h
public API header, in order to remove the dependency on drm_fourcc.h.
The header is generated by a Python script from a list of supported
formats. The numerical values for the FourCC and modifier are extracted
from drm_fourcc.h by the script, ensuring that numerical values are not
inadvertently modified and preserving the direct interoperability.

The pixel formats constants can't be generated solely from drm_fourcc.h,
as that header defines FourCC values and modifier values, but doesn't
list the valid combinations. The supported formats are thus stored in a
YAML file, which contains the FourCC and optional modifier for each
supported format. We may later extend the YAML file to include formats
documentation, and possibly formats metadata to populate the
pixelFormatInfo map (in formats.cpp) automatically.

Now that two formats.h header are present (one in include/libcamera/ and
one in include/libcamera/internal/), we need to explicitly qualify the
Doxygen \file directive with a path.

Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
---
Changes since v2:

- Fix typo in comment
- Add formats.h to the libcamera sources to avoid races during build

Changes since v1:

- Add a note about the Doxygen \file change to the commit message
- Generate formats.h from formats.yaml
- Dropped Kieran's R-b tag due to the switch to auto-generation
- Mention libcamera/formats.h in the PixelFormat class documentation
- Add IPU3-packed Bayer formats
---
 include/libcamera/formats.h.in   |  44 +++++++++++
 include/libcamera/gen-formats.py | 118 +++++++++++++++++++++++++++++
 include/libcamera/meson.build    |  22 ++++++
 src/libcamera/formats.cpp        |   2 +-
 src/libcamera/formats.yaml       | 124 +++++++++++++++++++++++++++++++
 src/libcamera/meson.build        |   3 +-
 src/libcamera/pixel_format.cpp   |   4 +-
 7 files changed, 314 insertions(+), 3 deletions(-)
 create mode 100644 include/libcamera/formats.h.in
 create mode 100755 include/libcamera/gen-formats.py
 create mode 100644 src/libcamera/formats.yaml

diff --git a/include/libcamera/formats.h.in b/include/libcamera/formats.h.in
new file mode 100644
index 000000000000..8e7b95812afa
--- /dev/null
+++ b/include/libcamera/formats.h.in
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2020, Google Inc.
+ *
+ * formats.h - Formats
+ *
+ * This file is auto-generated. Do not edit.
+ */
+#ifndef __LIBCAMERA_FORMATS_H__
+#define __LIBCAMERA_FORMATS_H__
+
+#include <stdint.h>
+
+#include <libcamera/pixel_format.h>
+
+namespace libcamera {
+
+namespace formats {
+
+namespace {
+
+constexpr uint32_t __fourcc(char a, char b, char c, char d)
+{
+	return (static_cast<uint32_t>(a) <<  0) |
+	       (static_cast<uint32_t>(b) <<  8) |
+	       (static_cast<uint32_t>(c) << 16) |
+	       (static_cast<uint32_t>(d) << 24);
+}
+
+constexpr uint64_t __mod(unsigned int vendor, unsigned int mod)
+{
+	return (static_cast<uint64_t>(vendor) << 56) |
+	       (static_cast<uint64_t>(mod) << 0);
+}
+
+} /* namespace */
+
+${formats}
+
+} /* namespace formats */
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_FORMATS_H__ */
diff --git a/include/libcamera/gen-formats.py b/include/libcamera/gen-formats.py
new file mode 100755
index 000000000000..60dcecc345d5
--- /dev/null
+++ b/include/libcamera/gen-formats.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2020, Google Inc.
+#
+# Author: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
+#
+# gen-formats.py - Generate formats definitions from YAML
+
+import argparse
+import re
+import string
+import sys
+import yaml
+
+
+class DRMFourCC(object):
+    format_regex = re.compile(r"#define (DRM_FORMAT_[A-Z0-9_]+)[ \t]+fourcc_code\(('.', '.', '.', '.')\)")
+    mod_vendor_regex = re.compile(r"#define DRM_FORMAT_MOD_VENDOR_([A-Z0-9_]+)[ \t]+([0-9a-fA-Fx]+)")
+    mod_regex = re.compile(r"#define ([A-Za-z0-9_]+)[ \t]+fourcc_mod_code\(([A-Z0-9_]+), ([0-9a-fA-Fx]+)\)")
+
+    def __init__(self, filename):
+        self.formats = {}
+        self.vendors = {}
+        self.mods = {}
+
+        for line in open(filename, 'rb').readlines():
+            line = line.decode('utf-8')
+
+            match = DRMFourCC.format_regex.match(line)
+            if match:
+                format, fourcc = match.groups()
+                self.formats[format] = fourcc
+                continue
+
+            match = DRMFourCC.mod_vendor_regex.match(line)
+            if match:
+                vendor, value = match.groups()
+                self.vendors[vendor] = int(value, 0)
+                continue
+
+            match = DRMFourCC.mod_regex.match(line)
+            if match:
+                mod, vendor, value = match.groups()
+                self.mods[mod] = (vendor, int(value, 0))
+                continue
+
+    def fourcc(self, name):
+        return self.formats[name]
+
+    def mod(self, name):
+        vendor, value = self.mods[name]
+        return self.vendors[vendor], value
+
+
+def generate_h(formats, drm_fourcc):
+    template = string.Template('constexpr PixelFormat ${name}{ __fourcc(${fourcc}), __mod(${mod}) };')
+
+    fmts = []
+
+    for format in formats:
+        name, format = format.popitem()
+
+        data = {
+            'name': name,
+            'fourcc': drm_fourcc.fourcc(format['fourcc']),
+            'mod': '0, 0',
+        }
+
+        mod = format.get('mod')
+        if mod:
+            data['mod'] = '%u, %u' % drm_fourcc.mod(mod)
+
+        fmts.append(template.substitute(data))
+
+    return {'formats': '\n'.join(fmts)}
+
+
+def fill_template(template, data):
+
+    template = open(template, 'rb').read()
+    template = template.decode('utf-8')
+    template = string.Template(template)
+    return template.substitute(data)
+
+
+def main(argv):
+
+    # Parse command line arguments
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-o', dest='output', metavar='file', type=str,
+                        help='Output file name. Defaults to standard output if not specified.')
+    parser.add_argument('input', type=str,
+                        help='Input file name.')
+    parser.add_argument('template', type=str,
+                        help='Template file name.')
+    parser.add_argument('drm_fourcc', type=str,
+                        help='Path to drm_fourcc.h.')
+    args = parser.parse_args(argv[1:])
+
+    data = open(args.input, 'rb').read()
+    formats = yaml.safe_load(data)['formats']
+    drm_fourcc = DRMFourCC(args.drm_fourcc)
+
+    data = generate_h(formats, drm_fourcc)
+    data = fill_template(args.template, data)
+
+    if args.output:
+        output = open(args.output, 'wb')
+        output.write(data.encode('utf-8'))
+        output.close()
+    else:
+        sys.stdout.write(data)
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
index 73c5b999acf4..cdb8e0372e77 100644
--- a/include/libcamera/meson.build
+++ b/include/libcamera/meson.build
@@ -29,6 +29,11 @@ subdir('ipa')
 install_headers(libcamera_public_headers,
                 subdir : include_dir)
 
+#
+# Generate headers from templates.
+#
+
+# control_ids.h and property_ids.h
 gen_controls = files('../../src/libcamera/gen-controls.py')
 
 control_source_files = [
@@ -51,6 +56,22 @@ endforeach
 
 libcamera_public_headers += control_headers
 
+# formats.h
+gen_formats = files('gen-formats.py')
+
+formats_h = custom_target('formats_h',
+                          input : files(
+                              '../../src/libcamera/formats.yaml',
+                              'formats.h.in',
+                              '../linux/drm_fourcc.h'
+                          ),
+                          output : 'formats.h',
+                          command : [gen_formats, '-o', '@OUTPUT@', '@INPUT@'],
+                          install : true,
+                          install_dir : join_paths('include', include_dir))
+libcamera_public_headers += formats_h
+
+# libcamera.h
 gen_header = files('gen-header.sh')
 
 libcamera_h = custom_target('gen-header',
@@ -62,6 +83,7 @@ libcamera_h = custom_target('gen-header',
 
 libcamera_public_headers += libcamera_h
 
+# version.h
 version = libcamera_version.split('.')
 libcamera_version_config = configuration_data()
 libcamera_version_config.set('LIBCAMERA_VERSION_MAJOR', version[0])
diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp
index 2ac3b412ecdb..74c239a5e710 100644
--- a/src/libcamera/formats.cpp
+++ b/src/libcamera/formats.cpp
@@ -12,7 +12,7 @@
 #include "libcamera/internal/log.h"
 
 /**
- * \file formats.h
+ * \file internal/formats.h
  * \brief Types and helper methods to handle libcamera image formats
  */
 
diff --git a/src/libcamera/formats.yaml b/src/libcamera/formats.yaml
new file mode 100644
index 000000000000..a6841c618f93
--- /dev/null
+++ b/src/libcamera/formats.yaml
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# Copyright (C) 2020, Google Inc.
+#
+%YAML 1.2
+---
+formats:
+  - R8:
+      fourcc: DRM_FORMAT_R8
+
+  - RGB888:
+      fourcc: DRM_FORMAT_RGB888
+  - BGR888:
+      fourcc: DRM_FORMAT_BGR888
+
+  - XRGB8888:
+      fourcc: DRM_FORMAT_XRGB8888
+  - XBGR8888:
+      fourcc: DRM_FORMAT_XBGR8888
+  - RGBX8888:
+      fourcc: DRM_FORMAT_RGBX8888
+  - BGRX8888:
+      fourcc: DRM_FORMAT_BGRX8888
+
+  - ARGB8888:
+      fourcc: DRM_FORMAT_ARGB8888
+  - ABGR8888:
+      fourcc: DRM_FORMAT_ABGR8888
+  - RGBA8888:
+      fourcc: DRM_FORMAT_RGBA8888
+  - BGRA8888:
+      fourcc: DRM_FORMAT_BGRA8888
+
+  - YUYV:
+      fourcc: DRM_FORMAT_YUYV
+  - YVYU:
+      fourcc: DRM_FORMAT_YVYU
+  - UYVY:
+      fourcc: DRM_FORMAT_UYVY
+  - VYUY:
+      fourcc: DRM_FORMAT_VYUY
+
+  - NV12:
+      fourcc: DRM_FORMAT_NV12
+  - NV21:
+      fourcc: DRM_FORMAT_NV21
+  - NV16:
+      fourcc: DRM_FORMAT_NV16
+  - NV61:
+      fourcc: DRM_FORMAT_NV61
+  - NV24:
+      fourcc: DRM_FORMAT_NV24
+  - NV42:
+      fourcc: DRM_FORMAT_NV42
+
+  - MJPEG:
+      fourcc: DRM_FORMAT_MJPEG
+
+  - SRGGB8:
+      fourcc: DRM_FORMAT_SRGGB8
+  - SGRBG8:
+      fourcc: DRM_FORMAT_SGRBG8
+  - SGBRG8:
+      fourcc: DRM_FORMAT_SGBRG8
+  - SBGGR8:
+      fourcc: DRM_FORMAT_SBGGR8
+
+  - SRGGB10:
+      fourcc: DRM_FORMAT_SRGGB10
+  - SGRBG10:
+      fourcc: DRM_FORMAT_SGRBG10
+  - SGBRG10:
+      fourcc: DRM_FORMAT_SGBRG10
+  - SBGGR10:
+      fourcc: DRM_FORMAT_SBGGR10
+
+  - SRGGB12:
+      fourcc: DRM_FORMAT_SRGGB12
+  - SGRBG12:
+      fourcc: DRM_FORMAT_SGRBG12
+  - SGBRG12:
+      fourcc: DRM_FORMAT_SGBRG12
+  - SBGGR12:
+      fourcc: DRM_FORMAT_SBGGR12
+
+  - SRGGB10_CSI2P:
+      fourcc: DRM_FORMAT_SRGGB10
+      mod: MIPI_FORMAT_MOD_CSI2_PACKED
+  - SGRBG10_CSI2P:
+      fourcc: DRM_FORMAT_SGRBG10
+      mod: MIPI_FORMAT_MOD_CSI2_PACKED
+  - SGBRG10_CSI2P:
+      fourcc: DRM_FORMAT_SGBRG10
+      mod: MIPI_FORMAT_MOD_CSI2_PACKED
+  - SBGGR10_CSI2P:
+      fourcc: DRM_FORMAT_SBGGR10
+      mod: MIPI_FORMAT_MOD_CSI2_PACKED
+
+  - SRGGB12_CSI2P:
+      fourcc: DRM_FORMAT_SRGGB12
+      mod: MIPI_FORMAT_MOD_CSI2_PACKED
+  - SGRBG12_CSI2P:
+      fourcc: DRM_FORMAT_SGRBG12
+      mod: MIPI_FORMAT_MOD_CSI2_PACKED
+  - SGBRG12_CSI2P:
+      fourcc: DRM_FORMAT_SGBRG12
+      mod: MIPI_FORMAT_MOD_CSI2_PACKED
+  - SBGGR12_CSI2P:
+      fourcc: DRM_FORMAT_SBGGR12
+      mod: MIPI_FORMAT_MOD_CSI2_PACKED
+
+  - SRGGB10_IPU3:
+      fourcc: DRM_FORMAT_SRGGB10
+      mod: IPU3_FORMAT_MOD_PACKED
+  - SGRBG10_IPU3:
+      fourcc: DRM_FORMAT_SGRBG10
+      mod: IPU3_FORMAT_MOD_PACKED
+  - SGBRG10_IPU3:
+      fourcc: DRM_FORMAT_SGBRG10
+      mod: IPU3_FORMAT_MOD_PACKED
+  - SBGGR10_IPU3:
+      fourcc: DRM_FORMAT_SBGGR10
+      mod: IPU3_FORMAT_MOD_PACKED
+...
diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
index 611fc061e1cf..3aad4386ffc2 100644
--- a/src/libcamera/meson.build
+++ b/src/libcamera/meson.build
@@ -51,6 +51,8 @@ libcamera_sources = files([
     'v4l2_videodevice.cpp',
 ])
 
+libcamera_sources += libcamera_public_headers
+
 includes = [
     libcamera_includes,
 ]
@@ -87,7 +89,6 @@ foreach source : control_source_files
                                      command : [gen_controls, '-o', '@OUTPUT@', '@INPUT@'])
 endforeach
 
-libcamera_sources += control_headers
 libcamera_sources += control_sources
 
 gen_version = join_paths(meson.source_root(), 'utils', 'gen-version.sh')
diff --git a/src/libcamera/pixel_format.cpp b/src/libcamera/pixel_format.cpp
index d501c5f09c6b..f191851ae22c 100644
--- a/src/libcamera/pixel_format.cpp
+++ b/src/libcamera/pixel_format.cpp
@@ -5,6 +5,7 @@
  * pixel_format.cpp - libcamera Pixel Format
  */
 
+#include <libcamera/formats.h>
 #include <libcamera/pixel_format.h>
 
 /**
@@ -21,7 +22,8 @@ namespace libcamera {
  * The PixelFormat type describes the format of images in the public libcamera
  * API. It stores a FourCC value as a 32-bit unsigned integer and a modifier.
  * The FourCC and modifier values are defined in the Linux kernel DRM/KMS API
- * (see linux/drm_fourcc.h).
+ * (see linux/drm_fourcc.h). Constant expressions for all pixel formats
+ * supported by libcamera are available in libcamera/formats.h.
  */
 
 /**
-- 
Regards,

Laurent Pinchart



More information about the libcamera-devel mailing list