Converting a GStreamer buffer PTS plus base_time into a std::chrono::steady_clock time point

From GStreamer PTS to std::chrono::steady_clock

A buffer’s PTS is running time, not wall time. Add the pipeline’s base time and you get the clock time the frame was captured at. With the monotonic system clock that is a std::chrono::steady_clock time point you can compare to IMU or telemetry timestamps directly.

October 20, 2026 · 7 min · Pavel Guzenfeld
Measuring GStreamer latency to an intermediate checkpoint with the latency tracer and a decoupled tee tap

GStreamer Latency to a Midpoint, Not Just the Sink

The latency tracer measures source to sink. To measure source to some point in the middle, hang a fakesink off a tee. Without queues on both branches the slow branch leaks into your number, or hangs the pipeline. Measured on GStreamer 1.24 in Docker.

October 20, 2026 · 7 min · Pavel Guzenfeld
Same-host ROS 2 Jazzy latency for 1 KB to 4 MB messages: Fast DDS UDP, SHM and data-sharing vs Cyclone DDS with iceoryx

ROS 2 Shared Memory, Measured: Fast DDS SHM and Data-Sharing vs Cyclone DDS + iceoryx

I benchmarked same-host ROS 2 Jazzy pub/sub latency for 1 KB, 1 MB and 4 MB messages across six transport setups. Cyclone DDS + iceoryx with loaned messages moved 4 MB at an 83 µs median. Getting there took two settings nobody turns on by default, and the Fast DDS defaults fall over above 512 KB.

October 20, 2026 · 12 min · Pavel Guzenfeld
The Road to Boost.SML 1.2.0

The Road to Boost.SML 1.2.0: New API and a Type-Name Heisenbug

A warts-and-all account of cutting the Boost.SML 1.2.0 release — four new public APIs, a behavior change rooted in undefined behavior, a type-name Heisenbug that only fired on GCC and MSVC, a dead “Run” button, and the surprisingly deep rabbit hole of making 30 Compiler Explorer links that actually work.

June 1, 2026 · 14 min · Pavel Guzenfeld
Hunting an undocumented AHRS on the serial bus

Which tty Is the AHRS? Hunting an Undocumented Serial Device on a Jetson

A small AHRS was wired to a Jetson over USB, but nobody wrote down which serial port. Here’s how I tracked it down by its protocol instead of its name, fell into the classic dialout permissions trap, and decoded its orientation stream into human-readable numbers.

June 1, 2026 · 12 min · Pavel Guzenfeld
H.264 vs H.265 vs AV1 end-to-end latency on Jetson Orin — grouped bar chart

H.264, H.265, and AV1 on Jetson Orin: A Real Hardware Latency Benchmark

A rigorous per-stage latency benchmark across H.264, H.265, and AV1 hardware codecs on NVIDIA Jetson Orin (JetPack 6), measuring encode, wire, and decode separately at FHD and HD resolutions. AV1 wins end-to-end at 104 ms FHD / 86 ms HD. H.264 is the worst choice despite being the oldest: its nvv4l2decoder holds ~4 frames in an internal DPB buffer, adding 130–170 ms of hidden latency. Wire latency is governed by parse-element lookahead, not byte volume. Clock sync achieves ±234 µs via chrony. Full pipeline source, CSVs, and reproduction steps included.

May 12, 2026 · 33 min · Pavel Guzenfeld
Cleaning Up, Pipelining, and Bake-Testing the STM32H750 Tracker

Cleaning Up, Pipelining, and Bake-Testing the STM32H750 Tracker

A sequel to the first STM32H750 tracker post. After the C++ port was proven in production, I spent a week of evenings cutting dead vendor code, splitting the algorithm out to host for unit tests, wiring the LCD SPI through DMA to let the CPU run the tracker in parallel with the blit, unlocking the camera’s real frame rate, chasing a subtle BB-drift bug back to a too-wide SAD search, and finally building an offline A/B harness that compares SAD, NCC, and MOSSE on four synthetic scenarios so the next tracker port is a data decision, not a vibes one.

April 23, 2026 · 18 min · Pavel Guzenfeld
Building a Template-Matching Tracker on an STM32H750

Building a Template-Matching Tracker on an STM32H750: What Worked, What Didn't

A long, honest retrospective on turning a WeAct STM32H750 board, a cheap OV7725 IR camera, and an Xbox controller into a live template-matching tracker. Every dead end, every wrong assumption, every fix — and what I’d do differently next time.

April 21, 2026 · 23 min · Pavel Guzenfeld
O3DE multi-camera rendering performance analysis

Chasing 18 Milliseconds: A Performance Deep Dive into O3DE's Render Readback Pipeline

We spent a full session systematically profiling O3DE’s multi-camera streaming pipeline, testing eight different optimization approaches, and pinpointed the exact bottleneck: 18 ms of fixed overhead in the AttachmentReadback scope system. Here’s what we tried, what we measured, and what it means for the engine.

April 17, 2026 · 7 min · Pavel Guzenfeld
Three live Godot camera streams over RTP/UDP rendered by GStreamer clients

From Unity to Godot: Multi-Camera Streaming at 50 FPS with Async GPU Readback

After O3DE’s 18 ms frame-graph readback made 30 FPS streaming impossible, we tried Godot. It got us there — eventually. This is the full path from 105 FPS on nothing to 50 FPS per camera with three live RTP streams, including every wrong turn and every underdocumented Godot behavior we hit on the way.

April 17, 2026 · 12 min · Pavel Guzenfeld