diff mbox series

[v4l-utils,v10,1/5] Add support for meson building

Message ID 20230223164441.22719-2-laurent.pinchart@ideasonboard.com
State New
Headers show
Series Switch build system to meson | expand

Commit Message

Laurent Pinchart Feb. 23, 2023, 4:44 p.m. UTC
From: Ariel D'Alessandro <ariel.dalessandro@collabora.com>

Supports building libraries and tools found in contrib/, lib/ and
utils/ directories, along with the implemented gettext translations.

Co-developed-by: Ezequiel Garcia <ezequiel@collabora.com>
Signed-off-by: Ezequiel Garcia <ezequiel@collabora.com>
Acked-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Acked-by: Gregor Jasny <gjasny@googlemail.com>
[Gregor: Control symbol visibility]
Signed-off-by: Gregor Jasny <gjasny@googlemail.com>
Tested-by: Gregor Jasny <gjasny@googlemail.com>
Signed-off-by: Ariel D'Alessandro <ariel.dalessandro@collabora.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Tested-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Tested-by: Sean Young <sean@mess.org>
Tested-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
Changes since v9:

- Update project version to 1.25.0

Changes since v8:

- Fix LIBTRACER_PATH
- Update project version to 1.22.0
- Update installation documentation to specify build directory in
  command lines
- Move '-I.' from common_arguments to v4l2_utils_incdir_arr

Changes since v7:

- Make v4l2gl conditional on dep_gl and dep_libudev
- Fix udev dependency handling
- Add comment about switching to install_emptydir()
- Use meson's native dependency('iconv') when possible
- Properly test for visibility support
- Add v4l2-tracer
- Add v4l-wrappers option
- Simplify check for libdvbv5 option
- Drop unused variables dep_v4l1compat and dep_v4l2convert
- Push handling of have_qt5_opengl and have_fork in subdirs
- Add summary
- White space fixes

Changes since v6:

- Generate v4l-utils.spec

Changes since v5:

- Drop unneeded bpf option check
- Avoid double-quoting strings
- Use external_program object directly without calling path()
- Specify check kwarg to run_command()
- Replace deprecated get_cross_property() with get_external_property()
- Fix SDL dependency fallback check
- Set the default build type to debugoptimized
---
 .gitignore                                    |   1 +
 INSTALL.meson.md                              | 142 +++++++
 README.md                                     |  83 +++-
 contrib/cobalt-ctl/meson.build                |   8 +
 contrib/decode_tm6000/meson.build             |  14 +
 contrib/gconv/meson.build                     |  44 ++
 contrib/meson.build                           |  13 +
 contrib/rds-saa6588/meson.build               |   7 +
 contrib/test/meson.build                      | 143 +++++++
 contrib/xc3028-firmware/meson.build           |  11 +
 lib/libdvbv5/meson.build                      | 156 +++++++
 lib/libv4l-mplane/meson.build                 |  23 +
 lib/libv4l1/meson.build                       |  64 +++
 lib/libv4l2/meson.build                       |  73 ++++
 lib/libv4l2rds/meson.build                    |  37 ++
 lib/libv4lconvert/meson.build                 | 117 ++++++
 lib/meson.build                               |  11 +
 libdvbv5-po/meson.build                       |   3 +
 meson.build                                   | 396 ++++++++++++++++++
 meson_options.txt                             |  46 ++
 utils/cec-compliance/meson.build              |  23 +
 utils/cec-ctl/meson.build                     |  18 +
 utils/cec-follower/meson.build                |  19 +
 utils/cx18-ctl/meson.build                    |   8 +
 utils/dvb/meson.build                         |  70 ++++
 utils/gen_media_bus_format_codes.sh           |   7 +
 utils/gen_media_bus_format_names.sh           |   7 +
 utils/ir-ctl/meson.build                      |  23 +
 utils/ivtv-ctl/meson.build                    |  13 +
 .../bpf_protocols/clang_sys_includes.sh       |   9 +
 utils/keytable/bpf_protocols/meson.build      |  31 ++
 utils/keytable/meson.build                    |  85 ++++
 utils/keytable/rc_keymaps/meson.build         | 150 +++++++
 utils/libcecutil/meson.build                  |  45 ++
 utils/libmedia_dev/meson.build                |  14 +
 utils/libv4l2util/meson.build                 |  16 +
 utils/media-ctl/meson.build                   |  43 ++
 utils/meson.build                             |  43 ++
 utils/qv4l2/meson.build                       |  79 ++++
 utils/qvidcap/meson.build                     |  87 ++++
 utils/rds-ctl/meson.build                     |  17 +
 utils/v4l2-compliance/meson.build             |  63 +++
 utils/v4l2-ctl/meson.build                    |  75 ++++
 utils/v4l2-dbg/meson.build                    |  20 +
 utils/v4l2-sysfs-path/meson.build             |  14 +
 utils/v4l2-tracer/media-info.cpp              |   1 +
 utils/v4l2-tracer/meson.build                 | 133 ++++++
 utils/v4l2-tracer/v4l2-info.cpp               |   1 +
 v4l-utils-po/meson.build                      |   3 +
 49 files changed, 2493 insertions(+), 16 deletions(-)
 create mode 100644 INSTALL.meson.md
 create mode 100644 contrib/cobalt-ctl/meson.build
 create mode 100644 contrib/decode_tm6000/meson.build
 create mode 100644 contrib/gconv/meson.build
 create mode 100644 contrib/meson.build
 create mode 100644 contrib/rds-saa6588/meson.build
 create mode 100644 contrib/test/meson.build
 create mode 100644 contrib/xc3028-firmware/meson.build
 create mode 100644 lib/libdvbv5/meson.build
 create mode 100644 lib/libv4l-mplane/meson.build
 create mode 100644 lib/libv4l1/meson.build
 create mode 100644 lib/libv4l2/meson.build
 create mode 100644 lib/libv4l2rds/meson.build
 create mode 100644 lib/libv4lconvert/meson.build
 create mode 100644 lib/meson.build
 create mode 100644 libdvbv5-po/meson.build
 create mode 100644 meson.build
 create mode 100644 meson_options.txt
 create mode 100644 utils/cec-compliance/meson.build
 create mode 100644 utils/cec-ctl/meson.build
 create mode 100644 utils/cec-follower/meson.build
 create mode 100644 utils/cx18-ctl/meson.build
 create mode 100644 utils/dvb/meson.build
 create mode 100755 utils/gen_media_bus_format_codes.sh
 create mode 100755 utils/gen_media_bus_format_names.sh
 create mode 100644 utils/ir-ctl/meson.build
 create mode 100644 utils/ivtv-ctl/meson.build
 create mode 100755 utils/keytable/bpf_protocols/clang_sys_includes.sh
 create mode 100644 utils/keytable/bpf_protocols/meson.build
 create mode 100644 utils/keytable/meson.build
 create mode 100644 utils/keytable/rc_keymaps/meson.build
 create mode 100644 utils/libcecutil/meson.build
 create mode 100644 utils/libmedia_dev/meson.build
 create mode 100644 utils/libv4l2util/meson.build
 create mode 100644 utils/media-ctl/meson.build
 create mode 100644 utils/meson.build
 create mode 100644 utils/qv4l2/meson.build
 create mode 100644 utils/qvidcap/meson.build
 create mode 100644 utils/rds-ctl/meson.build
 create mode 100644 utils/v4l2-compliance/meson.build
 create mode 100644 utils/v4l2-ctl/meson.build
 create mode 100644 utils/v4l2-dbg/meson.build
 create mode 100644 utils/v4l2-sysfs-path/meson.build
 create mode 120000 utils/v4l2-tracer/media-info.cpp
 create mode 100644 utils/v4l2-tracer/meson.build
 create mode 120000 utils/v4l2-tracer/v4l2-info.cpp
 create mode 100644 v4l-utils-po/meson.build

Comments

Gregor Jasny March 12, 2023, 2:31 p.m. UTC | #1
Hello,

while packaging the v4l-utils master branch for the Ubuntu PPA[1] I 
noticed two issues:

On 23.02.23 17:44, Laurent Pinchart wrote:
> +dep_libbpf = dependency('bpf', required : get_option('bpf'), version : '>=0.7')
> +if not dep_libbpf.found()
> +    dep_libbpf = cc.find_library('bpf', has_headers: 'bpf/bpf.h', required : get_option('bpf'))
> +endif

Ubuntu Jammy contains libbpf 1:0.5.0-1ubuntu22.04.1. Therefore the first 
dep_libbpf check fails due to the version constraint. But the second 
check for the header succeeds. Afterwards the build fails due to the too 
old libbpf.

What's the reason for the fallback? I guess new enough versions of 
libbpf always ship a pkgconfig file.

> +git_sha = run_command(prog_git, '-C', meson.project_source_root(), 'rev-parse', '--short=12', 'HEAD',
> +                      check : true).stdout().strip()
> +conf.set('GIT_SHA', git_sha)
> +git_commit_cnt = run_command(prog_git, '-C', meson.project_source_root(), 'rev-list', '--count', 'HEAD',
> +                             check : true).stdout().strip()
> +conf.set('GIT_COMMIT_CNT', '-' + git_commit_cnt)
> +git_commit_date = run_command(prog_git, '-C', meson.project_source_root(), 'show', '--quiet',
> +                              '--date=format-local:%F %T', '--format=%cd',
> +                              env : ['TZ=UTC'], check : true).stdout().strip()
> +conf.set('GIT_COMMIT_DATE', git_commit_date)

In Debian / Ubuntu we built from a published tarball (created by meson 
dist). It does not contain a .git directory and therefore those checks fail.

I created a patch to work-around the issue:
https://git.launchpad.net/~libv4l/+git/v4l-utils-packaging/tree/patches/conditional-git-ops.diff

But I'm not too fluent in Meson, yet.


Thanks,
Gregor


[1] https://code.launchpad.net/~libv4l/+recipe/v4l-utils-master
Laurent Pinchart March 12, 2023, 2:49 p.m. UTC | #2
Hi Gregor,

On Sun, Mar 12, 2023 at 03:31:29PM +0100, Gregor Jasny wrote:
> Hello,
> 
> while packaging the v4l-utils master branch for the Ubuntu PPA[1] I 
> noticed two issues:
> 
> On 23.02.23 17:44, Laurent Pinchart wrote:
> > +dep_libbpf = dependency('bpf', required : get_option('bpf'), version : '>=0.7')
> > +if not dep_libbpf.found()
> > +    dep_libbpf = cc.find_library('bpf', has_headers: 'bpf/bpf.h', required : get_option('bpf'))
> > +endif
> 
> Ubuntu Jammy contains libbpf 1:0.5.0-1ubuntu22.04.1. Therefore the first 
> dep_libbpf check fails due to the version constraint. But the second 
> check for the header succeeds. Afterwards the build fails due to the too 
> old libbpf.
> 
> What's the reason for the fallback? I guess new enough versions of 
> libbpf always ship a pkgconfig file.

autoconf didn't have any fallback as far as I can tell, so I think we
could drop it here too. As I can't easily test this on Ubuntu, would you
be able to send a patch ?

> > +git_sha = run_command(prog_git, '-C', meson.project_source_root(), 'rev-parse', '--short=12', 'HEAD',
> > +                      check : true).stdout().strip()
> > +conf.set('GIT_SHA', git_sha)
> > +git_commit_cnt = run_command(prog_git, '-C', meson.project_source_root(), 'rev-list', '--count', 'HEAD',
> > +                             check : true).stdout().strip()
> > +conf.set('GIT_COMMIT_CNT', '-' + git_commit_cnt)
> > +git_commit_date = run_command(prog_git, '-C', meson.project_source_root(), 'show', '--quiet',
> > +                              '--date=format-local:%F %T', '--format=%cd',
> > +                              env : ['TZ=UTC'], check : true).stdout().strip()
> > +conf.set('GIT_COMMIT_DATE', git_commit_date)
> 
> In Debian / Ubuntu we built from a published tarball (created by meson 
> dist). It does not contain a .git directory and therefore those checks fail.
> 
> I created a patch to work-around the issue:
> https://git.launchpad.net/~libv4l/+git/v4l-utils-packaging/tree/patches/conditional-git-ops.diff
>
> But I'm not too fluent in Meson, yet.

You're doing quite fine :-) The patch looks good, except for

if fs.is_dir('.gitd')

which should be '.git' unless there's something I'm missing. Will you
submit the patch to the linux-media mailing list ?

> [1] https://code.launchpad.net/~libv4l/+recipe/v4l-utils-master
Gregor Jasny March 13, 2023, 7:57 a.m. UTC | #3
Hello,

On 12.03.23 15:49, Laurent Pinchart wrote:
> Will you submit the patch to the linux-media mailing list ?

after fighting more than one hour with git send-email and Google Mail I 
finally gave up and pushed the patches to the master branch.

/me wishes for:
* a low-entry barrier patch submitting mechanism
* a nice CI system with configuration-as-code
* a bug tracker

Thanks,
Gregor
Laurent Pinchart March 13, 2023, 8:11 a.m. UTC | #4
Hi Gregor,

On Mon, Mar 13, 2023 at 08:57:21AM +0100, Gregor Jasny wrote:
> On 12.03.23 15:49, Laurent Pinchart wrote:
> > Will you submit the patch to the linux-media mailing list ?
> 
> after fighting more than one hour with git send-email and Google Mail I 
> finally gave up and pushed the patches to the master branch.
> 
> /me wishes for:
> * a low-entry barrier patch submitting mechanism

If you want to give git-send-email another try (which is still the
recommended option), https://git-send-email.io/ provides instructions
tailored for different distributions and e-mail providers.

Otherwise, b4 can be used to submit patches without SMTP:
https://people.kernel.org/monsieuricon/sending-a-kernel-patch-with-b4-part-1.

> * a nice CI system with configuration-as-code
> * a bug tracker
Sean Young March 13, 2023, 9:09 a.m. UTC | #5
On Mon, Mar 13, 2023 at 08:57:21AM +0100, Gregor Jasny wrote:
> Hello,
> 
> On 12.03.23 15:49, Laurent Pinchart wrote:
> > Will you submit the patch to the linux-media mailing list ?
> 
> after fighting more than one hour with git send-email and Google Mail I
> finally gave up and pushed the patches to the master branch.
> 
> /me wishes for:
> * a low-entry barrier patch submitting mechanism
> * a nice CI system with configuration-as-code
> * a bug tracker

Me too. 

 - Would save a lot of time, submitting patches is too manual
 - Make make things much easier to track
 - CI would undoubtedly improve code quality
 - Too hard for users to submit bugs
 - much more..

gitlab would be great for v4l-utils, I think.


Sean
Mauro Carvalho Chehab March 18, 2023, 6:17 p.m. UTC | #6
Em Tue, 14 Mar 2023 08:03:42 +0100
Gregor Jasny <gjasny@googlemail.com> escreveu:

> Hello,
> 
> On 13.03.23 09:11, Laurent Pinchart wrote:
> > If you want to give git-send-email another try (which is still the
> > recommended option), https://git-send-email.io/ provides instructions
> > tailored for different distributions and e-mail providers.  
> 
> I re-did the setup at home and it worked as expected. Turns out that 
> it's the company firewall which blocks git-send-email. Surprisingly 
> Thunderbird works with the same host and port.
> 

Please revert it or fix it to build against Meson 0.56, as such change
broke CI:

	https://builder.linuxtv.org/job/v4l-utils/
	https://builder.linuxtv.org/job/v4l-utils-coverity/

Thanks,
Mauro
Laurent Pinchart March 18, 2023, 11:06 p.m. UTC | #7
Hi Mauro,

On Sat, Mar 18, 2023 at 07:17:53PM +0100, Mauro Carvalho Chehab wrote:
> Em Tue, 14 Mar 2023 08:03:42 +0100 Gregor Jasny escreveu:
> > On 13.03.23 09:11, Laurent Pinchart wrote:
> > > If you want to give git-send-email another try (which is still the
> > > recommended option), https://git-send-email.io/ provides instructions
> > > tailored for different distributions and e-mail providers.  
> > 
> > I re-did the setup at home and it worked as expected. Turns out that 
> > it's the company firewall which blocks git-send-email. Surprisingly 
> > Thunderbird works with the same host and port.
> > 
> 
> Please revert it or fix it to build against Meson 0.56, as such change
> broke CI:
> 
> 	https://builder.linuxtv.org/job/v4l-utils/
> 	https://builder.linuxtv.org/job/v4l-utils-coverity/

I've tested this simple patch and it seems to work fine for me:

diff --git a/meson.build b/meson.build
index 7b9ca7036b27..6443427486a9 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,6 @@
 project('v4l-utils', 'c', 'cpp',
     version: '1.25.0',
-    meson_version : '>= 0.57',
+    meson_version : '>= 0.56',
     default_options : [
         'buildtype=debugoptimized',
         'warning_level=1',

My meson version is however newer. Could you test this with meson 0.56 ?
Mauro Carvalho Chehab March 19, 2023, 12:20 a.m. UTC | #8
Em Sun, 19 Mar 2023 01:06:52 +0200
Laurent Pinchart <laurent.pinchart@ideasonboard.com> escreveu:

> Hi Mauro,
> 
> On Sat, Mar 18, 2023 at 07:17:53PM +0100, Mauro Carvalho Chehab wrote:
> > Em Tue, 14 Mar 2023 08:03:42 +0100 Gregor Jasny escreveu:  
> > > On 13.03.23 09:11, Laurent Pinchart wrote:  
> > > > If you want to give git-send-email another try (which is still the
> > > > recommended option), https://git-send-email.io/ provides instructions
> > > > tailored for different distributions and e-mail providers.    
> > > 
> > > I re-did the setup at home and it worked as expected. Turns out that 
> > > it's the company firewall which blocks git-send-email. Surprisingly 
> > > Thunderbird works with the same host and port.
> > >   
> > 
> > Please revert it or fix it to build against Meson 0.56, as such change
> > broke CI:
> > 
> > 	https://builder.linuxtv.org/job/v4l-utils/
> > 	https://builder.linuxtv.org/job/v4l-utils-coverity/  
> 
> I've tested this simple patch and it seems to work fine for me:
> 
> diff --git a/meson.build b/meson.build
> index 7b9ca7036b27..6443427486a9 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -1,6 +1,6 @@
>  project('v4l-utils', 'c', 'cpp',
>      version: '1.25.0',
> -    meson_version : '>= 0.57',
> +    meson_version : '>= 0.56',
>      default_options : [
>          'buildtype=debugoptimized',
>          'warning_level=1',
> 
> My meson version is however newer. Could you test this with meson 0.56 ?

I already tested it: just changing it won't work:

$ meson setup build
The Meson build system
Version: 0.56.2
Source dir: /var/lib/jenkins/workspace/v4l-utils
Build dir: /var/lib/jenkins/workspace/v4l-utils/build
Build type: native build
Project name: v4l-utils
Project version: 1.25.0
C compiler for the host machine: ccache cc (gcc 10.2.1 "cc (Debian 10.2.1-6) 10.2.1 20210110")
C linker for the host machine: cc ld.bfd 2.35.2
C++ compiler for the host machine: ccache c++ (gcc 10.2.1 "c++ (Debian 10.2.1-6) 10.2.1 20210110")
C++ linker for the host machine: c++ ld.bfd 2.35.2
Host machine cpu family: x86_64
Host machine cpu: x86_64
Compiler for C supports link arguments -m32: YES 
Compiler for C supports arguments -fvisibility=hidden: YES 
Compiler for C supports function attribute visibility:default: YES 
Program bash found: YES (/bin/bash)
Program clang found: NO
Program doxygen found: YES (/usr/bin/doxygen)
Program grep found: YES (/bin/grep)
Program perl found: YES (/usr/bin/perl)
Found pkg-config: /usr/bin/pkg-config (0.29.2)
Run-time dependency alsa found: YES 1.2.4
Run-time dependency gl found: YES 1.2
Run-time dependency glu found: YES 9.0.1
Found CMake: /usr/bin/cmake (3.18.4)
Run-time dependency json-c found: NO (tried pkgconfig and cmake)
Library dl found: YES
Library elf found: YES
Library m found: YES
Library rt found: YES
Run-time dependency qt5 (modules: Core, Gui, Widgets, OpenGL) found: YES 5.15.2 (pkg-config)
Run-time dependency bpf found: NO (tried pkgconfig and cmake)
Run-time dependency sdl2 found: YES 2.0.14
Run-time dependency sdl2_image found: YES 2.0.5
Run-time dependency threads found: YES
Run-time dependency x11 found: YES 1.7.2
Run-time dependency xmlrpc found: NO (tried pkgconfig and cmake)
Checking for function "fork" : YES 
Has header "linux/i2c-dev.h" : YES 
Checking for function "klogctl" : YES 
Checking for function "secure_getenv" : YES 
Checking for function "__secure_getenv" : NO 
Has header "sys/klog.h" : YES 
Header <execinfo.h> has symbol "backtrace" : YES 
Checking for function "argp_parse" : YES 
Checking for function "strerrorname_np" : NO 
Checking for function "iconv_open" : YES 

meson.build:156:10: ERROR: Dependencies must be external dependencies

A full log can be found at /var/lib/jenkins/workspace/v4l-utils/build/meson-logs/meson-log.txt

$ tail -20  /var/lib/jenkins/workspace/v4l-utils/build/meson-logs/meson-log.txt
        
        #ifdef __cplusplus
        extern "C"
        #endif
        char iconv_open (void);
        
        #if defined __stub_iconv_open || defined __stub___iconv_open
        fail fail fail this function is not going to work
        #endif
        
        int main(void) {
          return iconv_open ();
        }
Compiler stdout:
 
Compiler stderr:
 
Checking for function "iconv_open" : YES 

meson.build:156:10: ERROR: Dependencies must be external dependencies
diff mbox series

Patch

diff --git a/.gitignore b/.gitignore
index f899ecfcc72c..7c900fe5a004 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,3 +61,4 @@  v4l-utils-po/en@quot.header
 v4l-utils-po/insert-header.sin
 v4l-utils-po/quot.sed
 v4l-utils-po/remove-potcdate.sin
+build/
diff --git a/INSTALL.meson.md b/INSTALL.meson.md
new file mode 100644
index 000000000000..ed7b10a77a39
--- /dev/null
+++ b/INSTALL.meson.md
@@ -0,0 +1,142 @@ 
+# Installation
+
+## Requirements
+
+* meson and a C and C++ compiler
+* optionally libjpeg v6 or later
+* optionally Qt5 for building qv4l2
+
+## Basic installation
+
+v4l-utils can be built and installed using meson as follows:
+
+```
+meson setup build/
+ninja -C build/
+sudo ninja -C build/ install
+```
+
+## Configuration
+
+You can get a summary of possible configurations running:
+
+```
+meson configure build/
+```
+
+To change the options values use the `-D` option:
+
+```
+meson configure -Doption=newvalue build/
+```
+
+After configuration you need to start the build process with:
+
+```
+ninja -C build/
+```
+
+More info about meson options:
+[https://mesonbuild.com/Build-options.html](https://mesonbuild.com/Build-options.html)
+
+## Installing
+
+If you need to install to a different directory than the install prefix, use
+the `DESTDIR` environment variable:
+
+```
+DESTDIR=/path/to/staging/area ninja -C build/ install
+```
+
+## Static builds
+
+Meson provides a built-in option to set the default library type:
+
+```
+Core options     Default Value  Possible Values         Description
+------------     -------------  ---------------         -----------
+default_library  shared         [shared, static, both]  Default library type
+```
+
+As previously described, it can be set as follows during the configuration step:
+
+```
+meson configure -Ddefault_library=static build/
+```
+
+Note that this will just build static libraries, but linking to dependencies and
+system libraries dynamically.
+
+*Fully static* builds are not supported yet and would require custom
+configuration and setting proper flags. By the time of this writing, there's an
+ongoing issue in meson to add this feature, see
+https://github.com/mesonbuild/meson/issues/7621
+
+## Cross Compiling
+
+Meson supports cross-compilation by specifying a number of binary paths and
+settings in a file and passing this file to `meson` or `meson configure` with
+the `--cross-file` parameter.
+
+Below are a few example of cross files, but keep in mind that you will likely
+have to alter them for your system.
+
+32-bit build on x86 linux:
+
+```
+[binaries]
+c = '/usr/bin/gcc'
+cpp = '/usr/bin/g++'
+ar = '/usr/bin/gcc-ar'
+strip = '/usr/bin/strip'
+pkgconfig = '/usr/bin/pkg-config-32'
+llvm-config = '/usr/bin/llvm-config32'
+
+[properties]
+c_args = ['-m32']
+c_link_args = ['-m32']
+cpp_args = ['-m32']
+cpp_link_args = ['-m32']
+
+[host_machine]
+system = 'linux'
+cpu_family = 'x86'
+cpu = 'i686'
+endian = 'little'
+```
+
+64-bit build on ARM linux:
+
+```
+[binaries]
+c = '/usr/bin/aarch64-linux-gnu-gcc'
+cpp = '/usr/bin/aarch64-linux-gnu-g++'
+ar = '/usr/bin/aarch64-linux-gnu-gcc-ar'
+strip = '/usr/bin/aarch64-linux-gnu-strip'
+pkgconfig = '/usr/bin/aarch64-linux-gnu-pkg-config'
+exe_wrapper = '/usr/bin/qemu-aarch64-static'
+
+[host_machine]
+system = 'linux'
+cpu_family = 'aarch64'
+cpu = 'aarch64'
+endian = 'little'
+```
+
+64-bit build on x86 windows:
+
+```
+[binaries]
+c = '/usr/bin/x86_64-w64-mingw32-gcc'
+cpp = '/usr/bin/x86_64-w64-mingw32-g++'
+ar = '/usr/bin/x86_64-w64-mingw32-ar'
+strip = '/usr/bin/x86_64-w64-mingw32-strip'
+pkgconfig = '/usr/bin/x86_64-w64-mingw32-pkg-config'
+exe_wrapper = 'wine'
+
+[host_machine]
+system = 'windows'
+cpu_family = 'x86_64'
+cpu = 'i686'
+endian = 'little'
+```
diff --git a/README.md b/README.md
index e351d8022d2b..b11b7fe2ee80 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,10 @@  There is also a wiki page for the v4l-utils:
 
 ## Building
 
+Temporarily, both meson and autotools build systems are supported in parallel.
+*NOTE*: Packagers should be aware that autotools support will be dropped soon,
+to be fully replaced by meson.
+
 A number of packages is required to fully build v4l-utils. The first step is to
 install those packages. The package names are different on each distro.
 
@@ -25,15 +29,15 @@  On Debian and derivated distributions, you need to install the following
 packages with `apt-get` or `aptitude`:
 
 ```
-debhelper dh-autoreconf autotools-dev autoconf-archive doxygen graphviz
-libasound2-dev libtool libjpeg-dev qtbase5-dev qt5-default libqt5opengl5-dev
-libudev-dev libx11-dev pkg-config udev make gcc git
+debhelper dh-autoreconf doxygen graphviz libasound2-dev libtool libjpeg-dev
+qtbase5-dev qt5-default libqt5opengl5-dev libudev-dev libx11-dev pkg-config
+udev gcc git
 ```
 
 On Fedora, the package list for a minimal install with `dnf` or `yum` is:
 
 ```
-git automake autoconf libtool make gcc gcc-c++ which perl gettext-devel
+git libtool gcc gcc-c++ which perl gettext-devel
 ```
 
 (git is only requiried if you're cloning from the main git repository at
@@ -50,7 +54,46 @@  mesa-libGLU-devel
 The v4l2-tracer also needs the json-c library. On Debian: `libjson-c-dev' ; on
 Fedora: `json-c-devel`.
 
-After downloading and installing the needed packages, you should run:
+### Meson build
+
+Extra packages required for meson:
+
+```
+# On Debian/Ubuntu
+apt-get install meson ninja-build
+
+# On Fedora
+dnf install meson ninja-build
+```
+
+After downloading and installing the needed packages on your distribution, you
+should run:
+
+```
+meson build/
+ninja -C build/
+```
+
+And, to install on your system:
+
+```
+sudo ninja -C build/ install
+```
+
+### Autotools build
+
+Extra packages required for autotools:
+
+```
+# On Debian/Ubuntu
+apt-get install autotools-dev autoconf-archive make
+
+# On Fedora
+dnf install automake autoconf make
+```
+
+After downloading and installing the needed packages on your distribution, you
+should run:
 
 ```
 ./bootstrap.sh
@@ -78,7 +121,15 @@  Japanese DVB tables via iconv. This is meant to be used when the iconv itself
 doesn't come with the *ARIB-STD-B24* and *EN300-468-TAB00* tables.
 
 That requires not only the gconv package, but it also needs to be manually
-enabled with `--enable-gconv`.
+enabled running autoconf with `--enable-gconv` option.
+
+In meson, gconv is an auto feature, so it will be auto-enabled in case the
+dependencies are satisfied. However, the gconv feature can be forced to enabled
+by running the following command during configuration step:
+
+```
+meson configure -Dgconv=enabled build/
+```
 
 ## Versioning
 
@@ -144,7 +195,7 @@  This library is meant to be used by digital TV applications that need to talk
 with media hardware.
 
 Full documentation is provided via Doxygen. It can be built, after configuring
-the package, with:
+the package with autotools, running:
 
 ```
 make doxygen-run
@@ -181,7 +232,7 @@  v4l-utils includes the following utilities:
 
 Decodes tm6000 proprietary format streams.
 
-Installed by make install under `<prefix>/bin`.
+Installed under `<prefix>/bin`.
 
 ### ir-keytable
 
@@ -189,7 +240,7 @@  Dump, Load or Modify ir receiver input tables. The ir tables for remotes which
 are known by the kernel (and loaded by default depending on dvb card type) can
 be found under `utils/keytable/keycodes`.
 
-v4l-keytable does not get installed by `make install`.
+v4l-keytable does not get installed during the install step.
 
 ### ir-ctl
 
@@ -199,25 +250,25 @@  A swiss-knife tool to handle raw IR and to set lirc options.
 
 QT v4l2 control panel application.
 
-Installed by `make install` under `<prefix>/bin`.
+Installed under `<prefix>/bin`.
 
 ### rds-saa6588
 
 Poll i2c RDS receiver [Philips saa6588].
 
-rds-saa6588 does not get installed by `make install`.
+rds-saa6588 does not get installed during the install step.
 
 ### v4l2-compliance
 
 Tool to test v4l2 API compliance of drivers.
 
-Installed by `make install` under `<prefix>/bin`.
+Installed under `<prefix>/bin`.
 
 ### v4l2-ctl
 
 Tool to control v4l2 controls from the cmdline.
 
-Installed by `make install` under `<prefix>/bin`.
+Installed under `<prefix>/bin`.
 
 ### v4l2-dbg
 
@@ -225,13 +276,13 @@  Tool to directly get and set registers of v4l2 devices, this requires a
 *kernel >= 2.6.29* with the `ADV_DEBUG` option enabled. This tool can only be
 used by root and is meant for development purposes only!
 
-Installed by `make install` under `<prefix>/sbin`.
+Installed under `<prefix>/sbin`.
 
 ### v4l2-sysfs-path
 
 *FIXME* add description.
 
-Installed by `make install` under `<prefix>/bin`.
+Installed under `<prefix>/bin`.
 
 ### v4l2-tracer
 
@@ -244,7 +295,7 @@  Installed by `make install` under `<prefix>/bin`.
 
 Xceive XC2028/3028 tuner module firmware manipulation tool.
 
-xc3028-firmware does not get installed by `make install`.
+xc3028-firmware does not get installed during the install step.
 
 ## Syncing with Kernel
 
diff --git a/contrib/cobalt-ctl/meson.build b/contrib/cobalt-ctl/meson.build
new file mode 100644
index 000000000000..f76fcba33b9f
--- /dev/null
+++ b/contrib/cobalt-ctl/meson.build
@@ -0,0 +1,8 @@ 
+cobalt_ctl_sources = files(
+    'cobalt-ctl.c',
+    's-record.c',
+)
+
+cobalt_ctl = executable('cobalt-ctl',
+                        cobalt_ctl_sources,
+                        include_directories : v4l2_utils_incdir)
diff --git a/contrib/decode_tm6000/meson.build b/contrib/decode_tm6000/meson.build
new file mode 100644
index 000000000000..5147278ba561
--- /dev/null
+++ b/contrib/decode_tm6000/meson.build
@@ -0,0 +1,14 @@ 
+decode_tm6000_sources = files(
+    'decode_tm6000.c',
+)
+
+decode_tm6000_deps = [
+    dep_argp,
+    dep_libv4l2util,
+]
+
+decode_tm6000 = executable('decode_tm6000',
+                           decode_tm6000_sources,
+                           install : true,
+                           dependencies: decode_tm6000_deps,
+                           include_directories : v4l2_utils_incdir)
diff --git a/contrib/gconv/meson.build b/contrib/gconv/meson.build
new file mode 100644
index 000000000000..e95278fde671
--- /dev/null
+++ b/contrib/gconv/meson.build
@@ -0,0 +1,44 @@ 
+gconv_install_dir = get_option('libdir') / 'gconv'
+
+arib_std_b24_sources = files(
+    'arib-std-b24.c',
+    'jis0201.h',
+    'jis0208.h',
+    'jisx0213.h',
+)
+
+arib_std_b24_deps = [
+    dep_jis,
+    dep_jisx0213,
+]
+
+arib_std_b24 = shared_module('ARIB-STD-B24',
+                             arib_std_b24_sources,
+                             name_prefix : '',
+                             dependencies : arib_std_b24_deps,
+                             install : true,
+                             install_dir : gconv_install_dir,
+                             include_directories : v4l2_utils_incdir)
+
+dep_arib_std_b24 = declare_dependency(link_with : arib_std_b24)
+
+en300_468_tab00_sources = files(
+    'en300-468-tab00.c',
+)
+
+en300_468_tab00_deps = [
+    dep_jis,
+    dep_jisx0213,
+]
+
+en300_468_tab00 = shared_module('EN300-468-TAB00',
+                                en300_468_tab00_sources,
+                                name_prefix : '',
+                                dependencies : en300_468_tab00_deps,
+                                install : true,
+                                install_dir : gconv_install_dir,
+                                include_directories : v4l2_utils_incdir)
+
+dep_en300_468_tab00 = declare_dependency(link_with : en300_468_tab00)
+
+install_data('gconv-modules', install_dir : gconv_install_dir)
diff --git a/contrib/meson.build b/contrib/meson.build
new file mode 100644
index 000000000000..e3aa05ac72fb
--- /dev/null
+++ b/contrib/meson.build
@@ -0,0 +1,13 @@ 
+if host_machine.system() == 'linux'
+    subdir('test')
+    subdir('xc3028-firmware')
+    if have_i2c_dev
+        subdir('rds-saa6588')
+    endif
+endif
+
+subdir('decode_tm6000')
+
+if have_gconv
+    subdir('gconv', if_found : [dep_jis, dep_jisx0213])
+endif
diff --git a/contrib/rds-saa6588/meson.build b/contrib/rds-saa6588/meson.build
new file mode 100644
index 000000000000..037d2e20fc60
--- /dev/null
+++ b/contrib/rds-saa6588/meson.build
@@ -0,0 +1,7 @@ 
+rds_saa6588_sources = files(
+    'rds-saa6588.c',
+)
+
+rds_saa6588 = executable('rds-saa6588',
+                         rds_saa6588_sources,
+                         include_directories : v4l2_utils_incdir)
diff --git a/contrib/test/meson.build b/contrib/test/meson.build
new file mode 100644
index 000000000000..29b51df640e0
--- /dev/null
+++ b/contrib/test/meson.build
@@ -0,0 +1,143 @@ 
+ioctl_test_sources = files(
+    'ioctl-test.c',
+    'ioctl-test.h',
+    'ioctl_32.h',
+    'ioctl_64.h',
+)
+
+ioctl_test = executable('ioctl-test',
+                        ioctl_test_sources,
+                        include_directories : v4l2_utils_incdir)
+
+sliced_vbi_test_sources = files(
+    'sliced-vbi-test.c',
+)
+
+sliced_vbi_test = executable('sliced-vbi-test',
+                             sliced_vbi_test_sources,
+                             include_directories : v4l2_utils_incdir)
+
+sliced_vbi_detect_sources = files(
+    'sliced-vbi-detect.c',
+)
+
+sliced_vbi_detect = executable('sliced-vbi-detect',
+                               sliced_vbi_detect_sources,
+                               include_directories : v4l2_utils_incdir)
+
+v4l2grab_sources = files(
+    'v4l2grab.c',
+
+)
+
+v4l2grab_deps = [
+    dep_argp,
+    dep_libv4l2,
+    dep_libv4lconvert,
+    dep_threads,
+]
+
+v4l2grab = executable('v4l2grab',
+                      v4l2grab_sources,
+                      dependencies : v4l2grab_deps,
+                      include_directories : v4l2_utils_incdir)
+
+driver_test_sources = files(
+    'driver-test.c',
+
+)
+
+driver_test_deps = [
+    dep_libv4l2util,
+]
+
+driver_test = executable('driver-test',
+                         driver_test_sources,
+                         dependencies : driver_test_deps,
+                         include_directories : v4l2_utils_incdir)
+
+mc_nextgen_test_sources = files(
+    'mc_nextgen_test.c',
+)
+
+mc_nextgen_test_deps = [
+    dep_argp,
+    dep_libudev,
+]
+
+mc_nextgen_test = executable('mc-nextgen-test',
+                             mc_nextgen_test_sources,
+                             dependencies : mc_nextgen_test_deps,
+                             include_directories : v4l2_utils_incdir)
+
+stress_buffer_sources = files(
+    'stress-buffer.c',
+)
+
+stress_buffer = executable('stress-buffer',
+                           stress_buffer_sources,
+                           include_directories : v4l2_utils_incdir)
+
+capture_example_sources = files(
+    'capture-example.c',
+)
+
+capture_example = executable('capture-example',
+                             capture_example_sources,
+                             include_directories : v4l2_utils_incdir)
+
+if dep_x11.found()
+    pixfmt_test_sources = files(
+        'pixfmt-test.c',
+    )
+
+    pixfmt_test_deps = [
+        dep_x11,
+    ]
+
+    pixfmt_test = executable('pixfmt-test',
+                             pixfmt_test_sources,
+                             dependencies : pixfmt_test_deps,
+                             include_directories : v4l2_utils_incdir)
+endif
+
+if dep_gl.found() and dep_glu.found() and dep_x11.found()
+    v4l2gl_sources = files(
+        'v4l2gl.c',
+    )
+
+    v4l2gl_deps = [
+        dep_gl,
+        dep_glu,
+        dep_libv4l2,
+        dep_libv4lconvert,
+        dep_x11,
+    ]
+
+    v4l2gl = executable('v4l2gl',
+                        v4l2gl_sources,
+                        dependencies : v4l2gl_deps,
+                        include_directories : v4l2_utils_incdir)
+endif
+
+if dep_jpeg.found() and dep_sdl.found() and dep_sdl_image.found()
+    sdlcam_sources = files(
+        'sdlcam.c',
+    )
+
+    sdlcam_deps = [
+        dep_jpeg,
+        dep_libdl,
+        dep_libm,
+        dep_librt,
+        dep_libv4l2,
+        dep_libv4lconvert,
+        dep_sdl,
+        dep_sdl_image,
+    ]
+
+    sdlcam = executable('sdlcam',
+                        sdlcam_sources,
+                        dependencies : sdlcam_deps,
+                        include_directories : v4l2_utils_incdir)
+endif
diff --git a/contrib/xc3028-firmware/meson.build b/contrib/xc3028-firmware/meson.build
new file mode 100644
index 000000000000..802c68586a8f
--- /dev/null
+++ b/contrib/xc3028-firmware/meson.build
@@ -0,0 +1,11 @@ 
+xc3028_firmware_sources = files(
+    'extract_head.h',
+    'firmware-tool.c',
+    'standards.c',
+    'standards.h',
+    'xc2028-types.h',
+)
+
+xc3028_firmware = executable('xc3028-firmware',
+                             xc3028_firmware_sources,
+                             include_directories : v4l2_utils_incdir)
diff --git a/lib/libdvbv5/meson.build b/lib/libdvbv5/meson.build
new file mode 100644
index 000000000000..0b92e4047a81
--- /dev/null
+++ b/lib/libdvbv5/meson.build
@@ -0,0 +1,156 @@ 
+libdvbv5_option = get_option('libdvbv5')
+if libdvbv5_option.disabled() or not dep_libudev.found()
+    dep_libdvbv5 = dependency('', required : false)
+    subdir_done()
+endif
+
+libdvbv5_sources = files(
+    'compat-soname.c',
+    'countries.c',
+    'crc32.c',
+    'descriptors.c',
+    'descriptors/desc_atsc_service_location.c',
+    'descriptors/desc_ca.c',
+    'descriptors/desc_ca_identifier.c',
+    'descriptors/desc_cable_delivery.c',
+    'descriptors/desc_event_extended.c',
+    'descriptors/desc_event_short.c',
+    'descriptors/desc_extension.c',
+    'descriptors/desc_frequency_list.c',
+    'descriptors/desc_hierarchy.c',
+    'descriptors/desc_isdbt_delivery.c',
+    'descriptors/desc_language.c',
+    'descriptors/desc_logical_channel.c',
+    'descriptors/desc_network_name.c',
+    'descriptors/desc_partial_reception.c',
+    'descriptors/desc_registration_id.c',
+    'descriptors/desc_sat.c',
+    'descriptors/desc_service.c',
+    'descriptors/desc_t2_delivery.c',
+    'descriptors/desc_terrestrial_delivery.c',
+    'descriptors/desc_ts_info.c',
+    'dvb-demux.c',
+    'dvb-dev-local.c',
+    'dvb-dev-priv.h',
+    'dvb-dev-remote.c',
+    'dvb-dev.c',
+    'dvb-fe-priv.h',
+    'dvb-fe.c',
+    'dvb-file.c',
+    'dvb-legacy-channel-format.c',
+    'dvb-log.c',
+    'dvb-sat.c',
+    'dvb-scan.c',
+    'dvb-v5-std.c',
+    'dvb-v5.c',
+    'dvb-v5.h',
+    'dvb-vdr-format.c',
+    'dvb-zap-format.c',
+    'parse_string.c',
+    'parse_string.h',
+    'tables/atsc_eit.c',
+    'tables/cat.c',
+    'tables/eit.c',
+    'tables/header.c',
+    'tables/mgt.c',
+    'tables/mpeg_es.c',
+    'tables/mpeg_pes.c',
+    'tables/mpeg_ts.c',
+    'tables/nit.c',
+    'tables/pat.c',
+    'tables/pmt.c',
+    'tables/sdt.c',
+    'tables/vct.c',
+)
+
+configure_file(
+    output : 'libdvb-version.h',
+    input : '../include/libdvbv5/libdvb-version.h.in',
+    configuration : conf,
+    install: true,
+    install_dir: 'include/libdvbv5',
+)
+
+libdvbv5_api = files(
+    '../include/libdvbv5/atsc_eit.h',
+    '../include/libdvbv5/atsc_header.h',
+    '../include/libdvbv5/cat.h',
+    '../include/libdvbv5/countries.h',
+    '../include/libdvbv5/crc32.h',
+    '../include/libdvbv5/desc_atsc_service_location.h',
+    '../include/libdvbv5/desc_ca.h',
+    '../include/libdvbv5/desc_ca_identifier.h',
+    '../include/libdvbv5/desc_cable_delivery.h',
+    '../include/libdvbv5/desc_event_extended.h',
+    '../include/libdvbv5/desc_event_short.h',
+    '../include/libdvbv5/desc_extension.h',
+    '../include/libdvbv5/desc_frequency_list.h',
+    '../include/libdvbv5/desc_hierarchy.h',
+    '../include/libdvbv5/desc_isdbt_delivery.h',
+    '../include/libdvbv5/desc_language.h',
+    '../include/libdvbv5/desc_logical_channel.h',
+    '../include/libdvbv5/desc_network_name.h',
+    '../include/libdvbv5/desc_partial_reception.h',
+    '../include/libdvbv5/desc_registration_id.h',
+    '../include/libdvbv5/desc_sat.h',
+    '../include/libdvbv5/desc_service.h',
+    '../include/libdvbv5/desc_t2_delivery.h',
+    '../include/libdvbv5/desc_terrestrial_delivery.h',
+    '../include/libdvbv5/desc_ts_info.h',
+    '../include/libdvbv5/descriptors.h',
+    '../include/libdvbv5/dvb-demux.h',
+    '../include/libdvbv5/dvb-dev.h',
+    '../include/libdvbv5/dvb-fe.h',
+    '../include/libdvbv5/dvb-file.h',
+    '../include/libdvbv5/dvb-frontend.h',
+    '../include/libdvbv5/dvb-log.h',
+    '../include/libdvbv5/dvb-sat.h',
+    '../include/libdvbv5/dvb-scan.h',
+    '../include/libdvbv5/dvb-v5-std.h',
+    '../include/libdvbv5/eit.h',
+    '../include/libdvbv5/header.h',
+    '../include/libdvbv5/mgt.h',
+    '../include/libdvbv5/mpeg_es.h',
+    '../include/libdvbv5/mpeg_pes.h',
+    '../include/libdvbv5/mpeg_ts.h',
+    '../include/libdvbv5/nit.h',
+    '../include/libdvbv5/pat.h',
+    '../include/libdvbv5/pmt.h',
+    '../include/libdvbv5/sdt.h',
+    '../include/libdvbv5/vct.h',
+)
+
+install_headers(libdvbv5_api, subdir: 'libdvbv5')
+
+libdvbv5_deps = [
+    dep_iconv,
+    dep_libm,
+    dep_librt,
+    dep_libudev,
+    dep_threads,
+]
+
+libdvbv5_c_args = [
+    '-DHAVE_DVBV5_REMOTE',
+    '-DHAVE_PTHREAD',
+    '-DLIBDVBV5_DOMAIN="libdvbv5"',
+]
+
+libdvbv5 = library('dvbv5',
+                   libdvbv5_sources,
+                   soversion: '0',
+                   version: '0.0.0',
+                   install : true,
+                   dependencies : libdvbv5_deps,
+                   c_args : libdvbv5_c_args,
+                   include_directories : v4l2_utils_incdir)
+
+dep_libdvbv5 = declare_dependency(link_with : libdvbv5)
+meson.override_dependency('libdvbv5', dep_libdvbv5)
+
+pkg.generate(
+    libdvbv5,
+    name : 'libdvbv5',
+    version : meson.project_version(),
+    requires_private : 'libudev',
+    description : 'DVBv5 utility library')
diff --git a/lib/libv4l-mplane/meson.build b/lib/libv4l-mplane/meson.build
new file mode 100644
index 000000000000..0e0e558bf2f8
--- /dev/null
+++ b/lib/libv4l-mplane/meson.build
@@ -0,0 +1,23 @@ 
+libv4l_mplane_sources = files(
+    'libv4l-mplane.c',
+)
+
+libv4l_mplane_deps = [
+    dep_threads,
+]
+
+libv4l_mplane_c_args = []
+
+if have_visibility
+    libv4l_mplane_c_args += ['-fvisibility=hidden']
+endif
+
+libv4l_mplane = shared_module('v4l-mplane',
+                              libv4l_mplane_sources,
+                              install : true,
+                              install_dir : libv4l2plugindir,
+                              dependencies : libv4l_mplane_deps,
+                              c_args : libv4l_mplane_c_args,
+                              include_directories : v4l2_utils_incdir)
+
+dep_libv4l_mplane = declare_dependency(link_with : libv4l_mplane)
diff --git a/lib/libv4l1/meson.build b/lib/libv4l1/meson.build
new file mode 100644
index 000000000000..e1df2fa29b5b
--- /dev/null
+++ b/lib/libv4l1/meson.build
@@ -0,0 +1,64 @@ 
+libv4l1_sources = files(
+    'libv4l1-priv.h',
+    'libv4l1.c',
+    'log.c',
+)
+
+libv4l1_api = files(
+    '../include/libv4l1-videodev.h',
+    '../include/libv4l1.h',
+)
+
+install_headers(libv4l1_api)
+
+libv4l1_deps = [
+    dep_libv4l2,
+    dep_threads,
+]
+
+libv4l1_c_args = []
+
+if have_visibility
+    libv4l1_c_args += ['-fvisibility=hidden']
+endif
+
+libv4l1 = library('v4l1',
+                  libv4l1_sources,
+                  install : true,
+                  soversion: '0',
+                  version: '0.0.0',
+                  dependencies : libv4l1_deps,
+                  c_args : libv4l1_c_args,
+                  include_directories : v4l2_utils_incdir)
+
+dep_libv4l1 = declare_dependency(link_with : libv4l1)
+meson.override_dependency('libv4l1', dep_libv4l1)
+
+pkg.generate(
+    libv4l1,
+    name : 'libv4l1',
+    version : meson.project_version(),
+    requires_private : 'libv4l2',
+    description : 'v4l1 compatibility library')
+
+if not get_option('v4l-wrappers')
+    subdir_done()
+endif
+
+v4l1compat_sources = files(
+    'v4l1compat.c',
+)
+
+v4l1compat_deps = [
+    dep_libv4l1,
+]
+
+libv4l1privdir = get_option('prefix') / get_option('libdir') / get_option('libv4l1subdir')
+
+v4l1compat = shared_module('v4l1compat',
+                           v4l1compat_sources,
+                           name_prefix : '',
+                           install : true,
+                           install_dir : libv4l1privdir,
+                           dependencies : v4l1compat_deps,
+                           include_directories : v4l2_utils_incdir)
diff --git a/lib/libv4l2/meson.build b/lib/libv4l2/meson.build
new file mode 100644
index 000000000000..bd6e0e7fb6b9
--- /dev/null
+++ b/lib/libv4l2/meson.build
@@ -0,0 +1,73 @@ 
+libv4l2_sources = files(
+    'libv4l2-priv.h',
+    'libv4l2.c',
+    'log.c',
+)
+
+libv4l2_api = files(
+    '../include/libv4l-plugin.h',
+    '../include/libv4l2.h',
+)
+
+install_headers(libv4l2_api)
+
+libv4l2_deps = [
+    dep_libdl,
+    dep_libv4lconvert,
+    dep_threads,
+]
+
+libv4l2_c_args = []
+
+if get_option('v4l-plugins')
+    libv4l2_sources += files('v4l2-plugin.c')
+    libv4l2_c_args += [
+        '-DHAVE_V4L_PLUGINS',
+        '-DLIBV4L2_PLUGIN_DIR="@0@"'.format(libv4l2plugindir)
+    ]
+endif
+
+if have_visibility
+    libv4l2_c_args += ['-fvisibility=hidden']
+endif
+
+libv4l2 = library('v4l2',
+                  libv4l2_sources,
+                  soversion: '0',
+                  version: '0.0.0',
+                  install : true,
+                  dependencies : libv4l2_deps,
+                  c_args : libv4l2_c_args,
+                  include_directories : v4l2_utils_incdir)
+
+dep_libv4l2 = declare_dependency(link_with : libv4l2)
+meson.override_dependency('libv4l2', dep_libv4l2)
+
+pkg.generate(
+    libv4l2,
+    name : 'libv4l2',
+    version : meson.project_version(),
+    requires_private : 'libv4lconvert',
+    description : 'v4l2 device access library')
+
+if not get_option('v4l-wrappers')
+    subdir_done()
+endif
+
+v4l2convert_sources = files(
+    'v4l2convert.c',
+)
+
+v4l2convert_deps = [
+    dep_libv4l2,
+]
+
+libv4l2privdir = get_option('prefix') / get_option('libdir') / get_option('libv4l2subdir')
+
+v4l2convert = shared_module('v4l2convert',
+                            v4l2convert_sources,
+                            name_prefix : '',
+                            install : true,
+                            install_dir : libv4l2privdir,
+                            dependencies : v4l2convert_deps,
+                            include_directories : v4l2_utils_incdir)
diff --git a/lib/libv4l2rds/meson.build b/lib/libv4l2rds/meson.build
new file mode 100644
index 000000000000..338a97f87029
--- /dev/null
+++ b/lib/libv4l2rds/meson.build
@@ -0,0 +1,37 @@ 
+libv4l2rds_sources = files(
+    'libv4l2rds.c',
+)
+
+libv4l2rds_api = files(
+    '../include/libv4l2rds.h',
+)
+
+install_headers(libv4l2rds_api)
+
+libv4l2rds_deps = [
+    dep_threads,
+]
+
+libv4l2rds_c_args = []
+
+if have_visibility
+    libv4l2rds_c_args += ['-fvisibility=hidden']
+endif
+
+libv4l2rds = library('v4l2rds',
+                     libv4l2rds_sources,
+                     soversion: '0',
+                     version: '0.0.0',
+                     install : true,
+                     dependencies : libv4l2rds_deps,
+                     c_args : libv4l2rds_c_args,
+                     include_directories : v4l2_utils_incdir)
+
+dep_libv4l2rds = declare_dependency(link_with : libv4l2rds)
+meson.override_dependency('libv4l2rds', dep_libv4l2rds)
+
+pkg.generate(
+    libv4l2rds,
+    name : 'libv4l2rds',
+    version : meson.project_version(),
+    description : 'v4l2 RDS decode library')
diff --git a/lib/libv4lconvert/meson.build b/lib/libv4lconvert/meson.build
new file mode 100644
index 000000000000..3874075575c2
--- /dev/null
+++ b/lib/libv4lconvert/meson.build
@@ -0,0 +1,117 @@ 
+libv4lconvert_sources = files(
+    'bayer.c',
+    'control/libv4lcontrol-priv.h',
+    'control/libv4lcontrol.c',
+    'control/libv4lcontrol.h',
+    'cpia1.c',
+    'crop.c',
+    'flip.c',
+    'helper-funcs.h',
+    'jidctflt.c',
+    'jl2005bcd.c',
+    'jpeg.c',
+    'jpgl.c',
+    'libv4lconvert-priv.h',
+    'libv4lconvert.c',
+    'libv4lsyscall-priv.h',
+    'mr97310a.c',
+    'nv12_16l16.c',
+    'pac207.c',
+    'processing/autogain.c',
+    'processing/gamma.c',
+    'processing/libv4lprocessing-priv.h',
+    'processing/libv4lprocessing.c',
+    'processing/libv4lprocessing.h',
+    'processing/whitebalance.c',
+    'rgbyuv.c',
+    'se401.c',
+    'sn9c10x.c',
+    'sn9c2028-decomp.c',
+    'sn9c20x.c',
+    'spca501.c',
+    'spca561-decompress.c',
+    'sq905c.c',
+    'stv0680.c',
+    'tinyjpeg-internal.h',
+    'tinyjpeg.c',
+    'tinyjpeg.h',
+)
+
+libv4lconvert_api = files(
+    '../include/libv4lconvert.h',
+)
+
+install_headers(libv4lconvert_api)
+
+libv4lconvert_deps = [
+    dep_libm,
+    dep_librt,
+]
+
+libv4lconvert_priv_libs = [
+    '-lm',
+    '-lrt',
+]
+
+libv4lconvertprivdir = get_option('prefix') / get_option('libdir') / get_option('libv4lconvertsubdir')
+
+libv4lconvert_c_args = ['-DLIBV4LCONVERT_PRIV_DIR="@0@"'.format(libv4lconvertprivdir)]
+
+if dep_jpeg.found()
+    libv4lconvert_deps += dep_jpeg
+    libv4lconvert_priv_libs += dep_jpeg_priv_libs
+    libv4lconvert_sources += files(
+        'jpeg_memsrcdest.c',
+        'jpeg_memsrcdest.h'
+    )
+    libv4lconvert_c_args += [
+        '-DHAVE_JPEG',
+    ]
+endif
+
+if have_fork
+    libv4lconvert_sources += files(
+        'helper.c',
+    )
+    ov511_decomp_sources = files(
+        'ov511-decomp.c',
+    )
+    ov511_decomp = executable('ov511-decomp',
+                              ov511_decomp_sources,
+                              install : true,
+                              install_dir : libv4lconvertprivdir,
+                              include_directories : v4l2_utils_incdir)
+    ov518_decomp_sources = files(
+        'ov518-decomp.c',
+    )
+    ov518_decomp = executable('ov518-decomp',
+                              ov518_decomp_sources,
+                              install : true,
+                              install_dir : libv4lconvertprivdir,
+                              include_directories : v4l2_utils_incdir)
+endif
+
+if have_visibility
+    libv4lconvert_c_args += [
+      '-fvisibility=hidden',
+      '-DHAVE_LIBV4LCONVERT_HELPERS',
+    ]
+endif
+
+libv4lconvert = library('v4lconvert',
+                        libv4lconvert_sources,
+                        soversion: '0',
+                        version: '0.0.0',
+                        install : true,
+                        dependencies : libv4lconvert_deps,
+                        c_args : libv4lconvert_c_args,
+                        include_directories : v4l2_utils_incdir)
+
+dep_libv4lconvert = declare_dependency(link_with : libv4lconvert)
+meson.override_dependency('libv4lconvert', dep_libv4lconvert)
+
+pkg.generate(
+    libv4lconvert,
+    name : 'libv4lconvert',
+    version : meson.project_version(),
+    description : 'v4l format conversion library')
diff --git a/lib/meson.build b/lib/meson.build
new file mode 100644
index 000000000000..47cee16d12b5
--- /dev/null
+++ b/lib/meson.build
@@ -0,0 +1,11 @@ 
+libv4l2plugindir = get_option('prefix') / get_option('libdir') / get_option('libv4l2subdir') / 'plugins'
+
+subdir('libdvbv5')
+subdir('libv4lconvert')
+subdir('libv4l2')
+subdir('libv4l1')
+subdir('libv4l2rds')
+
+if get_option('v4l-plugins')
+    subdir('libv4l-mplane')
+endif
diff --git a/libdvbv5-po/meson.build b/libdvbv5-po/meson.build
new file mode 100644
index 000000000000..e382651ee5d1
--- /dev/null
+++ b/libdvbv5-po/meson.build
@@ -0,0 +1,3 @@ 
+i18n.gettext('libdvbv5',
+    args : i18n_gettext_arguments,
+)
diff --git a/meson.build b/meson.build
new file mode 100644
index 000000000000..0458fca74a26
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,396 @@ 
+project('v4l-utils', 'c', 'cpp',
+    version: '1.25.0',
+    meson_version : '>= 0.57',
+    default_options : [
+        'buildtype=debugoptimized',
+        'warning_level=1',
+        'c_std=gnu99',
+        'cpp_std=gnu++11',
+    ],
+    license : 'LGPL 2.1+')
+
+cc = meson.get_compiler('c')
+cpp = meson.get_compiler('cpp')
+have_m32 = cc.has_link_argument('-m32')
+have_visibility = cc.has_argument('-fvisibility=hidden') and \
+                  cc.has_function_attribute('visibility:default')
+
+sys_root = meson.get_external_property('sys_root', '/')
+
+fs = import('fs')
+i18n = import('i18n')
+pkg = import('pkgconfig')
+qt5 = import('qt5')
+
+as_version = meson.project_version()
+ver_arr = as_version.split('.')
+as_major_version = ver_arr[0]
+as_minor_version = ver_arr[1]
+as_patch_version = ver_arr[2]
+
+conf = configuration_data()
+conf.set_quoted('PACKAGE', meson.project_name())
+conf.set_quoted('PACKAGE_VERSION', as_version)
+conf.set_quoted('V4L_UTILS_VERSION', as_version)
+conf.set('MAJOR', as_major_version)
+conf.set('MINOR', as_minor_version)
+conf.set('PATCH', as_patch_version)
+
+common_arguments = [
+    '-Wpointer-arith',
+    '-D_GNU_SOURCE',
+    '-DPROMOTED_MODE_T=int',
+    '-DENABLE_NLS',
+]
+
+v4l2_utils_incdir_arr = [
+    '.', # Needed for config.h
+    'lib' / 'include',
+]
+
+if host_machine.system() == 'linux'
+    v4l2_utils_incdir_arr += 'include'
+elif host_machine.system() == 'freebsd'
+    v4l2_utils_incdir_arr += 'contrib/freebsd/include'
+endif
+
+v4l2_utils_incdir = include_directories(v4l2_utils_incdir_arr)
+
+prog_bash = find_program('bash')
+prog_clang = find_program('clang', required : get_option('bpf'))
+prog_git = find_program('git')
+prog_grep = find_program('grep')
+prog_perl = find_program('perl')
+
+dep_alsa = dependency('alsa', required : false)
+if dep_alsa.found()
+    conf.set('HAVE_ALSA', 1)
+endif
+
+dep_gl = dependency('gl', required : get_option('qvidcap').enabled() or
+                                     get_option('qv4l2').enabled())
+dep_glu = dependency('glu', required : false)
+
+dep_jsonc = dependency('json-c', required : get_option('v4l2-tracer'), version : '>=0.15')
+
+dep_libdl = cc.find_library('dl')
+dep_libelf = cc.find_library('elf', required : get_option('bpf'))
+dep_libm = cc.find_library('m')
+dep_librt = cc.find_library('rt')
+dep_qt5 = dependency('qt5', modules: ['Core', 'Gui', 'Widgets', 'OpenGL'],
+                     required : get_option('qvidcap').enabled() or get_option('qv4l2').enabled())
+
+dep_libbpf = dependency('bpf', required : get_option('bpf'), version : '>=0.7')
+if not dep_libbpf.found()
+    dep_libbpf = cc.find_library('bpf', has_headers: 'bpf/bpf.h', required : get_option('bpf'))
+endif
+
+dep_sdl = dependency('SDL2', required: false)
+if not dep_sdl.found()
+    dep_sdl = cc.find_library('SDL2', has_headers: 'SDL2/SDL.h', required: false)
+endif
+
+dep_sdl_image = dependency('SDL2_image', required: false)
+if not dep_sdl_image.found()
+    dep_sdl_image = cc.find_library('SDL2_image', has_headers: 'SDL2/SDL_image.h', required: false)
+endif
+
+dep_threads = dependency('threads')
+dep_x11 = dependency('x11', required : false)
+dep_xmlrpc = dependency('xmlrpc', required : false)
+
+have_fork = cc.has_function('fork')
+have_i2c_dev = cc.has_header('linux/i2c-dev.h')
+
+if have_visibility
+    conf.set('HAVE_VISIBILITY', 1)
+endif
+
+if cc.has_function('klogctl')
+    conf.set('HAVE_KLOGCTL', 1)
+endif
+
+if cc.has_function('secure_getenv')
+    conf.set('HAVE_SECURE_GETENV', 1)
+endif
+
+if cc.has_function('__secure_getenv')
+    conf.set('HAVE___SECURE_GETENV', 1)
+endif
+
+if cc.has_header('sys/klog.h')
+    conf.set('HAVE_SYS_KLOG_H', 1)
+endif
+
+if cc.has_header_symbol('execinfo.h', 'backtrace')
+    conf.set('HAVE_BACKTRACE', 1)
+endif
+
+if cc.has_function('argp_parse')
+    dep_argp = dependency('', required : false)
+else
+    dep_argp = cc.find_library('argp')
+endif
+
+if cc.has_function('strerrorname_np')
+    conf.set('HAVE_STRERRORNAME_NP', 1)
+endif
+
+conf.set_quoted('LOCALEDIR', get_option('prefix') / get_option('datadir') / 'locale')
+
+# Meson 0.60 handles the iconv dependency natively. For older versions, fall
+# back to manual checks for the iconv_open function in libc, or finding an
+# external library otherwise.
+if meson.version().version_compare('>= 0.60')
+    dep_iconv = dependency('iconv', required : false)
+else
+    if cc.has_function('iconv_open')
+        dep_iconv = declare_dependency()
+    else
+        dep_iconv = cc.find_library('iconv', required : false)
+    endif
+endif
+
+if dep_iconv.found()
+    conf.set('HAVE_ICONV', 1)
+    iconv_const_test = '''#include <iconv.h>
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+'''
+    if cc.compiles(iconv_const_test, dependencies : dep_iconv)
+        conf.set('ICONV_CONST', '')
+    else
+        conf.set('ICONV_CONST', 'const')
+    endif
+endif
+
+have_gconv = cc.has_header('gconv.h', required : get_option('gconv'))
+
+# Detect system gconv directory
+gconvsysdir = get_option('gconvsysdir')
+
+# Generic check: works with most distributions
+gconv_dirs_generic = [
+    'lib64',
+    'usr/lib64',
+    'usr/local/lib64',
+    'lib',
+    'usr/lib',
+    'usr/local/lib',
+]
+
+if gconvsysdir == ''
+    foreach dir : gconv_dirs_generic
+        dir = sys_root / dir / 'gconv'
+        if fs.is_dir(dir)
+            gconvsysdir = dir
+            break
+        endif
+    endforeach
+endif
+
+# Debian/Ubuntu-specific check: should be aligned with the debian package
+gconv_dirs_debian = [
+    'aarch64-linux-gnu',
+    'alphaev67-linux-gnu',
+    'arm-linux-gnueabi',
+    'arm-linux-gnueabihf',
+    'i686-kfreebsd-gnu',
+    'i686-linux-gnu',
+    'mips-linux-gnu',
+    'mips64-linux-gnuabi64',
+    'mips64-linux-gnuabin32',
+    'mips64el-linux-gnuabi64',
+    'mips64el-linux-gnuabin32',
+    'mipsel-linux-gnu',
+    'mipsisa32r6-linux-gnu',
+    'mipsisa32r6el-linux-gnu',
+    'mipsisa64r6-linux-gnuabi64',
+    'mipsisa64r6-linux-gnuabin32',
+    'mipsisa64r6el-linux-gnuabi64',
+    'mipsisa64r6el-linux-gnuabin32',
+    'powerpc-linux-gnu',
+    'powerpc64-linux-gnu',
+    's390-linux-gnu',
+    'sparc64-linux-gnu',
+    'sparcv9-linux-gnu',
+    'x86_64-linux-gnu',
+    'x86_64-linux-gnux32',
+]
+
+if gconvsysdir == ''
+    foreach dir : gconv_dirs_debian
+        dir = sys_root / 'usr' / 'lib' / dir / 'gconv'
+        if fs.is_dir(dir)
+            gconvsysdir = dir
+            break
+        endif
+    endforeach
+endif
+
+if gconvsysdir == ''
+    dep_jis = cc.find_library('JIS', required : get_option('gconv'))
+    dep_jisx0213 = cc.find_library('JISX0213', required : get_option('gconv'))
+else
+    dep_jis = cc.find_library('JIS', required : get_option('gconv'), dirs : gconvsysdir)
+    dep_jisx0213 = cc.find_library('JISX0213', required : get_option('gconv'), dirs : gconvsysdir)
+endif
+
+dep_jpeg = dependency('libjpeg', required : get_option('jpeg'))
+if dep_jpeg.found()
+    dep_jpeg_priv_libs = '-ljpeg'
+endif
+
+systemd_systemdir = get_option('systemdsystemunitdir')
+if systemd_systemdir == ''
+    dep_systemd = dependency('systemd', required : false)
+    if dep_systemd.found()
+        systemd_systemdir = dep_systemd.get_variable(pkgconfig : 'systemdsystemunitdir')
+    endif
+endif
+if systemd_systemdir == ''
+    systemd_systemdir = '/lib/systemd/system'
+endif
+# Since systemd v239, udevd is not allowed to execute BPF systems calls;
+# add an override to allow bpf(2) in that case. On earlier versions, the
+# override will restrict udevd to bpf syscall only and will stop the system
+# from booting. This is also true on current debian versions.
+have_udevdsyscallfilter = run_command(prog_grep, '-s', 'SystemCallFilter',
+                                      systemd_systemdir / 'systemd-udevd.service',
+                                      check : false).returncode() == 0
+
+dep_libudev = dependency('libudev', required : get_option('libdvbv5'))
+if dep_libudev.found()
+    conf.set('HAVE_LIBUDEV', 1)
+endif
+
+udevdir = get_option('udevdir')
+if udevdir == ''
+    dep_udev = dependency('udev', required : false)
+    if dep_udev.found()
+        udevdir = dep_udev.get_variable(pkgconfig : 'udevdir')
+    endif
+endif
+if udevdir == ''
+    udevdir = '/lib/udev'
+endif
+
+qt5_opengl_test = '''
+#define GL_GLEXT_PROTOTYPES
+#define QT_NO_OPENGL_ES_2
+
+#include <QGLWidget>
+#include <QGLShader>
+#include <QGLShaderProgram>
+#include <QGLFunctions>
+
+#ifndef GL_UNSIGNED_INT_8_8_8_8
+#error Missing OpenGL Extensions
+#endif
+'''
+have_qt5_opengl = cpp.compiles(qt5_opengl_test,
+                               dependencies : [dep_gl, dep_qt5],
+                               args : '-fPIC')
+if have_qt5_opengl
+    conf.set('HAVE_QTGL', 1)
+endif
+
+ioctl_posix_test = '''
+#include <sys/ioctl.h>
+int ioctl (int, int, ...);
+'''
+if cc.compiles(ioctl_posix_test)
+    conf.set('HAVE_POSIX_IOCTL', 1)
+endif
+
+c_arguments = []
+cpp_arguments = []
+
+c_arguments += common_arguments
+cpp_arguments += common_arguments
+
+add_project_arguments(c_arguments, language : 'c')
+add_project_arguments(cpp_arguments, language : 'cpp')
+add_project_link_arguments(cpp_arguments, language : 'cpp')
+
+git_sha = run_command(prog_git, '-C', meson.project_source_root(), 'rev-parse', '--short=12', 'HEAD',
+                      check : true).stdout().strip()
+conf.set('GIT_SHA', git_sha)
+git_commit_cnt = run_command(prog_git, '-C', meson.project_source_root(), 'rev-list', '--count', 'HEAD',
+                             check : true).stdout().strip()
+conf.set('GIT_COMMIT_CNT', '-' + git_commit_cnt)
+git_commit_date = run_command(prog_git, '-C', meson.project_source_root(), 'show', '--quiet',
+                              '--date=format-local:%F %T', '--format=%cd',
+                              env : ['TZ=UTC'], check : true).stdout().strip()
+conf.set('GIT_COMMIT_DATE', git_commit_date)
+
+man_pages = []
+
+i18n_gettext_arguments = ['--directory=' + meson.project_source_root(),
+                          '--keyword=_', '--keyword=N_', '--keyword=P_:1,2']
+subdir('libdvbv5-po')
+subdir('v4l-utils-po')
+
+subdir('lib')
+
+if get_option('v4l-utils')
+    subdir('utils')
+    subdir('contrib')
+endif
+
+configure_file(output : 'config.h', configuration : conf)
+
+foreach m : man_pages
+    configure_file(input : join_paths(m[0], '@0@.@1@.in'.format(m[1], m[2])),
+                   output : '@0@.@1@'.format(m[1], m[2]),
+                   install_dir : join_paths(get_option('mandir'), 'man@0@'.format(m[2])),
+                   configuration : conf)
+endforeach
+
+configure_file(input : 'v4l-utils.spec.in', output : 'v4l-utils.spec',
+               configuration : conf)
+
+summary({
+            'ALSA' : dep_alsa,
+            'GL' : dep_gl,
+            'GLU' : dep_glu,
+            'JSON-C' : dep_jsonc,
+            'Qt5' : [
+                dep_qt5,
+                have_qt5_opengl ? 'with QtGL' : 'without QtGL',
+            ],
+            'SDL' : dep_sdl,
+            'X11' : dep_x11,
+            'gconv' : have_gconv,
+            'iconv' : dep_iconv,
+            'libjpeg' : dep_jpeg,
+            'libudev' : dep_libudev,
+            'threads' : dep_threads,
+        }, bool_yn : true, section : 'Dependencies')
+
+summary({
+            'udevdir' : udevdir,
+        }, section : 'Directories')
+
+summary({
+            'libdvbv5' : is_variable('libdvbv5'),
+            'v4l-plugins' : get_option('v4l-plugins'),
+            'v4l-wrappers' : get_option('v4l-wrappers'),
+        }, bool_yn : true, section : 'Libraries')
+
+summary({
+            'BPF IR decoders' : ir_bpf_enabled,
+            'qv4l2' : is_variable('qv4l2'),
+            'qvidcap' : is_variable('qvidcap'),
+            'v4l-utils' : get_option('v4l-utils'),
+            'v4l2-compliance' : [
+                is_variable('v4l2_compliance'),
+                get_option('v4l2-compliance-libv4l') ? 'with libv4l' : 'without libv4l',
+            ],
+            'v4l2-compliance-32' : is_variable('v4l2_compliance_32'),
+            'v4l2-ctl' : [
+                is_variable('v4l2_ctl'),
+                get_option('v4l2-ctl-libv4l') ? 'with libv4l' : 'without libv4l',
+            ],
+            'v4l2-ctl-32' : is_variable('v4l2_ctl_32'),
+            'v4l2-tracer' : is_variable('v4l2_tracer'),
+        }, bool_yn : true, section : 'Applications')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 000000000000..6fc57bdee168
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,46 @@ 
+# Features
+option('bpf', type : 'feature', value : 'auto',
+       description : 'Enable IR BPF decoders')
+option('gconv', type : 'feature', value : 'auto',
+       description : 'Enable compilation of gconv modules')
+option('jpeg', type : 'feature', value : 'auto')
+option('libdvbv5', type : 'feature', value : 'auto',
+       description : 'Enable libdvbv5 compilation')
+option('qv4l2', type : 'feature', value : 'auto',
+       description : 'Enable qv4l2 compilation')
+option('qvidcap', type : 'feature', value : 'auto',
+       description : 'Enable qvidcap compilation')
+option('v4l2-tracer', type : 'feature', value : 'auto',
+       description : 'Enable v4l2-tracer compilation')
+
+# Options
+option('v4l-plugins', type : 'boolean',
+       description : 'V4L plugin support')
+option('v4l-utils', type : 'boolean',
+       description : 'Enable v4l-utils compilation')
+option('v4l-wrappers', type : 'boolean',
+       description : 'V4L wrappers support')
+option('v4l2-compliance-32', type : 'boolean', value : false,
+       description : 'Enable v4l2-compliance-32 compilation (for debugging purposes only)')
+option('v4l2-compliance-libv4l', type : 'boolean',
+       description : 'Enable use of libv4l in v4l2-compliance')
+option('v4l2-ctl-32', type : 'boolean', value : false,
+       description : 'Enable v4l2-ctl-32 compilation (for debugging purposes only)')
+option('v4l2-ctl-libv4l', type : 'boolean',
+       description : 'Enable use of libv4l in v4l2-ctl')
+option('v4l2-ctl-stream-to', type : 'boolean',
+       description : 'Enable use of --stream-to in v4l2-ctl')
+
+# Directories
+option('gconvsysdir', type : 'string',
+       description : 'Set system gconv directory (default is to autodetect)')
+option('libv4l1subdir', type : 'string', value : 'libv4l',
+       description : 'Set libv4l1 library subdir')
+option('libv4l2subdir', type : 'string', value : 'libv4l',
+       description : 'Set libv4l2 library subdir')
+option('libv4lconvertsubdir', type : 'string', value : 'libv4l',
+       description : 'Set libv4lconvert library subdir')
+option('systemdsystemunitdir', type : 'string',
+       description : 'Set systemd system unit directory')
+option('udevdir', type : 'string',
+       description : 'Set udev directory')
diff --git a/utils/cec-compliance/meson.build b/utils/cec-compliance/meson.build
new file mode 100644
index 000000000000..9cc0017bcccb
--- /dev/null
+++ b/utils/cec-compliance/meson.build
@@ -0,0 +1,23 @@ 
+cec_compliance_sources = files(
+    'cec-compliance.cpp',
+    'cec-compliance.h',
+    'cec-test-adapter.cpp',
+    'cec-test-audio.cpp',
+    'cec-test-fuzzing.cpp',
+    'cec-test-power.cpp',
+    'cec-test-tuner-record-timer.cpp',
+    'cec-test.cpp',
+)
+
+cec_compliance_deps = [
+    dep_libcecutil,
+    dep_librt,
+]
+
+cec_compliance = executable('cec-compliance',
+                            cec_compliance_sources,
+                            install : true,
+                            dependencies : cec_compliance_deps,
+                            include_directories : v4l2_utils_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'cec-compliance', 1 ]]
diff --git a/utils/cec-ctl/meson.build b/utils/cec-ctl/meson.build
new file mode 100644
index 000000000000..059ca20660a9
--- /dev/null
+++ b/utils/cec-ctl/meson.build
@@ -0,0 +1,18 @@ 
+cec_ctl_sources = files(
+    'cec-ctl.cpp',
+    'cec-ctl.h',
+    'cec-pin.cpp',
+)
+
+cec_ctl_deps = [
+    dep_libcecutil,
+    dep_librt,
+]
+
+cec_ctl = executable('cec-ctl',
+                     cec_ctl_sources,
+                     install : true,
+                     dependencies : cec_ctl_deps,
+                     include_directories : v4l2_utils_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'cec-ctl', 1 ]]
diff --git a/utils/cec-follower/meson.build b/utils/cec-follower/meson.build
new file mode 100644
index 000000000000..2d58fac4e6f0
--- /dev/null
+++ b/utils/cec-follower/meson.build
@@ -0,0 +1,19 @@ 
+cec_follower_sources = files(
+    'cec-follower.cpp',
+    'cec-follower.h',
+    'cec-processing.cpp',
+    'cec-tuner.cpp',
+)
+
+cec_follower_deps = [
+    dep_libcecutil,
+    dep_librt,
+]
+
+cec_follower = executable('cec-follower',
+                          cec_follower_sources,
+                          install : true,
+                          dependencies : cec_follower_deps,
+                          include_directories : v4l2_utils_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'cec-follower', 1 ]]
diff --git a/utils/cx18-ctl/meson.build b/utils/cx18-ctl/meson.build
new file mode 100644
index 000000000000..161b91c951f0
--- /dev/null
+++ b/utils/cx18-ctl/meson.build
@@ -0,0 +1,8 @@ 
+cx18_ctl_sources = files(
+    'cx18-ctl.c',
+)
+
+cx18_ctl = executable('cx18-ctl',
+                      cx18_ctl_sources,
+                      install : true,
+                      include_directories : v4l2_utils_incdir)
diff --git a/utils/dvb/meson.build b/utils/dvb/meson.build
new file mode 100644
index 000000000000..871f5a398a06
--- /dev/null
+++ b/utils/dvb/meson.build
@@ -0,0 +1,70 @@ 
+dvb_common_deps =  [
+    dep_argp,
+    dep_libdvbv5,
+    dep_libudev,
+    dep_threads,
+    dep_xmlrpc,
+]
+
+dvb_fe_tool_sources = files(
+    'dvb-fe-tool.c',
+)
+
+dvb_fe_tool = executable('dvb-fe-tool',
+                         dvb_fe_tool_sources,
+                         install : true,
+                         dependencies : dvb_common_deps,
+                         include_directories : v4l2_utils_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'dvb-fe-tool', 1 ]]
+
+dvbv5_zap_sources = files(
+    'dvbv5-zap.c',
+)
+
+dvbv5_zap = executable('dvbv5-zap',
+                       dvbv5_zap_sources,
+                       install : true,
+                       dependencies : dvb_common_deps,
+                       include_directories : v4l2_utils_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'dvbv5-zap', 1 ]]
+
+dvbv5_scan_sources = files(
+    'dvbv5-scan.c',
+)
+
+dvbv5_scan = executable('dvbv5-scan',
+                        dvbv5_scan_sources,
+                        install : true,
+                        dependencies : dvb_common_deps,
+                        include_directories : v4l2_utils_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'dvbv5-scan', 1 ]]
+
+dvb_format_convert_sources = files(
+    'dvb-format-convert.c',
+)
+
+dvb_format_convert = executable('dvb-format-convert',
+                                dvb_format_convert_sources,
+                                install : true,
+                                dependencies : dvb_common_deps,
+                                include_directories : v4l2_utils_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'dvb-format-convert', 1 ]]
+
+dvbv5_daemon_sources = files(
+    'dvbv5-daemon.c',
+)
+
+dvbv5_daemon_c_args = [
+    '-DHAVE_DVBV5_REMOTE',
+]
+
+dvbv5_daemon = executable('dvbv5-daemon',
+                          dvbv5_daemon_sources,
+                          install : true,
+                          dependencies : dvb_common_deps,
+                          c_args : dvbv5_daemon_c_args,
+                          include_directories : v4l2_utils_incdir)
diff --git a/utils/gen_media_bus_format_codes.sh b/utils/gen_media_bus_format_codes.sh
new file mode 100755
index 000000000000..4bdcc3b721ee
--- /dev/null
+++ b/utils/gen_media_bus_format_codes.sh
@@ -0,0 +1,7 @@ 
+#!/bin/bash
+
+src="$1"
+
+sed -e \
+'/#define MEDIA_BUS_FMT/ ! d; s/.*#define //; /FIXED/ d; s/\t.*//; s/.*/ &,/;' \
+${src}
diff --git a/utils/gen_media_bus_format_names.sh b/utils/gen_media_bus_format_names.sh
new file mode 100755
index 000000000000..3fdc830d1f97
--- /dev/null
+++ b/utils/gen_media_bus_format_names.sh
@@ -0,0 +1,7 @@ 
+#!/bin/bash
+
+src="$1"
+
+sed -e \
+'/#define MEDIA_BUS_FMT/ ! d; s/.*FMT_//; /FIXED/ d; s/\t.*//; s/.*/{ \"&\", MEDIA_BUS_FMT_& },/;' \
+${src}
diff --git a/utils/ir-ctl/meson.build b/utils/ir-ctl/meson.build
new file mode 100644
index 000000000000..24d73a15e63b
--- /dev/null
+++ b/utils/ir-ctl/meson.build
@@ -0,0 +1,23 @@ 
+ir_ctl_sources = files(
+    'bpf_encoder.c',
+    'bpf_encoder.h',
+    'ir-ctl.c',
+    'ir-encode.c',
+    'ir-encode.h',
+    'keymap.c',
+    'keymap.h',
+    'toml.c',
+    'toml.h',
+)
+
+ir_ctl_deps =  [
+    dep_argp,
+]
+
+ir_ctl = executable('ir-ctl',
+                    ir_ctl_sources,
+                    install : true,
+                    dependencies : ir_ctl_deps,
+                    include_directories : v4l2_utils_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'ir-ctl', 1 ]]
diff --git a/utils/ivtv-ctl/meson.build b/utils/ivtv-ctl/meson.build
new file mode 100644
index 000000000000..410a8439e296
--- /dev/null
+++ b/utils/ivtv-ctl/meson.build
@@ -0,0 +1,13 @@ 
+ivtv_ctl_sources = files(
+    'ivtv-ctl.c',
+)
+
+ivtv_ctl_deps = [
+    dep_libm,
+]
+
+ivtv_ctl = executable('ivtv-ctl',
+                      ivtv_ctl_sources,
+                      install : true,
+                      dependencies : ivtv_ctl_deps,
+                      include_directories : v4l2_utils_incdir)
diff --git a/utils/keytable/bpf_protocols/clang_sys_includes.sh b/utils/keytable/bpf_protocols/clang_sys_includes.sh
new file mode 100755
index 000000000000..9dc4af12ecbb
--- /dev/null
+++ b/utils/keytable/bpf_protocols/clang_sys_includes.sh
@@ -0,0 +1,9 @@ 
+#!/bin/sh
+# Get Clang's default includes on this system, as opposed to those seen by
+# '-target bpf'. This fixes "missing" files on some architectures/distros,
+# such as asm/byteorder.h, asm/socket.h, asm/sockios.h, sys/cdefs.h etc.
+#
+# Use '-idirafter': Don't interfere with include mechanics except where the
+# build would have failed anyways.
+$CLANG -v -E - </dev/null 2>&1 \
+	| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }'
diff --git a/utils/keytable/bpf_protocols/meson.build b/utils/keytable/bpf_protocols/meson.build
new file mode 100644
index 000000000000..1e4f0064fdd8
--- /dev/null
+++ b/utils/keytable/bpf_protocols/meson.build
@@ -0,0 +1,31 @@ 
+bpf_protocols_files = [
+    'grundig',
+    'imon_rsc',
+    'manchester',
+    'pulse_distance',
+    'pulse_length',
+    'raw',
+    'rc_mm',
+    'samsung36',
+    'xbox-dvd',
+]
+
+clang_sys_includes = run_command('clang_sys_includes.sh',
+                                 check : true,
+                                 env : ['CLANG=' + prog_clang.full_path()])
+
+foreach file : bpf_protocols_files
+    output = file + '.o'
+    input = file + '.c'
+    custom_target(output,
+                  output : output,
+                  input : input,
+                  command : [
+                      prog_clang,
+                      clang_sys_includes.stdout().split(),
+                      '-D__linux__', '-fno-stack-protector', '-target', 'bpf',
+                      '-O2', '-c', '@INPUT@', '-o', '@OUTPUT@',
+                  ],
+                  install : true,
+                  install_dir : ir_keytable_system_dir / 'rc_keymaps' / 'protocols')
+endforeach
diff --git a/utils/keytable/meson.build b/utils/keytable/meson.build
new file mode 100644
index 000000000000..0ca08a183d1d
--- /dev/null
+++ b/utils/keytable/meson.build
@@ -0,0 +1,85 @@ 
+ir_keytable_sources = files(
+    'ir-encode.c',
+    'ir-encode.h',
+    'keymap.c',
+    'keymap.h',
+    'keytable.c',
+    'parse.h',
+    'toml.c',
+    'toml.h',
+)
+
+ir_keytable_deps = [
+    dep_argp,
+]
+
+ir_keytable_system_dir = udevdir
+ir_keytable_user_dir = get_option('sysconfdir') / 'rc_keymaps'
+
+ir_keytable_c_args = [
+    '-DIR_KEYTABLE_SYSTEM_DIR="@0@"'.format(ir_keytable_system_dir),
+    '-DIR_KEYTABLE_USER_DIR="@0@"'.format(ir_keytable_user_dir),
+]
+
+ir_bpf_enabled = prog_clang.found() and dep_libbpf.found() and dep_libelf.found()
+
+if ir_bpf_enabled
+    ir_keytable_sources += files(
+        'bpf_load.c',
+        'bpf_load.h',
+    )
+    ir_keytable_deps += [
+        dep_libbpf,
+        dep_libelf,
+    ]
+    ir_keytable_c_args += [
+        '-DHAVE_BPF',
+    ]
+    subdir('bpf_protocols')
+endif
+
+ir_keytable_incdir = [
+    utils_common_incdir,
+    v4l2_utils_incdir,
+]
+
+ir_keytable = executable('ir-keytable',
+                         sources : ir_keytable_sources,
+                         install : true,
+                         dependencies : ir_keytable_deps,
+                         c_args : ir_keytable_c_args,
+                         include_directories : ir_keytable_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'ir-keytable', 1 ]]
+man_pages += [[ meson.current_source_dir(), 'rc_keymap', 5 ]]
+
+ir_keytable_sysconf_files = files(
+    'rc_maps.cfg',
+)
+install_data(ir_keytable_sysconf_files,
+             install_dir : get_option('sysconfdir'))
+
+subdir('rc_keymaps')
+install_data(ir_keytable_rc_keymaps,
+             install_dir : ir_keytable_system_dir / 'rc_keymaps')
+
+ir_keytable_udev_rules = files(
+    '70-infrared.rules',
+)
+install_data(ir_keytable_udev_rules,
+             install_dir : ir_keytable_system_dir / 'rules.d')
+
+if have_udevdsyscallfilter
+    ir_keytable_systemd_files = files(
+        '50-rc_keymap.conf',
+    )
+    install_data(ir_keytable_systemd_files,
+                 install_dir : systemd_systemdir / 'systemd-udevd.service.d')
+endif
+
+# Install non-existing directory to create empty directory structure
+# See: https://github.com/mesonbuild/meson/issues/2904
+# This should be replaced with install_emptydir() when bumping the minimum meson
+# version to 0.60.0.
+install_subdir('protocols',
+               install_dir : ir_keytable_user_dir)
diff --git a/utils/keytable/rc_keymaps/meson.build b/utils/keytable/rc_keymaps/meson.build
new file mode 100644
index 000000000000..9ea0bc776642
--- /dev/null
+++ b/utils/keytable/rc_keymaps/meson.build
@@ -0,0 +1,150 @@ 
+ir_keytable_rc_keymaps = files(
+    'adstech_dvb_t_pci.toml',
+    'af9005.toml',
+    'alink_dtu_m.toml',
+    'allwinner_ba10_tv_box.toml',
+    'allwinner_i12_a20_tv_box.toml',
+    'anysee.toml',
+    'apac_viewcomp.toml',
+    'astrometa_t2hybrid.toml',
+    'asus_pc39.toml',
+    'asus_ps3_100.toml',
+    'ati_tv_wonder_hd_600.toml',
+    'ati_x10.toml',
+    'avermedia.toml',
+    'avermedia_a16d.toml',
+    'avermedia_cardbus.toml',
+    'avermedia_dvbt.toml',
+    'avermedia_m135a.toml',
+    'avermedia_m733a_rm_k6.toml',
+    'avermedia_rm_ks.toml',
+    'avertv_303.toml',
+    'az6027.toml',
+    'azurewave_ad_tu700.toml',
+    'beelink_gs1.toml',
+    'behold.toml',
+    'behold_columbus.toml',
+    'budget_ci_old.toml',
+    'cec.toml',
+    'cinergy.toml',
+    'cinergy_1400.toml',
+    'cinergyt2.toml',
+    'd680_dmb.toml',
+    'delock_61959.toml',
+    'dib0700_nec.toml',
+    'dib0700_rc5.toml',
+    'dibusb.toml',
+    'digitalnow_tinytwin.toml',
+    'digittrade.toml',
+    'digitv.toml',
+    'dish_network.toml',
+    'dm1105_nec.toml',
+    'dntv_live_dvb_t.toml',
+    'dntv_live_dvbt_pro.toml',
+    'dtt200u.toml',
+    'dvbsky.toml',
+    'dvico_mce.toml',
+    'dvico_portable.toml',
+    'em_terratec.toml',
+    'encore_enltv.toml',
+    'encore_enltv2.toml',
+    'encore_enltv_fm53.toml',
+    'evga_indtube.toml',
+    'eztv.toml',
+    'flydvb.toml',
+    'flyvideo.toml',
+    'fusionhdtv_mce.toml',
+    'gadmei_rm008z.toml',
+    'geekbox.toml',
+    'genius_tvgo_a11mce.toml',
+    'gotview7135.toml',
+    'haupp.toml',
+    'hauppauge.toml',
+    'hisi_poplar.toml',
+    'hisi_tv_demo.toml',
+    'imon_mce.toml',
+    'imon_pad.toml',
+    'imon_rsc.toml',
+    'iodata_bctv7e.toml',
+    'it913x_v1.toml',
+    'it913x_v2.toml',
+    'kaiomy.toml',
+    'khadas.toml',
+    'khamsin.toml',
+    'kii_pro.toml',
+    'kworld_315u.toml',
+    'kworld_pc150u.toml',
+    'kworld_plus_tv_analog.toml',
+    'leadtek_y04g0051.toml',
+    'lme2510.toml',
+    'manli.toml',
+    'mce_keyboard.toml',
+    'medion_x10.toml',
+    'medion_x10_digitainer.toml',
+    'medion_x10_or2x.toml',
+    'megasky.toml',
+    'minix_neo.toml',
+    'msi_digivox_ii.toml',
+    'msi_digivox_iii.toml',
+    'msi_tvanywhere.toml',
+    'msi_tvanywhere_plus.toml',
+    'nebula.toml',
+    'nec_terratec_cinergy_xs.toml',
+    'norwood.toml',
+    'npgtech.toml',
+    'odroid.toml',
+    'opera1.toml',
+    'pctv_sedna.toml',
+    'pine64.toml',
+    'pinnacle310e.toml',
+    'pinnacle_color.toml',
+    'pinnacle_grey.toml',
+    'pinnacle_pctv_hd.toml',
+    'pixelview.toml',
+    'pixelview_002t.toml',
+    'pixelview_mk12.toml',
+    'pixelview_new.toml',
+    'powercolor_real_angel.toml',
+    'proteus_2309.toml',
+    'purpletv.toml',
+    'pv951.toml',
+    'rc6_mce.toml',
+    'real_audio_220_32_keys.toml',
+    'reddo.toml',
+    'samsung_ak59_00125a.toml',
+    'snapstream_firefly.toml',
+    'streamzap.toml',
+    'su3000.toml',
+    'tanix_tx3mini.toml',
+    'tanix_tx5max.toml',
+    'tbs_nec.toml',
+    'technisat_ts35.toml',
+    'technisat_usb2.toml',
+    'terratec_cinergy_c_pci.toml',
+    'terratec_cinergy_s2_hd.toml',
+    'terratec_cinergy_xs.toml',
+    'terratec_slim.toml',
+    'terratec_slim_2.toml',
+    'tevii_nec.toml',
+    'tivo.toml',
+    'total_media_in_hand.toml',
+    'total_media_in_hand_02.toml',
+    'trekstor.toml',
+    'tt_1500.toml',
+    'tvwalkertwin.toml',
+    'twinhan_dtv_cab_ci.toml',
+    'twinhan_vp1027_dvbs.toml',
+    'vega_s9x.toml',
+    'videomate_k100.toml',
+    'videomate_s350.toml',
+    'videomate_tv_pvr.toml',
+    'vp702x.toml',
+    'wetek_hub.toml',
+    'wetek_play2.toml',
+    'winfast.toml',
+    'winfast_usbii_deluxe.toml',
+    'wobo_i5.toml',
+    'x96max.toml',
+    'xbox_dvd.toml',
+    'zx_irdec.toml',
+)
diff --git a/utils/libcecutil/meson.build b/utils/libcecutil/meson.build
new file mode 100644
index 000000000000..ed3aa88ceefb
--- /dev/null
+++ b/utils/libcecutil/meson.build
@@ -0,0 +1,45 @@ 
+libcecutil_sources = files(
+    'cec-htng-funcs.h',
+    'cec-htng.h',
+    'cec-info.cpp',
+    'cec-info.h',
+    'cec-log.cpp',
+    'cec-log.h',
+    'cec-parse.cpp',
+    'cec-parse.h',
+)
+
+libcecutil_deps = [
+    dep_libdl,
+    dep_libv4lconvert,
+    dep_threads,
+]
+
+libcecutil_incdir = [
+    utils_common_incdir,
+    v4l2_utils_incdir,
+]
+
+cec_gen_sources = files(
+    '../../include/linux/cec.h',
+    'cec-htng.h',
+    '../../include/linux/cec-funcs.h',
+    'cec-htng-funcs.h',
+)
+
+configure_file(
+    input : 'cec-gen.pl',
+    output : 'cec-gen-dummy.stamp',
+    command : [prog_perl, '@INPUT@', cec_gen_sources, 'utils/libcecutil'],
+)
+
+libcecutil = static_library('cecutil',
+                            libcecutil_sources,
+                            install : false,
+                            dependencies : libcecutil_deps,
+                            include_directories : libcecutil_incdir)
+
+dep_libcecutil = declare_dependency(
+    link_with : libcecutil,
+    include_directories : '.',
+)
diff --git a/utils/libmedia_dev/meson.build b/utils/libmedia_dev/meson.build
new file mode 100644
index 000000000000..f97238e63076
--- /dev/null
+++ b/utils/libmedia_dev/meson.build
@@ -0,0 +1,14 @@ 
+libmedia_dev_sources = files(
+    'get_media_devices.c',
+    'get_media_devices.h',
+)
+
+libmedia_dev = static_library('media_dev',
+                              libmedia_dev_sources,
+                              install : false,
+                              include_directories : v4l2_utils_incdir)
+
+dep_libmedia_dev = declare_dependency(
+    link_with : libmedia_dev,
+    include_directories : '.',
+)
diff --git a/utils/libv4l2util/meson.build b/utils/libv4l2util/meson.build
new file mode 100644
index 000000000000..9d1c6e12d1be
--- /dev/null
+++ b/utils/libv4l2util/meson.build
@@ -0,0 +1,16 @@ 
+libv4l2util_sources = files(
+    'frequencies.c',
+    'libv4l2util.h',
+    'v4l2_driver.c',
+    'v4l2_driver.h',
+)
+
+libv4l2util = static_library('v4l2util',
+                             libv4l2util_sources,
+                             install : false,
+                             include_directories : v4l2_utils_incdir)
+
+dep_libv4l2util = declare_dependency(
+    link_with : libv4l2util,
+    include_directories : '.',
+)
diff --git a/utils/media-ctl/meson.build b/utils/media-ctl/meson.build
new file mode 100644
index 000000000000..3a7b0c9add4a
--- /dev/null
+++ b/utils/media-ctl/meson.build
@@ -0,0 +1,43 @@ 
+libmediactl_sources = files(
+    'libmediactl.c',
+    'mediactl-priv.h',
+)
+
+libmediactl_deps = [
+    dep_libudev,
+]
+
+libmediactl = static_library('mediactl',
+                             libmediactl_sources,
+                             dependencies : libmediactl_deps,
+                             include_directories : v4l2_utils_incdir)
+
+dep_libmediactl = declare_dependency(link_with : libmediactl)
+
+libv4l2subdev_sources = files('libv4l2subdev.c')
+libv4l2subdev_sources += media_bus_format_names_h
+libv4l2subdev_sources += media_bus_format_codes_h
+
+libv4l2subdev = static_library('v4l2subdev',
+                               libv4l2subdev_sources,
+                               include_directories : v4l2_utils_incdir)
+
+dep_libv4l2subdev = declare_dependency(link_with : libv4l2subdev)
+
+media_ctl_sources = files(
+    'media-ctl.c',
+    'options.c',
+    'options.h',
+    'tools.h',
+)
+
+media_ctl_deps = [
+    dep_libmediactl,
+    dep_libv4l2subdev,
+]
+
+media_ctl = executable('media-ctl',
+                       media_ctl_sources,
+                       dependencies : media_ctl_deps,
+                       install : true,
+                       include_directories : v4l2_utils_incdir)
diff --git a/utils/meson.build b/utils/meson.build
new file mode 100644
index 000000000000..25f50191a037
--- /dev/null
+++ b/utils/meson.build
@@ -0,0 +1,43 @@ 
+utils_common_incdir = include_directories('common')
+
+# Generate targets for media-bus-format-{names,codes}.h
+foreach x: [ 'names', 'codes' ]
+    output_file = 'media-bus-format-@0@.h'.format(x)
+    input_file = 'gen_media_bus_format_@0@.sh'.format(x)
+    target = custom_target(
+        output_file,
+        output : output_file,
+        input : input_file,
+        command : [
+            prog_bash, '@INPUT@', files('..' / 'include' / 'linux' / 'media-bus-format.h'),
+        ],
+        capture : true,
+    )
+    set_variable(output_file.underscorify(), target)
+endforeach
+
+# Libraries
+subdir('libcecutil')
+subdir('libmedia_dev')
+subdir('libv4l2util')
+
+# Utils
+subdir('cec-ctl')
+subdir('cec-follower')
+subdir('cx18-ctl')
+subdir('dvb', if_found : dep_libdvbv5)
+subdir('ir-ctl')
+subdir('ivtv-ctl')
+subdir('keytable')
+subdir('media-ctl')
+subdir('qv4l2')
+subdir('qvidcap')
+subdir('rds-ctl')
+subdir('v4l2-ctl')
+subdir('v4l2-dbg')
+subdir('v4l2-sysfs-path')
+subdir('v4l2-tracer')
+
+# Compliance tools
+subdir('cec-compliance')
+subdir('v4l2-compliance')
diff --git a/utils/qv4l2/meson.build b/utils/qv4l2/meson.build
new file mode 100644
index 000000000000..54676be85749
--- /dev/null
+++ b/utils/qv4l2/meson.build
@@ -0,0 +1,79 @@ 
+if get_option('qv4l2').disabled() or not dep_gl.found() or not dep_qt5.found()
+    subdir_done()
+endif
+
+qv4l2_sources = files(
+    'alsa_stream.c',
+    'alsa_stream.h',
+    'capture-win-gl.cpp',
+    'capture-win-gl.h',
+    'capture-win-qt.cpp',
+    'capture-win-qt.h',
+    'capture-win.cpp',
+    'capture-win.h',
+    'ctrl-tab.cpp',
+    'general-tab.cpp',
+    'general-tab.h',
+    'qv4l2.cpp',
+    'qv4l2.h',
+    'raw2sliced.cpp',
+    'raw2sliced.h',
+    'tpg-tab.cpp',
+    'v4l2-tpg-colors.c',
+    'v4l2-tpg-core.c',
+    'vbi-tab.cpp',
+    'vbi-tab.h',
+)
+
+qv4l2_deps = [
+    dep_alsa,
+    dep_gl,
+    dep_libmedia_dev,
+    dep_libv4l2,
+    dep_libv4l2util,
+    dep_libv4lconvert,
+    dep_qt5,
+    dep_threads,
+]
+
+qv4l2_incdir = [
+    utils_common_incdir,
+    v4l2_utils_incdir,
+]
+
+qt5_files = qt5.preprocess(
+    moc_headers : ['qv4l2.h', 'general-tab.h', 'vbi-tab.h', 'capture-win.h'],
+    qresources : 'qv4l2.qrc',
+)
+qv4l2_sources += qt5_files
+
+qv4l2 = executable('qv4l2',
+                   sources : qv4l2_sources,
+                   install : true,
+                   dependencies : qv4l2_deps,
+                   include_directories : qv4l2_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'qv4l2', 1 ]]
+
+qv4l2_applications_files = files(
+    'qv4l2.desktop',
+)
+
+install_data('qv4l2.desktop',
+             install_dir : get_option('datadir') / 'applications')
+
+qv4l2_icons_dir = get_option('datadir') / 'icons' / 'hicolor'
+
+qv4l2_icons_files = [
+    ['qv4l2_16x16.png', '16x16',    'qv4l2.png'],
+    ['qv4l2_24x24.png', '24x24',    'qv4l2.png'],
+    ['qv4l2_32x32.png', '32x32',    'qv4l2.png'],
+    ['qv4l2_64x64.png', '64x64',    'qv4l2.png'],
+    ['qv4l2.svg',       'scalable', 'qv4l2.svg'],
+]
+
+foreach f : qv4l2_icons_files
+    install_data(f[0],
+                 rename: f[1] / 'apps' / f[2],
+                 install_dir : qv4l2_icons_dir)
+endforeach
diff --git a/utils/qvidcap/meson.build b/utils/qvidcap/meson.build
new file mode 100644
index 000000000000..faae18fbb812
--- /dev/null
+++ b/utils/qvidcap/meson.build
@@ -0,0 +1,87 @@ 
+qvidcap_option = get_option('qvidcap')
+
+if qvidcap_option.enabled() and not have_qt5_opengl
+    error('qvidcap enabled but Qt5 is missing OpenGL support')
+endif
+
+if qvidcap_option.disabled() or not dep_gl.found() or not dep_qt5.found() or not have_qt5_opengl
+    subdir_done()
+endif
+
+qvidcap_sources = files(
+    'capture.cpp',
+    'capture.h',
+    'codec-fwht.c',
+    'codec-v4l2-fwht.c',
+    'paint.cpp',
+    'qvidcap.cpp',
+    'qvidcap.h',
+    'v4l-stream.c',
+    'v4l2-info.cpp',
+    'v4l2-tpg-colors.c',
+    'v4l2-tpg-core.c',
+)
+
+qvidcap_deps = [
+    dep_alsa,
+    dep_gl,
+    dep_libmedia_dev,
+    dep_libv4l2,
+    dep_libv4l2util,
+    dep_libv4lconvert,
+    dep_qt5,
+    dep_threads,
+]
+
+qvidcap_incdir = [
+    utils_common_incdir,
+    v4l2_utils_incdir,
+]
+
+qt5_files = qt5.preprocess(
+    moc_headers : 'capture.h',
+    qresources : 'qvidcap.qrc',
+)
+qvidcap_sources += qt5_files
+
+v4l2_convert_sources = files(
+    'v4l2-convert.glsl',
+)
+
+configure_file(
+    input : 'v4l2-convert.pl',
+    output : 'v4l2-convert.h',
+    capture : true,
+    command : [prog_perl, '@INPUT@', v4l2_convert_sources],
+)
+
+qvidcap = executable('qvidcap',
+                     sources : qvidcap_sources,
+                     install : true,
+                     dependencies : qvidcap_deps,
+                     include_directories : qvidcap_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'qvidcap', 1 ]]
+
+qvidcap_applications_files = files(
+    'qvidcap.desktop',
+)
+
+install_data('qvidcap.desktop',
+             install_dir : get_option('datadir') / 'applications')
+
+qvidcap_icons_dir = get_option('datadir') / 'icons' / 'hicolor'
+
+qvidcap_icons_files = [
+    ['qvidcap_16x16.png', '16x16',    'qvidcap.png'],
+    ['qvidcap_24x24.png', '24x24',    'qvidcap.png'],
+    ['qvidcap_32x32.png', '32x32',    'qvidcap.png'],
+    ['qvidcap_64x64.png', '64x64',    'qvidcap.png'],
+    ['qvidcap.svg',       'scalable', 'qvidcap.svg'],
+]
+
+foreach f : qvidcap_icons_files
+    install_data(f[0],
+                 rename: f[1] / 'apps' / f[2],
+                 install_dir : qvidcap_icons_dir)
+endforeach
diff --git a/utils/rds-ctl/meson.build b/utils/rds-ctl/meson.build
new file mode 100644
index 000000000000..f94ffb0c50cd
--- /dev/null
+++ b/utils/rds-ctl/meson.build
@@ -0,0 +1,17 @@ 
+rds_ctl_sources = files(
+    'rds-ctl.cpp',
+    'v4l2-info.cpp',
+)
+
+rds_ctl_deps = [
+    dep_libv4l2rds,
+]
+
+rds_ctl = executable('rds-ctl',
+                     rds_ctl_sources,
+                     install : true,
+                     dependencies : rds_ctl_deps,
+                     include_directories : [
+                         v4l2_utils_incdir,
+                         utils_common_incdir,
+                     ])
diff --git a/utils/v4l2-compliance/meson.build b/utils/v4l2-compliance/meson.build
new file mode 100644
index 000000000000..142e9a94bf0e
--- /dev/null
+++ b/utils/v4l2-compliance/meson.build
@@ -0,0 +1,63 @@ 
+if not have_fork
+    subdir_done()
+endif
+
+v4l2_compliance_sources = files(
+    'media-info.cpp',
+    'v4l2-compliance.cpp',
+    'v4l2-compliance.h',
+    'v4l2-info.cpp',
+    'v4l2-test-buffers.cpp',
+    'v4l2-test-codecs.cpp',
+    'v4l2-test-colors.cpp',
+    'v4l2-test-controls.cpp',
+    'v4l2-test-debug.cpp',
+    'v4l2-test-formats.cpp',
+    'v4l2-test-input-output.cpp',
+    'v4l2-test-io-config.cpp',
+    'v4l2-test-media.cpp',
+    'v4l2-test-subdevs.cpp',
+    'v4l2-test-time32-64.cpp',
+)
+
+v4l2_compliance_deps = [
+    dep_librt,
+    dep_threads,
+]
+
+v4l2_compliance_cpp_args = []
+
+if get_option('v4l2-compliance-libv4l')
+    v4l2_compliance_deps += [
+        dep_libv4lconvert,
+        dep_libv4l2,
+    ]
+else
+    v4l2_compliance_cpp_args += '-DNO_LIBV4L2'
+endif
+
+v4l2_compliance_incdir = [
+    utils_common_incdir,
+    v4l2_utils_incdir,
+]
+
+v4l2_compliance = executable('v4l2-compliance',
+                             v4l2_compliance_sources,
+                             install : true,
+                             dependencies : v4l2_compliance_deps,
+                             cpp_args : v4l2_compliance_cpp_args,
+                             include_directories : v4l2_compliance_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'v4l2-compliance', 1 ]]
+
+v4l2_compliance_32_cpp_args = ['-m32', '-DNO_LIBV4L2']
+v4l2_compliance_32_link_args = ['-m32', '-static']
+
+if get_option('v4l2-compliance-32') and have_m32
+    v4l2_compliance_32 = executable('v4l2-compliance-32',
+                                    v4l2_compliance_sources,
+                                    install : true,
+                                    cpp_args : v4l2_compliance_32_cpp_args,
+                                    link_args : v4l2_compliance_32_link_args,
+                                    include_directories : v4l2_compliance_incdir)
+endif
diff --git a/utils/v4l2-ctl/meson.build b/utils/v4l2-ctl/meson.build
new file mode 100644
index 000000000000..3e366c6c0496
--- /dev/null
+++ b/utils/v4l2-ctl/meson.build
@@ -0,0 +1,75 @@ 
+v4l2_ctl_sources = files(
+    'codec-fwht.c',
+    'codec-v4l2-fwht.c',
+    'media-info.cpp',
+    'v4l-stream.c',
+    'v4l2-ctl-common.cpp',
+    'v4l2-ctl-edid.cpp',
+    'v4l2-ctl-io.cpp',
+    'v4l2-ctl-meta.cpp',
+    'v4l2-ctl-misc.cpp',
+    'v4l2-ctl-modes.cpp',
+    'v4l2-ctl-overlay.cpp',
+    'v4l2-ctl-sdr.cpp',
+    'v4l2-ctl-selection.cpp',
+    'v4l2-ctl-stds.cpp',
+    'v4l2-ctl-streaming.cpp',
+    'v4l2-ctl-subdev.cpp',
+    'v4l2-ctl-tuner.cpp',
+    'v4l2-ctl-vbi.cpp',
+    'v4l2-ctl-vidcap.cpp',
+    'v4l2-ctl-vidout.cpp',
+    'v4l2-ctl.cpp',
+    'v4l2-ctl.h',
+    'v4l2-info.cpp',
+    'v4l2-tpg-colors.c',
+    'v4l2-tpg-core.c',
+)
+v4l2_ctl_sources += media_bus_format_names_h
+
+v4l2_ctl_deps = [
+    dep_librt,
+    dep_threads,
+]
+
+v4l2_ctl_cpp_args = []
+
+if get_option('v4l2-ctl-libv4l')
+    v4l2_ctl_deps += [
+        dep_libv4l2,
+        dep_libv4lconvert,
+    ]
+else
+    v4l2_ctl_cpp_args += '-DNO_LIBV4L2'
+endif
+
+if not get_option('v4l2-ctl-stream-to')
+    v4l2_ctl_cpp_args += '-DNO_STREAM_TO'
+endif
+
+v4l2_ctl_incdir = [
+    utils_common_incdir,
+    v4l2_utils_incdir,
+]
+
+v4l2_ctl = executable('v4l2-ctl',
+                      v4l2_ctl_sources,
+                      install : true,
+                      dependencies : v4l2_ctl_deps,
+                      cpp_args : v4l2_ctl_cpp_args,
+                      include_directories : v4l2_ctl_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'v4l2-ctl', 1 ]]
+
+v4l2_ctl_32_c_cpp_args = ['-m32', '-DNO_LIBV4L2']
+v4l2_ctl_32_link_args = ['-m32', '-static']
+
+if get_option('v4l2-ctl-32') and have_m32
+    v4l2_ctl_32 = executable('v4l2-ctl-32',
+                             v4l2_ctl_sources,
+                             install : true,
+                             c_args : v4l2_ctl_32_c_cpp_args,
+                             cpp_args : v4l2_ctl_32_c_cpp_args,
+                             link_args : v4l2_ctl_32_link_args,
+                             include_directories : v4l2_ctl_incdir)
+endif
diff --git a/utils/v4l2-dbg/meson.build b/utils/v4l2-dbg/meson.build
new file mode 100644
index 000000000000..c23bf8f35101
--- /dev/null
+++ b/utils/v4l2-dbg/meson.build
@@ -0,0 +1,20 @@ 
+v4l2_dbg_sources = files(
+    'v4l2-dbg-ac97.h',
+    'v4l2-dbg-bttv.h',
+    'v4l2-dbg-em28xx.h',
+    'v4l2-dbg-micron.h',
+    'v4l2-dbg-saa7134.h',
+    'v4l2-dbg-tvp5150.h',
+    'v4l2-dbg.cpp',
+    'v4l2-dbg.h',
+    'v4l2-info.cpp',
+)
+
+v4l2_dbg = executable('v4l2-dbg',
+                      v4l2_dbg_sources,
+                      install : true,
+                      install_dir : 'sbin',
+                      include_directories : [
+                          v4l2_utils_incdir,
+                          utils_common_incdir,
+                      ])
diff --git a/utils/v4l2-sysfs-path/meson.build b/utils/v4l2-sysfs-path/meson.build
new file mode 100644
index 000000000000..5a74af126c82
--- /dev/null
+++ b/utils/v4l2-sysfs-path/meson.build
@@ -0,0 +1,14 @@ 
+v4l2_sysfs_path_sources = files(
+    'v4l2-sysfs-path.c',
+)
+
+v4l2_sysfs_path_deps = [
+    dep_argp,
+    dep_libmedia_dev,
+]
+
+v4l2_sysfs_path = executable('v4l2-sysfs-path',
+                             v4l2_sysfs_path_sources,
+                             install : true,
+                             dependencies : v4l2_sysfs_path_deps,
+                             include_directories : v4l2_utils_incdir)
diff --git a/utils/v4l2-tracer/media-info.cpp b/utils/v4l2-tracer/media-info.cpp
new file mode 120000
index 000000000000..89676ff50494
--- /dev/null
+++ b/utils/v4l2-tracer/media-info.cpp
@@ -0,0 +1 @@ 
+../common/media-info.cpp
\ No newline at end of file
diff --git a/utils/v4l2-tracer/meson.build b/utils/v4l2-tracer/meson.build
new file mode 100644
index 000000000000..ed2c1df88722
--- /dev/null
+++ b/utils/v4l2-tracer/meson.build
@@ -0,0 +1,133 @@ 
+if not dep_jsonc.found()
+    subdir_done()
+endif
+
+# Generated sources
+
+v4l2_tracer_gen = files('v4l2-tracer-gen.pl')
+
+# Don't reorder the inputs The order of the input headers matters
+v4l2_tracer_gen_inputs = files(
+    '..' / '..' / 'include' / 'linux' / 'v4l2-controls.h',
+    '..' / '..' / 'include' / 'linux' / 'videodev2.h',
+    '..' / '..' / 'include' / 'linux' / 'media.h',
+    '..' / '..' / 'include' / 'linux' / 'v4l2-common.h',
+)
+
+v4l2_tracer_gen_common_sources = custom_target('v4l2-tracer-gen-common-sources',
+                                               input : v4l2_tracer_gen_inputs,
+                                               output : ['v4l2-tracer-info-gen.h'],
+                                               command : [
+                                                   v4l2_tracer_gen,
+                                                  '-o', meson.current_build_dir(),
+                                                    '-t', 'common',
+                                                   '@INPUT@',
+                                               ])
+
+v4l2_tracer_gen_retrace_sources = custom_target('v4l2-tracer-gen-retrace-sources',
+                                                input : v4l2_tracer_gen_inputs,
+                                                output : ['retrace-gen.cpp', 'retrace-gen.h'],
+                                                command : [
+                                                    v4l2_tracer_gen,
+                                                    '-o', meson.current_build_dir(),
+                                                    '-t', 'retrace',
+                                                    '@INPUT@',
+                                                ])
+
+v4l2_tracer_gen_trace_sources = custom_target('v4l2-tracer-gen-trace-sources',
+                                              input : v4l2_tracer_gen_inputs,
+                                              output : ['trace-gen.cpp', 'trace-gen.h'],
+                                              command : [
+                                                  v4l2_tracer_gen,
+                                                  '-o', meson.current_build_dir(),
+                                                  '-t', 'trace',
+                                                  '@INPUT@',
+                                              ])
+
+# V4L2 tracer library
+
+libv4l2tracer_sources = files(
+    'libv4l2tracer.cpp',
+    'media-info.cpp',
+    'trace-helper.cpp',
+    'trace.cpp',
+    'v4l2-info.cpp',
+    'v4l2-tracer-common.cpp',
+)
+
+libv4l2tracer_sources += [
+    v4l2_tracer_gen_common_sources,
+    v4l2_tracer_gen_trace_sources,
+]
+
+libv4l2tracer_deps = [
+    dep_jsonc,
+    dep_libdl,
+]
+
+libv4l2_tracer_incdir = [
+    utils_common_incdir,
+    v4l2_utils_incdir,
+]
+
+libv4l2_tracer_cpp_args = [
+    # Meson enables large file support unconditionally, which redirects file
+    # operations to 64-bit versions. This results in some symbols being
+    # renamed, for instance open() being renamed to open64(). As the library
+    # needs to provide both 32-bit and 64-bit versions of file operations,
+    # disable transparent large file support.
+    '-U_FILE_OFFSET_BITS',
+    '-D_FILE_OFFSET_BITS=32',
+    '-D_LARGEFILE64_SOURCE',
+]
+
+libv4l2tracer = shared_module('v4l2tracer',
+                              libv4l2tracer_sources,
+                              install : true,
+                              cpp_args : libv4l2_tracer_cpp_args,
+                              dependencies : libv4l2tracer_deps,
+                              include_directories : libv4l2_tracer_incdir)
+
+# Command line tool
+
+v4l2_tracer_sources = files(
+    'media-info.cpp',
+    'retrace-helper.cpp',
+    'retrace.cpp',
+    'v4l2-info.cpp',
+    'v4l2-tracer-common.cpp',
+    'v4l2-tracer.cpp',
+)
+
+v4l2_tracer_sources += [
+    v4l2_tracer_gen_common_sources,
+    v4l2_tracer_gen_retrace_sources,
+]
+
+v4l2_tracer_deps = [
+    dep_jsonc,
+    dep_librt,
+    dep_threads,
+]
+
+v4l2_tracer_cpp_args = [
+    '-DLIBTRACER_PATH=@0@'.format(get_option('prefix') / get_option('libdir')),
+]
+
+if have_visibility
+    v4l2_tracer_cpp_args += ['-fvisibility=hidden']
+endif
+
+v4l2_tracer_incdir = [
+    utils_common_incdir,
+    v4l2_utils_incdir,
+]
+
+v4l2_tracer = executable('v4l2-tracer',
+                         v4l2_tracer_sources,
+                         install : true,
+                         dependencies : v4l2_tracer_deps,
+                         cpp_args : v4l2_tracer_cpp_args,
+                         include_directories : v4l2_tracer_incdir)
+
+man_pages += [[ meson.current_source_dir(), 'v4l2-tracer', 1 ]]
diff --git a/utils/v4l2-tracer/v4l2-info.cpp b/utils/v4l2-tracer/v4l2-info.cpp
new file mode 120000
index 000000000000..c87caf75bbfd
--- /dev/null
+++ b/utils/v4l2-tracer/v4l2-info.cpp
@@ -0,0 +1 @@ 
+../common/v4l2-info.cpp
\ No newline at end of file
diff --git a/v4l-utils-po/meson.build b/v4l-utils-po/meson.build
new file mode 100644
index 000000000000..4fad42eb0b4a
--- /dev/null
+++ b/v4l-utils-po/meson.build
@@ -0,0 +1,3 @@ 
+i18n.gettext('v4l-utils',
+    args : i18n_gettext_arguments,
+)