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..9bbff5f1cf6f
--- /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@ideasonboard.com>
+#
+# gen-formatss.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/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.
  */
 
 /**
