Skip to content

Instantly share code, notes, and snippets.

@LrWm3
Last active January 4, 2024 22:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LrWm3/d8c6fc1b3ba6c3a2e8b6606facf3bb5c to your computer and use it in GitHub Desktop.
Save LrWm3/d8c6fc1b3ba6c3a2e8b6606facf3bb5c to your computer and use it in GitHub Desktop.
DeepStream SDK 6.2 x86 and Jetson docker image pyds and gst-python configured

gst-python-docker

This Gist provides a Dockerfile that extends the NVIDIA DeepStream base image to include gst-python and pyds. The Dockerfile installs the Python bindings for gst-python and pyds.

This enables the creation of custom DeepStream GStreamer plugins using Python, which the default DeepStream docker images do not allow.

Features

  • Configures GST_PLUGIN_PATH and copies Python plugins into the GST_PLUGIN_PATH/python directory.
  • Supports software decode & encode by reinstalling specific packages.
  • Detailed setup steps in the Dockerfile for gst-python, pyds, and other dependencies.
  • Sample Python plugins demonstrating how to create GStreamer elements in Python.

Directory Structure

├── Dockerfile
├── requirements.txt
├── Makefile
├── .dockerignore
└── python/
├──── sinkup.py

Usage

  1. Create Python plugins following the pattern shown in the GStreamer gst-python examples.
  2. Place your Python plugins in the 'plugins' directory.
  3. Build the Docker image.
  4. Run the Docker image in interactive mode.
  5. Using gst-inspect-1.0 python, you can see the Python plugin plus your custom plugins.
  6. Execute your Python plugins as part of a gst-launch-1.0 pipeline.

Troubleshooting

If the Docker image fails to build during the gst-inspect-1.0 python step, it's likely one of the added Python plugins is missing a dependency. Consider adding a requirements.txt file and execute RUN pip install -r requirements.txt.

Potential Improvements

  • Clean up the build process and combine RUN steps.
  • Implement a multi-stage build to reduce the size of the final image.
  • Use a multi-stage branching build approach to cater to differences between aarch64 and x86 images.
##
# gst-python-docker/Dockerfile
##
# This docker image extends the NVIDIA DeepStream base image to include
# gst-python and pyds. It also installs the python bindings for gst-python
# and pyds.
#
# DeepStream docker images do not configure gst-python to allow
# for creating custom gstreamer plugins in python.
#
# This image fixes that by configuring GST_PLUGIN_PATH and creating
# and copying python plugins into the GST_PLUGIN_PATH/python directory.
#
# Additionally, in order to support software decode & encode, it reinstalls
# the following packages.
# - libavformat58
# - libavcodec58
# - libavresample4
# - libavutil56
# - libvpx6
# - libx264-155
# - libx265-179
# - libmpg123-0
# - gstreamer1.0-libav
# - gstreamer1.0-plugins-ugly
##
# Usage:
# - create python plugins similarly to https://github.com/GStreamer/gst-python/tree/master/examples
# - place your python plugins in the 'plugins' directory
# - build the docker image
# - run the docker image in interactive mode
# - 'gst-inspect-1.0 python' will show the python plugin plus your custom plugins
# - run your python plugins as part of a gst-launch-1.0 pipeline.
##
# Troubleshooting:
# - if the docker image fails to build during the gst-inspect-1.0 python step,
# it is likely one of the added python plugins is missing a dependency.
# it may be necessary to add a 'requirements.txt' file & 'RUN pip install -r requirements.txt'
##
# Potential improvements:
# - Clean up the build process & combine RUN steps
# - Use a multi-stage build to reduce the size of the final image
# - Use a multi-stage branching build approach to allow for
# differences between aarch64 and x86 images
##
# ARG NVIDIA_BASE_IMAGE=nvcr.io/nvidia/deepstream-l4t:6.2
# ARG NVIDIA_BASE_IMAGE=nvcr.io/nvidia/deepstream-l4t:6.2-samples
ARG NVIDIA_BASE_IMAGE=nvcr.io/nvidia/deepstream:6.2-devel
FROM "${NVIDIA_BASE_IMAGE}"
# To get video driver libraries at runtime (libnvidia-encode.so/libnvcuvid.so)
ENV NVIDIA_DRIVER_CAPABILITIES $NVIDIA_DRIVER_CAPABILITIES,video
# Can set GST_DEBUG log levels here if needed
# ENV GST_DEBUG=2
# ENV GST_DEBUG_FILE=/app/output/GST_DEBUG.log
#
# Install gst-python and pyds
#
# Install dependencies for building gst-python and pyds
RUN apt update && apt install -y \
python3-gi python3-dev python3-gst-1.0 python3-numpy python3-opencv \
python-gi-dev git python-dev python3 python3-pip python3.8-dev cmake g++ build-essential \
libglib2.0-dev libglib2.0-dev-bin libgstreamer1.0-dev libtool m4 autoconf automake \
libgirepository1.0-dev libcairo2-dev
# We need 'python-is-python3' to make sure we compile gst-python with python3 as a dependency and
# and not python2.7.
RUN apt install -y python-is-python3
# from: https://raw.githubusercontent.com/ml6team/deepstream-python/master/deepstream/Dockerfile
# author: (Jules Talloen) https://github.com/Joxis
RUN cd /opt/nvidia/deepstream/deepstream/sources/ \
&& git clone https://github.com/NVIDIA-AI-IOT/deepstream_python_apps.git \
&& cd deepstream_python_apps \
&& git submodule update --init \
&& apt-get install -y apt-transport-https ca-certificates -y \
&& update-ca-certificates \
&& cd 3rdparty/gst-python/ \
&& ./autogen.sh \
&& make \
&& make install \
&& cd ../../bindings \
&& mkdir build \
&& cd build \
&& cmake .. \
&& make \
&& pip3 install ./pyds-*.whl
# Set GST_PLUGIN_PATH for gst-python
ENV GST_PLUGIN_PATH=/usr/local/lib/gstreamer-1.0
# Link python3.8 to a place we can find it for gst-python
RUN ln -s /usr/lib/x86_64-linux-gnu/libpython3.8.so /usr/lib/libpython3.8.so
# gst-python plugins must be installed in '$GST_PLUGIN_PATH/python'
RUN mkdir -p /usr/local/lib/gstreamer-1.0/python
# We will copy the python plugins as the final step to allow for caching & quick rebuilds
#
# Done configuring gst-python & pyds
#
#
# RTSP
#
RUN apt-get install -y libgstrtspserver-1.0-0 gstreamer1.0-rtsp libgirepository1.0-dev gobject-introspection gir1.2-gst-rtsp-server-1.0
#
# fix software decoder, reinstall avlib deps explicitly
#
RUN apt update && \
apt install --reinstall -y \
libavformat58 \
libavcodec58 \
libavresample4 \
libavutil56 \
libvpx6 \
libx264-155 \
libx265-179 \
libmpg123-0
#
# fix software encoder, adding x264enc
#
RUN apt-get update && apt-get install -y --reinstall \
gstreamer1.0-libav \
gstreamer1.0-plugins-ugly
# Check if the python plugin is installed before we add additional python plugin elements which may break it
RUN gst-inspect-1.0 python && echo "DOCKER-BUILD: gst-python with no plugins installed sucessfully" || echo "DOCKER-BUILD: gst-python failed to install"
#
# Install additional python dependencies
#
COPY requirements.txt /tmp/requirements.txt
RUN pip3 install -r /tmp/requirements.txt && rm /tmp/requirements.txt
#
# Copy gst-python plugins to '$GST_PLUGIN_PATH/python'
#
COPY python /usr/local/lib/gstreamer-1.0/python
#
# Create the gstreamer cache & confirm that the python plugin elements
# ---
# Note that this can fail if any of the added python plugin elements cannot be loaded
# the most common reason being the system python is missing dependencies required by these python plugin elements
# ---
# This check compares the number of python plugins found by gst-inspect-1.0 to the number of python plugin elements we've loaded into the image
# we filter by '.py' to avoid counting '__pythoncache__' and other non-plugin element files.
RUN if [ "$(gst-inspect-1.0 | grep python | wc -l)" -eq "$(ls /usr/local/lib/gstreamer-1.0/python | grep '\.py' | wc -w)" ]; then echo "DOCKER-BUILD: gst-python + python plugins installed successfully"; else echo "DOCKER-BUILD: gst-python + python plugins failed to install; are there missing pip dependencies?"; exit 1; fi
MIT License
Copyright (c) 2023 William Marsman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# add dependencies for gst-python 'python/*.py' files here
# note that pyds is built in the docker image
#!/usr/bin/env python
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4
##
# sinkup.py
##
# Place in 'python/sinkup.py' to use
##
# $ export GST_PLUGIN_PATH="$GST_PLUGIN_PATH:$PWD"
# $ GST_DEBUG=python:4 gst-launch-1.0 fakesrc num-buffers=10 ! sinkup
##
import gi
gi.require_version('GstBase', '1.0')
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GObject, GstBase
Gst.init(None)
# import pyds to show this library may be used in the docker image as well
import pyds
#
# Simple Sink element created entirely in python
#
class MyCustomDsSink(GstBase.BaseSink):
__gstmetadata__ = ('CustomSink','Sink', \
'Test sink element', 'William Marsman')
__gsttemplates__ = Gst.PadTemplate.new("sink",
Gst.PadDirection.SINK,
Gst.PadPresence.ALWAYS,
Gst.Caps.new_any())
def do_render(self, buffer):
Gst.info("timestamp(buffer):%s" % (Gst.TIME_ARGS(buffer.pts)))
return Gst.FlowReturn.OK
GObject.type_register(MyCustomDsSink)
__gstelementfactory__ = ("sinkup", Gst.Rank.NONE, MyCustomDsSink)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment