Fix initial video quality blurriness for all codecs - #1197
Merged
xianshijing-lk merged 6 commits intoJun 30, 2026
Merged
xianshijing-lk merged 6 commits into
xianshijing-lk merged 6 commits into
Conversation
Contributor
ChangesetThe following package versions will be affected by this PR:
|
cloudwebrtc
approved these changes
Jun 29, 2026
xianshijing-lk
requested review from
MaxHeimbrock,
alan-george-lk and
stephen-derosa
as code owners
June 29, 2026 07:56
lukasIO
reviewed
Jun 29, 2026
xianshijing-lk
force-pushed
the
sxian/CLT-3068/fix-initial-video-quality-blurriness-by-setting-x-google-start-bitrate
branch
from
June 29, 2026 10:09
bf4b429 to
ac2f359
Compare
xianshijing-lk
deleted the
sxian/CLT-3068/fix-initial-video-quality-blurriness-by-setting-x-google-start-bitrate
branch
June 30, 2026 02:27
sionzee
added a commit
to evobug-com/rust-sdks
that referenced
this pull request
Jul 5, 2026
- drop 2 Mbps screenshare min_bitrate floor: exceeds preset max_bitrate (INVALID_RANGE, publish fails); upstream livekit#1197 covers the localhost blurriness it worked around - revert H265 Main10/HDR VUI to Main profile: bitstream broke Main-only decoders and mismatched SDP-negotiated profile - update frameRateNum before VBV sizing in SetRates (h264+h265) - delay-load nvcuda.dll/nvcuvid.dll so non-NVIDIA Windows hosts fall back to software codecs instead of failing at load - fix vcvarsall import: raw_arg quoting, verify vars parsed - warn when CUDA present but nvenc-linux feature disabled - clamp min/max_bitrate u64->i32 casts to i32::MAX - sync-upstream.yml: add contents:write, pre-push sanity gate, note cron requires file on default branch - remove dead nvidia_factory_bridge.{cpp,h}
sergeyphi
added a commit
to sergeyphi/client-sdk-swift
that referenced
this pull request
Sep 12, 2026
…-bitrate libwebrtc starts every new video send stream at roughly 300 kbps and ramps up from there regardless of the encodings' maxBitrate, so the first seconds of a published track are visibly blurry (measured: QP 39-42 for ~12 s, the 2.3 Mbps ceiling reached only after ~30 s on a healthy network). Match what client-sdk-js (livekit/client-sdk-js#1987) and rust-sdks (livekit/rust-sdks#1197, #1226) already do: when a video sender is added, derive a start bitrate from its encodings — the sum of the active layers' maxBitrate, times 0.9, capped at 1 Mbps unless the track is a screen share, and no hint under 300 kbps — and declare `x-google-start-bitrate=<kbps>` on every video codec's fmtp (VP8/VP9/AV1/H264/H265) of that sender's section in the publisher's offer, matched through the `a=msid` track id. Not opt-in and no public API, as in the sibling SDKs. - `SDPMediaSection.setFmtpParameter(_:value:forPayload:)`: replaces an existing value, appends to an existing fmtp line, or inserts one for payloads that have none (VP8), keeping every other parameter verbatim. - `Transport.startBitrateKbps(targetBps:isScreenShare:)` / `startBitrateKbps(for:isScreenShare:)`: the shared formula. - `Transport.mungeVideoStartBitrate(_:kbpsBySenderId:)`, appended as the last (optional) munge of `set(localDescription:munging:)` (livekit#1068) in both single- and dual-PC negotiation, on the SDP module from livekit#1078. - `Transport.addTransceiver(with:transceiverInit:startBitrateKbps:)` records the hint against the new sender before returning, so the offer libwebrtc requests in response cannot be created without it; `remove(track:)` clears it. Both `LocalParticipant` video publish paths (primary and backup codec) pass the derived value. Tests: the formula, the encodings sum, the per-sender munge (codec case, replace/append/insert, rtx/audio/unmapped sections untouched, no-op identity), `setFmtpParameter`, and — against the shipped libwebrtc — that a send-only video section's msid carries the sender id and that the munged offer is accepted by `setLocalDescription` rather than rejected as disallowed munging. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
sergeyphi
added a commit
to sergeyphi/client-sdk-swift
that referenced
this pull request
Sep 12, 2026
…-bitrate libwebrtc starts every new video send stream at roughly 300 kbps and ramps up from there regardless of the encodings' maxBitrate, so the first seconds of a published track are visibly blurry (measured: QP 39-42 for ~12 s, the 2.3 Mbps ceiling reached only after ~30 s on a healthy network). Match what client-sdk-js (livekit/client-sdk-js#1987) and rust-sdks (livekit/rust-sdks#1197, #1226) already do: when a video sender is added, derive a start bitrate from its encodings — the sum of the active layers' maxBitrate, times 0.9, capped at 1 Mbps unless the track is a screen share, and no hint under 300 kbps — and declare `x-google-start-bitrate=<kbps>` on every video codec's fmtp (VP8/VP9/AV1/H264/H265) of that sender's section in the publisher's offer, matched through the `a=msid` track id. Not opt-in and no public API, as in the sibling SDKs. - `SDPMediaSection.setFmtpParameter(_:value:forPayload:)`: replaces an existing value, appends to an existing fmtp line, or inserts one for payloads that have none (VP8), keeping every other parameter verbatim. - `Transport.startBitrateKbps(targetBps:isScreenShare:)` / `startBitrateKbps(for:isScreenShare:)`: the shared formula. - `Transport.mungeVideoStartBitrate(_:kbpsBySenderId:)`, appended as the last (optional) munge of `set(localDescription:munging:)` (livekit#1068) in both single- and dual-PC negotiation, on the SDP module from livekit#1078. - `Transport.addTransceiver(with:transceiverInit:startBitrateKbps:)` records the hint against the new sender before returning, so the offer libwebrtc requests in response cannot be created without it; `remove(track:)` clears it. Both `LocalParticipant` video publish paths (primary and backup codec) pass the derived value. - The backup-codec publish path now computes its encodings with `isScreenShare`, as the primary path does; it had defaulted to the camera encoding since livekit#275, which the screen-share branch of the new formula made visible. Tests: the formula, the encodings sum, the per-sender munge (codec case, replace/append/insert, rtx/audio/unmapped sections untouched, no-op identity), `setFmtpParameter`, the backup codec's screen-share encodings, and — against the shipped libwebrtc — that a send-only video section's msid carries the sender id and that the munged offer is accepted by `setLocalDescription` rather than rejected as disallowed munging. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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
Fixes initial video quality blurriness by:
Problem
Users report video starting blurry for 5-15 seconds before reaching full quality (https://www.loom.com/share/9a34ae565f6949b891a155a436b3d573). This happens because:
Changes
livekit/src/rtc_engine/peer_transport.rs
libwebrtc/src/rtp_parameters.rs
livekit/src/room/options.rs
livekit/src/room/participant/local_participant.rs
Behavior
│ Setting │ Before │ After │
│ x-google-start-bitrate │ VP9/AV1 only │ All video codecs │
│ DegradationPreference │ Not set (WebRTC default) │ MaintainResolution │
Users can override degradation_preference in TrackPublishOptions if they prefer Balanced or MaintainFramerate.
Testing