Skip to content

HLS

The video player uses hls.js for HLS playback. The player core’s stream adapter wraps hls.js behind the IVideoBackend interface. HDR-aware ABR is automatic.

How hls.js is wired in

hls.js installs automatically with the player (a direct dependency of the player package) — nothing extra to install for the npm / bundler path. See Installation for the CDN exception.

The build output marks hls.js as external so it is not inlined into the player’s own dist bundle. At runtime the player loads it via a dynamic import on first HLS source, so it stays out of your initial bundle until you actually play .m3u8. On Safari / iOS, native HLS is used and hls.js is never instantiated.

For the CDN / IIFE path (no bundler), the IIFE bundle expects Hls as a global, so load hls.js via a separate <script> before the player script. See Quick Start: CDN embed.

Adaptive bitrate (ABR)

ABR is on by default. hls.js selects quality levels automatically based on estimated bandwidth.

TypeScript
player.setup({
defaultQuality: 'auto', // default, ABR active
});

Lock to a specific quality level (index into qualityLevels()):

TypeScript
player.quality(2); // lock to level index 2
player.quality('auto'); // back to adaptive (ABR)

Listen for level changes:

TypeScript
player.on('level-switched', ({ level }) => {
console.log(`Switched to quality level ${level}`);
});

player.on('levels', ({ levels }) => {
// levels becomes available after the HLS manifest is parsed
levels.forEach((level, idx) => {
console.log(`Level ${idx}: ${level.width}x${level.height} @ ${level.bitrate} bps`);
});
});

HDR-aware ABR

On SDR displays, the player filters HDR levels out of the ABR selection pool. hls.js will not automatically promote to an HDR level when the display cannot render it.

Display-HDR detection uses matchMedia('(dynamic-range: high)'). No configuration is required. On HDR-capable displays, all levels are eligible.

Multi-monitor handling: when a player window moves across displays (e.g. from an HDR monitor to an SDR one), the player re-evaluates display capabilities and constrains the ABR pool accordingly. The re-evaluation runs on the matchMedia('(dynamic-range: high)') change event.

Quality level shape

player.qualityLevels() returns QualityLevel[]:

TypeScript
interface QualityLevel {
bitrate: number; // stream bitrate in bits per second
height?: number; // encoded height in px, if known
width?: number; // encoded width in px, if known
label: string; // human-readable (e.g. '1080p')
index: number; // zero-based level index; pass to quality(idx)
supported?: boolean; // set when qualityLevels({ includeUnsupported: true })
dynamicRange?: 'sdr' | 'hdr'; // 'hdr' for PQ/HLG streams, 'sdr' otherwise
}

Auth on HLS segments

The player’s auth pipeline injects Authorization: Bearer <token> on every HLS manifest and segment request. No hls.js config needed, the IVideoBackend intercepts requests before they reach hls.js.

See Core, Auth and Fetch for the full auth pipeline.

Stream registration

The player ships an HLS stream factory and a native stream factory. The stream registry picks the right one based on the URL and browser capabilities:

  • .m3u8 URLs → HLS stream via hls.js
  • Other URLs → native <video> src

Register additional stream types:

TypeScript
import { myDashStreamFactory } from './dash-adapter';

player.registerStream(myDashStreamFactory); // registered at highest priority
player.streams(); // ['dash', 'hls', 'native']
// (pass `true` to register at LOWEST priority instead, behind the built-ins)

Custom backend

For full control over the <video> element or for non-standard streaming protocols:

TypeScript
import type { IVideoBackend, VideoPlayerConfig } from '@nomercy-entertainment/nomercy-video-player';
import type { BasePlaylistItem } from '@nomercy-entertainment/nomercy-player-core';

class MyBackend implements IVideoBackend {
constructor(_config: VideoPlayerConfig<BasePlaylistItem>) {
// ... receive config
}
// ... implement the interface
}

player.setup({
backendFactory: (kind, config) => new MyBackend(config),
});

Low-latency HLS and custom hls.js config

The built-in Html5VideoBackend creates its hls.js instance internally and does not currently expose a hook for custom hls.js config — lowLatencyMode is off and cannot be toggled through the player config. Customizing hls.js settings (including LL-HLS) requires supplying your own backend via backendFactory that owns its Hls instance and implements IVideoBackend. See the Video Backend adapter for the contract.