mn-video-player-v2
v1.5.6
Published
MN Video Player for WebSocket streaming
Maintainers
Readme
MnVideoPlayer Multi 多路视频播放器
概述
MnVideoPlayerMulti 在单个容器内管理多路实时/回放视频:统一控制(播放/暂停/倍速/音频)、多路同步播放、布局切换、窗口拖拽交换、窗口全屏、顶部通道信息栏,且每个窗口自带完整控制条(播放、码流切换、倍速、截屏、录屏、关闭、全屏等)。
import { MnVideoPlayerMulti } from './src/index' // 源码(开发调试)
// import { MnVideoPlayerMulti } from 'mn-video-player-v2' // 或发布产物
const multi = new MnVideoPlayerMulti()
multi.init({
el: document.getElementById('multiPlayer'),
layout: 4,
urls: [
{ channelNo: 1, streamType: 1, channelInfoCustom: '前门摄像头' },
{ channelNo: 4, streamType: 1 },
],
playerOptions: {
host: '172.16.0.144',
port: 16202,
ws: 'ws',
userId: '1',
tenantId: '1',
accessToken: 'your-access-token',
phone: '260300380002',
renderType: 'wasm',
beginTime: '', // 回放时间(YYYY-MM-DD HH:mm:ss)
streamType: 1,
},
})
multi.playAll()Vite 项目中使用发布产物时,建议排除依赖预加载,避免 Worker 资源获取失败:
// vite.config.js optimizeDeps: { exclude: ['mn-video-player-v2'] }
init(options) 配置项
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| el | HTMLElement | - | 多路容器元素(必填) |
| num | number | urls 长度,缺省 1 | 初始路数 |
| layout | number | 4 | 初始布局,取值 1/4/6/8/9/16/24/36 |
| urls | (string | object)[] | [] | 每一路的配置(见「每路配置」) |
| syncMode | boolean | false | 单路音频模式:仅允许一路发声(一路开启音频时其余路自动静音) |
| unifiedTimer | boolean | true | 是否使用统一时钟(syncMode=true 时多路共用一个时钟调度播放节奏);置 false 各路用自身时钟 |
| strictSync | boolean | false | 严格同步(需 unifiedTimer=true):任一通道断流无缓存且落后超过 syncThreshold 时暂停所有通道等待恢复 |
| syncThreshold | number | 100 | 严重不同步判定阈值(ms),运行时可用 setSyncThreshold(ms) 动态修改 |
| showToolbar | boolean | false | 是否显示顶部工具条(布局切换/统一控制) |
| fullscreenMode | 'window' | 'browser' | 'window' | 全屏方式:'window' 窗口全屏(该窗口占满整个网格,双击/按钮均走窗口全屏);'browser' 网页全屏(requestFullscreen) |
| playerOptions | object | - | 公共播放器参数,与每路配置合并后传给各子播放器(见下) |
| controlCallback | (from, type) => boolean | void | - | 通道控制监听:用户操作某一路控制条时触发;返回 false 可阻止该操作后续的联动/默认行为 |
playerOptions(公共子播放器参数)
与每路配置合并后传给每个窗口的播放器。常用字段:
| 参数 | 类型 | 必填 | 说明 |
|------|------|--------|------|
| host / port / ws | string / number / string | 是 | WebSocket 服务器地址与协议(ws/wss) |
| userId / tenantId / accessToken | string | 是 | 平台鉴权信息 |
| phone | string | 是 | 设备编码 |
| lang | string | 否 | 界面语言(如 'zh') |
| renderType | string | 否 | 解码方式:'wasm' / 'decode'(VideoDecoder),回放建议 decode |
| beginTime | string | 否 | 统一回放时间(YYYY-MM-DD HH:mm:ss);某路可用 beginTime 单独覆盖 |
| streamType | number | 否 | 统一码流类型(实时:0=主码流/1=子码流;回放:1=主码流/2=子码流);某路可用 streamType 单独覆盖 |
| debug | boolean | 否 | 是否显示每路调试信息悬浮层(默认 false) |
| showControlBar | boolean | 否 | 是否显示每路内置控制条(默认 true) |
| controlItems | string[] | 否 | 控制条按钮白名单(见下),空数组/不配置表示全部显示 |
| showChannelInfo | boolean | 否 | 是否显示顶部通道信息栏(默认 false) |
| channelInfoTemplate / channelInfoCustom | string | 否 | 通道信息栏模板与自定义内容(见下) |
| channelInfoPosition | 'top-left' | 'bottom-right' | 否 | 通道信息栏位置(默认 'top-left') |
| onlineWorker | object | 否 | 在线解码 Worker 资源(见「特殊场景」) |
| url | string | 否 | 直连播放地址,优先于 host/port/phone/channelNo 拼接 |
控制条按钮(controlItems)
| 值 | 按钮 | 说明 | |----|------|------| | play | ▶/⏸ | 播放/暂停 | | audio | 🔊/🔇 | 音频开关 | | speed | 倍速 | 回放时显示(- / 倍速 / +) | | refresh | ↻ | 刷新回放(回放时显示) | | stream | FHD/HD/SD | 码流切换(实时 HD/SD,回放 FHD/HD/SD) | | snapshot | ▲ | 截屏:当前画面导出 PNG 下载 | | record | ⏺/⏹ | 录屏:开始/停止(浏览器支持时输出 mp4(H.264+AAC),否则回退 webm),录制中右上角红点"REC 录制中" | | close | ✕ | 关闭该路:停止播放并清为空窗口 | | fullscreen | ⛶/▣ | 全屏(网页全屏或窗口全屏,随 fullscreenMode) |
顶部通道信息栏
开启 showChannelInfo: true 后,窗口内显示通道信息栏,内容由 channelInfoTemplate 模板定制:
| 占位符 | 含义 |
|--------|------|
| $custom | 自定义内容(摄像头名称等,来自 channelInfoCustom 或每路配置,未提供为空) |
| $code | 设备号 |
| $chn | 通道号 |
| $net | 网速(KB/s,播放中动态刷新) |
playerOptions: {
showChannelInfo: true,
channelInfoTemplate: '$custom $code CHN:$chn $net',
}
// 每路也可单独覆盖:urls: [{ channelNo: 1, channelInfoCustom: '前门摄像头' }]每路配置(urls 元素)
每路可为以下任一种:
- 地址字符串:
'ws://host:port/mndp/stream/xxx' - 对象
{ url }:同上 - 结构化参数对象:
{ url?, phone?, channelNo?, streamType?, beginTime?, channelInfoCustom?, ... },其中url可选;未给url时由公共host/port/phone/channelNo拼接
未配置(自动补齐的空窗口)显示虚线占位;appendChns 追加时会优先填充最早的空窗口。
布局与通道上限
- 布局取值
1/4/6/8/9/16/24/36;6/8为异形布局(1 大窗 + 其余小窗)。 setLayout(路数)自动取不小于输入值的最近布局(如 10 → 16);setNum/setChns/appendChns也会自动匹配布局路数。- 上限 36 路:
appendChns追加时,先填充最早空窗口 → 不足再新增 → 已满 36 时覆盖**最久未使用(LRU)**的窗口,轮流覆盖而非总覆盖同一个。 - 超过布局路数的窗口会按 36 上限的多行网格排布。
controlCallback:通道控制监听
用户操作某一路控制条(播放/暂停/关闭/码流切换/全屏等)时触发,可用于外部状态同步、接管或拦截。
multi.init({
// ...其他参数
controlCallback: (from, type) => {
console.log('通道操作', from.id, from.opts, 'type =', type)
// 窗口被关闭后(内部已清空该路为占位窗口)读取最新通道列表同步外部缓存:
if (type === 'close') {
setTimeout(() => console.log(multi.getAll()), 0)
}
// 返回 false 可阻止该操作后续的联动处理(含当前路默认行为)
},
})type 取值:'play' | 'stop' | 'audio' | 'speedDec' | 'speedInc' | 'fullscreen' | 'close' | 'refresh' | 'stream0' | 'stream1' | 'stream2' | 'windowFullscreen'
常用方法
| 方法 | 说明 |
|------|------|
| setLayout(n) | 切换布局(自动取最近不小于 n 的布局) |
| setNum(n) | 设置路数(多于当前追加空位,少于当前移除多余) |
| createChns(num, opts) | 重置为 num 路(用于整批重建) |
| setChns(opts) | 批量替换每路配置(截取/补齐/重建播放器) |
| appendChns(opts) | 追加路及配置(填充空位 → 新增 → 达上限 LRU 覆盖) |
| removeChns(index \| index[]) | 按索引删除窗口 |
| destroyChns() | 清空所有通道(保留网格空位);stop() 即调用它 |
| getAll() | 返回当前所有路副本 MnVideoMultiChn[] |
| getHasChnNum() | 已配置(可播放)的路数,不含空占位 |
| playChn(id) | 播放指定路(按该路 streamType/beginTime,缺省取全局) |
| playAll() | 播放全部已配置路 |
| pause() / resume() | 统一暂停/恢复 |
| stop() | 停止并清理所有路(销毁统一时钟、worker 等) |
| resetAll() | 停止全部并按当前各路配置整体重建(stop + setChns,用于整批重置) |
| refreshAll() | 刷新所有在播通道:回放路以当前全局时间作为新 beginTime 重播,实时路重连当前码流 |
| reloadChn(chn) | 重载指定路(销毁并重建该路子播放器;chn 为 getAll() 中的元素) |
| switchStreamAll(chn, type) | 切换某路码流并联动刷新所有在播路(控制条码流切换内部使用) |
| changeSpeed(spd) | 统一倍速(0.5–16,所有路同步) |
| resetSpeed() | 恢复 1x |
| enableAudio(enable) | 统一音频开关;syncMode 下仅一路发声 |
| toggleAudio() | 切换统一音频开关 |
| setSyncThreshold(ms) | 动态修改严重不同步判定阈值 |
| setStrictSync(on) | 动态开关严格同步 |
| swapChn(aId, bId) | 交换两路窗口(拖拽换位内部使用) |
| setPlaybackTime(t) | 设置统一回放时间(更新全局 beginTime,对后续播放/重建生效) |
| timeCallBack(fn) | 设置时间回调(继承自单路;统一时钟模式下回调为全局同步时间) |
| setSyncTime(t) | 供统一时钟写入全局同步时间(一般内部使用) |
MnVideoMultiChn 结构(来自 getAll()):
| 字段 | 说明 |
|------|------|
| id | 窗口自增 ID |
| url / opts | 该路播放地址 / 每路覆盖参数(phone/channelNo/... 或 null) |
| streamType / beginTime | 该路独立码流/回放时间(缺省回退全局) |
| lastUsed | LRU 序号(appendChns 覆盖时用到) |
| el / body | 窗口容器 / 播放器挂载容器 |
| player | 该路子播放器(MnVideoPlayer,播放中可用) |
示例
通道管理
// 追加两个通道(自动填充空位;已满 36 时覆盖最久未使用窗口)
multi.appendChns([
{ phone: '13695962142', channelNo: 2, streamType: 1 },
{ channelNo: 3 },
])
// 删除最后一路
multi.removeChns(multi.getHasChnNum() - 1)
// 读取当前通道(如持久化到 localStorage,供下次重建 urls)
const snapshot = multi.getAll().map(c => ({
url: c.url,
phone: c.opts?.phone,
channelNo: c.opts?.channelNo,
streamType: c.streamType,
}))同步模式(多路帧级同步)
multi.init({
// ...其他参数
syncMode: true, // 统一倍速 / 单路音频
unifiedTimer: true, // 多路共用统一时钟,帧时间同步(< syncThreshold)
strictSync: true, // 某路断流无缓存且落后时暂停所有路等待
syncThreshold: 100, // 判定严重不同步的阈值(ms)
})
multi.setSyncThreshold(150) // 运行时动态调整阈值
multi.setStrictSync(false) // 或临时关闭严格同步
multi.changeSpeed(2) // 所有路同步 2x同步模式下任一路窗口上的播放/暂停、倍速、码流等用户操作会联动到所有路;程序化调用(playAll/changeSpeed 等)本身即面向全体。
unifiedTimer: false时各路使用自身时钟,但 syncMode 的联动/单路音频/统一倍速仍生效。启动首帧对齐:同步播放启动时,各通道注册后标记"未出帧",出帧后标记"已出帧"。先就绪的通道出首帧前会等待最慢通道首帧到达(多因解码器初始化/等 I 帧较慢),待所有通道首帧就绪后尽量在同一时刻一起出帧,消除各路启动渲染的时间差;某通道始终无流时最多等 5 秒(对齐上限,超时强制出帧兜底),不会卡死其他路。
窗口全屏与网页全屏
multi.init({
// ...其他参数
fullscreenMode: 'window', // 默认:控制条 ▣ + 双击 → 该窗口占满整个网格
// fullscreenMode: 'browser', // 控制条 ⛶ + 双击 → 浏览器原生网页全屏
})- 窗口全屏退出后自动恢复原布局(含 6/8 异形)。
- 若某路正在窗口全屏,切换布局/销毁时会自动退出全屏。
播放/暂停/恢复
multi.playAll() // 播放全部已配置路(空占位窗口跳过)
multi.pause() // 全部暂停
multi.resume() // 全部恢复
multi.stop() // 停止并清理(保留网格空位)
multi.playChn(3) // 只播放指定 id 的路特殊场景:file:// 直开等环境的解码 Worker(onlineWorker)
多路播放器各窗口的解码 Worker 默认与页面同源部署(相对路径加载 mn-common-c.js / mn-media-v2.js / mn-media-v2.wasm)。当插件运行在 file:// 直开、离线壳等无法按相对路径加载的环境时,可通过 playerOptions.onlineWorker 传入这三份构建产物的在线地址(须为同一版本、允许 CORS),播放器将以「内置 worker 源码 + Blob URL」方式创建解码 Worker:
playerOptions: {
onlineWorker: {
common: 'https://cdn.example.com/mn-common-c.js',
media: 'https://cdn.example.com/mn-media-v2.js',
wasm: 'https://cdn.example.com/mn-media-v2.wasm',
},
}说明:地址缺失或创建失败会自动回退内置加载方式;宿主环境若完全禁止创建 Worker(含 Blob),则该模式也无法生效。
注意事项
- 容器元素:init 时必须提供有效 DOM 元素;重建实例前先调用旧实例的
stop()并清空容器。 - 联动范围:控制条上的用户操作(播放/暂停/码流切换/关闭/全屏等)在 syncMode 下联动全体;程序化 API 不重复联动。
- 资源清理:
stop()/destroyChns()会停止所有路播放器、销毁统一时钟并释放 worker 等资源;单路关闭(✕)只清空该窗口。 - 网速/调试:各窗口独立统计,可通过
multi.getAll()[i].player访问对应子播放器的netSpeedCallback/timerCtrl等。 - 录屏声音:录屏时同步录制该路播放声音;多路各窗口独立录制。
浏览器兼容性
- Chrome 90+ / Edge 90+ / Firefox 88+ / Safari 14+
- 需要支持:WebSocket、Canvas、Web Audio、WebAssembly(WASM 解码时)、VideoDecoder(decode 解码时)
