Skip to content

Commit e2da385

Browse files
committed
Add AV1 support and runtime hardening
1 parent a6bbf87 commit e2da385

46 files changed

Lines changed: 2671 additions & 514 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
name: Bug report
3+
about: Report a runtime, build, or integration problem
4+
title: "[Bug]: "
5+
labels: bug
6+
assignees: ""
7+
---
8+
9+
## Summary
10+
11+
Describe the problem.
12+
13+
## Environment
14+
15+
- OS:
16+
- ROS distribution:
17+
- GStreamer version:
18+
- Host platform:
19+
- Camera source:
20+
21+
## Command
22+
23+
```bash
24+
25+
```
26+
27+
## Expected Behavior
28+
29+
Describe what should happen.
30+
31+
## Actual Behavior
32+
33+
Describe what happened.
34+
35+
## Runtime Evidence
36+
37+
```bash
38+
ros2 topic echo /gst_video_bridge/runtime_status --once
39+
ros2 topic echo /gst_video_bridge/runtime_events --once
40+
```
41+
42+
Paste relevant output here.
43+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
name: Platform validation
3+
about: Record a tested host/camera/codec/transport combination
4+
title: "[Platform]: "
5+
labels: validation
6+
assignees: ""
7+
---
8+
9+
## Platform
10+
11+
- Host:
12+
- OS / kernel:
13+
- ROS distribution:
14+
- GStreamer version:
15+
16+
## Camera
17+
18+
- Model:
19+
- Connection:
20+
- ROS image topic:
21+
- Encoding:
22+
- Resolution / FPS:
23+
24+
## Bridge Configuration
25+
26+
- Machine profile:
27+
- Stream profile:
28+
- Codec:
29+
- Encoder:
30+
- Transport:
31+
- Sink URI:
32+
33+
## Result
34+
35+
- Duration:
36+
- `fps_in`:
37+
- `fps_out`:
38+
- `dropped_total`:
39+
- `dropped_backpressure_total`:
40+
- `reconnect_count`:
41+
- Receiver validation:
42+
43+
## Notes
44+
45+
Add platform-specific notes or caveats.
46+

.github/workflows/ci.yml

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,25 @@ on:
88
- cron: "0 3 * * *"
99

1010
jobs:
11+
clang-format-check:
12+
runs-on: ubuntu-22.04
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
17+
- name: Install clang-format-15
18+
run: |
19+
sudo apt-get update
20+
sudo apt-get install -y clang-format-15
21+
22+
- name: Check formatting
23+
run: |
24+
find ros2_gst_video_bridge/include ros2_gst_video_bridge/src \
25+
\( -name '*.hpp' -o -name '*.cc' \) | \
26+
xargs clang-format-15 --dry-run --Werror
27+
1128
build-and-test:
29+
needs: clang-format-check
1230
runs-on: ubuntu-22.04
1331
steps:
1432
- name: Checkout
@@ -25,8 +43,11 @@ jobs:
2543
run: |
2644
sudo apt-get update
2745
sudo apt-get install -y \
46+
gstreamer1.0-tools \
2847
gstreamer1.0-plugins-base \
2948
gstreamer1.0-plugins-good \
49+
gstreamer1.0-plugins-bad \
50+
gstreamer1.0-libav \
3051
libgstreamer1.0-dev \
3152
libgstreamer-plugins-base1.0-dev
3253
@@ -35,11 +56,7 @@ jobs:
3556
run: |
3657
source /opt/ros/humble/setup.bash
3758
colcon build \
38-
--packages-select ros2_gst_video_bridge_msgs \
39-
--event-handlers console_direct+
40-
source install/setup.bash
41-
colcon build \
42-
--packages-select ros2_gst_video_bridge \
59+
--packages-up-to ros2_gst_video_bridge \
4360
--event-handlers console_direct+ \
4461
--cmake-args \
4562
-DROS2_GST_VIDEO_BRIDGE_ENABLE_CLANG_TIDY=OFF \
@@ -55,6 +72,23 @@ jobs:
5572
--event-handlers console_direct+
5673
colcon test-result --all --verbose
5774
75+
- name: Resilience preflight smoke
76+
working-directory: ws
77+
run: |
78+
source /opt/ros/humble/setup.bash
79+
source install/setup.bash
80+
build/ros2_gst_video_bridge/gst_video_bridge_node \
81+
--ros-args \
82+
-p runtime.mode:=validate_config \
83+
-p codec.name:=h264 \
84+
-p codec.encoder:=definitely_missing_encoder
85+
86+
build/ros2_gst_video_bridge/gst_video_bridge_node \
87+
--ros-args \
88+
-p runtime.mode:=validate_config \
89+
-p transport.kind:=rtsp \
90+
-p transport.sink_uri:=rtsp://127.0.0.1:8554/live
91+
5892
nightly-matrix:
5993
if: github.event_name == 'schedule'
6094
runs-on: ubuntu-22.04
@@ -73,8 +107,11 @@ jobs:
73107
run: |
74108
sudo apt-get update
75109
sudo apt-get install -y \
110+
gstreamer1.0-tools \
76111
gstreamer1.0-plugins-base \
77112
gstreamer1.0-plugins-good \
113+
gstreamer1.0-plugins-bad \
114+
gstreamer1.0-libav \
78115
libgstreamer1.0-dev \
79116
libgstreamer-plugins-base1.0-dev
80117
@@ -83,11 +120,7 @@ jobs:
83120
run: |
84121
source /opt/ros/humble/setup.bash
85122
colcon build \
86-
--packages-select ros2_gst_video_bridge_msgs \
87-
--event-handlers console_direct+
88-
source install/setup.bash
89-
colcon build \
90-
--packages-select ros2_gst_video_bridge \
123+
--packages-up-to ros2_gst_video_bridge \
91124
--event-handlers console_direct+ \
92125
--cmake-args \
93126
-DROS2_GST_VIDEO_BRIDGE_ENABLE_CLANG_TIDY=OFF \

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
build/
33
install/
44
log/
5+
*.stale.*/
56

67
# Python
78
__pycache__/
@@ -21,5 +22,8 @@ compile_commands.json
2122
*.swp
2223
*~
2324

24-
# Local planning
25+
# Local planning scratch files — never commit
2526
TODO.md
27+
TODO2.md
28+
TODO*.md
29+
TODO.local.md

CHANGELOG.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Changelog
2+
3+
All notable changes to this project are documented here.
4+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5+
Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6+
7+
---
8+
9+
## [Unreleased] — pre-release, branch `ft/1stversion_w_srt`
10+
11+
### Added
12+
13+
**Node architecture**
14+
- Modular node split: `src/node/` with one file per responsibility (`core`, `lifecycle`, `modes`, `streaming`, `recovery`, `fallback`, `observability`). Each file stays under 300 lines.
15+
- Separate `src/core/` (config loading and pipeline building) and `src/runtime/` (capability probe, stream engine, metrics, image format, topic introspector) layers.
16+
17+
**Codec & encoder selection**
18+
- `codec.name:=auto` resolves the best available codec and encoder using `gst-inspect-1.0` output, scored by machine profile (`jetson`, `x86`, `raspi`, `generic`).
19+
- Machine profile auto-detection from host CPU architecture when `profile.machine` is left as `generic`.
20+
- Hardware-to-software encoder fallback after configurable consecutive failures (`runtime.hw_fallback_failures`, default 3).
21+
22+
**Transport × codec pipeline matrix**
23+
- Full support for `h264`, `h265`, `mjpeg` codecs across `srt`, `udp`, `rtsp`, `file` sinks.
24+
- Jetson NVMM path for `nvv4l2h264enc` / `nvv4l2h265enc` (CPU → I420 → nvvidconv → NVMM → encoder).
25+
- Software-only path for `x264enc`, `x265enc`, `jpegenc`, `openh264enc`.
26+
27+
**Image format support**
28+
- BGR8, RGB8, BGRA8, RGBA8, MONO8, MONO16 (`GRAY16_LE`).
29+
- Bayer 8-bit and 16-bit encodings streamed as grayscale fallback with a throttled warning to use `image_proc/debayer` for colour output.
30+
- `validateImageShape` validates width × height × step × data-size consistency before pushing frames.
31+
32+
**Adaptive resilience**
33+
- Three-level bitrate/fps/gop adaptation loop (levels 0–2) triggered by `Degraded` / `Reconnecting` state transitions and recovered during sustained `Streaming`.
34+
- Three adaptation profiles: `conservative`, `balanced`, `aggressive`.
35+
- Configurable interval and cooldown (`runtime.adaptation.interval_ms`, `runtime.adaptation.cooldown_ms`).
36+
- Pipeline reconfigure on adaptation policy change (stops/rebuilds engine with updated parameters).
37+
38+
**Observability**
39+
- `~/runtime_status` (`ros2_gst_video_bridge_msgs/msg/RuntimeStatus`): typed status at 1 Hz including fps_in/fps_out, drop counters split by throttle/malformed/backpressure, reconnect count, latency EWMA, push latency estimate + observed max, adaptation profile/level, and codec/encoder/fallback flags.
40+
- `~/runtime_events` (`ros2_gst_video_bridge_msgs/msg/RuntimeEvent`): asynchronous events for `PIPELINE_STARTED`, `PIPELINE_DEGRADED`, `RECONNECT_FAILED`, `ADAPTATION_APPLIED`, `ENCODER_FALLBACK_SW`, `FIRST_FAILURE_SNAPSHOT`, `OPERATOR_PROFILE_UPDATE`, and others.
41+
- `~/runtime_metrics` (`std_msgs/msg/String`): backward-compatible legacy key=value string.
42+
- `~/set_streaming_profile` (`ros2_gst_video_bridge_msgs/srv/SetStreamingProfile`): operator service to switch adaptation profile and optionally reset all counters at runtime.
43+
- `FIRST_FAILURE_SNAPSHOT` event captures session ID, stream ID, codec, encoder, transport, sink URI, SW-fallback flag, and full effective pipeline on the first streaming failure.
44+
- Session ID (UUID-like) and stream ID are tracked across all events and status messages.
45+
46+
**Runtime modes**
47+
- `stream` (default): run the bridge.
48+
- `list_topics`: print visible `sensor_msgs/msg/Image` topics and exit.
49+
- `list_capabilities`: run `gst-inspect-1.0` and report detected plugins, encoders, and sinks.
50+
- `validate_config`: validate parameters and exit with code 0 (valid) or 1 (invalid).
51+
- `discover`: combines `list_topics` + `list_capabilities`.
52+
53+
**Reconnect**
54+
- Automatic reconnect with configurable interval and optional maximum attempt limit.
55+
- SW-fallback is attempted on reconnect if HW encoder has failed repeatedly.
56+
- `pipeline_reconfigure_requested_` flag ensures a new `StreamEngine` is created with the updated pipeline after adaptation or fallback.
57+
58+
**Launch files**
59+
- `gst_video_bridge_minimal.launch.py`: essential arguments only.
60+
- `gst_video_bridge_advanced.launch.py`: full parameter surface + `params_file` support.
61+
- `gst_video_bridge.launch.py`: compatibility wrapper.
62+
- All launches support optional `image_proc/debayer` node via `enable_debayer` argument.
63+
64+
**Profile presets**
65+
- Machine profiles: `jetson`, `x86`, `raspi`, `generic`.
66+
- Stream profiles: `default`, `low_latency`, `low_bandwidth`, `high_quality`, `monitoring_udp`.
67+
- Seven curated YAML profile files under `config/profiles/`.
68+
69+
**Testing**
70+
- `test_config_loader`: profile defaults, invalid mode rejection, alias precedence (4 tests).
71+
- `test_pipeline_builder`: SRT/UDP h264, HW encoder (Jetson nvv4l2), h265 × 4 transports, mjpeg × 4 transports (5 tests).
72+
- `test_image_format`: shape validation, unsupported encoding, invalid step, truncated data, Bayer grayscale fallback (5 tests).
73+
- `test_stream_engine`: synthetic frame pushed through `appsrc → fakesink` pipeline (1 test).
74+
- `test_detail_utils`: `startsWith`, `extractElementName`, `selectSoftwareEncoderForCodec`, `computeAdaptationScales` — 18 cases covering all profiles and edge conditions.
75+
- `test_metrics_publisher`: counter accumulation, state reflection, adaptation/encoding metadata in published `RuntimeStatus` (9 tests).
76+
- Smoke tests: `validate_config`, `list_capabilities`, and `--show-args` for all three launch files.
77+
- Total: **11 CTest entries** (6 gtest targets + 5 smoke tests), **42 individual test cases**.
78+
79+
**Tooling**
80+
- `clang-format-15` with `.clang-format` (LLVM style, 100-column limit, C++17).
81+
- `clang-tidy-15` with `.clang-tidy` (bugprone, performance, readability, modernize, cppcoreguidelines checks).
82+
- Both tools discovered by versioned binary names in `CMakeLists.txt`; build continues gracefully if not found.
83+
- CI (`build-and-test` + `nightly-matrix`) on Ubuntu 22.04 / ROS 2 Humble.
84+
- CI `clang-format-check` job runs `--dry-run --Werror` on all headers and sources.
85+
- Codec/transport matrix script (`run_transport_codec_matrix.zsh`) and soak script (`run_soak_profile.zsh`).
86+
87+
**Documentation**
88+
- `docs/CONTROL_PLANE.md`: topic/service contract reference.
89+
- `docs/DEPENDENCIES.md`: required and optional apt packages, plugin checks.
90+
- `docs/PLATFORM_MATRIX.md`: tested hardware/OS/ROS combinations.
91+
- `docs/TROUBLESHOOTING.md`: common failure modes with diagnosis and recovery steps.
92+
- `README.md`: full parameter reference tables with types, defaults, and descriptions.
93+
- `CONTRIBUTING.md`: development setup, coding conventions, test requirements, PR checklist.
94+
95+
### Changed
96+
97+
- `appsrc` configured as non-blocking (`block=false`) with a bounded 2-buffer internal queue and upstream leaky policy; back-pressure drops are counted separately and do not cause a reconnect when the queue is the only error.
98+
- `busLoop` switched from a 100 ms blocking `gst_bus_timed_pop_filtered` call (held mutex) to a non-blocking poll + 10 ms sleep, eliminating push stalls under high frame rates.
99+
- Modern `transport.*`, `codec.*`, `runtime.*` parameter names always override legacy `gst.*` aliases when both are set.
100+
- CI checkout uses `path: ws/src/ros2_gst_video_bridge` matching a real colcon workspace layout.
101+
- Internal duplicate utility functions (`startsWith`, `extractElementName`) extracted to `detail/string_utils.hpp`; adaptation scaling extracted to `detail/adaptation.hpp`; SW encoder selection to `detail/encoder_selection.hpp`.
102+
103+
### Fixed
104+
105+
- `busLoop` mutex stall: the bus thread no longer holds `mutex_` during a potentially blocking GStreamer poll.
106+
- `buildLegacyPayload` now correctly declared and defined as `static`.
107+
- Redundant `encoder{""}` default initializer removed from `CodecConfig`.
108+
- `.gitignore` extended to exclude `TODO*.md` patterns.
109+
110+
### Verified
111+
112+
- Jetson Orin / aarch64, Linux 5.15.148-tegra, ROS Humble, GStreamer 1.20.x.
113+
- Basler acA2440-35uc USB3 camera at ~30 Hz BayerRG8.
114+
- MPEG-TS/H.264 file sink validated end-to-end.
115+
- All 11 CTest tests pass on the Jetson build.
116+
- `clang-format` check passes on all headers and sources.
117+
118+
---
119+
120+
## [0.1.0] — First tagged release (pending)
121+
122+
_See Unreleased above. This section will be finalised when the first annotated tag is created._
123+

0 commit comments

Comments
 (0)