JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 44
  • Score
    100M100P100Q85120F
  • License MIT

Rust/WASM-powered browser video player runtime with FLV/HLS/MP4 demux, WebCodecs decode, WebGL2 render, and HEVC software decode fallback.

Package Exports

  • @flow-player/browser-runtime
  • @flow-player/browser-runtime/wasm/flow_player_wasm.wasm
  • @flow-player/browser-runtime/worker

Readme

@flow-player/browser-runtime

ESM browser runtime for H.264 / H.265 FLV live and VOD playback with WebCodecs, WebGL2, and a Rust-powered WASM demux core. Zero npm dependencies.

0.4.0 新增(@beta):HEVC 软件解码兜底。decodeMode: "auto" 在浏览器 WebCodecs HEVC 不可用时自动软解;默认 decodeMode: "webcodecs" 零回归。详见 HEVC 软解(@beta)

Quick Start (Live)

import { flowLivePlayer } from "@flow-player/browser-runtime";
import PlayerWorker from "@flow-player/browser-runtime/worker?worker";
import wasmUrl from "@flow-player/browser-runtime/wasm/flow_player_wasm.wasm?url";

const player = new flowLivePlayer({
  canvas: document.getElementById("player-canvas") as HTMLCanvasElement,
  workerFactory: () => new PlayerWorker(),
  wasmUrl,           // 生产构建必须显式声明(见下方说明)
  useWCS: true,
});

player.on("play", () => console.log("playing"));
player.on("stats", (stats) => console.log(stats.fps, "fps"));
player.on("diagnostic", (detail) => console.warn("normalization:", detail));

await player.play("https://example.com/live.flv");

接入说明wasmUrlworkerFactory 在生产构建中必须显式声明new URL(variable, import.meta.url) 自动推断在 dev 模式可用,但生产构建因 bundler 资产检测只识别字面量而失效。详见 Consumer 接入体验优化 PRD?worker / ?url 需要 /// <reference types="vite/client" /> 类型声明(vite 模板默认已有)。

Quick Start (VOD)

import { flowVodPlayer } from "@flow-player/browser-runtime";
import PlayerWorker from "@flow-player/browser-runtime/worker?worker";
import wasmUrl from "@flow-player/browser-runtime/wasm/flow_player_wasm.wasm?url";

const player = flowVodPlayer({
  canvas: document.getElementById("vod-canvas") as HTMLCanvasElement,
  workerFactory: () => new PlayerWorker(),
  wasmUrl,
});

player.playList([
  { url: "/vod/1.mp4", startTimestamp: 0, endTimestamp: 60000, timeLen: 60, fileSize: 1024000, channelID: 1, RecordType: 0 },
]);

Worker Setup

The module worker is at @flow-player/browser-runtime/worker.

Bundler Import
Vite import PlayerWorker from "@flow-player/browser-runtime/worker?worker"
webpack 5 new Worker(new URL("@flow-player/browser-runtime/worker", import.meta.url))
esbuild new Worker(new URL("@flow-player/browser-runtime/worker", import.meta.url), { type: "module" })

WASM 部署

.wasm 产物(~147 KB release)包含在 npm 包的 wasm/flow_player_wasm.wasm,通过 ./wasm/* 子路径暴露。

加载机制

提供两种互斥的 wasm 来源(按优先级):

选项 模式 生产构建 适用场景
wasmUrl URL 字符串 consumer ?url 导入 推荐(Vite/Webpack)
wasmBytes BufferSource consumer ?arraybuffer 导入 需绕过 URL(如内联)
不传 new URL() 自动推断 不可用(非字面量不被 bundler 识别) 仅 dev

另有独立并行通道 wasmModuleWebAssembly.Module):作为 init payload 独立字段 postMessage 到 worker,与上述选项可共存(Safari fallback:wasmModule 失败时回落到 wasm config)。不是互斥选项的第三选

Vite / webpack 5(推荐)

?url 导入让 bundler 自动拷贝:

import wasmUrl from "@flow-player/browser-runtime/wasm/flow_player_wasm.wasm?url";

new flowLivePlayer({ wasmUrl, /* ... */ });

手动部署(其他 bundler)

拷贝 wasm/flow_player_wasm.wasm 到静态资源并传 URL:

new flowLivePlayer({
  wasmUrl: "https://cdn.example.com/flow_player_wasm.wasm",
  // ...
});

API Reference

flowLivePlayer

Method Description
play(url) Start streaming
pause() Pause
close() / destroy() Stop and release resources
screenshot(filename?, format?, quality?, type?) Capture frame → string | Blob | void
startRecord(name?, type?) / stopRecordAndSave() / isRecording() Recording
mute() / cancelMute() / setVolume(v) / isMute() Audio control
setScaleMode(m) / setRotate(deg) / resize(w, h) / clearView() Display
setFullscreen(f) / toggleControlBar(b) / getControlBarShow() Fullscreen
setKeepScreenOn() Prevent screen sleep
Property Type
metrics RuntimeMetrics (chunksPushed, firstFrameAt, ...)
loaded, playing, muted, volume State booleans/numbers
scaleMode, fullscreen, rotate Display state
Key Events Payload
play, pause, destroy void
start void (first frame rendered)
stats FlowLivePlayerStats {buf, fps, abps, vbps, ts}
videoInfo FlowLivePlayerVideoInfo {width, height, codec, codecString}
error unknown
diagnostic unknown (stream normalization detail)
timeout FlowLivePlayerTimeoutDetail
resize FlowLivePlayerResizeDetail
clearView FlowLivePlayerClearViewDetail
mute / fullscreen boolean
volume number
scaleMode FlowLivePlayerScaleMode
rotate number
recordStart / recordEnd / recordError unknown
recordingTimestamp number (seconds)

HEVC 软解(@beta)

⚠️ 商用前置:HEVC/H.265 涉及标准必要专利(HEVC Advance、MPEG LA、独立持有人),无论用哪种 codec 实现,只要发生 HEVC 解码就触发专利授权义务。商用前必须完成专利授权确认。详见 HEVC 专利授权与商用合规。默认 decodeMode: "webcodecs" 不加载软解;启用 auto/software 前请确认授权。

flowLivePlayer 支持 HEVC 软件解码兜底。软解 adapter 基于第三方 HEVC 解码库(MIT),由接入方通过 URL 或 module 注入,不进入默认 npm 包(包隔离 release gate 强约束)。

decodeMode 行为
"webcodecs"(默认) 仅 WebCodecs 硬解;不加载软解资源,零回归
"auto" WebCodecs 不可用时自动软解兜底(仅 decoder-capability 错误触发,排除 keyframe/seek/network 暂态错误)
"software" 强制软解(HEVC);不支持的 codec(如 H.264)自动回退 WebCodecs
const player = new flowLivePlayer({
  canvas,
  workerFactory: () => new PlayerWorker(),
  decodeMode: "auto",            // @beta
  softwareDecoderUrl: "/wasm/hevc-software-decoder-adapter.js",  // 注入软解 adapter URL
  softwareDecoderLoadTimeoutMs: 1000,  // 默认 1000ms
});

软解触发时 metrics.decoderLoadingState 流转:idleloadingdecoder-ready / decoder-errormetrics.decoderWasmMemoryPeakMb 记录 WASM 内存峰值。decode-error 事件携带 classifyWebCodecsError 分类(decoder-capability / keyframe-required / keyframe-wait / seek-flush / network)。

获取 HEVC 软解 adapter

软解 adapter 源码不在 npm 包内(第三方 HEVC 解码库 MIT 隔离 + 构建流程复杂)。consumer 获取 adapter 的步骤:

  1. demo 仓库复制源码 apps/player-demo/scripts/hevc-software-decoder-adapter-src.ts
  2. 按 demo 仓库 apps/player-demo/package.json 的软解依赖声明安装对应版本(MIT 软件授权;HEVC 专利风险见上)
  3. 用 esbuild bundle 成单个 .js + 拷贝软解库的 wasm 资源(参考 apps/player-demo/scripts/prepare-wasm.ts)。注意:软解库的传递依赖 mp4box 在 npm registry 上的 exports 字段声明了 ./dist/mp4box.all.js,但实际产物是 mp4box.all.mjs,esbuild 解析会报 Could not resolve "mp4box"。需加 alias 规避:esbuild adapter.ts --bundle --format=esm --alias:mp4box=./node_modules/mp4box/dist/mp4box.all.mjs --outfile=...
  4. 输出到 consumer 的 public/wasm/,通过 softwareDecoderUrl: "/wasm/hevc-software-decoder-adapter.js" 传入

worker 内 await import(/* @vite-ignore */ url) 动态加载 adapter——URL 必须同源或配 CORS。

⚠️ 软解 adapter 依赖的第三方 HEVC 解码库为 MIT license;HEVC 标准必要专利授权独立于软件 license(详见 专利文档)。API 标注 @beta,后续版本可能调整。

flowVodPlayer

Method Description
playList(segments: FlowVodRecordSegment[]) Load and start VOD playback
seek(timestampMs) Seek to absolute millisecond timestamp
pause() / resume() Playback control
nextSegment() / previousSegment() Segment navigation
nextFrame() / previousFrame() Frame-stepping
setRate(rate) Playback speed. rate > 0 = forward (e.g. 2 = 2×), rate < 0 = reverse (e.g. -4 = backward 4×, |rate| must be 1/2/4/8). 0 rejects.
setPlaybackDirection("forward"|"backward", speed?) Reverse playback control. Equivalent to setRate(-speed) for backward.
setGapPolicy(policy: FlowVodGapPolicy) Gap handling ("jump" or "hold")
Property Type
state "idle" | "loading" | "playing" | "paused" | ...
rate number
snapshot FlowVodPlayerSnapshot
videoElement HTMLVideoElement | null (MSE mode only)

FlowVodRecordSegment

interface FlowVodRecordSegment {
  url: string;
  startTimestamp: number;
  endTimestamp: number;
  timeLen: number;
  fileSize: number;
  channelID: number | string;
  RecordType: number | string;
}

Tree Shaking

Package is "sideEffects": false with per-module output. Modern bundlers (Vite, webpack 5, Rollup, esbuild) will remove unused code automatically. Importing only flowLivePlayer excludes VOD from your bundle.

License

MIT

Development

# Build WASM (requires Rust wasm32-unknown-unknown target)
npm run build:wasm

# Build npm-grade package
npm run build:package

# Verify before publish
npm run publish:check

# Full test suite
npm run test:smoke

# Type check
npm run typecheck