ABR: findBestLevel hard-excludes smooth:false levels, capping quality below maxLevel (MediaCapabilities false-negative)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 16.9k
- Forks
- 2.8k
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 27
Description
Overview
AbrController.findBestLevel hard-excludes any candidate whose decodingInfoResults[0].smooth === false:
// src/controller/abr-controller.ts
(levelInfo.supportedResult &&
!levelInfo.supportedResult.decodingInfoResults?.[0].smooth)
// → levelsSkipped.push(i); continue;
For type: 'media-source', smooth is a probabilistic prediction from Chromium's VideoDecodePerfHistory (learned per codec-profile / resolution / fps bucket), not a deterministic capability like supported. When a false-negative lands on the only renditions at/under the configured cap, ABR is permanently stranded a tier lower — even though the level decodes fine.
Concrete case
- A Windows machine (AMD Radeon 860M iGPU) returns
{ supported: true, powerEfficient: true, smooth: false }for the 720p60avc1.640028rendition. - macOS and a second, same-spec Windows machine return
smooth: truefor the identical config and stream. - The ladder's only high-fps level ≤ 720p is 720p60 (there is no 720p30). With
maxLevel/ viewport capping at 720p, the only candidate above 480p issmooth:falseand gets excluded → playback caps at 480p30. powerEfficient: trueindicates a hardware decoder is engaged; steady-statedroppedVideoFramesstays ≈ 0.
Note: we are still confirming via
chrome://media-internalswhether this specific machine has real startup/level-switch drop bursts. But independent of that measurement, the design issue stands: hls.js has no graceful fallback when the only in-cap level issmooth:false.
Why this is an hls.js robustness concern (not only a Chromium bug)
smoothis soft/probabilistic;supportedis a hard fact.findBestLevelcurrently treats both as equally-hard exclusions.- hls.js already works around Windows MediaCapabilities unreliability for HEVC (#7046, #6849). This is the same class of false-negative for H.264.
- Filed upstream at Chromium (accepted & assigned): https://issues.chromium.org/issues/525612738
Proposal (no new config option)
Treat smooth: false as a soft signal in findBestLevel:
- Prefer
smoothlevels when available. - Allow a
smooth: falselevel up to the configured cap only when (a) nosmoothcandidate exists at/under the cap, AND (b) that level ispowerEfficient: true(HW decoder engaged — the strongest false-negative signature). powerEfficient: false+smooth: falsestays excluded, preserving protection for genuinely weak setups.
This bounds the behavior change to exactly the false-negative shape and keeps the supported:false protection intact (so useMediaCapabilities: false is not needed). Happy to open a PR.
Environment
- hls.js v1.6.0
- Chrome / Edge / Whale (all Chromium) 149.0.7827.156, Windows 11 24H2 (26100.8655)
- GPU: AMD Radeon 860M, driver 32.0.13058.2;
Video Decode: Hardware accelerated; no HW video overlay (NV12 overlay = SOFTWARE)
Reproduction
decodingInfo query:
navigator.mediaCapabilities.decodingInfo({
type: 'media-source',
video: { contentType: 'video/mp4; codecs="avc1.640028"', width: 1280, height: 720, framerate: 60, bitrate: 3192000 },
});
Multivariant playlist (relevant levels):
#EXT-X-STREAM-INF:BANDWIDTH=3192000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1280x720,FRAME-RATE=60.00
#EXT-X-STREAM-INF:BANDWIDTH=1692000,CODECS="avc1.4D001F,mp4a.40.2",RESOLUTION=852x480,FRAME-RATE=30.00
#EXT-X-STREAM-INF:BANDWIDTH=696000,CODECS="avc1.4D001E,mp4a.40.2",RESOLUTION=640x360,FRAME-RATE=30.00
#EXT-X-STREAM-INF:BANDWIDTH=192000,CODECS="avc1.4D000C,mp4a.40.2",RESOLUTION=256x144,FRAME-RATE=30.00
#EXT-X-STREAM-INF:BANDWIDTH=6336000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=30.00
Steps:
- On the affected machine, set
maxLevel(or use a viewport) so the cap is 720p. - Play the stream; observe ABR caps at 480p30 and never reaches 720p60.
navigator.mediaCapabilities.decodingInfo(...)for the 720p60 config returnssmooth: falsewhilevideoEl.getVideoPlaybackQuality().droppedVideoFrames≈ 0.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/controller/abr-controller.ts at AbrController.findBestLevel and trace how supportedResult.decodingInfoResults[0].smooth and powerEfficient affect candidate exclusion under maxLevel. Use the supplied MediaCapabilities reproduction and capped playlist to verify the fallback case; done means smooth levels remain preferred while a power-efficient smooth:false level can be selected only when no smooth candidate exists within the cap.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 64/100