Skip to content
Open
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
1 change: 1 addition & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
},
"runArgs": [
"--net=host",
"--runtime=nvidia"
//"<env>"
],
"containerEnv": {
Expand Down
2 changes: 2 additions & 0 deletions applications/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ add_holohub_application(endoscopy_tool_tracking DEPENDS
yuan_qcap
vtk_renderer)

add_subdirectory(gstreamer)

add_subdirectory(h264)

add_holohub_application(isaac_sim_holoscan_bridge)
Expand Down
17 changes: 17 additions & 0 deletions applications/gstreamer/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 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.

add_holohub_application(gst_video_recorder DEPENDS OPERATORS gstreamer)

37 changes: 37 additions & 0 deletions applications/gstreamer/gst_video_recorder/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 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.

project(gst_video_recorder CXX)

find_package(holoscan REQUIRED CONFIG
PATHS "/opt/nvidia/holoscan" "/workspace/holoscan-sdk/install")

add_executable(gst-video-recorder
gst_video_recorder.cpp
pattern_generator.cpp
)

target_link_libraries(gst-video-recorder
PRIVATE
holoscan::core
holoscan::ops::gstreamer_bridge
holoscan::ops::v4l2
holoscan::ops::format_converter
)

# Install target
install(TARGETS gst-video-recorder DESTINATION bin/gst_video_recorder)


87 changes: 87 additions & 0 deletions applications/gstreamer/gst_video_recorder/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# syntax=docker/dockerfile:1

# SPDX-FileCopyrightText: Copyright (c) 2025 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.

ARG GPU_TYPE
ARG BASE_SDK_VERSION
ARG BASE_IMAGE=nvcr.io/nvidia/clara-holoscan/holoscan:v${BASE_SDK_VERSION}-${GPU_TYPE}
FROM ${BASE_IMAGE} AS base

ARG DEBIAN_FRONTEND=noninteractive
ARG CMAKE_BUILD_TYPE=Release

# --------------------------------------------------------------------------
#
# Set up prerequisites to run HoloHub CLI
#
# --------------------------------------------------------------------------
FROM base AS holohub-cli-prerequisites

# Install python3 if not present (needed for holohub CLI)
ARG PYTHON_VERSION=python3
RUN if ! command -v python3 >/dev/null 2>&1; then \
apt-get update \
&& apt-get install --no-install-recommends -y \
software-properties-common curl gpg-agent \
&& add-apt-repository ppa:deadsnakes/ppa \
&& apt-get update \
&& apt-get install --no-install-recommends -y \
${PYTHON_VERSION} \
&& apt purge -y \
python3-pip \
software-properties-common \
&& apt-get autoremove --purge -y \
&& rm -rf /var/lib/apt/lists/* \
&& update-alternatives --install /usr/bin/python python /usr/bin/${PYTHON_VERSION} 100 \
&& if [ "${PYTHON_VERSION}" != "python3" ]; then \
update-alternatives --install /usr/bin/python3 python3 /usr/bin/${PYTHON_VERSION} 100 \
; fi \
; fi
ENV PIP_BREAK_SYSTEM_PACKAGES=1
RUN if ! python3 -m pip --version >/dev/null 2>&1; then \
curl -sS https://bootstrap.pypa.io/get-pip.py | ${PYTHON_VERSION} \
; fi

# --------------------------------------------------------------------------
#
# Set up GStreamer-specific dependencies for gst_video_recorder
#
# --------------------------------------------------------------------------
FROM holohub-cli-prerequisites AS holohub-cli

RUN mkdir -p /tmp/scripts
COPY holohub /tmp/scripts/
RUN mkdir -p /tmp/scripts/utilities
COPY utilities /tmp/scripts/utilities/
RUN chmod +x /tmp/scripts/holohub
RUN /tmp/scripts/holohub setup && rm -rf /var/lib/apt/lists/*

# Install GStreamer development packages and pkg-config
COPY applications/gstreamer/gst_video_recorder/install_deps.sh /tmp/install_gst_video_recorder_deps.sh
RUN /tmp/install_gst_video_recorder_deps.sh

# Enable autocomplete
RUN echo ". /etc/bash_completion.d/holohub_autocomplete" >> /etc/bash.bashrc

# Set default Holohub data directory
ENV HOLOSCAN_INPUT_PATH=/workspace/holohub/data

# --------------------------------------------------------------------------
#
# Default development stage for GStreamer applications
#
# --------------------------------------------------------------------------
FROM holohub-cli AS holohub-dev
227 changes: 227 additions & 0 deletions applications/gstreamer/gst_video_recorder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# GStreamer Video Recorder

A Holoscan application that demonstrates video recording using the GStreamer encoding pipeline.

## Description

This application showcases how to:
- Capture video from V4L2 cameras (USB webcams, MIPI cameras, etc.) or generate test patterns
- Feed video frames to GStreamer for encoding
- Record encoded video to files in various formats (MP4, MKV)
- Use different video codecs (H.264, H.265, and other GStreamer-supported codecs)
- Support both host and CUDA device memory for zero-copy operation

**Supported Video Sources:**
- **V4L2 Camera** - Capture from any V4L2-compatible camera (USB webcams, MIPI cameras, etc.)
- **Pattern Generator** - Generate animated test patterns (gradient, checkerboard, color bars)

## Requirements

- NVIDIA Holoscan SDK
- GStreamer 1.0 with the following plugins:
- gstreamer1.0-plugins-base (videoconvert for host memory support)
- gstreamer1.0-plugins-bad (cudaconvert, nvh264enc, nvh265enc for NVIDIA hardware encoding)
- gstreamer1.0-plugins-good (mp4mux, matroskamux for container formats)
- gstreamer1.0-plugins-ugly (x264enc for CPU-based H.264 encoding)
- Additional codecs available through gstreamer1.0-libav if needed
- V4L2-compatible camera (optional, for camera capture mode)
- USB webcams, MIPI CSI cameras, or any V4L2 video device
- Use `v4l2-ctl --list-devices` to see available cameras

## Building

### Option 1: Containerized Build (Recommended)
No setup required - all dependencies are included in the container:

```bash
./holohub build gst_video_recorder
```

### Option 2: Local Build
For faster builds and easier debugging. First install dependencies:

```bash
# From the gst_video_recorder directory
./install_deps.sh

# Then build locally
./holohub build --local gst_video_recorder
```

The `install_deps.sh` script installs:
- pkg-config (required for CMake)
- GStreamer development libraries
- All necessary GStreamer plugins for encoding

## Usage

```bash
gst-video-recorder [OPTIONS]
```
Comment on lines +56 to +60
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any concerns about standardizing to HoloHub CLI recommended approach? The following command would build the app container, build the containerized app, and run the containerized app:

./holohub run gst-video-recorder

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This standardized way is working now as well.


### Options

**General Options:**
- `--source <type>` - Video source: `pattern` or `v4l2` (default: pattern)
- `-o, --output <filename>` - Output video filename (default: output.mp4)
- Supported formats: .mp4, .mkv
- If no extension, defaults to .mp4
- `-e, --encoder <name>` - Encoder base name (default: nvh264)
- Examples: nvh264, nvh265, x264, x265
- Note: 'enc' suffix is automatically appended
- `-c, --count <number>` - Number of frames to capture/generate (default: unlimited)
- `-f, --framerate <rate>` - Frame rate as fraction or decimal (default: 30/1)
- Examples: '30/1', '30000/1001', '29.97', '60'
- Use '0/1' for live mode (no throttling, real-time timestamps)
- `--property <key=value>` - Set encoder property (can be used multiple times)
- Examples: --property bitrate=8000 --property preset=1
- Property types are automatically detected and converted
- `--help` - Show help message

**Resolution Options:**
- `-w, --width <pixels>` - Frame width (default: 1920)
- For V4L2: Must match a supported camera resolution
- For pattern: Any reasonable resolution (64-8192 pixels)
- `-h, --height <pixels>` - Frame height (default: 1080)
- For V4L2: Must match a supported camera resolution
- For pattern: Any reasonable resolution (64-8192 pixels)

**V4L2 Camera Options:**
- `--device <path>` - V4L2 device path (default: /dev/video0)
- `--pixel-format <format>` - V4L2 pixel format (default: auto)
- Examples: YUYV, MJPEG, auto

**Pattern Generator Options:**
- `--pattern <type>` - Pattern type (default: 0)
- 0 = animated gradient
- 1 = animated checkerboard
- 2 = color bars (SMPTE style)
- `--storage <type>` - Memory storage type (default: 1)
- 0 = host memory
- 1 = device/CUDA memory

### Examples

#### V4L2 Camera Examples

**Record from default V4L2 camera at 1920x1080 (30 seconds at 30fps):**
```bash
gst-video-recorder --source v4l2 --width 1920 --height 1080 --count 900 -o camera.mp4
```

**Record from specific V4L2 device with H.265:**
```bash
gst-video-recorder --source v4l2 --device /dev/video1 --width 1920 --height 1080 --encoder nvh265 --count 600 -o camera_h265.mp4
```

**Record at 720p resolution:**
```bash
gst-video-recorder --source v4l2 --width 1280 --height 720 --count 300 -o camera_720p.mp4
```

**Record with specific pixel format (YUYV):**
```bash
gst-video-recorder --source v4l2 --width 640 --height 480 --pixel-format YUYV --count 300 -o camera_yuyv.mp4
```

**Record with custom encoder settings:**
```bash
gst-video-recorder --source v4l2 --property bitrate=12000 --property preset=1 --count 900 -o high_quality.mp4
```

#### Pattern Generator Examples

**Record 10 seconds of animated gradient (300 frames at 30fps):**
```bash
gst-video-recorder --source pattern --count 300 -o video.mp4
```

**Record high quality H.265 video:**
```bash
gst-video-recorder --source pattern --count 300 --encoder nvh265 --property bitrate=10000 -o video.mp4
```

**Record 720p video:**
```bash
gst-video-recorder --source pattern --count 300 --width 1280 --height 720 -o video_720p.mp4
```

**Record checkerboard pattern:**
```bash
gst-video-recorder --source pattern --count 300 --pattern 1 -o checkerboard.mp4
```

**Record using host memory (CPU):**
```bash
gst-video-recorder --source pattern --count 300 --storage 0 --encoder x264 -o video.mp4
```

## Architecture

The application supports two video sources and uses a common encoding backend:

### Video Sources:
1. **V4L2VideoCaptureOp**: Captures video from V4L2-compatible cameras (USB webcams, MIPI CSI cameras, etc.)
2. **PatternGenOperator**: Generates animated test patterns as Holoscan entities with tensors

### Encoding Backend:
- **GstVideoRecorderOperator**: Receives video frames, manages the GStreamer pipeline, and handles encoding

### Pipeline Flow

**V4L2 Camera Pipeline:**
```
V4L2VideoCaptureOp → FormatConverterOp → GstVideoRecorderOperator → GStreamer Pipeline → File
```

**Pattern Generator Pipeline:**
```
PatternGenOperator → GstVideoRecorderOperator → GStreamer Pipeline → File
```

The GStreamer encoding pipeline is automatically constructed based on the encoder and file format:

- **Pipeline structure**: `[converter] ! [encoder]enc ! [parser] ! [muxer] ! filesink`
- **Converter**: Automatically selected based on memory type (videoconvert for host, cudaconvert for device)
- **Encoder**: Specified via `--encoder` option (nvh264, nvh265, x264, x265, etc.)
- **Parser**: Automatically determined from encoder (h264parse, h265parse, etc.)
- **Muxer**: Automatically determined from file extension (mp4mux for .mp4, matroskamux for .mkv)

Example pipelines:

- **NVIDIA H.264 to MP4**: `cudaconvert ! nvh264enc ! h264parse ! mp4mux ! filesink`
- **NVIDIA H.265 to MKV**: `cudaconvert ! nvh265enc ! h265parse ! matroskamux ! filesink`
- **CPU x264 to MP4**: `videoconvert ! x264enc ! h264parse ! mp4mux ! filesink`

## Performance

The application supports both host and device (CUDA) memory:

- **Device memory** (`--storage 1`, default): Zero-copy operation for better performance when using NVIDIA hardware encoders (nvh264enc, nvh265enc)
- **Host memory** (`--storage 0`): Required for CPU encoders (x264, x265) but involves memory copies

## Notes

### Video Sources

**V4L2 Camera:**
- Supports any V4L2-compatible camera (USB webcams, MIPI CSI cameras)
- Camera resolution must be explicitly specified with `--width` and `--height`
- Use `v4l2-ctl --list-formats-ext` to see supported resolutions and formats
- FormatConverterOp automatically converts camera output to the format expected by the recorder

**Pattern Generator:**
- Supports three test patterns:
- Animated gradient (default): Colorful sine wave patterns
- Animated checkerboard: Moving checkerboard with variable square size
- Color bars: SMPTE-style color bars (7 colors)
- Useful for testing the encoding pipeline without hardware dependencies

### Recording

- The application waits for encoding to complete before exiting to ensure proper file finalization
- EOS (End-Of-Stream) signal is sent automatically when recording completes
- Video parameters (width, height, format, storage) are automatically detected from incoming frames
- Frame count can be limited with `--count` or runs indefinitely if not specified


Loading