Repository navigation
video_stage: PC worker that forwards Orin cameras to LiveKit over a direct link - #1443
Open
gareth-morgan-nv wants to merge 23 commits into
Open
gareth-morgan-nv wants to merge 23 commits into
gareth-morgan-nv wants to merge 23 commits into
Conversation
Contributor
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the
|
gareth-morgan-nv
force-pushed
the
gmorgan/TimestampAlignment
branch
2 times, most recently
from
November 6, 2026 05:39
b7d8f99 to
be24085
Compare
gareth-morgan-nv
force-pushed
the
gmorgan/VideoStage
branch
from
November 6, 2026 05:39
396d6e0 to
29c8b08
Compare
gareth-morgan-nv
force-pushed
the
gmorgan/TimestampAlignment
branch
from
November 6, 2026 05:42
be24085 to
fbdc7e3
Compare
gareth-morgan-nv
force-pushed
the
gmorgan/VideoStage
branch
2 times, most recently
from
November 6, 2026 16:58
27a09c5 to
15bfa3f
Compare
gareth-morgan-nv
force-pushed
the
gmorgan/TimestampAlignment
branch
from
November 6, 2026 18:04
c6f0635 to
d9d408f
Compare
gareth-morgan-nv
force-pushed
the
gmorgan/VideoStage
branch
from
November 6, 2026 18:04
d2827f7 to
abbb6ef
Compare
gareth-morgan-nv
force-pushed
the
gmorgan/TimestampAlignment
branch
from
November 6, 2026 20:31
d9d408f to
0dc1c08
Compare
gareth-morgan-nv
force-pushed
the
gmorgan/VideoStage
branch
from
November 6, 2026 20:32
abbb6ef to
f3b76d9
Compare
…xample sine warp and NVENC A worker receives H.264 access units over TCP in the repository's AVS1 wire format (codec 2 added for H.264), decodes on NVDEC into device memory, applies a GpuOperation (an example sine-wave warp that Part 2 replaces with fisheye rectification), and re-encodes on NVENC with low-latency settings. Frame identity travels by key through decode and encode. Tests cover the warp on a GPU and the wire codec. Measured on one RTX PRO 5000 at 2560x1984, 30 fps, local loopback: decode p50 1.5 ms, warp+encode p50 ~4 ms, receive-to-output p50 ~5.5 ms. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…exchange and control The worker serves one Orin session per configured camera (--stream=PORT:TRACK), all tracks published under one LiveKit participant, each with its own receiver, control channel (keyframe requests and a four-timestamp clock exchange whose replies are matched to outstanding requests), NVDEC -> GPU operation -> NVENC pipeline and bounded intake queue. Orin stamps are converted onto the PC monotonic clock before publication; frames are withheld when the mapping is missing or worse than the budget, and a clock jump unpublishes the track. The LiveKit publisher library moves to src/livekit_publisher; the Orin producer gets a per-stream direct= destination. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
A new Orin session unpublishes the previous publication, resets frame numbering and starts the encoder at an IDR, and its control channel gets an epoch that is never reused across sessions. The DATA/CTRL hello is read with a timeout on a socket a stop can reach, so a half-open peer cannot block shutdown. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…ct sender Replaces the simple replay script. It mirrors DirectSender and its feed: Jetson-style H.264 (no AUDs, IDR every 5 s, constant bitrate), frame ids stepping by 2, an offset and drifting Orin clock, DATA then CTRL hellos with retry, a bounded queue that drops to the next keyframe, keyframe requests, and clock answers stamped on arrival. The worker now counts a frame-number gap only when the id does not increase. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
The first failed connection and then one every 30 s are logged with the reason, so a producer that cannot connect is distinguishable from one that never tried. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…rt where latency goes The sender drops a queue whose oldest unit has waited more than 250 ms and resumes at a keyframe, keeps its kernel send buffer small so a backlog stays visible, and both ends notice a dead link in seconds. The worker prints live percentiles every few seconds, including Orin frame-ready to PC arrival and to publication. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…t publish Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
… lag in frames The real Orin stream makes NVDEC hold back about nine pictures (about 300 ms at 30 fps) because its sequence header does not state that pictures are never reordered. The worker now logs the source's SPS and, for a source whose contract is no B-frames, rewrites the SPS to declare bitstream_restriction with no reordering before decoding. The decode timer now uses each picture's own submission time, and the decoder lag is reported in frames. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…g rewrite Embedded SPS bytes from x264 (with and without B-frames, baseline and high, with CBR HRD, full range) and NVENC check every parsed field, that the rewrite changes only the reordering declaration, that the rest of the access unit is untouched, and that it is idempotent and handles emulation prevention and truncated input. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
The default operation is none: no decode, no GPU, no re-encode, so latency is the Orin, the link and LiveKit only, with no quality loss. --operation=sine-warp enables the example GPU stage. The CUDA context is created only when an operation needs it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
DirectSender: connect is non-blocking and polled so a stop request is noticed within 100 ms, TCP_USER_TIMEOUT is set before connect, and the destructor shuts down any socket the worker thread is blocked on. Add a test that bounds destruction time for a stalled connect, a blocked send and an idle link. Mock sender: per-camera frame cursors, per-camera keyframe requests, and a stop() that cancels blocked sockets and fails loudly if the thread is stuck. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
… SDK block The SDK block lives in src/livekit_publisher; the stray marker broke configure. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
The producer no longer exits when a camera cannot start: it reports a plain message (for example an unpowered camera), retries, and keeps a WebSocket management channel up. Clients with the shared token can read the status and change where a stream's direct link sends its video; every bad request gets an error reply. The direct sender moves to its own library so a mock producer can run the same channel, supervisor and sender over looped H.264 files. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…ct-link errors A fault table covers the producer's own failures (camera power and link, Argus service, GPU mapping, encoder, LiveKit) and the capture driver's log lines, which are collected while the cameras start and attached to the failure. SIPL notifications are decoded by kind; repeated capture timeouts or sensor-control failures and a stream with no new frame for 5 s fail the session so it restarts. A direct link that cannot reach the PC is reported with its reason in the status and as a one-time error event. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…eKit on the Orin camera_plugin_sensing no longer links or uses LiveKit: the video output encodes and hands units to the direct sender, and the PC video stage publishes to LiveKit. The wire library gains the encoded-frame type and the clock-sync messages that both sides share, and the LiveKit publisher builds only with the video stage. Options are --fps, --bitrate and --scale-div; a stream is sensor=N,name=NAME[,direct=HOST:PORT]. Also: benign I2C NACK lines no longer read as a camera fault, and SIPL status codes are named in errors. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…ate the plugin description Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
… space forced keyframes and follow the link The worker no longer unpublishes a track because the Orin-to-PC clock mapping is missing or over budget: frames are published without a capture timestamp, so a viewer keeps its last picture and a recording that needs a timestamp says so. The producer spaces forced keyframes at least a second apart and lowers its video bitrate while the direct link has to drop frames, raising it again after a calm stretch. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…d timestamps The management server is stopped before the objects its thread calls into. One thread owns the camera session; the channel only records a destination change and the owner applies it before the next frame, including one made while the cameras were starting. The producer accepts only monotonic timestamp bases. The PC receiver guards its session descriptors with one lock, and the worker's counters are atomic. The control server bounds its reads, work per round and output, and tracks fragmentation. A new source session rebuilds the decoder and clears the identity ring. Non-default chroma siting is refused, and a downstream bitrate request is logged once. Stale LiveKit fault text is removed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
…FIFO order The Jetson encoder numbers units from its own frame clock unless asked to copy input timestamps, so FIFO order is not frame identity. Ask the driver to copy them, match units by stamp, count skipped inputs, and send an unmatched unit without a capture time. --frame-correlation=fifo keeps the approximate mode as an explicit choice. The bitrate controller no longer treats an unconnected link as congestion. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
gareth-morgan-nv
force-pushed
the
gmorgan/TimestampAlignment
branch
from
November 6, 2026 22:37
0dc1c08 to
30c47c3
Compare
gareth-morgan-nv
force-pushed
the
gmorgan/VideoStage
branch
from
November 6, 2026 22:37
f3b76d9 to
3f51c5b
Compare
This branch has not been deployed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
The Orin camera producer sends H.264 straight to a PC worker over a direct link, with no LiveKit on the Orin; the PC worker publishes to LiveKit so the egocap consumers (backend, recorder, page) are unchanged. Also adds a management channel and fault diagnosis to the producer, and a mock producer for testing without cameras.
Orin to PC link
DirectSendersends AVS1 H.264 records over a DATA connection and exchanges keyframe requests and a four-timestamp clock exchange over a CTRL connection. It has a bounded queue (size and age), reconnects, and shuts down promptly.--frame-correlation=fifokeeps an approximate in-order mode as an explicit choice.PC worker (
video_stage_worker)--operation=sine-warpruns NVDEC, an example GPU operation and NVENC; a VUI-less Orin stream's SPS is rewritten to declare no reordering.--max-upstream-uncertainty-ms, or the record has no source stamp, the frame is published without a capture timestamp and counted. A session reset rebuilds the decoder; a stream with non-default chroma siting is refused.Management channel and fault diagnosis (producer)
--control-token-file, off by default; port 5610) withget_status,set_direct_targetandping, plustools/orin_control.py. One thread owns the camera session; retargets are recorded and applied by that thread.sensing_mock_producerruns the same server, handler, supervisor andDirectSenderover looped H.264 files.Measurements (real Orin, Wi-Fi, two cameras)
Orin-to-publish p50 about 45-78 ms on a good link; clock mapping within about 4.5 ms. On a loaded Wi-Fi link round trips reached 150-300 ms, which is what produced mapping outside the budget; those frames now flow without timestamps instead of being dropped. With the timestamp copy enabled, the Orin reported every unit matched and none skipped. These are not webpage latency.
Validation
DirectSender, and the control server/handler/supervisor (the control server under sanitizers); a mock-producer end-to-end test; pre-commit. These were last run before the final encoder edit, which cannot be built on the PC.stamps matched N, unmatched 0, encoder skipped 0.sine-warpmode in this revision; the management channel against a real client over a long session.Base is
gmorgan/TimestampAlignment.🤖 Generated with Claude Code