--- name: vss-dlstreamer-pipeline description: Helps developers understand and safely modify the DLStreamer/GStreamer Pipeline Server (EVAM) video ingestion pipelines in the video-search-and-summarization sample app. Use when the user wants to change the DLStreamer/GStreamer pipeline, extract frames differently, modify the EVAM pipeline, add a detection model to video ingestion, or tune chunk/frame extraction in the pipeline server. --- # VSS DLStreamer Pipeline Use this skill for the Video Search & Summarization sample app when work touches the DL Streamer Pipeline Server-backed video ingestion flow. ## Environment setup (run first) This skill drives the Video Search & Summarization app through its real source files, so the VSS application must be present and you must run commands from its app root. **Do this before anything else**, and it works whether or not the VSS source is already in your workspace. Run the bundled bootstrap. It first tries to find an existing VSS checkout - walking up from the current directory and inspecting the enclosing git repo - and reuses it **without ever re-cloning**. Only when no checkout is found does it do a shallow, single-branch, sparse checkout of just `sample-applications/video-search-and-summarization` from `main`. It prints the resolved app root on stdout: ```bash # SKILL_DIR is THIS skill's own directory (shown to you when the skill loads); # in-repo it is .github/skills/vss-dlstreamer-pipeline. Works the same if the skill is installed standalone. SKILL_DIR=".github/skills/vss-dlstreamer-pipeline" APP_ROOT="$(bash "$SKILL_DIR/scripts/vss-bootstrap.sh")" cd "$APP_ROOT" ``` Every command below assumes the working directory is this `APP_ROOT`. To pull from a fork/branch or reuse a specific checkout dir, override `VSS_REPO_URL`, `VSS_REPO_BRANCH`, or `VSS_CLONE_DIR` before running it. ## Ground truth first Before editing, read these repo paths; do not infer pipeline names or payloads from generic DL Streamer examples: - `video-ingestion/resources/conf/config.json` - the actual pipeline definitions loaded into the DL Streamer Pipeline Server image. - `video-ingestion/src/publish.py` - `gvapython` sink that writes frames/metadata to MinIO and publishes chunk messages. - `pipeline-manager/src/evam/models/evam.model.ts` - request DTO and `EVAMPipelines` enum. - `pipeline-manager/src/evam/services/evam.service.ts` - endpoint and request body sent to EVAM. - `pipeline-manager/src/config/configuration.ts` and `docker/compose.summary.yaml` - host, ports, model path, device, RabbitMQ, MinIO wiring. - For architecture language, see `docs/user-guide/how-it-works/*.md`; `docs/user-guide/how-it-works.md` references `_assets/TEAI_VideoPipelines.png`. ## Actual flow in this repo 1. The summary pipeline stores the input video in MinIO and obtains an HTTP object URL. 2. `pipeline-manager/src/state-manager/services/pipeline.service.ts` calls `EvamService.startChunkingStub(stateId, videoUrl, state.userInputs, state.systemConfig.evamPipeline)`. 3. `EvamService` POSTs to: ```text http://${EVAM_HOST}:${EVAM_PIPELINE_PORT}/pipelines/user_defined_pipelines/${pipeline} ``` where `${pipeline}` is one of the real configured names: - `object_detection` - `video_ingestion` 4. DL Streamer Pipeline Server executes the matching GStreamer template from `video-ingestion/resources/conf/config.json`. 5. Frames pass through `gvapython ... class=Publisher function=process module=/home/pipeline-server/gvapython/publisher/publish.py`. 6. `Publisher` writes frame JPEGs and metadata JSON to MinIO and publishes a chunk message to RabbitMQ MQTT topic `topic/video_stream`. 7. `pipeline-manager/src/evam/services/rabbitmq.service.ts` consumes AMQP queue `my_mqtt_queue` bound to exchange `amq.topic` with routing key `topic.video_stream`, then emits `CHUNK_RECEIVED`. 8. Captioning, summarization, and search embedding generation happen downstream from the extracted frames/metadata; EVAM itself only chunks/extracts/detects/publishes in this repo. ## Request payload shape `EvamService.startChunkingStub()` sends this shape: ```json { "source": { "element": "curlhttpsrc", "type": "gst", "properties": { "location": "" } }, "parameters": { "detection-properties": { "model": "/home/pipeline-server/models/object-detection/ultralytics/public/yolov8l/FP32/yolov8l.xml", "device": "CPU" }, "publish": { "minio_bucket": "", "video_identifier": "", "topic": "topic/video_stream" }, "frame": 5, "chunk_duration": 10, "frame_width": 480 } } ``` `frame`, `chunk_duration`, and `frame_width` are validated by JSON Schema in `video-ingestion/resources/conf/config.json`. ## Pipelines as defined in `video-ingestion/resources/conf/config.json` - `object_detection`: `... videorate ! videoconvertscale ! video/x-raw,framerate={parameters[frame]}/{parameters[chunk_duration]},format=BGR,width=[1,{parameters[frame_width]}],pixel-aspect-ratio=1/1 ! gvadetect name=detection pre-process-backend=ie ! queue ! gvapython ... ! fakesink` - `video_ingestion`: same decode/rate/scale/publish chain, but without `gvadetect`. The `detection-properties` request parameter maps to the element named `detection`, so it only has an effect when the selected pipeline contains `gvadetect name=detection`. ## Safe modification workflow GStreamer pipeline strings are fragile: a missing `!`, caps typo, bad element name, or parameter mismatch can make the pipeline fail at runtime even if TypeScript compiles. When changing extraction behavior: 1. Edit `video-ingestion/resources/conf/config.json` first. 2. Keep parameter placeholders aligned with the request DTO and schema: `{parameters[frame]}`, `{parameters[chunk_duration]}`, `{parameters[frame_width]}`, `publish`, and any element-property mappings. 3. If adding a new selectable pipeline, also update: - `pipeline-manager/src/evam/models/evam.model.ts` (`EVAMPipelines`) - `pipeline-manager/src/evam/services/evam.service.ts` (`availablePipelines()`) - UI/API config paths that expose `evamPipeline` if needed. 4. If adding/changing a detection model, ensure the model is available under the container mount `/home/pipeline-server/models` (`../ov_models` in `docker/compose.summary.yaml`) and update `pipeline-manager/src/config/configuration.ts` model path or make it configurable. 5. Rebuild/restart `video-ingestion`; `video-ingestion/docker/Dockerfile` copies `resources/conf/config.json` into `/home/pipeline-server/config.json` and copies `src/` into `/home/pipeline-server/gvapython/publisher/`. 6. Validate with `GET /pipelines`, then POST a real `object_detection` or `video_ingestion` request and confirm: - the POST returns a pipeline UUID, - `GET /pipelines/{id}` reaches `COMPLETED`, - MinIO contains `video_id/frame/chunk_N_frame_M.jpeg` and metadata JSON, - RabbitMQ delivers chunk messages. See `references/evam-pipelines.md` for the detailed request/config reference and a worked modification example.