Skip to content

Runtime bitrate endpoint + ABR capability negotiation (Foundation/Moonlight V+ compatible)#273

Open
AsafMah wants to merge 1 commit into
Nonary:masterfrom
AsafMah:feat/runtime-bitrate-abr
Open

Runtime bitrate endpoint + ABR capability negotiation (Foundation/Moonlight V+ compatible)#273
AsafMah wants to merge 1 commit into
Nonary:masterfrom
AsafMah:feat/runtime-bitrate-abr

Conversation

@AsafMah

@AsafMah AsafMah commented Jun 14, 2026

Copy link
Copy Markdown

Implements #272 — runtime (mid-stream) bitrate changes so Foundation / Moonlight V+ clients can adjust encoder bitrate without reconnecting.

Endpoints (HTTPS, paired client, View permission)

  • GET /bitrate?bitrate=<kbps> — apply a new encoder bitrate to the caller's active session. Clamped to max_bitrate and an absolute 500 Mbps ceiling. Returns <root status_code=200><bitrate>N</bitrate></root> (0 = failure) — the exact shape NvHTTP.setBitrate() parses (and its verifyResponseStatus requires the status_code attribute).
  • GET /api/abr/capabilities — returns {"supported":false,"version":1,"features":["runtime_bitrate"]}. Verified against AdaptiveBitrateService.kt: supported:false makes V+ run its local ABR controller, which drives the host through /bitrate. So both the manual slider and adaptive mode work. Server-side ABR decisioning (POST /api/abr, /feedback) is intentionally out of scope.

Apply mechanism

A per-session mail event (dynamic_bitrate), coalesced to the latest value on the encode thread:

  • NVENC reconfigures the live encoder via nvEncReconfigureEncoder using saved init params (ported from foundation-sunshine, adapted to Vibepollo's runtime-versioned NVENC structs / api::reconfigure_params_version). Seamless, no hitch.
  • avcodec encoders (AMD/Intel/software) report set_bitrate()==false and fall back to an encode-session rebuild via the existing reinit path. Correct, but a brief hitch per change. Backend-native AMF/QSV reconfigure is a possible follow-up (mirrors foundation staging NVENC first, AMF later).

Clamping/overflow: rejects <=0, clamps to max_bitrate (when set) and an absolute ceiling; set_bitrate() also rejects >800000 kbps so kbps*1000 cannot overflow the 32-bit rate-control fields.

Files

globals.h (event), stream.{h,cpp} (set_bitrate_for_sessions, per-session event), video.{h,cpp} (encode_session_t::set_bitrate, NVENC override, both encode paths), nvenc/nvenc_base.{h,cpp} (set_bitrate live reconfigure), nvhttp.cpp (routes).

Verification

  • Builds + links: compiled with gcc 16 (MSYS2 UCRT64), ninja sunshinesunshine.exe links cleanly (no undefined symbols from the new functions). NVENC reconfigure struct fields/version confirmed against the bundled ffnvcodec/nvEncodeAPI.h.
  • Client contract: response shapes verified against Moonlight V+ NvHTTP/AdaptiveBitrateService source.
  • Not yet runtime-tested on a live GPU stream. I don't have a suitable host+client loop to exercise an actual encode session. Requesting a maintainer/community runtime check on NVENC (seamless) and one avcodec backend (reinit fallback). Happy to iterate.

Client reference: qiin2333/moonlight-vplus (NvHTTP.setBitrate, getAbrCapabilities, AdaptiveBitrateService). Server reference: AlkaidLab/foundation-sunshine (#193 /bitrate + NVENC reconfigure, #571 /api/abr/*, ClassicOldSong#690 max_bitrate clamp).

Lets Foundation/Moonlight V+ clients change the encoder bitrate mid-stream
without reconnecting.

Endpoints (HTTPS, paired client, View permission):
- GET /bitrate?bitrate=<kbps>   apply a new encoder bitrate to the caller's
  active session. Clamped to config max_bitrate and an absolute 500 Mbps ceiling.
  Returns <root status_code=200><bitrate>N</bitrate></root> (0 = failure), the
  shape V+ NvHTTP.setBitrate() parses (and verifyResponseStatus requires the
  status_code attribute).
- GET /api/abr/capabilities     reports {supported:false,...}; verified against
  AdaptiveBitrateService.kt this makes V+ run its local ABR controller, which
  drives the host via /bitrate. Server-side ABR decisioning (/api/abr,
  /feedback) is intentionally out of scope.

Apply path: a per-session mail event (dynamic_bitrate), coalesced to the latest
value on the encode thread. NVENC reconfigures the live encoder via
nvEncReconfigureEncoder (no hitch; ported from foundation-sunshine, adapted to
Vibepollo's runtime-versioned NVENC structs). avcodec encoders (AMD/Intel/
software) report set_bitrate()==false and fall back to an encode-session rebuild
via the existing reinit path -- correct, but produces a brief hitch per change.

Not yet compiled (needs the MSYS2/MinGW toolchain); review/runtime test pending.
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