Skip to content

Feature/egress h264 passthrough#1295

Open
curruwilla wants to merge 6 commits into
livekit:mainfrom
curruwilla:feature/egress-h264-passthrough
Open

Feature/egress h264 passthrough#1295
curruwilla wants to merge 6 commits into
livekit:mainfrom
curruwilla:feature/egress-h264-passthrough

Conversation

@curruwilla

Copy link
Copy Markdown

No description provided.

curruwilla and others added 2 commits July 13, 2026 13:50
Adds an enable_video_passthrough deployment flag (default false). When
set, track composite and participant egress with HLS segment output no
longer force VideoDecoding/VideoEncoding at request time: the request
becomes a pass-through candidate if it subscribes to at most one video
track and carries no video encoding options (preset or advanced).

Any file, stream, or image output, and any input codec that does not
match the output codec at subscription time, falls back to the default
decode+encode pipeline with an informative log. With the flag off,
behavior is byte-for-byte identical to before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
In pass-through mode there is no local encoder, so the GstForceKeyUnit
events emitted by splitmuxsink (send-keyframe-requests=true) at segment
boundaries died unanswered. The keyframe probe now installs an upstream
event probe on the parser src pad when video decoding is disabled and
bridges those events to the appwriter's existing PLI path, reusing its
1s throttle rather than adding a second one.

Both the event receipt and the actual PLI send are logged with
nanosecond timestamps so the egress->SFU->publisher keyframe delay can
be measured in staging.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@curruwilla curruwilla requested a review from a team as a code owner July 13, 2026 17:12
@CLAassistant

CLAassistant commented Jul 13, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

curruwilla and others added 4 commits July 13, 2026 14:24
Without a decoder, the input-selector + videotestsrc fallback does not
exist in pass-through mode: a muted or disconnected publisher stops the
buffer flow and splitmuxsink stalls, freezing the HLS playlist and the
viewer's player.

The selector machinery is now also built in pass-through mode, operating
on the encoded H.264 stream, with the videotestsrc replaced by a freeze
injector: an auxiliary appsrc that caches the last keyframe seen on the
real track and re-pushes it (2fps, do-timestamp PTS) while the fallback
pad is selected. Since every injected frame is an IDR, splitmuxsink
keeps cutting segments at the nominal duration while frozen.

Switching uses the existing mute/unmute/removed callbacks - the
appwriter's inactivity path (jitter buffer latency) already acts as the
sample watchdog, and unmute re-selects the track pad, dropping delta
frames until the PLI-requested keyframe arrives. A secondary stall
detector (2x segment duration) logs if data stops without any mute
event firing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
#EXTINF entries already carry the measured duration of each closed
fragment, so variable-length segments were mostly handled. But
EXT-X-TARGETDURATION was declared as the nominal segment duration, and
in pass-through mode real segments regularly exceed it (keyframe
boundaries depend on the publisher GOP + PLI round trip), violating the
HLS spec requirement that no segment's rounded duration exceed the
declared target.

Pass-through playlists now declare 2x the nominal duration, and any
segment that still exceeds the declared target logs a warning. Audited
remaining SegmentDuration uses: splitmuxsink max-size-time (split
threshold, intentional), x264 vbv-buf-capacity (encoder path only), and
upload queue sizing - none assume fixed real durations.

Player note documented in README: window sizing by segment count
(hls.js liveSyncDurationCount) sees slightly variable latency.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Failure-focused staging scenarios for the pass-through feature: without
a decoder there is no loss concealment, so a corrupted bitstream reaches
h264parse/mpegtsmux directly and must degrade gracefully.

- publish.sh: synthetic OBS-like publisher (pre-encoded H.264, fixed 2s
  GOP + Opus) over WHIP bypass, with pause/resume/stop for mute and
  disconnect scenarios
- egress.sh: participant egress with HLS output; --transcode adds a
  preset to force the decode+encode fallback on the same deployment
- netem.sh: port-scoped packet loss on loopback (publisher<->ingress and
  SFU<->egress legs)
- measure-cpu.sh: container + per-handler CPU sampling to CSV for the
  30-minute pass-through vs transcode comparison
- check-avsync.sh: per-segment audio/video first-PTS offset (transcoded
  audio vs pass-through video drift detection)

README maps each script to the five scenarios and their pass criteria.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants