Skip to content

Pipeline examples

Transport, processing and encoding pipelines. For detector / tracker / classifier / optical-flow compositions see Inference graphs.

nvmmconvert/nvmmappsrc work in video/x-raw(memory:NVMM). Cross the NVMM boundary with nvvidconv (VIC) — not videoconvert (CPU) — or feed a hardware consumer (nvv4l2h264enc, nvjpegenc) that takes NVMM directly.

Decode and scale (Jetson)

gst-launch-1.0 \
  filesrc location=video.mp4 ! qtdemux ! h264parse ! nvv4l2decoder \
  ! 'video/x-raw(memory:NVMM)' \
  ! nvmmconvert \
  ! 'video/x-raw(memory:NVMM),width=640,height=480' \
  ! nvmmsink shm-name=/camera_feed

Crop a region of interest

gst-launch-1.0 ... ! nvmmconvert crop-x=100 crop-y=50 crop-w=800 crop-h=600 ! ...

Flip / rotate

gst-launch-1.0 ... ! nvmmconvert flip-method=rotate-180 ! ...      # 180°
gst-launch-1.0 ... ! nvmmconvert flip-method=horizontal-flip ! ... # mirror
gst-launch-1.0 ... ! nvmmconvert flip-method=rotate-90 ! \
  'video/x-raw(memory:NVMM),width=480,height=640' ! ...            # 90° (swaps dims)

Choose a scaling filter

gst-launch-1.0 ... ! nvmmconvert interpolation=5-tap ! \
  'video/x-raw(memory:NVMM),width=640,height=480' ! ...

Encode to H.264 / JPEG

NVIDIA's stock encoders are already NVMM-native, so this suite does not wrap them: nvv4l2h264enc, nvv4l2h265enc, nvjpegenc, and nvjpegdec all advertise video/x-raw(memory:NVMM) and consume an NVMM buffer directly (verified on Xavier NX / JP5 and Orin NX / JP6 — see Validation).

# H.264 encode straight from NVMM (no nvvidconv-to-sysmem in the path)
gst-launch-1.0 -e \
  nvmmappsrc shm-name=/camera_feed ! 'video/x-raw(memory:NVMM),format=NV12' \
  ! nvv4l2h264enc bitrate=8000000 ! h264parse ! qtmux ! filesink location=out.mp4

# JPEG snapshot from NVMM
gst-launch-1.0 -e \
  nvmmappsrc shm-name=/camera_feed ! 'video/x-raw(memory:NVMM),format=NV12' \
  ! nvjpegenc ! filesink location=frame.jpg

Inter-process video sharing

Process A (producer — nvv4l2decoder emits NVMM, which nvmmsink takes directly):

gst-launch-1.0 ... ! nvv4l2decoder ! 'video/x-raw(memory:NVMM)' ! nvmmsink shm-name=/video_feed

Process B (consumer — nvvidconv brings NVMM to system memory for display):

gst-launch-1.0 nvmmappsrc shm-name=/video_feed ! nvvidconv ! videoconvert ! autovideosink

Multi-camera fan-out to multiple consumers

One producer stream is published once and consumed by any number of processes, all staying on the GPU. Each nvmmsink pool is written once per frame; every consumer imports the fds and reads in place, so additional consumers add no extra GPU copy.

Producer (N ZED cameras → N shm segments, one process):

gst-launch-1.0 -e \
  zedsrc camera-sn=<SN1> camera-resolution=4 camera-fps=120 stream-type=7 \
    ! 'video/x-raw(memory:NVMM),format=NV12' ! queue ! nvmmsink shm-name=/cam1 \
  zedsrc camera-sn=<SN2> camera-resolution=4 camera-fps=120 stream-type=7 \
    ! 'video/x-raw(memory:NVMM),format=NV12' ! queue ! nvmmsink shm-name=/cam2 \
  zedsrc camera-sn=<SN3> camera-resolution=4 camera-fps=120 stream-type=7 \
    ! 'video/x-raw(memory:NVMM),format=NV12' ! queue ! nvmmsink shm-name=/cam3

Consumers (each instance attaches to all three segments and records — launch in as many shells as you want; the hardware encoder reads NVMM directly, no copy):

timeout -s INT 120 gst-launch-1.0 -e \
  nvmmappsrc shm-name=/cam1 do-timestamp=true is-live=true \
    ! 'video/x-raw(memory:NVMM),format=NV12' \
    ! nvv4l2h264enc bitrate=20000000 ! h264parse ! qtmux \
    ! filesink location=/tmp/out_cam1.mp4 sync=false async=false \
  nvmmappsrc shm-name=/cam2 do-timestamp=true is-live=true \
    ! 'video/x-raw(memory:NVMM),format=NV12' \
    ! nvv4l2h264enc bitrate=20000000 ! h264parse ! qtmux \
    ! filesink location=/tmp/out_cam2.mp4 sync=false async=false \
  nvmmappsrc shm-name=/cam3 do-timestamp=true is-live=true \
    ! 'video/x-raw(memory:NVMM),format=NV12' \
    ! nvv4l2h264enc bitrate=20000000 ! h264parse ! qtmux \
    ! filesink location=/tmp/out_cam3.mp4 sync=false async=false

The pool's per-slot ref_counts handle the fan-out: each consumer atomically increments its slot's count on read and decrements when done; the producer reuses a slot only once its count is back to 0. Buffers stay GPU-resident end to end.

Multi-input compositing (mosaic / PiP)

Combine several NVMM streams into one frame on the VIC — a 2-up side-by-side, a 2×2 quad, or a picture-in-picture — without DeepStream. Each input is scaled and blitted into its rectangle; the output stays NVMM and zero-copy into encoders, nvmmsink, or the IPC pool. See nvmmcompositor for the pad-placement properties and a Python snippet that sets them.

# 2x2 quad of four cameras into a 1280x720 NVMM frame, encoded to file.
# (Tile sizes/positions are pad properties — set them from code; gst-launch
#  links the pads positionally.)
gst-launch-1.0 -e \
  nvmmcompositor name=c width=1280 height=720 \
  c. ! 'video/x-raw(memory:NVMM)' ! nvv4l2h264enc ! h264parse ! qtmux \
     ! filesink location=/tmp/quad.mp4 \
  nvmmappsrc shm-name=/cam1 ! 'video/x-raw(memory:NVMM),format=NV12' ! c.sink_0 \
  nvmmappsrc shm-name=/cam2 ! 'video/x-raw(memory:NVMM),format=NV12' ! c.sink_1 \
  nvmmappsrc shm-name=/cam3 ! 'video/x-raw(memory:NVMM),format=NV12' ! c.sink_2 \
  nvmmappsrc shm-name=/cam4 ! 'video/x-raw(memory:NVMM),format=NV12' ! c.sink_3

Pair it with the multi-camera producer above to composite live camera feeds into a single monitoring view, all GPU-resident.

ROS2 / non-GStreamer bridge

See Zero-copy IPC for the wire protocol and handshake a non-GStreamer consumer follows (shm_protocol.h + SCM_RIGHTS).