Skip to content

Nvenc windows#1

Open
sionzee wants to merge 18 commits intomainfrom
nvenc-windows
Open

Nvenc windows#1
sionzee wants to merge 18 commits intomainfrom
nvenc-windows

Conversation

@sionzee
Copy link
Copy Markdown

@sionzee sionzee commented Apr 5, 2026

No description provided.

sionzee added 18 commits April 5, 2026 00:45
The NVIDIA NVENC encoder code already exists in webrtc-sys (h264/h265
encoder impls, cuda_context with Windows LoadLibrary support, NvCodec SDK)
but was only compiled on Linux. This enables it on Windows too.

Requires CUDA Toolkit headers at build time (set CUDA_HOME or use default
install path). At runtime, loads nvcuda.dll from the GPU driver.

The VideoEncoderFactory composite pattern automatically tries NVIDIA first,
falling back to software encoders if CUDA is unavailable.
Include winsock2.h before cuda.h in all NVIDIA headers to prevent
winsock.h/winsock2.h struct redefinition errors when compiling with
WebRTC headers on Windows.

Also fix NvCodec Logger.h to use winsock2.h instead of winsock.h.

Note: build still fails due to Chromium libc++ include path
pulling in windows.h without WIN32_LEAN_AND_MEAN. Needs separate
cc::Build for NVIDIA files or patched prebuilt headers.
The NVIDIA NVENC encoder code compiles fine with manual cl.exe but
fails when compiled via cc-rs due to the crate's INCLUDE env var
construction causing Windows SDK header conflicts.

All NVIDIA source patches and build.rs changes are in place. The
conflict is between cc-rs's environment and Windows SDK 26100.

Patched files: nvEncodeAPI.h, NvEncoder.cpp, Logger.h, cuda_context,
encoder impl headers. Added win_compat.h and factory bridge.
The NVIDIA encoder files compile successfully when the build runs
from a Visual Studio Developer Command Prompt (vcvarsall x64).
The winsock.h/winsock2.h conflict was caused by cc-rs's find-msvc-tools
constructing a different INCLUDE environment than vcvarsall.

Build requirements:
- CUDA Toolkit installed (CUDA_HOME or auto-detected)
- Run cargo from a VS Developer Command Prompt (vcvarsall x64)

Header patches for robustness:
- nvEncodeAPI.h, NvEncoder.cpp, Logger.h, cuda_context.cpp:
  All patched to use WIN32_LEAN_AND_MEAN before windows.h
- win_compat.h: Establishes correct winsock2.h include order
- nvidia_factory_bridge: Safe factory bridge without CUDA headers
The build.rs now automatically runs vcvarsall.bat and captures the
resulting INCLUDE/LIB/VCINSTALLDIR env vars when not already in a
Developer Command Prompt. This means NVENC compilation works from
any terminal — no need to manually run vcvarsall first.

Also cleaned up debug logging from previous iterations.
Revert to original USE_NVIDIA_VIDEO_CODEC define (encoder + decoder).
The nvcuvid.lib import library is generated from nvcuvid.dll (ships
with the NVIDIA GPU driver) and bundled in lib/x64/ since it's not
part of the CUDA Toolkit.

This enables:
- NVENC H264/H265 hardware encoding (screenshare)
- NVDEC H264/H265/AV1 hardware decoding (receiving streams)
- Changed H265 profile from Main to Main 10 (NV_ENC_HEVC_PROFILE_MAIN10_GUID)
- Set 10-bit output pixel depth (pixelBitDepthMinus8 = 2)
- Added VUI parameters for HDR signaling:
  - Color primaries: BT.2020 (9)
  - Transfer characteristics: ST.2084/PQ (16)
  - Matrix coefficients: BT.2020 non-constant (9)
- NVENC accepts 8-bit I420 input and internally upscales to 10-bit

This means H265 streams now carry HDR metadata in the HEVC SPS,
allowing receivers with HDR displays to render in wide color gamut.
Both H264 and H265 encoders stored the new bitrate/framerate from
WebRTC's bandwidth estimator but never actually reconfigured the
running NVENC encoder. This caused the encoder to keep producing at
the initial bitrate regardless of network conditions, leading to
progressive jitter buffer growth on receivers.

Now calls NvEncoder::Reconfigure() in SetRates() to dynamically
adjust bitrate and framerate, enabling proper WebRTC congestion
control.
…ottles

The WebRTC bandwidth estimator aggressively reduces bitrate from
120kbps to 27kbps over 30 seconds (even on localhost), causing
the encoder to produce only 17fps. Reverting to fixed initial
bitrate which maintained stable 55fps.

The root cause is the bandwidth estimator's interaction with the
loopback path. Proper fix needs adaptive streaming support in the
Rust SDK (not yet implemented).
…odecs

- SetRates: clamp minimum bitrate to 1.5 Mbps to prevent BWE from
  throttling NVENC to unusable levels (27kbps for 1080p screenshare)
- SetRates: actually call Reconfigure() so NVENC adapts to new bitrate
  (previously the encoder was stuck at initial startBitrate forever)
- InitEncode: add maxQP=28 cap to prevent quality collapse at low bitrate
- GetEncoderInfo: set has_trusted_rate_controller=true to disable
  libwebrtc's frame dropper which was dropping frames behind NVENC's back
- SDP: extend x-google-start-bitrate munging to H264/H265 (was VP9/AV1
  only), so BWE starts at ~5.6 Mbps instead of default 300kbps
Remove bitrate floor and has_trusted_rate_controller — these caused
a death spiral where NVENC produced 1.5Mbps but BWE only allowed
~100kbps through the pacer, causing massive jitter which made BWE
throttle even harder.

Now the encoder follows BWE's rate via Reconfigure (can ramp up as
BWE probes higher), and maxQP=28 prevents quality collapse at low
bitrates during the initial probing phase.
maxQP=28 prevented NVENC from compressing below ~2Mbps at 1920x808,
but BWE only allows ~800kbps during initial probing. The encoder
couldn't reach the target rate, causing pacer buffering, growing
jitter (150→519ms), and frame drops (74 frames in 45s).

Without the cap, NVENC can use whatever QP is needed to match BWE's
rate. Quality starts lower but improves as BWE probes upward.
Add min_bitrate field to RtpEncodingParameters and wire it to the
native webrtc-sys layer. Set 2 Mbps min for screenshare tracks so
the BitrateAllocator won't let BWE throttle below usable levels.

This fixes the localhost screenshare lag where BWE's delay-based
estimator incorrectly detects congestion and throttles to <100kbps.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 5, 2026

No changeset found

This PR modifies the following packages but doesn't include a changeset:

Directly changed:

  • libwebrtc
  • livekit
  • webrtc-sys

Downstream dependencies (also need a version bump):

  • livekit-ffi

Click here to create a changeset

The link pre-populates a changeset file with patch bumps for all affected packages.
Edit the description and bump types as needed before committing.

If this change doesn't require a version bump, add the internal label to this PR.

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.

1 participant