Pipeline examples¶
Transport, processing and encoding pipelines. For detector / tracker / classifier / optical-flow compositions see Inference graphs.
nvmmconvert/nvmmappsrcwork invideo/x-raw(memory:NVMM). Cross the NVMM boundary withnvvidconv(VIC) — notvideoconvert(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¶
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):
Process B (consumer — nvvidconv brings NVMM to system memory for display):
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).