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");接入说明:
wasmUrl和workerFactory在生产构建中必须显式声明。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 |
另有独立并行通道 wasmModule(WebAssembly.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 流转:idle → loading → decoder-ready / decoder-error;metrics.decoderWasmMemoryPeakMb 记录 WASM 内存峰值。decode-error 事件携带 classifyWebCodecsError 分类(decoder-capability / keyframe-required / keyframe-wait / seek-flush / network)。
获取 HEVC 软解 adapter
软解 adapter 源码不在 npm 包内(第三方 HEVC 解码库 MIT 隔离 + 构建流程复杂)。consumer 获取 adapter 的步骤:
- 从 demo 仓库复制源码
apps/player-demo/scripts/hevc-software-decoder-adapter-src.ts - 按 demo 仓库
apps/player-demo/package.json的软解依赖声明安装对应版本(MIT 软件授权;HEVC 专利风险见上) - 用 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=... - 输出到 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