Skip to content

Stop rewriting H264 profile-level-id to 42e032#1006

Draft
pblazej wants to merge 2 commits into
mainfrom
blaze/h264-accel
Draft

Stop rewriting H264 profile-level-id to 42e032#1006
pblazej wants to merge 2 commits into
mainfrom
blaze/h264-accel

Conversation

@pblazej
Copy link
Copy Markdown
Contributor

@pblazej pblazej commented May 13, 2026

Removes the rewriteCodecsIfNeeded() mutation in RTC.swift that forced every H264 entry to profile-level-id=42e032. The override was added in #147 to work around upstream WebRTC pinning ConstrainedHigh at Level 3.1 (issue #144); modern WebRTC now publishes ConstrainedHigh at the device's actual max via UIDevice+H264Profile.mm, making the rewrite obsolete. On iOS 26 the rewrite is also actively harmful — combined with EnableLowLatencyRateControl, an explicit Baseline ProfileLevel disables HW acceleration in VideoToolbox (#1002).

Companion upstream patch in livekit/webrtc (branch blaze/h264-accel) gates EnableLowLatencyRateControl on the High-profile family so the dual-profile advertisement enabled here works end-to-end: ConstrainedHigh negotiations take the LL HW path; ConstrainedBaseline takes the plain HW path.

Fixes #1002. Related: #144, #147, #118.

The encoder/decoder/simulcast factories were collapsing every H264
codec entry to a single ConstrainedBaseline Level 5.0
(profile-level-id=42e032). On iOS 26.3 VideoToolbox refuses hardware
acceleration when only ConstrainedBaseline is on offer, dropping
H264 simulcast publishers onto the software encoder and saturating
~5 cores (see #1002).

The workaround was originally added for macOS in #118 and extended
to iOS in #147 to fix 1080p simulcast failing on iOS — at the time
upstream WebRTC pinned ConstrainedHigh at Level 3.1, too low for
1080p sources. Modern WebRTC consults a per-device profile table
(UIDevice+H264Profile.mm) and publishes ConstrainedHigh at the
device's actual max level (5.2 on iPhone 13 Pro+), so the override
is now actively harmful.

Drop the rewrite, keep the factory subclasses as @unchecked Sendable
shims, and add a regression test that asserts both ConstrainedHigh
(640c…) and ConstrainedBaseline (42e0…) profiles are exposed with
a level ≥ 3.1 floor.

Fixes #1002.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pblazej pblazej marked this pull request as draft May 13, 2026 07:44
@pblazej pblazej force-pushed the blaze/h264-accel branch from 880040b to 6fab667 Compare May 13, 2026 08:38
@pblazej pblazej marked this pull request as ready for review May 14, 2026 09:57
@pblazej pblazej marked this pull request as draft May 14, 2026 09:57
@pblazej pblazej force-pushed the blaze/h264-accel branch from 6fab667 to 18c200e Compare May 28, 2026 09:45
`set(preferredVideoCodec:)` used `first { name == codec.name }` which was
fine when each codec name had exactly one capability entry. With the H264
factory rewrite removed (previous commit), upstream WebRTC exposes two
H264 entries — ConstrainedHigh and ConstrainedBaseline — and the
single-pick logic dropped the second one, leaving only ConstrainedHigh
in the SDP offer. LiveKit Cloud's H264 negotiation rejected that and
answered with no H264 at all, falling the publisher back to VP8.

Filter all capabilities matching the preferred codec name and keep them
together at the front of `setCodecPreferences`, mirroring the upstream
intent (and Android's sort-based approach).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@pblazej pblazej force-pushed the blaze/h264-accel branch 2 times, most recently from 18c200e to 88a81f4 Compare May 28, 2026 10:01
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.

Forcing all H264 codecs to ConstrainedBaseline (profile-level-id=42e032) causes VideoToolbox to reject hardware encoding on iOS

1 participant