GStreamer pipeline examples for Jetson: nvarguscamerasrc, nvvidconv, encode, and decode
GStreamer on Jetson uses NVIDIA-specific elements for hardware-accelerated camera capture, format conversion, and encode/decode. These elements — nvarguscamerasrc, nvvidconv, nvv4l2h264enc, nvv4l2decoder — have different properties and caps requirements than their generic Linux equivalents. This post is a practical reference for the GStreamer pipelines that actually work on Jetson Orin, with copy-paste commands for the most common use cases.
Key Insights
- NVMM caps (
video/x-raw(memory:NVMM)) keep frames in GPU memory between NVIDIA elements — always use them between nvarguscamerasrc, nvvidconv, and nvv4l2h264enc - nvarguscamerasrc is for ISP-processed camera capture; v4l2src is for raw sensor frames
- kmssink works without X or Wayland — use it for headless display output on embedded setups
- nvv4l2h264enc and nvv4l2decoder use Jetson’s hardware encode/decode engines;
avenc_h264andavdec_h264are software fallbacks - gst-inspect-1.0 and GST_DEBUG are your primary debugging tools — inspect before troubleshooting
Prerequisites
Install NVIDIA’s GStreamer plugins:
sudo apt install nvidia-l4t-gstreamer gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-tools
Verify NVIDIA elements are available:
gst-inspect-1.0 nvarguscamerasrc
gst-inspect-1.0 nvvidconv
gst-inspect-1.0 nvv4l2h264enc
gst-inspect-1.0 nvv4l2decoder
If any of these fail, the nvidia-l4t-gstreamer package wasn’t installed or its plugins didn’t load. Check gst-inspect-1.0 --gst-plugin-path /usr/lib/aarch64-linux-gnu/gstreamer-1.0/.
Camera capture pipelines
nvarguscamerasrc (ISP path — recommended for production)
Basic display test:
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvvidconv ! 'video/x-raw,format=BGRx' ! \
videoconvert ! autovideosink
Headless — capture to file:
gst-launch-1.0 nvarguscamerasrc sensor-id=0 num-buffers=300 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvv4l2h264enc ! h264parse ! qtmux ! \
filesink location=/tmp/capture.mp4
Get ISP-processed frames as NV12 for OpenCV or inference:
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1280,height=720,framerate=30/1' ! \
nvvidconv ! 'video/x-raw,format=NV12' ! \
appsink name=sink max-buffers=1 drop=true
Check available sensor IDs:
gst-launch-1.0 nvarguscamerasrc ! fakesink -v 2>&1 | grep "Available Sensor"
v4l2src (raw V4L2 path)
Basic display (format depends on sensor):
gst-launch-1.0 v4l2src device=/dev/video0 ! \
'video/x-raw,format=YUY2,width=1920,height=1080,framerate=30/1' ! \
videoconvert ! autovideosink
Display via KMS/DRM without X server:
gst-launch-1.0 v4l2src device=/dev/video0 ! \
'video/x-raw,format=YUY2,width=1920,height=1080,framerate=30/1' ! \
videoconvert ! kmssink
Check what formats your camera supports:
v4l2-ctl --list-formats-ext -d /dev/video0
Raw capture to file (useful for debugging sensor output):
gst-launch-1.0 v4l2src device=/dev/video0 num-buffers=30 ! \
'video/x-raw,format=RG10,width=1920,height=1080' ! \
filesink location=/tmp/raw_frames.bin
Hardware encode
H.264 encode
Camera → H.264 file:
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvv4l2h264enc bitrate=8000000 ! h264parse ! \
qtmux ! filesink location=output.mp4
Camera → H.264 UDP stream (for remote viewing):
# Sender (Jetson)
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvv4l2h264enc ! h264parse ! \
rtph264pay ! udpsink host=192.168.1.100 port=5000
# Receiver (laptop)
gst-launch-1.0 udpsrc port=5000 ! \
'application/x-rtp,encoding-name=H264,payload=96' ! \
rtph264depay ! avdec_h264 ! autovideosink
H.265 encode
H.265 typically achieves the same quality at half the bitrate:
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvv4l2h265enc bitrate=4000000 ! h265parse ! \
qtmux ! filesink location=output.mp4
nvv4l2h264enc key properties:
bitrate— target bitrate in bps (default: 4000000)maxperf-enable— set to true for maximum throughput at higher powerpreset-level— 1 (ultra-fast) to 4 (best quality), default 3
Hardware decode
MP4 file → display:
gst-launch-1.0 filesrc location=video.mp4 ! \
qtdemux ! h264parse ! nvv4l2decoder ! \
nvvidconv ! 'video/x-raw,format=BGRx' ! \
videoconvert ! autovideosink
H.265 decode:
gst-launch-1.0 filesrc location=video.mp4 ! \
qtdemux ! h265parse ! nvv4l2decoder ! \
nvvidconv ! autovideosink
Note: nvv4l2decoder outputs NVMM-format frames. Connect directly to nvvidconv (not videoconvert) to stay in the hardware path.
nvvidconv — format conversion and scaling
nvvidconv is Jetson’s hardware video converter. Use it between NVIDIA elements for format conversion and scaling without CPU involvement.
Convert YUY2 → BGRx:
gst-launch-1.0 v4l2src device=/dev/video0 ! \
'video/x-raw,format=YUY2,width=1920,height=1080' ! \
nvvidconv ! 'video/x-raw,format=BGRx,width=1920,height=1080' ! \
videoconvert ! autovideosink
Scale and convert in one step:
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvvidconv ! 'video/x-raw(memory:NVMM),width=640,height=360' ! \
nvv4l2h264enc ! h264parse ! qtmux ! filesink location=scaled.mp4
Important: When connecting two NVIDIA elements, add (memory:NVMM) to the caps between them:
# Correct — stays in GPU memory
! nvvidconv ! 'video/x-raw(memory:NVMM),format=NV12' ! nvv4l2h264enc
# Wrong — forces CPU copy
! nvvidconv ! 'video/x-raw,format=NV12' ! nvv4l2h264enc
Multi-camera pipelines
View two cameras side by side:
gst-launch-1.0 \
nvarguscamerasrc sensor-id=0 name=cam0 ! \
'video/x-raw(memory:NVMM),width=1280,height=720,framerate=30/1' ! \
nvvidconv ! 'video/x-raw,format=BGRx,width=640,height=360' ! videoconvert ! \
compositor name=mix sink_0::xpos=0 sink_0::ypos=0 sink_1::xpos=640 sink_1::ypos=0 ! \
autovideosink \
nvarguscamerasrc sensor-id=1 ! \
'video/x-raw(memory:NVMM),width=1280,height=720,framerate=30/1' ! \
nvvidconv ! 'video/x-raw,format=BGRx,width=640,height=360' ! videoconvert ! \
mix.
Record both cameras independently:
gst-launch-1.0 \
nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvv4l2h264enc ! h264parse ! qtmux ! filesink location=cam0.mp4 \
nvarguscamerasrc sensor-id=1 ! \
'video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1' ! \
nvv4l2h264enc ! h264parse ! qtmux ! filesink location=cam1.mp4
Debugging pipelines
Inspect element properties:
gst-inspect-1.0 nvarguscamerasrc
gst-inspect-1.0 nvv4l2h264enc
Verbose caps negotiation:
gst-launch-1.0 -v nvarguscamerasrc ! fakesink 2>&1 | head -50
Enable debug logging:
# Log all elements at level 3
GST_DEBUG=3 gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! fakesink
# Log specific elements
GST_DEBUG=nvarguscamerasrc:5,nvvidconv:4 gst-launch-1.0 ...
Check pipeline state manually:
# Add -v to see state changes
gst-launch-1.0 -v nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM)' ! nvvidconv ! autovideosink
Common pipeline errors:
| Error | Cause | Fix |
|---|---|---|
| ”No such element: nvarguscamerasrc” | nvidia-l4t-gstreamer not installed | sudo apt install nvidia-l4t-gstreamer |
| ”Internal data flow error” | Buffer backpressure | Add ! queue after the source |
| ”nvarguscamerasrc: No cameras available” | nvargus-daemon not running | sudo systemctl start nvargus-daemon |
| Pipeline hangs at PLAYING | NVMM path broken | Check caps have (memory:NVMM) between NVIDIA elements |
| ”Cannot identify /dev/video0” | Camera not probed | Check v4l2-ctl --list-devices |
For camera driver bring-up that these pipelines depend on, see CSI camera driver on Jetson: V4L2, Argus, and IMX sensor bring-up. For Argus-specific setup including nvargus-daemon, see NVIDIA Argus API camera driver on Jetson. For pipeline performance issues — nvvidconv throughput collapse under multiple processes — see nvvidconv performance with multiple GStreamer processes on Jetson.
FAQ
Why does nvarguscamerasrc say “No such element or plugin”?
The nvidia-l4t-gstreamer package isn’t installed. Install it with: sudo apt install nvidia-l4t-gstreamer. Also verify gst-inspect-1.0 nvarguscamerasrc returns the element description. If it still fails after install, nvargus-daemon isn’t running — start it with sudo systemctl start nvargus-daemon.
What is the difference between v4l2src and nvarguscamerasrc on Jetson?
v4l2src reads raw frames directly from the V4L2 kernel driver — no ISP processing. nvarguscamerasrc routes through the nvargus-daemon and Jetson ISP, providing auto-exposure, auto-white-balance, and hardware noise reduction. Use nvarguscamerasrc for production pipelines that need ISP output; use v4l2src when you need raw Bayer frames or have a sensor that isn’t Argus-compatible.
What does “video/x-raw(memory:NVMM)” mean in a Jetson GStreamer pipeline?
NVMM keeps frame buffers in GPU memory, avoiding a CPU copy between NVIDIA hardware elements. When connecting nvarguscamerasrc to nvvidconv, or nvvidconv to nvv4l2h264enc, always use NVMM caps to maintain the hardware-accelerated path. Without NVMM, frames are copied through system RAM, adding latency and CPU load.
Why does my GStreamer pipeline stall or produce “Internal data flow error”?
Usually buffer backpressure — a downstream element isn’t consuming frames as fast as they arrive. Add ! queue between the source and a slow downstream element. If the pipeline stops after a few seconds, check for missing NVMM caps — this often causes stalls in the format conversion stage.
How do I display a Jetson camera feed without X or Wayland (headless)?
Use kmssink for DRM/KMS direct rendering without a display server: gst-launch-1.0 v4l2src device=/dev/video0 ! videoconvert ! kmssink. Or pipe to a file or network stream instead of a display sink.
NVIDIA Jetson Expert Support
Stuck on a Jetson bring-up?
We've debugged this failure mode before. BSP, device tree, camera pipelines, OTA — most blockers clear in the first session. No long retainers. No guessing.
Frequently Asked Questions
Why does nvarguscamerasrc say 'No such element or plugin'?
The nvidia-l4t-gstreamer package isn't installed. Install it with: sudo apt install nvidia-l4t-gstreamer. Also verify gst-inspect-1.0 nvarguscamerasrc returns the element description. If it still fails, the nvargus-daemon isn't running — start it with sudo systemctl start nvargus-daemon.
What is the difference between v4l2src and nvarguscamerasrc on Jetson?
v4l2src reads raw frames directly from the V4L2 kernel driver — no ISP processing. nvarguscamerasrc routes through the nvargus-daemon and Jetson ISP, providing auto-exposure, auto-white-balance, and hardware noise reduction. Use nvarguscamerasrc for production camera pipelines that need ISP output; use v4l2src when you need raw Bayer frames or have a sensor that isn't Argus-compatible.
What does 'video/x-raw(memory:NVMM)' mean in a Jetson GStreamer pipeline?
NVMM (NVIDIA Memory Management) keeps frame buffers in GPU memory, avoiding a CPU copy between NVIDIA hardware elements. When connecting nvarguscamerasrc to nvvidconv, or nvvidconv to nvv4l2h264enc, always use NVMM caps to maintain the hardware-accelerated path. Without NVMM, frames are copied through system RAM, adding latency and CPU load.
Why does my GStreamer pipeline stall or produce Internal data flow error?
Usually a buffer backpressure problem — a downstream element isn't consuming frames as fast as they arrive. Add '! queue' between the source and a slow downstream element. If the pipeline stops after a few seconds, check for nvvidconv NVMM caps — missing NVMM often causes stalls in the format conversion stage.
How do I display a Jetson camera feed without X or Wayland (headless)?
Use kmssink for DRM/KMS direct rendering without a display server: gst-launch-1.0 v4l2src device=/dev/video0 ! videoconvert ! kmssink. Or pipe to a file or network stream instead of a display sink. nvarguscamerasrc also works headless — route to filesink or udpsink instead of autovideosink.
Written by
Andrés CamposCo-Founder & CTO · ProventusNova
8 years deep in embedded systems — from underwater ROVs to edge AI. Andrés leads every technical delivery personally.
Connect on LinkedIn