Open Menu
How to cross-compile GStreamer for embedded systems

How to cross-compile GStreamer for embedded systems

User Name

Written by

Diego Nieto

August 20, 2024

Cross-compiling GStreamer can be worthwhile when working on embedded systems, especially if you need to compile it multiple times. That was the case of our work with NVIDIA Jetson TX2 for an internal project, and that’s why we decided to share our findings with everyone interested in this process. 

In this guide, we’ll walk you through the process of cross-compiling GStreamer, highlighting key considerations such as choosing the right toolchain and configuring the meson build system.

When should we cross-compile GStreamer?

Cross-compiling can be time-consuming to set up, but it offers significant time savings when compiling large systems like GStreamer. 

Here, we will focus on cross-compiling GStreamer using meson build statements, though other solutions like Yocto can also be used to cross-compile entire systems to generate a full production image. 

Choosing the right toolchain

Selecting the correct toolchain is crucial, since an incorrect toolchain can lead to numerous issues and wasted time. In our case, we used the official NVIDIA Jetson Jetpack image. You can verify the version of Jetpack installed on your system with the following command:

fluendo@jetsonTX2:~/dnieto$ sudo apt-cache show nvidia-jetpack
	Package: nvidia-jetpack
	Version: 4.6.5-b29
	Architecture: arm64
	Maintainer: NVIDIA Corporation
	Installed-Size: 194
	Depends: nvidia-l4t-jetson-multimedia-api (>> 32.7-0), nvidia-l4t-jetson-multimedia-api (<< 32.8-0), nvidia-cuda (= 4.6.5-b29), 	nvidia-tensorrt (= 4.6.5-b29), nvidia-nsight-sys (= 4.6.5-b29), nvidia-cudnn8 (= 4.6.5-b29), nvidia-opencv (= 4.6.5-b29), nvidia-container (	= 4.6.5-b29), nvidia-visionworks (= 4.6.5-b29), nvidia-vpi (= 4.6.5-b29)
	Homepage: http://developer.nvidia.com/jetson
	Priority: standard
	Section: metapackages
	Filename: pool/main/n/nvidia-jetpack/nvidia-jetpack_4.6.5-b29_arm64.deb
	Size: 29382
	SHA256: 3347532325b9e216c38274bbbc076d6f368fdd0423bad4de8860a7c2ac7da7c2
	SHA1: ad441acc5493fbcbae4f3243193bf6e47088da54
	MD5sum: 1d79a14bc5b01c0254b0fc45ec29e5db
	Description: NVIDIA Jetpack Meta Package
	Description-md5: ad1462289bdbc54909ae109d1d32c0a8

Or just showing the release file:

fluendo@jetsonTX2:~/dnieto$ cat /etc/nv_tegra_release
	# R32 (release), REVISION: 7.4, GCID: 33514132, BOARD: t186ref, EABI: aarch64, DATE: Fri Jun  9 04:18:38 UTC 2023

With this data, we are ready to find our toolchain in the corresponding NVIDIA release version, in our case, the right one is this one

In the section “Tools,” you will find a link to the toolchain, in our case, “GCC 7.3.1 for 64-bit BSP and Kernel.” After extracting the package contents, we are ready to set up our build system.

Set up the build system with Meson

Meson build simplifies the process of creating a clean, reusable build system for cross-compiling projects. This is based on the definition of cross-compilation files, which provides the necessary data for the compiler to cross-compile the solution properly.

The following is the cross-compile file which defines the basic elements needed to build the solution. Meson build defines several sections, among them:

  • Constants: Some attributes that will be used later are defined here. This section is always read first.
  • Host_machine: We can often ignore the target machine definition because the host and target are the same. So, if our case is the same, we can define our host architecture by adding a few attributes: system, cpu_family,  CPU, and endianness.
  • Binaries: Specifies the location of the binaries needed to cross-compile for the host machine, such as the compiler itself and the other different compile tools.
[constants]
	toolchain_dir = '@PATH@'
	toolchain_bin = toolchain_dir / 'bin'

	[host_machine]
	system = 'linux'
	cpu_family = 'aarch64'
	cpu = 'arm64'
	endian = 'little'

	[binaries]
	c 	= toolchain_bin / 'aarch64-linux-gnu-gcc'
	cpp   = toolchain_bin / 'aarch64-linux-gnu-g++'
	ar	= toolchain_bin / 'aarch64-linux-gnu-ar'
	strip = toolchain_bin / 'aarch64-linux-gnu-strip'

	rust_ld = toolchain_bin / 'aarch64-linux-gnu-gcc'
	rust = ['rustc', '--target', 'aarch64-unknown-linux-gnu']

Above, we are pointing the binaries path to the correct location of the previously downloaded toolchain.  Here you can check the full meson build guide, where it is also possible to define the sys_root path if your projects require it. Another interesting feature is that meson provides introspection, allowing you to behave depending on whether you are cross-compiling or not. The following functions could help us to enable or disable some subprojects dynamically when doing the setup process.

meson.is_cross_build()        # returns true when cross compiling
	meson.can_run_host_binaries() # returns true if the host binaries can be run, either with a wrapper or natively

We might have some dependencies we have to fulfill to cross-compile, e.g., OpenSSL. For those cases, generating dynamic pkg-config configuration through meson build is possible. This meson feature enables us to make this package visible by either loading a dependency or declaring it. 

pkgconfig = import('pkgconfig')
	openssl_dep = dependency('openssl', version: '1.1.1l')
	openssl_lib = shared_library('openssl', dependencies: openssl_dep)
	pkgconfig.generate(openssl_lib)

Once we have our cross-compile file, e.g., “nvidia_jetsontx2.cross”, we can run a meson setup statement to build our GStreamer solution:

builddir=builddir
	prefix=${PWD}/prefix
	buildtype=debug
	meson setup ${builddir} \
    	  	--prefix ${prefix} \
    	 	--buildtype ${buildtype} \
      	 	--cross-file nvidia_jetsontx2.cross \
       		-Dgst-plugins-bad:va=disabled \
      		-Dugly=disabled \
       		-Dges=disabled \
       		-Drtsp_server=disabled \
       		-Dlibav=disabled \
       		-Ddevtools=disabled

Notice that the only difference is in the argument “–cross-file,” which points to the path to the file we defined earlier.

After this step, we can launch ninja build as usual to build GStreamer:

ninja -C builddir

Build time comparison

Coming back to the reason we are cross-compiling, we must showcase why it’s worth it. A simple comparison measuring the wall time clock when compiling in both systems gives us the answer: We get a speed up of around three times.

Jetson TX2 compilation

[6423/6423] Linking target subprojects/glib-networking-2.74.0/tls/tests/connection-openssl
	real    12m2.542s
	user    39m17.896s
	sys     6m26.024s

Cross-compilation in an Intel i7-1165G7

[6652/6652] Linking target subprojects/glib-networking-2.74.0/tls/tests/connection-openssl
	1213.57user 200.94system 3:40.09elapsed 642%CPU (0avgtext+0avgdata 826476maxresident)k
	500632inputs+4273632outputs (1002major+54532611minor)pagefaults 0swaps

So, based on the same setup, we generate the same plugins around three times faster. If you compile the whole GStreamer solution frequently, this is clearly a reason to do it this way.

Do you want to take your business to the next level? Contact our experts here.