vios-deep-image-capture · git:20260603.14e198c · 2026-06-03 · sha256 f41afa8107b810b3

vios-deep-image-capture git:20260603.14e198cA

Immutable. This exact content is served forever at /api/v1/blob/f41afa8107b810b3.

---
description: "Deep reference: Image/picture capture end-to-end flow -- API to JPEG output"
globs: "src/framework/apis/common/vst_common.*,src/framework/media/video_source/encoders/image_encoder.*,src/framework/media/media_pipelines/gstnvimageencode.*"
alwaysApply: false
---

# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Image Capture Flow

## API Entry Points

GET with `action == "picture"` on stream endpoints. All call `vst_common::getCameraPicture()`.

| Module | File | Line |
|--------|------|------|
| Live | `src/modules/webrtc_live/LivePeerConnection.cpp` | 499 |
| Replay | `src/modules/webrtc_replay/ReplayPeerConnection.cpp` | 543 |
| StreamBridge | `src/modules/webrtc_stream_bridge/StreamBridgeService.cpp` | 430 |

## Orchestration (vst_common.cpp)

- `getCameraPicture()` (line 1313): resolves sensor/stream, builds opts with `image_capture=true`, `peerid=image_capture`
- `getCameraPictureDisconnected()` (line 1220): handles capture from recorded/file sources
- Creates dedicated `CommonVideoSource(url, opts)`, calls `getBuffer()`, async cleanup via detached thread

## Pipeline Selection (PipelineConfiguration.cpp:64)

`m_imageCapture = (opts.find("image_capture") != opts.end())`

## Pipeline Wiring (SingleStreamPipelineBuilder.cpp:370-455)

| Variant | Chain |
|---------|-------|
| Full (overlay+transform+transformSink) | Decoder -> Transform -> Overlay -> TransformSink -> ImageEncoder |
| Overlay+transform | Decoder -> Transform -> Overlay -> ImageEncoder |
| Overlay only | Decoder -> Overlay -> ImageEncoder |
| Transform only | Decoder -> Transform -> ImageEncoder |
| Minimal | Decoder -> ImageEncoder |
| Native stream | Same patterns with NativeStreamProducer |
| Composite | First Decoder -> Transform -> ImageEncoder |

## ImageEnc Class (encoders/image_encoder.h/.cpp)

Implements `IMediaDataConsumer`. Two encode paths:

- **SW path** (`pushBuffer()`): copies raw frame -> `appsrc -> videoparse -> videoscale -> capsfilter(I420) -> jpegenc -> appsink`
- **HW path** (`hwEncode()`): `NvJpegEncLoader::nvjpegEncodeFromFd()` direct GPU JPEG encode from fd

Key methods:
- `onFrame()` -- receives decoded RawFrameParams, routes to SW/HW
- `getImageBuffer()` -- blocks up to 75s on condvar, returns JPEG buffer
- `processJpegImageFromSink()` -- appsink callback, stores JPEG, signals condvar
- `create()` -- builds GStreamer SW pipeline

## Response

- Raw JPEG: `response["content_type"] = "image/jpeg"`, `response["data"] = buffer`
- URL mode (`isURLRequested`): writes to temp file, returns URL with expiry

## Legacy Paths

- `NvImageEncode` (gstnvimageencode.h/.cpp) -- older standalone image encoder
- `LiveGstNvVideoSource::getBuffer()` (livevideosource.h:733) -- via `m_gstdecoder->getImageBuffer()`
- `GstNvVideoDecoder::getImageBuffer()` (gstnvvideodecoder.cpp:3579) -- older decoder-level capture