Skip to content

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> src for other URLs
  • Parses HLS manifest quality levels and maps them to QualityLevel objects
  • 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

TypeScript
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

TypeScript
type BackendState = 'idle' | 'loading' | 'ready' | 'playing' | 'paused' | 'error';

Returned by backend.state().

VideoBackendKind

TypeScript
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:

TypeScript
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 eventDescription
loadedmetadataSource loaded; includes url, kind, duration
canplayEnough data buffered to begin playback
playingMedia is actively rendering (after buffer resolves)
waitingBuffering (forwarded to player 'waiting')
stalledNetwork stalled (forwarded to player 'stalled')
endedPlayback reached the end
errorA fatal error occurred
levelsHLS quality levels available
level-switchedABR switched to a different quality level
audioTracksAudio track list available after manifest parse
subtitleCueActive subtitle cues changed
stream:errorHLS non-fatal or escalated error with details
stream:recoveringHLS error recovery attempt in progress

See also