-
Notifications
You must be signed in to change notification settings - Fork 115
feat: Add GStreamer video recorder with comprehensive sample application #1243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
GilShpr
wants to merge
4
commits into
main
Choose a base branch
from
gshapira/holoscan_gstreamer_bridge
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+5,403
−0
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
7dbac57
feat: Add GStreamer video recorder with comprehensive sample application
GilShpr 5744774
refactor: split gst_video_recorder into modules and improve robustness
GilShpr 76e5bb8
refactor(gstreamer): Redesign C++ wrapper architecture with separate …
GilShpr a41dc90
gst_video_recorder: add V4L2 camera capture support
GilShpr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,7 @@ | |
| }, | ||
| "runArgs": [ | ||
| "--net=host", | ||
| "--runtime=nvidia" | ||
| //"<env>" | ||
| ], | ||
| "containerEnv": { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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) | ||
|
|
||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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] | ||
| ``` | ||
|
|
||
| ### 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 | ||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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:
There was a problem hiding this comment.
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.