nvsiplsrc: Hands-On Guide for the GStreamer SIPL Camera Source#

nvsiplsrc is a multi-pad GStreamer source element that captures ISP-processed frames from Sensor Input Processing Library (SIPL) cameras and delivers them as NVMM (video/x-raw(memory:NVMM), NV12) buffers to a standard GStreamer pipeline. It supports both Gigabit Multimedia Serial Link (GMSL) and Camera-over-Ethernet (CoE), as a camera system through a single unified code path.

The element creates one source pad per discovered sensor (src_0, src_1, and so on), so a multi-sensor module (for example, a HAWK module with two AR0234 sensors) fans out to multiple independently timestamped and independently pushed pads that can be branched to preview, encode, or file sinks.

Motivation#

SIPL delivers ISP output in NvSci buffers (NvSciBufObj), whereas the rest of the NVIDIA multimedia stack—nvvidconv, nvv4l2h264enc, nv3dsink, and other NVMM elements—operates on NvBufSurface (NvRM) memory. The central job of nvsiplsrc is therefore the NvSci-to-NvBufSurface interop: exposing SIPL camera output as standard NVMM buffers so that it can be consumed directly by the GStreamer multimedia pipeline. Understanding this interop (refer to Buffer and Interop API (NvSci ↔ NvBufSurface)) is key to integrating the source with downstream components.

Goals#

This guide is intended to make you productive quickly. It covers the following topics:

  • Installing and verifying the plug-in.

  • Understanding the runtime architecture and the NvSci-to-NvBufSurface buffer/interop model.

  • Running ready-to-use pipelines for common use cases (preview, YUV capture, and video encode).

Prerequisites and Build#

At a high level, the setup is four steps:

  1. Install GStreamer-1.0 and its development packages.

  2. Install the accelerated (NVIDIA L4T) GStreamer plug-ins.

  3. Build and install the nvsiplsrc plug-in.

  4. Verify the plug-in is registered.

Each step is detailed in the following sections.

Install GStreamer-1.0#

Install the base GStreamer tooling and development headers on the target (refer to Accelerated GStreamer):

sudo apt-get update
sudo apt-get install gstreamer1.0-tools gstreamer1.0-alsa \
    gstreamer1.0-plugins-base gstreamer1.0-plugins-good \
    gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly \
    gstreamer1.0-libav
sudo apt-get install libgstreamer1.0-dev \
    libgstreamer-plugins-base1.0-dev \
    libgstreamer-plugins-good1.0-dev \
    libgstreamer-plugins-bad1.0-dev

Install the Accelerated GStreamer Plug-ins#

sudo apt-get update
sudo apt-get install nvidia-l4t-gstreamer
sudo ldconfig
rm -rf ~/.cache/gstreamer-1.0/

Build and Install nvsiplsrc#

cd gst-nvsiplcamera
make
sudo make install       # installs libgstnvsiplsrc.so to the GStreamer plug-in dir
# or: DEST_DIR=<dir> make install

The plug-in installs to /usr/lib/aarch64-linux-gnu/gstreamer-1.0.

Verify Plug-in Registration#

gst-inspect-1.0 nvsiplsrc

Note

If gst-inspect-1.0 cannot find the plug-in, clear the registry cache (rm -rf ~/.cache/gstreamer-1.0) and retry.

Element Properties#

Property

Type

Default

Description

config-name

string

""

Required. Platform config name passed to GetSensorSystemConfig (such as AR0234CS_HAWK_NON_STEREO, R0SIM728S3RU2120NB2, or VB1940). If empty, the first available config is auto-detected.

link-mask

string

""

Required for GMSL. Hex link-enable mask selecting active deserializer links (such as 1000, 0100, or 010). Space- or comma-separated for multiple transports. Setting This property also enables bypass of sensor authentication.

json-file

string

""

Optional path to a CoE/GMSL JSON config. Not needed when the config is in the SIPL database.

bl-output

Boolean

TRUE

TRUE = block-linear NVMM output; FALSE = pitch-linear.

num-surfaces

uint (4–32)

16

Number of NVMM buffers allocated in the per-pad output pool.

num-buffers

int

-1

Frames to push per pad before sending EOS (-1 = unlimited).

Discover the sensors and pads dynamically:

GST_DEBUG=nvsiplsrc:4 gst-launch-1.0 nvsiplsrc config-name=<CFG> link-mask=<MASK> ! fakesink
# Look for "Creating pad src_<i> for sensor ... : WxH @ fps"

Architecture and Call Flow#

High-Level Design#

  • Multi-pad GstElement (not GstBaseSrc). Lifecycle is driven by GstElement::change_state.

  • SIPL is a singleton: A single Init() / Start() / Stop() covers all sensors.

  • Per-sensor isolation: Each pad owns its own NVMM buffer pool, a producer–consumer buffer queue, and a dedicated push thread. There is no cross-sensor mutable state.

  • Copy-and-release: Each ISP0 frame is VIC-transformed from the SIPL surface into a GStreamer-owned NVMM buffer. The SIPL buffer is released immediately afterward.

The following diagram shows how the single SIPL instance fans out per-sensor ISP0 frames into fully independent per-pad pipelines inside the element:

flowchart LR subgraph SIPL["SIPL — singleton (1× Init / Start / Stop)"] S0["Sensor 0 pipeline<br/>ISP0 + ICP + Event threads"] S1["Sensor 1 pipeline<br/>ISP0 + ICP + Event threads"] end subgraph ELEM["nvsiplsrc GstElement"] direction LR subgraph PAD0["Pad src_0"] CB0["frame callback 0"] P0["NVMM pool 0"] Q0["buffer queue 0"] T0["push thread 0"] end subgraph PAD1["Pad src_1"] CB1["frame callback 1"] P1["NVMM pool 1"] Q1["buffer queue 1"] T1["push thread 1"] end end S0 -->|ISP0 frame| CB0 S1 -->|ISP0 frame| CB1 P0 -.acquire NVMM buf.-> CB0 P1 -.acquire NVMM buf.-> CB1 CB0 -->|VIC copy + push| Q0 --> T0 -->|gst_pad_push| D0["downstream 0<br/>(sink / encoder)"] CB1 -->|VIC copy + push| Q1 --> T1 -->|gst_pad_push| D1["downstream 1<br/>(sink / encoder)"]

Per-Frame Data Flow (Steady State)#

sequenceDiagram participant HW as Sensor + ISP participant ISP0 as SIPL ISP0 thread (per sensor) participant CB as nvsipl_sensor_frame_callback participant VIC as VIC (NvBufSurfTransform) participant Q as Pad buffer queue participant PT as Pad push thread participant DS as Downstream HW->>ISP0: isp0CompletionQueue->Get(pBuffer) ISP0->>ISP0: Wait EOF NvSciSync fence ISP0->>ISP0: Match NvSciBufObj → interop buffer ISP0->>CB: readyFrameCallback(NvSiplFrame) CB->>CB: pool acquire NVMM buffer CB->>VIC: NvBufSurfTransform(SIPL surf → NVMM surf) VIC-->>CB: NV12 NVMM copy CB->>Q: queue_push(NvSiplMMBufferInfo) ISP0->>ISP0: ReleaseFrame() (SIPL buffer returned) PT->>Q: queue_pop (2s timeout) PT->>PT: set PTS / duration / auxdata PT->>DS: gst_pad_push(buf)

Buffer and Interop API (NvSci ↔ NvBufSurface)#

This is the most important part to understand for anyone extending the element. There are two distinct buffer domains, a zero-copy interop bridge between the domains, and one explicit copy per frame.

The Two Buffer Domains#

Domain

Producer

Type

Purpose

SIPL / NvSci

SIPL ISP0

NvSciBufObj

ISP writes processed frames here.

GStreamer / NvRM

nvsiplsrc pool

NvBufSurface (dmabuf fd)

The NVMM buffers pushed downstream.

The SIPL ISP0 output is allocated as an NvSciBufObj. The downstream GStreamer elements (nvvidconv, nvv4l2h264enc, nv3dsink, …) understand only NvBufSurface-backed NVMM memory. The bridge between them is the NvSci-to-NvRM interop.

Interop Bridge: NvmmNvSciBufToNvBufSurface#

The core interop call is as follows:

int NvmmNvSciBufToNvBufSurface(NvSciBufObj bufObj, NvBufSurface **nvbuf_surf);

It wraps an existing NvSciBufObj in an NvBufSurface view that shares the same underlying memory—no pixel copy. For this to be valid, the NvSciBufObj must have been allocated with attributes that satisfy both SIPL and NvBufSurface. That reconciliation is the key setup step.

Attribute Reconciliation (Setup, Once Per Sensor)#

SetupBufferAttributes() builds a single reconciled attribute list from two sources and allocates buffers against it:

SetNvSciBufAttributes(bl_output)          SetNvBufNvSciBufAttributes(&nvbufAttr, sipl)
(YUV420, 8bpc, REC709_ER, BL/PL,          (reads SIPL surf keys, maps NvSci→NvBuf
CPU access + cache)                       color format, NvmmImageFillNvSciBufAttrList)
          │                                                   │
          ▼                                                   ▼
GetImageAttributes(sensorId, ISP0)  ──►  siplAttrList    nvbufAttrList
                                               │              │
                                               └──────┬───────┘
                                                      │
                                                      ▼
                                        NvSciBufAttrListReconcile()
                                                      │
                                                      ▼
                                        sp.bufAttrList (reconciled)
                                                      │
                                                      ▼
                            NvSciBufObjAlloc(sp.bufAttrList, &bufObj)   [x N buffers]
                                                      │
                                                      ▼
                            NvmmNvSciBufToNvBufSurface(bufObj, &nvbuf_surf)
                                                      │
                                                      ▼
                     interop buffer = { NvSciBufObj, NvBufSurface, dmabuf fd }

Key helper functions (in NvNvSciBufHelper.cpp):

  • SetNvSciBufAttributes(&attrList, bl_output): Sets the SIPL-side image attributes—NvSciBufType_Image, ReadWrite, CPU access + cache, YUV, semi-planar 420, 8 BPC, REC709_ER, and layout (block-linear when bl-output=true; otherwise, pitch-linear).

  • SetNvBufNvSciBufAttributes(&attrList, coeAttrList): Reads the SIPL surface keys back (width/height base, sample type, color std, memory layout, BPC, layout), maps the NvSci color info to an NvBufSurfaceColorFormat (MapNvSciToNvBufColorFormat, currently NV12_709_ER / YUV420_709_ER), and then calls NvmmImageFillNvSciBufAttrList() to add NvBufSurface-required attributes.

  • Reconciling both lists guarantees a single allocation is simultaneously a valid SIPL ISP0 target and a valid NvBufSurface.

The registration side then makes SIPL write into the following buffers:

NvSciBufObjAlloc(sp.bufAttrList, &bufObj);                 // allocate NvSci buffer
NvmmNvSciBufToNvBufSurface(bufObj, &interop.nvbuf_surf);   // NvSci → NvRM view (zero-copy)
m_upCamera->RegisterImages(sensorId, ISP0, sp.bufObjects); // SIPL renders here

EOF Synchronization (NvSciSync)#

SIPL signals ISP completion through an EOF fence, not a blocking call. Per sensor, SetupSyncObjects() does the following:

  1. Creates a CPU waiter attribute list and a SIPL signaler attribute list (FillNvSciSyncAttrList(..., ISP0, SIPL_SIGNALER)).

  2. Reconciles the lists and allocates an NvSciSyncObj object.

  3. Registers the NvSciSyncObj object with RegisterNvSciSyncObj(sensorId, ISP0, NVSIPL_EOFSYNCOBJ).

At runtime, ProcessISP0Frame() calls GetEOFNvSciSyncFence() and NvSciSyncFenceWait() before touching the frame. This sequence guarantees that the ISP has finished writing before the CPU/VIC reads it.

The Per-Frame Copy (SIPL to NVMM) and Release#

Although the interop view is zero-copy, the element still performs one explicit VIC copy per frame so that the SIPL buffer can be recycled quickly and downstream owns an independent NVMM buffer:

// nvsipl_sensor_frame_callback()  [runs in SIPL ISP0 thread]
gst_buffer_pool_acquire_buffer(pad->pool, &nvmm_gst_buffer, NULL); // NvBufSurface pool buffer
gst_memory_map(nvmm_mem, &map_info, GST_MAP_WRITE);
NvBufSurfTransform(nvbuf_siplsurf, nvmm_nvbuf_surf, &transform_params); // VIC blit, copy
nvsipl_buffer_queue_push(pad->buffer_queue, info, 1000 /*ms*/);
// After callback returns, SIPL interface calls ReleaseFrame() → SIPL buffer recycled

The NVMM pool buffers themselves are allocated by the element’s custom allocator:

// gst_nvsipl_memory_allocator_alloc()
NvBufSurfaceAllocate(&nvbuf->surf, 1, &input_params); // NV12_709_ER, BL or PL
nvbuf->dmabuf_fd = nvbuf->surf->surfaceList[0].bufferDesc;
// Downstream maps it back:
NvBufSurfaceFromFd(fd, (void**)&nvbuf_surf);

Note

Why a copy at all? SIPL owns a small fixed pool of ICP buffers. Copying to a GStreamer-managed NVMM pool decouples downstream buffering (queues, encoder latency) from the ISP pipeline and lets SIPL recycle its buffers immediately, avoiding ISP stalls and frame drops. In the current plug-in design, this is also applicable for GMSL.

VIC throughput: NvBufSurfTransform uses the default global VIC session, whose internal mutex serializes concurrent blits across all sensor callback threads. This is safe. For many-sensor throughput, call NvBufSurfTransformSetSessionParams() once per callback thread to give each its own VIC handle.

Buffer API Quick Reference#

API

Domain

Role in nvsiplsrc

NvSciBufObjAlloc

NvSci

Allocate ISP0 output buffer from reconciled attributes.

NvSciBufAttrListReconcile

NvSci

Merge SIPL + NvBufSurface attribute requirements.

NvmmNvSciBufToNvBufSurface

NvSci→NvRM

Zero-copy interop: NvSciBufObj → NvBufSurface view.

NvmmImageFillNvSciBufAttrList

NvRM

Add NvBufSurface attributes to an NvSci attribute list.

RegisterImages

SIPL

Tell SIPL to render ISP0 into the NvSci buffers.

GetEOFNvSciSyncFence / NvSciSyncFenceWait

NvSciSync

Wait for ISP completion before read.

NvBufSurfaceAllocate

NvRM

Allocate the downstream NVMM pool buffers.

NvBufSurfTransform

VIC

Copy/convert SIPL surface → NVMM surface.

NvBufSurfaceFromFd

NvRM

Map dmabuf fd back to NvBufSurface downstream.

Pipelines by Use Case#

The following pipelines cover the common use cases for AR0234 (HAWK), IMX728, and IMX623 GMSL sensors. Adjust the config-name and link-mask values to match the sensor and platform.

Sensor Configuration Cheat Sheet#

Sensor

config-name

link-mask

Pads

AR0234 (HAWK)

AR0234CS_HAWK_NON_STEREO

1000

src_0, src_1 (dual)

IMX728

R0SIM728S3RU2120NB2

0100

src_0

IMX623

R0SIM623S5RU1197NB3

010

src_0

AR0234 / HAWK (Dual Sensor: src_0 + src_1)#

Fakesink (functional / throughput):

# Timed run with per-buffer logging
timeout 5 gst-launch-1.0 nvsiplsrc config-name=AR0234CS_HAWK_NON_STEREO link-mask=1000 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=false ! queue ! fakesink sync=false \
  cam.src_1 ! identity silent=false ! queue ! fakesink sync=false -v

# Plain
gst-launch-1.0 nvsiplsrc config-name=AR0234CS_HAWK_NON_STEREO link-mask=1000 num-buffers=100 name=cam \
  cam.src_0 ! queue ! fakesink sync=false \
  cam.src_1 ! queue ! fakesink sync=false

Preview (dual-tile on screen):

gst-launch-1.0 nvsiplsrc config-name=AR0234CS_HAWK_NON_STEREO link-mask=1000 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvvidconv ! nv3dsink sync=false window-x=0 window-y=0   window-width=1920 window-height=540 \
  cam.src_1 ! identity silent=false ! queue ! nvvidconv ! nv3dsink sync=false window-x=0 window-y=540 window-width=1920 window-height=540 -v

# Block-linear output variant
gst-launch-1.0 nvsiplsrc config-name=AR0234CS_HAWK_NON_STEREO link-mask=1000 num-buffers=100 bl-output=true name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvvidconv ! nv3dsink sync=false window-x=0 window-y=0   window-width=1920 window-height=540 \
  cam.src_1 ! identity silent=false ! queue ! nvvidconv ! nv3dsink sync=false window-x=0 window-y=540 window-width=1920 window-height=540 -v

YUV capture (I420 to file):

timeout 3 gst-launch-1.0 nvsiplsrc config-name=AR0234CS_HAWK_NON_STEREO link-mask=1000 name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvvidconv ! "video/x-raw, format=I420" ! filesink location=test_1.yuv \
  cam.src_1 ! identity silent=false ! queue ! nvvidconv ! "video/x-raw, format=I420" ! filesink location=test_2.yuv

Video capture (H.264 / H.265):

# H.264
gst-launch-1.0 nvsiplsrc config-name=AR0234CS_HAWK_NON_STEREO link-mask=1000 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvv4l2h264enc ! h264parse ! qtmux ! filesink location=test-ar0234_h264-0.mp4 \
  cam.src_1 ! identity silent=false ! queue ! nvv4l2h264enc ! h264parse ! qtmux ! filesink location=test-ar0234_h264-1.mp4

# H.265
gst-launch-1.0 nvsiplsrc config-name=AR0234CS_HAWK_NON_STEREO link-mask=1000 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvv4l2h265enc ! h265parse ! qtmux ! filesink location=test-ar0234_h265-0.mkv \
  cam.src_1 ! identity silent=false ! queue ! nvv4l2h265enc ! h265parse ! qtmux ! filesink location=test-ar0234_h265-1.mkv

# H.264, block-linear
gst-launch-1.0 nvsiplsrc config-name=AR0234CS_HAWK_NON_STEREO link-mask=1000 num-buffers=100 bl-output=true name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvv4l2h264enc ! h264parse ! qtmux ! filesink location=test-ar0234_h264-bl-0.mp4 \
  cam.src_1 ! identity silent=false ! queue ! nvv4l2h264enc ! h264parse ! qtmux ! filesink location=test-ar0234_h264-bl-1.mp4

# H.265, block-linear
gst-launch-1.0 nvsiplsrc config-name=AR0234CS_HAWK_NON_STEREO link-mask=1000 num-buffers=100 bl-output=true name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvv4l2h265enc ! h265parse ! qtmux ! filesink location=test-ar0234_h265-0-bl.mkv \
  cam.src_1 ! identity silent=false ! queue ! nvv4l2h265enc ! h265parse ! qtmux ! filesink location=test-ar0234_h265-1-bl.mkv

IMX728 (Single Sensor: src_0)#

Fakesink:

timeout 5 gst-launch-1.0 nvsiplsrc config-name=R0SIM728S3RU2120NB2 link-mask=0100 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=false ! queue ! fakesink sync=false -v

gst-launch-1.0 nvsiplsrc config-name=R0SIM728S3RU2120NB2 link-mask=0100 num-buffers=100 name=cam \
  cam.src_0 ! queue ! fakesink sync=false

Preview:

gst-launch-1.0 nvsiplsrc config-name=R0SIM728S3RU2120NB2 link-mask=0100 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvvidconv ! nv3dsink sync=false window-x=0 window-y=0 window-width=1920 window-height=1080 -v

# Block-linear
gst-launch-1.0 nvsiplsrc config-name=R0SIM728S3RU2120NB2 link-mask=0100 num-buffers=100 bl-output=true name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvvidconv ! nv3dsink sync=false window-x=0 window-y=0 window-width=1920 window-height=1080 -v

YUV capture:

timeout 3 gst-launch-1.0 nvsiplsrc config-name=R0SIM728S3RU2120NB2 link-mask=0100 num-buffers=10 name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvvidconv ! "video/x-raw, format=I420" ! filesink location=test_728.yuv -v

Video capture (H.264 / H.265, with block-linear variants):

# H.264
gst-launch-1.0 nvsiplsrc config-name=R0SIM728S3RU2120NB2 link-mask=0100 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=true ! queue ! nvv4l2h264enc ! h264parse ! qtmux ! filesink location=test_728-h264.mp4 -v

# H.265
gst-launch-1.0 nvsiplsrc config-name=R0SIM728S3RU2120NB2 link-mask=0100 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=true ! queue ! nvv4l2h265enc ! h265parse ! qtmux ! filesink location=test_728-h265.mkv -v

# H.264, block-linear
gst-launch-1.0 nvsiplsrc config-name=R0SIM728S3RU2120NB2 link-mask=0100 num-buffers=100 bl-output=true name=cam \
  cam.src_0 ! identity silent=true ! queue ! nvv4l2h264enc ! h264parse ! qtmux ! filesink location=test_728-h264-bl.mp4 -v

# H.265, block-linear
gst-launch-1.0 nvsiplsrc config-name=R0SIM728S3RU2120NB2 link-mask=0100 num-buffers=100 bl-output=true name=cam \
  cam.src_0 ! identity silent=true ! queue ! nvv4l2h265enc ! h265parse ! qtmux ! filesink location=test_728-h265-bl.mkv -v

IMX623 (Single Sensor: src_0)#

Fakesink:

timeout 5 gst-launch-1.0 nvsiplsrc config-name=R0SIM623S5RU1197NB3 link-mask=010 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=false ! queue ! fakesink sync=false -v

gst-launch-1.0 nvsiplsrc config-name=R0SIM623S5RU1197NB3 link-mask=010 num-buffers=100 name=cam \
  cam.src_0 ! queue ! fakesink sync=false

Preview:

gst-launch-1.0 nvsiplsrc config-name=R0SIM623S5RU1197NB3 link-mask=010 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvvidconv ! nv3dsink sync=false window-x=0 window-y=0 window-width=1920 window-height=1080 -v

# Block-linear
gst-launch-1.0 nvsiplsrc config-name=R0SIM623S5RU1197NB3 link-mask=010 num-buffers=100 bl-output=true name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvvidconv ! nv3dsink sync=false window-x=0 window-y=0 window-width=1920 window-height=1080 -v

YUV capture:

timeout 3 gst-launch-1.0 nvsiplsrc config-name=R0SIM623S5RU1197NB3 link-mask=010 num-buffers=10 name=cam \
  cam.src_0 ! identity silent=false ! queue ! nvvidconv ! "video/x-raw, format=I420" ! filesink location=test_623.yuv -v

Video capture (H.264 / H.265, with block-linear variants):

# H.264
gst-launch-1.0 nvsiplsrc config-name=R0SIM623S5RU1197NB3 link-mask=010 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=true ! queue ! nvv4l2h264enc ! h264parse ! qtmux ! filesink location=test_imx623-h264.mp4 -v

# H.265
gst-launch-1.0 nvsiplsrc config-name=R0SIM623S5RU1197NB3 link-mask=010 num-buffers=100 name=cam \
  cam.src_0 ! identity silent=true ! queue ! nvv4l2h265enc ! h265parse ! qtmux ! filesink location=test_imx623-h265.mkv -v

# H.264, block-linear
gst-launch-1.0 nvsiplsrc config-name=R0SIM623S5RU1197NB3 link-mask=010 num-buffers=100 bl-output=true name=cam \
  cam.src_0 ! identity silent=true ! queue ! nvv4l2h264enc ! h264parse ! qtmux ! filesink location=test_imx623-h264-bl.mp4 -v

# H.265, block-linear
gst-launch-1.0 nvsiplsrc config-name=R0SIM623S5RU1197NB3 link-mask=010 num-buffers=100 bl-output=true name=cam \
  cam.src_0 ! identity silent=true ! queue ! nvv4l2h265enc ! h265parse ! qtmux ! filesink location=test_imx623-h265-bl.mkv -v

CoE Example (Built-in / JSON Config)#

For CoE cameras, link-mask is not required; select the config by name (and optionally a JSON file):

# Single CoE sensor via database config
gst-launch-1.0 nvsiplsrc config-name=VB1940 ! fakesink

# Dual CoE sensors defined in one JSON (fans out to src_0 + src_1)
gst-launch-1.0 nvsiplsrc config-name=VB1940 json-file=vb1940_0.json name=cam \
  cam.src_0 ! queue ! nv3dsink \
  cam.src_1 ! queue ! nv3dsink

Tips and Troubleshooting#

  • Playing a YUV dump: test_*.yuv is raw I420. To view it, supply the resolution; for example, gst-launch-1.0 filesrc location=test_728.yuv ! videoparse format=i420 width=W height=H ! videoconvert ! autovideosink.

  • identity silent=false prints per-buffer info (timestamps, offsets). Useful for confirming both pads of a dual-sensor module produce frames.

  • sync=false on sinks avoids clock-based frame dropping for a live source; keep it for functional/throughput testing.

  • Pad names are dynamic (GST_PAD_SOMETIMES): They appear only after NULL→READY sensor discovery. Always reference them via name=cam + cam.src_<i> in gst-launch.

  • No frames or stalls: The push thread warns src_<i>: no frames for 5 seconds. Check link-mask and sensor power/cabling, and verify that config-name matches your platform.

  • Enable SIPL verbose trace (developer builds): Set the SIPL trace level to LevelDebug in gst_nvsipl_change_state() (NULL→READY), or run with GST_DEBUG=nvsiplsrc:5.

References#