What is a video backend?
The video backend is the layer between NMVideoPlayer and the browser’s media APIs.
The default implementation (Html5VideoBackend) wraps a <video> element and integrates hls.js for HLS streams.
A custom backend could target WebCodecs, a native shell bridge, or an experimental pipeline.
Default backend: Html5VideoBackend
Html5VideoBackend is used automatically when no backendFactory is provided. It:
- Detects HLS URLs (
.m3u8) and loads them via hls.js - Falls back to native
<video>srcfor other URLs - Parses HLS manifest quality levels and maps them to
QualityLevelobjects - Exposes multi-audio track switching via the HLS API
- Forwards
loadedmetadata,timeupdate,playing,waiting,stalled,ended,error, and HLS-specific events to the player’s event bus - Handles HDR/SDR level capping when the display changes
- Implements error recovery with retry logic for HLS network and media errors
IVideoBackend interface
import type { IVideoBackend } from '@nomercy-entertainment/nomercy-video-player';
Every backend must implement all methods in IVideoBackend.
See API: Backend Access for the full method table.
BackendState
type BackendState = 'idle' | 'loading' | 'ready' | 'playing' | 'paused' | 'error';
Returned by backend.state().
VideoBackendKind
type VideoBackendKind = 'html5' | 'mse' | 'webcodecs';
Passed to the VideoBackendFactory so factories can branch on the resolved kind.
Swapping the backend
Pass backendFactory in VideoPlayerConfig.
The factory receives the resolved kind and the full player config:
import nmplayer from '@nomercy-entertainment/nomercy-video-player';
import type {
VideoBackendFactory,
IVideoBackend,
VideoPlayerConfig,
} from '@nomercy-entertainment/nomercy-video-player';
import type { BasePlaylistItem } from '@nomercy-entertainment/nomercy-player-core';
class MyBackend implements IVideoBackend {
readonly kind = 'html5' as const;
async load(url: string): Promise<void> {
// mount url to a <video> element
}
unload(): void {
/* ... */
}
dispose(): void {
/* ... */
}
play(): Promise<void> {
return Promise.resolve();
}
pause(): void {
/* ... */
}
stop(): void {
/* ... */
}
time(): number {
return 0;
}
time(seconds: number): void {
/* ... */
}
duration(): number {
return 0;
}
// ... implement all IVideoBackend methods
}
const factory: VideoBackendFactory = (kind, config) => {
return new MyBackend();
};
const player = nmplayer('player').setup({
baseUrl: 'https://raw.githubusercontent.com/NoMercy-Entertainment/nomercy-media/master/Films',
backendFactory: factory,
playlist: [
{
url: '/Sintel.(2010)/Sintel.(2010).NoMercy.m3u8',
},
],
});
Backend events
Backends emit through the BackendEventPayload map.
The player’s event bus subscribes to these and re-emits them as video player events where applicable:
| Backend event | Description |
|---|---|
loadedmetadata | Source loaded; includes url, kind, duration |
canplay | Enough data buffered to begin playback |
playing | Media is actively rendering (after buffer resolves) |
waiting | Buffering (forwarded to player 'waiting') |
stalled | Network stalled (forwarded to player 'stalled') |
ended | Playback reached the end |
error | A fatal error occurred |
levels | HLS quality levels available |
level-switched | ABR switched to a different quality level |
audioTracks | Audio track list available after manifest parse |
subtitleCue | Active subtitle cues changed |
stream:error | HLS non-fatal or escalated error with details |
stream:recovering | HLS error recovery attempt in progress |