How to use GStreamer on Torizon OS
Introduction
Video processing has become a major feature in the embedded world and has many facets. From decoding a camera's video stream to pre-process frames for an AI application, the use of GStreamer is a must. Even more so if we can take advantage of Hardware Acceleration provided by the System on Module's Video Processing Unit (VPU). This article describes how to use GStreamer on Torizon OS to create simple pipelines. For iMX8 based SoMs, it also shows how to leverage hardware acceleration provided by the VPU in GStreamer pipelines.
For a comprehensive overview of GStreamer, see Video Processing - GStreamer.
The article Video Encoding and Playback (Linux) is not specific for Torizon, but some instructions may be applicable. For example, generic information about Wayland/Weston is provided.
The article How to use Cameras on Torizon aims to help you with instructions about the configuration and usage of cameras in the context of containers, using Gstreamer pipelines and Video4Linux2.
NXP provides GStreamer plugins to access the multimedia libraries using the i.MX SoC's hardware acceleration units. Torizon OS helps to reduce the complexity of the setup with Debian packages providing these HW optimized GStreamer plugins.
This article complies with the Typographic Conventions for Torizon Documentation.
Prerequisites
- A Toradex System on Module with Torizon OS installed.
- A configured build environment, as described in the Configure Build Environment for Torizon Containers article.
For iMX8 based System on Module (SoM), it's recommended to use the Torizon IDE Extension.
Wayland + Weston
This example will run a pipeline that uses waylandsink GStreamer's plugin. This plugin runs on top of Wayland and Weston. It will be necessary to start 2 containers: One with the Weston image, and one with the application image, with Wayland support. Both will communicate through shared folders by bind mounting.
Dockerfile instructions
The implementation details will be explained in this session. See the Quickstart Guide with the instructions about how to compile the image on a host pc and pull the image onto the board. You can also scp
this file to the board and build it locally.
Building the Container Image
Make sure you have configured your Build Environment for Torizon Containers.
- iMX8-based SoMs
- iMX8-based SoMs - VPU accelerated
- Apalis iMX6 / Colibri iMX6ULL/iMX6/iMX7
- AM62-based SoMs
Now it's a good time to use torizon-samples repository or download the sample Dockerfile:
$ cd ~
$ git clone --branch bullseye https://github.com/toradex/torizon-samples.git
$ cd ~/torizon-samples/gstreamer/bash/simple-pipeline
And build the container image:
$ docker build --build-arg BASE_NAME=wayland-base-vivante --build-arg IMAGE_ARCH=linux/arm64/v8 -t <your-dockerhub-username>/gst_example .
Now it's a good time to use torizon-samples repository or download the sample Dockerfile:
$ cd ~
$ git clone --branch bookworm-new https://github.com/toradex/torizon-samples.git
$ cd ~/torizon-samples/vpu/generic/vpuGeneric/
And build the container image:
$ docker build --build-arg BASE_NAME=wayland-base-vivante --build-arg IMAGE_ARCH=arm64/v8 -t <your-dockerhub-username>/gst_example .
Now it's a good time to use torizon-samples repository or download the sample Dockerfile:
$ cd ~
$ git clone --branch bullseye https://github.com/toradex/torizon-samples.git
$ cd ~/torizon-samples/gstreamer/bash/simple-pipeline
And build the container image:
$ docker build -t <your-dockerhub-username>/gst_example .
Now it's a good time to use torizon-samples repository or download the sample Dockerfile:
$ cd ~
$ git clone --branch bookworm https://github.com/toradex/torizon-samples.git
$ cd ~/torizon-samples/gstreamer/bash/simple-pipeline
And build the container image:
$ docker build --build-arg BASE_NAME=wayland-base-am62 --build-arg IMAGE_ARCH=linux/arm64/v8 --build-arg IMAGE_TAG=3 -t <your-dockerhub-username>/gst_example .
After the build, push the image to your Dockerhub account:
$ docker push <your-dockerhub-username>/gst_example
Details about the Dockerfile
In this section, you will go through some important snippets containing information about the Dockerfile.
Toradex Debian image - Wayland
Toradex provides a basic image with Wayland libraries on its Dockerhub page.
Ensure you use a the container image and tag compatible with your Torizon OS version.
Select the correct image for your module from the tabs below:
FROM torizon/wayland-base-vivante:3
FROM torizon/wayland-base:3
FROM torizon/wayland-base-am62:3
Install GStreamer application and plugins
Install the required packages on the image with the following commands:
RUN apt update
RUN apt install -y libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio
This is a more complex case because we need some downstream packages and binaries provided by NXP. To have a smaller sized final image, a multi-stage Dockerfile is used.
NXP provides downstream fork for some Gstreamer packages. These include gstreamer1.0
, gst-plugins-base1.0
, gst-plugins-good1.0
and gst-plugins-bad1.0
. Torizon OS 6 is synced to an NXP BSP that contains v1.20 of these packages. Torizon OS 6 uses the main Debian Bookworm feed which provides v1.22 of these packages.
To be able to use v1.20 NXP Gstreamer packages we use the Toradex unstable feed.
There are other Gstreamer packages that do not have a donwstream NXP fork, such as gstreamer1.0-plugins-ugly
and gstreamer1.0-libav
. By default v1.22 of these packages would be downloaded from Debian Bookworm feed. gstreamer1.0-plugins-ugly
and gstreamer1.0-libav
v1.22 depend on libgstreamer-plugins-base1.0-0
(>= 1.22.0) and libgstreamer1.0-0
(>= 1.22.0) and this will cause a conflict with the v1.20 downstream packages. To avoid this we download the older v1.20 packages by adding an older Debian snapshot feed and version pinning these packages.
To find which Debian snapshot has a particular version of a package we can use buildd.debian.org and metasnap.d.n. For example in case of gstreamer1.0-plugins-ugly
, in the buildd log we see that the latest 1.20 version ever available in Debian was 1.20.5-1
. Next, we use metasnap search to find the Debian snapshot where this version was available, in this case 20230111T033348Z
. Finally we add this snapshot to the list of feeds in /etc/apt/sources.list
and pin the version in /etc/apt/preferences.d/version-pinned-packages
. We can use the same workaround for any other packages that have a versioned dependency on the Gstreamer packages.
To use the VPU for hardware acceleration, we also need to fetch some binaries provided by NXP. They are dependent on the SoM used, so be sure to set the correct MACHINE
argument in the Dockerfile.
RUN apt update
RUN apt install -y libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-pulseaudio
RUN apt update
RUN apt install -y libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio
Test GStreamer
We will set gst-launch-1.0
as entrypoint for our Dockerfile with a default pipeline. A test source pattern will be output to a Wayland window.
ENTRYPOINT ["gst-launch-1.0"]
CMD ["videotestsrc", "!", "videoconvert", "!", "videoscale", "!", "waylandsink", "sync=false"]
You can modify the pipeline for your needs by adding it after the container name in the docker run
command. For example:
docker run -it --rm -v /tmp:/tmp -v /dev:/dev <your-username>/gst_example videotestsrc ! videoconvert ! videoscale ! waylandsink sync=false
Docker-compose
After building the Dockerfile image above and pushing it to your Dockerhub, you can launch Weston and Wayland with docker-compose.
Select your architecture from the tabs:
- iMX8-based SoMs
- iMX8-based SoMs - VPU accelerated
- Apalis iMX6 / Colibri iMX6
- Colibri iMX7
- AM62-based SoMs
The docker-compose file for arm64v8 is available on GitHub.
Still on the torizon-samples/gstreamer/bash/simple-pipeline
directory, edit the docker-compose.arm64.yaml
file by filling the wayland's service image field with your dockerhub username:
wayland:
depends_on:
weston:
condition: service_healthy
image: <your-username>/gst_example
volumes:
- /tmp:/tmp
- /sys:/sys
- /dev:/dev
restart: on-failure
After filling it, send it to your module using scp
:
$ scp docker-compose.arm64.yaml torizon@<SoM-ip>:/home/torizon
Now enter your module using SSH:
$ ssh torizon@<SoM-ip>
Now you can launch by using the command:
# docker-compose -f docker-compose.arm64.yaml up
The docker-compose file for arm64v8 is available on GitHub.
Still on the torizon-samples/vpu/generic/vpuGeneric/
directory, edit the docker-compose.yml
file by filling the vpugeneric
service fields correctly. Set the image field to match your dockerhub namespace and set the correct MACHINE
in the environment field:
vpugeneric:
build:
context: .
dockerfile: Dockerfile
image: ${DOCKER_LOGIN}/gst_example
environment:
#- MACHINE=verdin-imx8mm
- MACHINE=verdin-imx8mp
#- MACHINE=apalis-imx8
Also set weston's service image field to torizon/weston-vivante:3
.
After filling everything, send it to your module using scp
:
$ scp docker-compose.yml torizon@<SoM-ip>:/home/torizon
Now enter your module using SSH:
$ ssh torizon@<SoM-ip>
Now you can launch by using the command:
# docker-compose -f docker-compose.yml up
The docker-compose file for arm32v7 is available on GitHub.
Still on the torizon-samples/gstreamer/bash/simple-pipeline
directory, edit the docker-compose.armhf.yaml
file by filling the wayland's service image field with your dockerhub username:
wayland:
depends_on:
weston:
condition: service_healthy
image: <your-username>/gst_example
volumes:
- /tmp:/tmp
- /sys:/sys
- /dev:/dev
restart: on-failure
After filling it, send it to your module using scp
:
$ scp docker-compose.armhf.yaml torizon@<SoM-ip>:/home/torizon
Now enter your module using SSH:
$ ssh torizon@<SoM-ip>
Now you can launch by using the command:
# docker-compose -f docker-compose.armhf.yaml up
The docker-compose file for the Colibri iMX7 is available on GitHub.
Still on the torizon-samples/gstreamer/bash/simple-pipeline
directory, edit the docker-compose.colibri-imx7.yaml
file by filling the wayland's service image field with your dockerhub username:
wayland:
depends_on:
weston:
condition: service_healthy
image: <your-username>/gst_example
volumes:
- /tmp:/tmp
- /sys:/sys
- /dev:/dev
restart: on-failure
After filling it, send it to your module using scp
:
$ scp docker-compose.colibri-imx7.yaml torizon@<SoM-ip>:/home/torizon
Now enter your module using SSH:
$ ssh torizon@<SoM-ip>
Now you can launch by using the command:
# docker-compose -f docker-compose.colibri-imx7.yaml up
The docker-compose file for AM62 is available on GitHub.
Still on the torizon-samples/gstreamer/bash/simple-pipeline
directory, edit the docker-compose.am62.yaml
file by filling the wayland's service image field with your dockerhub username:
wayland:
depends_on:
weston:
condition: service_healthy
image: <your-username>/gst_example
volumes:
- /tmp:/tmp
- /sys:/sys
- /dev:/dev
restart: on-failure
After filling it, send it to your module using scp
:
$ scp docker-compose.am62.yaml torizon@<SoM-ip>:/home/torizon
Now enter your module using SSH:
$ ssh torizon@<SoM-ip>
Now you can launch by using the command:
# docker-compose -f docker-compose.am62.yaml up