Skip to content

5rahim/mpv-prism

Repository files navigation

mpv-prism logo

mpv-prism

Warning

This project is under active development and is not ready for production use.

What is it?

mpv-prism lets Electron apps use libmpv for decoding, playback control, subtitles, shaders, profiles, and media handling, then presents frames through a regular DOM <video> or <canvas>. Where supported, frames are passed through shared GPU textures. When that's not possible, it falls back to the CPU.

Features

  • Real DOM video integration through a standard <video> or <canvas> element.
  • Hardware-accelerated rendering with CPU fallback
  • Playback controls for loading, play/pause, seeking, volume, speed, tracks, subtitles, etc.
  • Typed playback, track, subtitle, error, and native events
  • Runtime mpv profiles, shaders, properties, and raw commands
  • Vanilla TypeScript core API with an optional React wrapper
  • Runtime loading of the correct native addon and sidecar libraries

Packages

@mpv-prism/core
@mpv-prism/electron
@mpv-prism/react

Requirements

  • Electron 42+
  • contextIsolation: true
  • nodeIntegration: false
  • sandbox: false
  • MediaStreamTrackGenerator and VideoFrame support in the renderer
  • Native artifacts in native-builds/<platform>-<arch>/

Setup

1. Native Artifacts

Prepare the libmpv artifacts for each platform you want to support.

2. Electron Main Process

Initialize the IPC bridge in the Electron main process prior to creating application windows or spawning players:

import { app, BrowserWindow } from 'electron';
import { join } from 'node:path';
import { registerMpvPrismIpc, type MpvPrismMain } from '@mpv-prism/electron/main';

let mpvPrism: MpvPrismMain | null = null;

async function createWindow() {
  // Register the IPC handlers once
  if (!mpvPrism) {
    mpvPrism = registerMpvPrismIpc({
      loader: {
        // Absolute base path to look for the native-builds/ directory
        baseDirectory: join(__dirname, '..'),
      },
    });
  }

  const window = new BrowserWindow({
    width: 1280,
    height: 720,
    webPreferences: {
      preload: join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false,
      sandbox: false, // Required for ESM preload bridge
      backgroundThrottling: false,
    },
  });

  await window.loadFile('index.html');
}

app.whenReady().then(createWindow);

app.on('will-quit', () => {
  mpvPrism?.dispose();
  mpvPrism = null;
});

To configure custom search paths for the native library loader, pass the folder option in loader.baseDirectory, or set the MPV_PRISM_NATIVE_ROOT environment variable.

3. Electron Preload Script

Expose the preload bridge:

import { exposeMpvPrismPreload } from '@mpv-prism/electron/preload';

exposeMpvPrismPreload();

The preload layer validates renderer input, forwards IPC commands, receives shared textures, creates VideoFrame targets, and releases frames when they are no longer needed.

Core usage

Use @mpv-prism/core directly with vanilla TypeScript, JavaScript, or other UI frameworks.

import { MpvPrismPlayer } from '@mpv-prism/core';

// Create a player instance
const player = new MpvPrismPlayer({
  mpv: {
    options: {
      'hwdec': 'auto-safe'
    }
  }
});

const video = document.querySelector('video') as HTMLVideoElement;

// Attach a video presenter
const presenter = player.createVideoPresenter({ fit: 'contain' });
await presenter.attach(video);

// Subscribe to state streams
const unsubscribe = player.on('position', (event) => {
  console.log('Position update:', event.position);
});

// Control playback 
await player.load('file:///path/to/media.mkv');
await player.play();
await player.seek(60, 'absolute+exact');

// Configure shaders and profiles
await player.setShaders(['/absolute/path/to/shader.glsl']);
await player.clearShaders();

// Cleanup
unsubscribe();
await presenter.destroy();
await player.destroy();

Environment Variables

Variable Platform Allowed Values / Type Description
MPV_PRISM_HIGH_PERFORMANCE_GPU Windows, Linux 1 / true / yes / on Prioritize the discrete high-performance GPU rather than integrated graphics.
MPV_PRISM_DEBUG_VIDEO All 1 / true / yes / on Enables detailed debug statements for the video presentation, queue levels, and rendering frame loop.
MPV_PRISM_DEBUG_NATIVE All 1 / true / yes / on Enables detailed native addon debugging in standard output.
MPV_PRISM_MPV_LOG_FILE All Absolute path File path where logs will be written.
MPV_PRISM_NATIVE_LOG_FILE All Absolute path File path where native runtime logs will be written.
MPV_PRISM_NATIVE_ROOT All Absolute path Custom search directory override for resolving the native-builds/ target folders.
MPV_PRISM_LIBMPV_PATH All Absolute path Instructs the dynamic native loader to import libmpv from a specific library binary directly.
MPV_PRISM_WIN32_BACKEND Windows auto, wgl, angle Explicitly overrides the graphics presentation backend. Defaults to auto.
MPV_PRISM_WIN32_ANGLE_ADAPTER Windows auto, default, high-performance Configures DXGI adapter preferences when using ANGLE on Windows. Defaults to auto.
MPV_PRISM_ANGLE_DLL_DIR Windows Absolute path Folder path containing the ANGLE library dependencies (libEGL.dll, libGLESv2.dll).
MPV_PRISM_WIN32_ALLOW_ES2 Windows 1 / true / yes / on Allows ANGLE initialization fallback to OpenGL ES 2 contexts.
MPV_PRISM_LINUX_GPU_PREFERENCE Linux default, discrete, nvidia, amd, intel, compatible Prefers a specific vendor GPU node for offscreen EGL context creation.
MPV_PRISM_DRM_DEVICE Linux Absolute path Explicit path to the DRM card node (e.g. /dev/dri/card0 or /dev/dri/renderD128).

Packaging

Exclude your prebuilt native folders from Electron's compressed ASAR container to allow dynamic loading of native addons and graphics libraries:

native-builds/<platform>-<arch>/*

In your build setup (e.g. electron-builder), configure extraResources or asarUnpack to keep the target binaries uncompressed:

"extraResources": [
  {
    "from": "native-builds",
    "to": "native-builds",
    "filter": ["**/*"]
  }
]

Keep your .node binaries directly alongside their required runtime dependencies (.dll, .dylib, .so) in their platform subdirectory. The native loader resolves paths from process.resourcesPath, unpacked directories, current execution roots, or MPV_PRISM_NATIVE_ROOT.


Platform support

Platform Backend Status
darwin-arm64 IOSurface Tested
linux-x64 EGL, GBM, dma-buf, NativePixmap Tested
win32-x64 WGL, D3D11 shared NT handle Tested

Limitations

  • VideoCompositor-related issues
  • Issues with dual-gpu setups

About

libmpv in Electron

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Contributors