Skip to content

Repository files navigation

live-player - 浏览器摄像头和直播播放器

中文 | English

live-player 是一款浏览器摄像头和直播播放器:支持 WS-FLV 直播 + 录像文件(FLV / MP4)。

安装

pnpm add @le5le/live-player mpegts.js

mpegts.jspeerDependency,需要宿主自己安装

npm 包里只有 dist/:一个未压缩的 ESM 文件 + 各文件的 .d.ts,另带 sourcemap。

不用打包器的项目直接 <script type="module"> import dist/live-player.js 即可。

适合什么场景

监控摄像头这类流写的播放器,不是通用视频播放器。它解决的是这几件在监控场景里反复出问题的事:

  • 一个地址既可能是直播也可能是录像。国标(GB28181)设备回放的 ws-flv 地址与直播长得一模一样, 容器也相同,只能由调用方告知语义(live),库据此决定要不要丢帧、要不要允许拖动、断了要不要重连。
  • H265 直播切后台再回来会断流重连。这是本库的起点:隐藏期积压的数据回到前台后触发 seek, 而 H265 跳到非 IDR 位置就解不开。库在 MSE 写入层拦下来,切走几分钟回来也不必等「正在恢复画面」。
  • 多路同屏带不动。九宫格主码流是 9 路 4MP H265 解码,浏览器没有任何 API 能查询剩余硬解会话数。 库只能在失败后反应:一路解码失败就整组降到子码流(设备原生双码流,服务端不转码)。
  • 播放地址带短寿命凭据。平台侧播放 token 常是 30 秒 TTL,而重连恰恰最容易撞上它过期。 库重连前会回调 renewSources 向宿主索取新地址。

不适合:点播站、HLS/DASH 自适应码率、直播带货这类只需要「放一个 mp4/m3u8」的场景 —— 那些用 <video> 或 hls.js 更合适,本库的复杂度全花在上面四件事上。

功能

协议

地址里的路径标记自动选传输方式(不是按扩展名 —— 现网直播地址常没有扩展名):

地址形态 传输方式 说明
ws:// wss:// + 路径含 flv/mpegts MSE 直播 主力路径,过 mpegts.js
http(s)://flv/ts 且路径有 .live./live/ MSE 直播 ZLM / 乐吾乐的 http-flv 直播
http(s)://flv/ts,不带 live 段 MSE 录像 FLV 录像文件,可拖动
http(s)://.mp4/fmp4 原生播放 交给浏览器,白拿 seek 与进度条
路径含 webrtc/whep WebRTC 延迟约 0.2~0.4s,需宿主开 preferWebrtc
  • WebSocket 地址不带容器标记时不猜,直接判 unsupported —— 猜错的代价是播不出来却报错到别处。 这是前后端契约:后端新增播放地址必须在 path 里带 flv/mpegts/ts/mp4 之一。
  • WebRTC 不由 URL 自动启用。两条路的取舍随同屏路数翻转(WebRTC 延迟低但没有 MSE、 后台仍满速解码),而库不知道自己是九宫格里的一格还是单画面,所以由宿主决定。 走不通会自动退回 FLV,不必宿主兜。

resolveTransport(url) 可以单独查某个地址会被判成什么,isLiveUrl(url) 判断要不要显示进度条。

格式

容器:FLV、MPEG-TS(均过 mpegts.js)、MP4 / fMP4(交给浏览器原生播放)。

视频编码:H264、H265(HEVC)。H265 的浏览器支持是分裂的 —— Chrome 136+ 原生支持但要求硬件解码、 Safari 18+ 通、Edge 至今未跟上、Firefox 不支持。hevcSupported() 可做静态能力查询,但要注意 它只说明浏览器认不认这个 codec,不代表还有可用的硬解会话 —— 已经开了 8 路解码器它照样返回 true。 真正能不能播只有喂进去才知道,由看门狗与自动降级兜底。

音频:MSE 这条路目前固定关闭音频hasAudio: false,不可配)。原因是国标 PS 流的音频常是 G.711,而 mpegts.js 只认 AAC/MP3,遇到别的会抛 CodecUnsupported 打断整条解复用;更要紧的是 音轨 SourceBuffer 一旦出错会把 <video> 整个置成 error 态,视频的 appendBuffer 也跟着全失败 —— 画面直接黑。监控场景不需要声音,所以选择让 demuxer 在读 soundFormat 之前就丢掉音频 tag。 WebRTC 这条路会协商 audio 轨(ZLM 少一条媒体行会整体协商失败),能不能出声取决于服务端。

使用

import { createPlayer, createGroup, isLiveUrl } from '@le5le/live-player';

const player = createPlayer(videoEl, {
  sources: {
    main: 'wss://host/ws/gb/flv?streamId=xxx',
    sub: 'wss://host/ws/gb/flv?streamId=xxx_sub', // 没有子码流就不传,不参与降级
  },
  live: true, // 录像回放必须传 false —— 国标回放地址与直播同形,库看不出区别
});

// 事件用 on/off 注册,不是构造参数
player.on('statechange', (s) => console.log(s)); // idle|connecting|playing|resyncing|reconnecting|failed
player.on('error', (e) => console.log(e.kind, e.message, e.fatal));
player.on('qualitychange', (q, reason) => console.log(q, reason));
player.on('ended', () => console.log('这一段放完了')); // 只有非实时流会触发

await player.play();

播放地址带短寿命凭据时,传 renewSources 让库在重连前换一份新地址:

const player = createPlayer(videoEl, {
  sources,
  live: true,
  renewSources: async () => (await api.renewPlay(channelId)).sources,
});

想用 WebRTC 换低延迟(单画面或小宫格):

createPlayer(videoEl, {
  sources: { main: flvUrl, webrtc: webrtcUrl },
  preferWebrtc: true, // 走不通会自动退回 main 的 FLV
  live: true,
});

player.transport 拿到实际在用的传输方式 —— preferWebrtc 为真时也可能已经退回 FLV, 想在界面上标「低延迟」就得读这个,读 preferWebrtc 会在退回后说谎。

其余成员:pause() / destroy() / setQuality(q) / snapshot() 抓拍,以及只读的 state / quality / hasSub / live

宫格

const group = createGroup();
group.add(player); // 任一路解码失败时,整组一起切子码流(有子码才切)
group.add(player2);

createGroup() 用于同屏多路:某一路因为解码带不动而降级时整组一起切,避免只降一格、 其余仍在抢解码会话。单画面不用。

手动 setQuality() 过的实例从组自动降级中豁免 —— 用户明确要这一格看主码流,库不跟他抢。

live: false 时库允许 seek(录像本来就该能拖),live: true永不 seek 到未缓冲位置—— 那正是断流重连的真身。

About

浏览器摄像头和直播播放器:支持 WS-FLV 直播 + 录像文件(FLV / MP4)。A browser player for IP cameras and live streams: WS-FLV live plus recording playback (FLV / MP4).

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages