Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file removed .agents/.gitkeep
Empty file.
420 changes: 420 additions & 0 deletions .agents/skills/README.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions .agents/skills/deepstream-dev/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "deepstream-dev",
"description": "NVIDIA DeepStream SDK 9.0 development with Python pyservicemaker API. Use when building video analytics pipelines, GStreamer-based video processing, TensorRT inference integration, object detection/tracking, or Kafka/message broker integration.",
"author": "NVIDIA CORPORATION",
"skills": "./"
}
178 changes: 178 additions & 0 deletions .agents/skills/deepstream-dev/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
---
name: deepstream-dev
description: NVIDIA DeepStream SDK 9.0 development with Python pyservicemaker API. Use when building video analytics pipelines, GStreamer-based video processing, TensorRT inference integration, object detection/tracking, or Kafka/message broker integration.
owner: NVIDIA CORPORATION
service: deepstream
version: 1.1.0
reviewed: 2026-04-24
license: CC-BY-4.0 AND Apache-2.0
---

# DeepStream Development Skill

When this skill is active, **ALWAYS read the relevant reference documents** before generating code. Do NOT rely on memory - the reference documents contain critical details about exact property names, correct API usage, and common pitfalls.

## SDK and Architecture Quick Reference

### DeepStream SDK 9.0 Version Requirements

- **GStreamer**: 1.24.2
- **NVIDIA Driver**: 590+
- **CUDA**: 13.1
- **TensorRT**: 10.14.1.48
- **Platforms**: Ubuntu 24.04 (x86_64 and ARM64/Jetson)

### Typical Pipeline Flow

```
Source → Stream Muxer → Inference → [Tracker] → OSD → Renderer
```
Components in `[brackets]` are **optional** -- only add them when the user explicitly requests them.

| Stage | Role | Key Element(s) | Required? |
|-------|------|-----------------|-----------|
| Source | Input from files, RTSP, cameras | `nvurisrcbin` (preferred), `nvmultiurisrcbin`, `filesrc` | Yes |
| Stream Muxer | Batches streams for inference | `nvstreammux` | Yes |
| Inference | TensorRT model execution | `nvinfer`, `nvinferserver` | Yes |
| Tracker | Multi-object tracking across frames | `nvtracker` | **Only if requested** |
| OSD | Draws bounding boxes, labels, overlays | `nvosdbin` | Yes (for visualization) |
| Renderer | Display or save output | `nveglglessink`, `nv3dsink`, `filesink` | Yes |

### Memory Model

DeepStream uses NVIDIA Video Memory Manager (NVMM) for zero-copy GPU buffer transfers. Caps strings use `memory:NVMM` to indicate GPU memory (e.g., `video/x-raw(memory:NVMM), format=NV12`).

## Critical Rules

1. **Only Add Requested Components**: Do NOT add pipeline elements the user did not ask for.
- **Tracker (`nvtracker`)**: Only add when the user explicitly requests tracking or object IDs across frames
- **Secondary GIEs**: Only add when the user requests classification or attribute extraction
- **Analytics (`nvdsanalytics`)**: Only add when the user requests line crossing, ROI counting, etc.
- **Message broker (`nvmsgbroker`/`nvmsgconv`)**: Only add when the user requests Kafka/cloud messaging
- When in doubt, build the **minimal working pipeline** and let the user ask for additions

2. **Default to `nvurisrcbin` for Sources**: When the user says "camera", "stream", "video", or provides a file path:
- Always use `nvurisrcbin` -- it handles RTSP, HTTP, and local files (`file://`) transparently
- Only use `filesrc` + `qtdemux` + parser when the user explicitly needs raw file source control
- For RTSP/live sources, also set `live-source=1` on `nvstreammux` and `sync=0` on the sink
- Convert local paths to URI: `"file://" + os.path.abspath(path)`

3. **Metadata Iteration**: Use `.frame_items` and `.object_items` (returns iterators, NOT lists)
- NEVER use `len()` on these - iterate to count
- Iterator can only be consumed once

4. **Request Pad Syntax**: Use `"sink_%u"` template, NEVER literal pad names
```python
pipeline.link(("decoder", "mux"), ("", "sink_%u")) # CORRECT
# pipeline.link(("decoder", "mux"), ("", "sink_0")) # WRONG - will fail
```

5. **Platform Detection for Sinks**:
```python
import platform
sink_type = "nv3dsink" if platform.processor() == "aarch64" else "nveglglessink"
```

6. **Buffer Cloning**: Always clone buffers for async processing
```python
tensor = buffer.extract(0).clone() # CRITICAL
```

7. **Queue Types**:
- `queue.Queue` → Use with `threading.Thread`
- `multiprocessing.Queue` → Use with `multiprocessing.Process`
- Using wrong type causes silent data loss!

8. **nvinfer Config Format**:
- YAML: Use `property:` section (NOT `model:`), `key: value` with space after colon
- INI: Use `[property]` section, `key=value` with equals sign
- Section MUST be named `property`

9. **nvmsgbroker is a SINK**: Cannot have downstream elements - use `tee` to split pipeline

10. **ALL Sinks Need async=0 for Tee Splits or Dynamic Sources**: CRITICAL for state transitions
```python
# When using tee splits OR dynamic sources, ALL sinks MUST have async=0
pipeline.add("nveglglessink", "sink", {
"sync": 0, "qos": 0,
"async": 0 # CRITICAL - prevents state transition deadlock
})
```
**Symptom if missing**: Pipeline stays in PAUSED state, no video displays.

11. **Built-in Probe Attachment**: `measure_fps_probe` can only be attached to processing elements (e.g., `nvinfer`, `nvosdbin`), **NOT** to sink elements. Attaching to a sink raises `RuntimeError: Probe failure`.

12. **Dynamic ONNX Models Require `infer-dims`**: When the ONNX model has dynamic input shapes (e.g., exported with `dynamic=True` in Ultralytics YOLO, or with dynamic batch/height/width axes), you **MUST** add `infer-dims=C;H;W` to the nvinfer config. Without it, TensorRT sees `-1` for dynamic dimensions and fails with `setDimensions: Error Code 3`. Common values:
- YOLO models (640 input): `infer-dims=3;640;640`
- Models with 416 input: `infer-dims=3;416;416`
- Models with 1280 input: `infer-dims=3;1280;1280`

13. **Ultralytics YOLO Output Format Depends on Model Generation** — newer models (v10+/v26+) output post-NMS results; older models (v8/v11) output raw pre-NMS tensors. The custom parser and `cluster-mode` **must** match the actual output:

| Model generation | Output tensor shape | Fields | `cluster-mode` |
|------------------|--------------------|---------------------------------|----------------|
| v8 / v11 | `[batch, 84, 8400]` | `[features(4+80), anchors]` — raw cx/cy/w/h + class scores, no NMS | `2` (NMS) |
| v10 / v26+ | `[batch, 300, 6]` | `[max_det, (x1,y1,x2,y2,conf,cls)]` — already post-NMS, pixel coords | `4` (none) |

**How to identify at runtime**: log `inferDims.d[0]` and `inferDims.d[1]` inside the custom parser.
- `d={84, 8400}` → pre-NMS (v8/v11 style)
- `d={300, 6}` → post-NMS (v10/v26+ style)

**Symptom of mismatch**: If `cluster-mode: 2` is used with a post-NMS `[N, 6]` output, bounding boxes appear shifted by 45° or 135° from the actual objects (DeepStream's NMS incorrectly re-processes already-final coordinates).
If you see tilted or rotated boxes, also check the OBB / `rotation_angle` note in `references/nvinfer_config.md`: for non-OBB models, value-initialize `NvDsInferObjectDetectionInfo` with `obj{}` and keep `rotation_angle = 0`; plain `NvDsInferObjectDetectionInfo obj;` leaves fields uninitialized.

14. **Virtual Environment Must Include pyservicemaker**: `pyservicemaker` is installed system-wide but is NOT accessible from a standard Python virtual environment. When a task requires a venv (e.g., for model download/conversion pip dependencies), **always install `pyservicemaker` and `pyyaml` inside the venv**. The venv setup in generated code and README must always include:
```bash
python3 -m venv venv
source venv/bin/activate
pip install /opt/nvidia/deepstream/deepstream/service-maker/python/pyservicemaker*.whl pyyaml
pip install -r requirements.txt # other dependencies
```
**Symptom if missing**: `ModuleNotFoundError: No module named 'pyservicemaker'` when running the app inside the venv.

## Key Paths (DeepStream 9.0)

- Models: `/opt/nvidia/deepstream/deepstream/samples/models/`
- Primary Detector: `/opt/nvidia/deepstream/deepstream/samples/models/Primary_Detector/resnet18_trafficcamnet_pruned.onnx`
- Tracker lib: `/opt/nvidia/deepstream/deepstream/lib/libnvds_nvmultiobjecttracker.so`
- Kafka lib: `/opt/nvidia/deepstream/deepstream/lib/libnvds_kafka_proto.so`
- Sample configs: `/opt/nvidia/deepstream/deepstream/samples/configs/deepstream-app/`

## Reference Documents

**IMPORTANT**: Always read these documents for complete details. Do NOT generate code from memory.

| Document | Use When |
|----------|----------|
| [references/gstreamer_plugins.md](references/gstreamer_plugins.md) | Looking up plugin properties, ALL properties listed |
| [references/service_maker_api.md](references/service_maker_api.md) | Using Pipeline/Flow API, metadata access, probes, EventMessageUserMetadata |
| [references/use_cases_pipelines.md](references/use_cases_pipelines.md) | Building pipelines: simple playback, multi-inference, cascaded GIE |
| [references/kafka_messaging.md](references/kafka_messaging.md) | Kafka/message broker setup, nvmsgconv/nvmsgbroker config, msg2p-newapi |
| [references/best_practices.md](references/best_practices.md) | Design patterns, common pitfalls, anti-patterns |
| [references/buffer_apis.md](references/buffer_apis.md) | BufferProvider/Feeder (injection), BufferRetriever/Receiver (extraction) |
| [references/media_extractor_advanced.md](references/media_extractor_advanced.md) | MediaExtractor, MediaChunk, FrameSampler |
| [references/utilities_config.md](references/utilities_config.md) | PerfMonitor, EngineFileMonitor, SourceConfig, SensorInfo, SmartRecordConfig |
| [references/nvinfer_config.md](references/nvinfer_config.md) | nvinfer config file format, ALL parameters |
| [references/tracker_config.md](references/tracker_config.md) | nvtracker config, NvDCF/IOU/DeepSORT/NvSORT |
| [references/troubleshooting.md](references/troubleshooting.md) | Error messages and solutions |
| [references/rest_api_dynamic.md](references/rest_api_dynamic.md) | REST API, dynamic source add/remove, nvmultiurisrcbin |
| [references/metamux_config.md](references/metamux_config.md) | nvdsmetamux config, parallel multi-model inference, metadata merging, source ID filtering |
| [references/docker_containers.md](references/docker_containers.md) | Docker images, Dockerfile examples, pyservicemaker install, container run commands |

## Quick Error Reference

| Error | Solution |
|-------|----------|
| `iterator has no len()` | Iterate to count, don't use `len()` |
| `pad template not found` | Use `"sink_%u"` not `"sink_0"` |
| Queue data loss | Use `multiprocessing.Queue` with `Process` |
| Config parse failed | Use `property:` not `model:` in YAML |
| `is-classifier` deprecation warning | Use `network-type: 1` instead of `is-classifier: 1` for classifiers; omit both for detectors |
| `min-boxes` unknown key warning | Use `minBoxes` (camelCase) in `class-attrs-*` sections, not `min-boxes` |
| Secondary GIE inactive | Set `process-mode: 2`, check `operate-on-gie-id` |
| Tee/dynamic source stuck PAUSED | Set `async: 0` on **ALL** sink elements |
| RTSP no data/reconnecting | Test URL with ffplay, check credentials |
| `RuntimeError: Probe failure` | `measure_fps_probe` cannot attach to sink elements; use `nvinfer` or `nvosdbin` instead |
| `setDimensions` negative dims / engine build failed | Add `infer-dims=C;H;W` for dynamic ONNX models (e.g., `infer-dims=3;640;640`) |
| `No module named 'pyservicemaker'` in venv | `pip install /opt/nvidia/deepstream/deepstream/service-maker/python/pyservicemaker*.whl pyyaml` inside the venv |
| `AttributeError: object has no attribute 'obj_label'` | Use `obj_meta.label` not `obj_meta.obj_label` in pyservicemaker (C API name differs from Python binding) |
185 changes: 185 additions & 0 deletions .agents/skills/deepstream-dev/evals/evals.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
{
"skill_name": "deepstream-dev",
"evals": [
{
"id": 1,
"name": "basic-video-file-inference-pipeline",
"prompt": "Using DeepStream SDK 9.0 and the pyservicemaker Python API, generate a pipeline that reads a local video file, runs primary inference with nvinfer using the ResNet18 TrafficCamNet detector shipped with DeepStream, draws bounding boxes with nvosdbin, and renders to the screen. The user did not ask for tracking or Kafka.",
"expected_output": "A minimal pipeline using nvurisrcbin -> nvstreammux -> nvinfer -> nvosdbin -> platform-appropriate sink, with no nvtracker, no secondary GIE, no nvmsgbroker, and correct request-pad syntax.",
"files": [],
"assertions": [
{
"text": "Pipeline uses nvurisrcbin as the source (preferred over filesrc for local files)",
"type": "contains_phrase",
"phrase": "nvurisrcbin"
},
{
"text": "Pipeline batches streams through nvstreammux",
"type": "contains_phrase",
"phrase": "nvstreammux"
},
{
"text": "Request pads use the sink_%u template, not a literal sink_0 pad name",
"type": "contains_phrase",
"phrase": "sink_%u"
},
{
"text": "Pipeline references the bundled ResNet18 TrafficCamNet ONNX model path",
"type": "contains_phrase",
"phrase": "resnet18_trafficcamnet_pruned.onnx"
},
{
"text": "No nvtracker element is added because the user did not request tracking",
"type": "not_contains",
"phrase": "nvtracker"
},
{
"text": "No Kafka message broker is added because the user did not request messaging",
"type": "not_contains",
"phrase": "nvmsgbroker"
}
]
},
{
"id": 2,
"name": "rtsp-multi-stream-with-tracker-and-kafka",
"prompt": "Build a DeepStream 9.0 pyservicemaker pipeline that ingests two RTSP cameras, runs primary detection, tracks objects across frames, displays the result in a tiled view, AND publishes detection metadata to a Kafka broker. Cover the live-source and tee-split requirements.",
"expected_output": "Pipeline uses nvurisrcbin for each RTSP source, sets live-source=1 on nvstreammux, adds nvtracker (explicitly requested), splits the flow with a tee so nvmsgbroker (a sink) can receive metadata, and sets async=0 on all sinks.",
"files": [],
"assertions": [
{
"text": "nvstreammux is configured with live-source=1 for RTSP/live input",
"type": "contains_phrase",
"phrase": "live-source"
},
{
"text": "nvtracker is included because the user explicitly requested tracking",
"type": "contains_phrase",
"phrase": "nvtracker"
},
{
"text": "Pipeline splits with a tee element to feed both the display branch and nvmsgbroker",
"type": "contains_phrase",
"phrase": "tee"
},
{
"text": "nvmsgbroker is used for Kafka publishing since the user requested cloud messaging",
"type": "contains_phrase",
"phrase": "nvmsgbroker"
},
{
"text": "All sinks set async=0 to avoid tee-split state-transition deadlocks",
"type": "contains_pattern",
"pattern": "async\\s*[:=]\\s*0"
},
{
"text": "Renderer sink honors live-source with sync=0",
"type": "contains_pattern",
"pattern": "sync\\s*[:=]\\s*0"
}
]
},
{
"id": 3,
"name": "yolo-dynamic-onnx-nvinfer-config",
"prompt": "Generate an nvinfer YAML config for a YOLOv11 model (640x640 input) exported from Ultralytics with dynamic=True. The model outputs a raw pre-NMS tensor of shape [batch, 84, 8400].",
"expected_output": "Config uses the property: section header, sets infer-dims=3;640;640 so TensorRT does not see -1, and uses cluster-mode: 2 (NMS) because the tensor is pre-NMS. No is-classifier flag for a detector.",
"files": [],
"assertions": [
{
"text": "Config uses the property: section header (not model:)",
"type": "contains_phrase",
"phrase": "property:"
},
{
"text": "infer-dims is explicitly set for the dynamic ONNX input shape",
"type": "contains_phrase",
"phrase": "infer-dims"
},
{
"text": "infer-dims matches the 640x640 YOLO input in C;H;W form",
"type": "contains_phrase",
"phrase": "3;640;640"
},
{
"text": "cluster-mode is 2 (NMS) because v8/v11 output is pre-NMS",
"type": "contains_pattern",
"pattern": "cluster-mode\\s*:\\s*2"
},
{
"text": "Config does not use the deprecated is-classifier flag for a detector",
"type": "not_contains",
"phrase": "is-classifier"
}
]
},
{
"id": 4,
"name": "negative-rejects-tracker-and-secondary-gie-when-not-requested",
"prompt": "Write a DeepStream pipeline that just plays a video file through inference and shows it on screen. Keep it as minimal as possible.",
"expected_output": "Minimal pipeline with nvurisrcbin, nvstreammux, nvinfer, nvosdbin, and a renderer. No nvtracker, no secondary GIE, no nvdsanalytics, and no nvmsgbroker are added since the user did not request them.",
"files": [],
"assertions": [
{
"text": "Skill does not add nvtracker when the user did not ask for tracking",
"type": "not_contains",
"phrase": "nvtracker"
},
{
"text": "Skill does not add nvdsanalytics when the user did not ask for line-crossing or ROI",
"type": "not_contains",
"phrase": "nvdsanalytics"
},
{
"text": "Skill does not add a secondary GIE (SGIE) for classification the user did not request",
"type": "not_contains_pattern",
"pattern": "process-mode\\s*[:=]\\s*2"
},
{
"text": "Skill does not add nvmsgbroker/nvmsgconv when no messaging was requested",
"type": "not_contains",
"phrase": "nvmsgbroker"
},
{
"text": "Pipeline still includes the required inference stage (nvinfer)",
"type": "contains_phrase",
"phrase": "nvinfer"
}
]
},
{
"id": 5,
"name": "negative-metadata-iteration-and-venv-setup",
"prompt": "My pyservicemaker probe runs len(frame.object_items) to count detections and I am installing my app inside a fresh python3 -m venv. It fails with ModuleNotFoundError: pyservicemaker and the probe raises 'iterator has no len()'. Fix both.",
"expected_output": "Guidance that .object_items and .frame_items return iterators (not lists), so counting must be done by iterating; and that the venv must install the bundled pyservicemaker wheel plus pyyaml because pyservicemaker is not picked up from the system site-packages.",
"files": [],
"assertions": [
{
"text": "Explains that object_items/frame_items are iterators and len() cannot be used",
"type": "contains_phrase",
"phrase": "iterator"
},
{
"text": "Suggests iterating to count instead of len()",
"type": "not_contains_pattern",
"pattern": "len\\(\\s*[a-zA-Z_]+\\.object_items\\s*\\)"
},
{
"text": "Instructs installing the bundled pyservicemaker wheel inside the venv",
"type": "contains_phrase",
"phrase": "pyservicemaker"
},
{
"text": "Includes the DeepStream 9.0 service-maker python wheel path",
"type": "contains_phrase",
"phrase": "/opt/nvidia/deepstream/deepstream/service-maker/python/"
},
{
"text": "Also installs pyyaml inside the venv so YAML nvinfer configs load",
"type": "contains_phrase",
"phrase": "pyyaml"
}
]
}
]
}
Loading