@video-supply/dahua-player 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -91,7 +91,9 @@ Optional:
91
91
  - `staticPath?: string` (default `/wsplayer-gov`)
92
92
  - `sdkUrl?: string` (default `/wsplayer-gov/wsplayer.min.js`)
93
93
  - `debug?: boolean` (default `false`)
94
- - callbacks: `onReady/onPlay/onPause/onError/onDestroy`
94
+ - callbacks: `onReady/onPlay/onPause/onPlaybackTime/onError/onDestroy`
95
+ - `onPlaybackTime(payload)` is record-mode only and fires when `timeSec` changes (about once per second).
96
+ - payload: `{ timeMs, timeSec, windowIndex?, channelCode?, raw? }`
95
97
 
96
98
  Returns: `DahuaPlayerInstance`
97
99
 
@@ -107,8 +109,37 @@ Returns: `DahuaPlayerInstance`
107
109
  - Destroys the instance and releases resources.
108
110
  - Removes DOM nodes, clears timers, and releases sessionStorage shims.
109
111
  - `on(event, handler) / off(event, handler)`
110
- - Subscribe/unsubscribe events: `ready` / `play` / `pause` / `error` / `destroy`.
112
+ - Subscribe/unsubscribe events: `ready` / `play` / `pause` / `playbackTime` / `error` / `destroy`.
111
113
  - `play` payload: `{ mode?: 'real' | 'record' }`.
114
+ - `getPlaybackTimeMs(): number | null`
115
+ - Returns the latest playback time in epoch milliseconds (record mode only).
116
+ - Returns `null` before the first playback timestamp arrives.
117
+
118
+ #### Playback time example (callback + imperative getter)
119
+
120
+ ```ts
121
+ const player = DahuaPlayer.init({
122
+ container: 'player',
123
+ auth: { token: 'YOUR_DAHUA_TOKEN' },
124
+ mode: 'record',
125
+ onPlaybackTime: ({ timeMs, timeSec }) => {
126
+ console.log('playback time changed:', timeSec, timeMs);
127
+ },
128
+ });
129
+
130
+ await player.ready;
131
+
132
+ player.on('playbackTime', ({ timeMs, timeSec }) => {
133
+ console.log('playbackTime event:', timeSec, timeMs);
134
+ });
135
+
136
+ player.sdk.playRecordVideo({
137
+ startTime: Math.floor(Date.now() / 1000) - 60,
138
+ endTime: Math.floor(Date.now() / 1000),
139
+ });
140
+
141
+ console.log('getPlaybackTimeMs:', player.getPlaybackTimeMs());
142
+ ```
112
143
 
113
144
  #### SDK methods (`instance.sdk`)
114
145
 
@@ -308,6 +339,8 @@ await player.ready;
308
339
  - `onReady`:内核初始化完成(不等同于播放成功)
309
340
  - `onPlay`:播放成功(包含 real/record)
310
341
  - `onPause`:暂停
342
+ - `onPlaybackTime`:回放当前时间变化(仅 mode=record,默认按秒变化触发)
343
+ - payload:`{ timeMs, timeSec, windowIndex?, channelCode?, raw? }`
311
344
  - `onError`:初始化/播放等错误
312
345
  - `onDestroy`:销毁
313
346
  - `onSdkMessage`:透出 WSPlayer 原始消息(排障用)
@@ -329,8 +362,11 @@ await instance.ready;
329
362
  - 销毁播放器实例并释放资源
330
363
  - 会移除 DOM、清理定时器、释放 sessionStorage shim
331
364
  - `instance.on(event, handler) / instance.off(event, handler)`
332
- - 订阅/取消订阅事件:`ready` / `play` / `pause` / `error` / `destroy`
365
+ - 订阅/取消订阅事件:`ready` / `play` / `pause` / `playbackTime` / `error` / `destroy`
333
366
  - `play` 事件 payload:`{ mode?: 'real' | 'record' }`
367
+ - `instance.getPlaybackTimeMs(): number | null`
368
+ - 主动获取最近一次收到的“当前回放时间(epoch ms)”
369
+ - 仅 mode=record 时有意义;未收到回放时间前返回 null
334
370
 
335
371
  `instance.sdk`:
336
372
 
package/README.zh-CN.md CHANGED
@@ -107,6 +107,14 @@ await player.ready;
107
107
  - `onReady`:内核初始化完成(不等同于播放成功)
108
108
  - `onPlay`:播放成功(包含 real/record)
109
109
  - `onPause`:暂停
110
+ - `onPlaybackTime`:回放当前时间变化(仅 mode=record,默认按秒变化触发)
111
+ - 触发时机:底层 SDK 会高频推送回放帧信息;库内部只在 `timeSec` 变化时对外触发(约 1 次/秒)
112
+ - payload:`{ timeMs, timeSec, windowIndex?, channelCode?, raw? }`
113
+ - `timeMs`:当前回放时间(epoch 毫秒)
114
+ - `timeSec`:当前回放时间(epoch 秒)
115
+ - `windowIndex`:窗口索引(可选)
116
+ - `channelCode`:通道编码(可选)
117
+ - `raw`:原始 SDK data(可选,用于排障)
110
118
  - `onError`:初始化/播放等错误
111
119
  - `onDestroy`:销毁
112
120
  - `onSdkMessage`:透出 WSPlayer 原始消息(排障用)
@@ -128,8 +136,38 @@ await instance.ready;
128
136
  - 销毁播放器实例并释放资源
129
137
  - 会移除 DOM、清理定时器、释放 sessionStorage shim
130
138
  - `instance.on(event, handler) / instance.off(event, handler)`
131
- - 订阅/取消订阅事件:`ready` / `play` / `pause` / `error` / `destroy`
139
+ - 订阅/取消订阅事件:`ready` / `play` / `pause` / `playbackTime` / `error` / `destroy`
132
140
  - `play` 事件 payload:`{ mode?: 'real' | 'record' }`
141
+ - `instance.getPlaybackTimeMs(): number | null`
142
+ - 主动获取最近一次收到的“当前回放时间(epoch ms)”
143
+ - 仅 mode=record 时有意义;未收到回放时间前返回 null
144
+
145
+ ### 回放时间示例(回调 + 主动获取)
146
+
147
+ ```ts
148
+ const player = DahuaPlayer.init({
149
+ container: 'player',
150
+ auth: { token: 'YOUR_DAHUA_TOKEN' },
151
+ mode: 'record',
152
+ onPlaybackTime: ({ timeMs, timeSec, windowIndex, channelCode }) => {
153
+ console.log('回放时间变化(秒级触发):', timeSec, timeMs, windowIndex, channelCode);
154
+ },
155
+ });
156
+
157
+ await player.ready;
158
+
159
+ player.on('playbackTime', ({ timeMs, timeSec }) => {
160
+ console.log('playbackTime 事件:', timeSec, timeMs);
161
+ });
162
+
163
+ player.sdk.playRecordVideo({
164
+ startTime: Math.floor(Date.now() / 1000) - 60,
165
+ endTime: Math.floor(Date.now() / 1000),
166
+ });
167
+
168
+ const t = player.getPlaybackTimeMs();
169
+ console.log('主动获取(可能为null):', t);
170
+ ```
133
171
 
134
172
  `instance.sdk`:
135
173
 
package/dist/index.cjs CHANGED
@@ -250,6 +250,7 @@ var PlayerAdapter = class {
250
250
  this.playerManager = null;
251
251
  this.destroyed = false;
252
252
  this.readyResolved = false;
253
+ this.lastStatus = null;
253
254
  this.currentNum = 1;
254
255
  this.currentMaxNum = 1;
255
256
  this.opts = opts;
@@ -356,8 +357,17 @@ var PlayerAdapter = class {
356
357
  return;
357
358
  }
358
359
  case "statusChanged": {
359
- if (data && typeof data === "object" && (data.status === "pause" || data.status === "paused")) {
360
- this.opts.emit("pause");
360
+ const status = data && typeof data === "object" ? data.status : void 0;
361
+ if (typeof status === "string" && status && status !== this.lastStatus) {
362
+ this.lastStatus = status;
363
+ if (status === "pause" || status === "paused") {
364
+ this.opts.emit("pause");
365
+ return;
366
+ }
367
+ if (status === "playing") {
368
+ this.opts.emit("play", { mode: this.opts.mode });
369
+ return;
370
+ }
361
371
  }
362
372
  return;
363
373
  }
@@ -676,8 +686,8 @@ var PlayerAdapter = class {
676
686
  this.playerManager.pause(0);
677
687
  } else if (typeof this.playerManager.close === "function") {
678
688
  this.playerManager.close(0);
689
+ this.opts.emit("pause");
679
690
  }
680
- this.opts.emit("pause");
681
691
  } catch {
682
692
  }
683
693
  }
@@ -690,8 +700,8 @@ var PlayerAdapter = class {
690
700
  this.playerManager.pause(idx);
691
701
  } else if (typeof this.playerManager.close === "function") {
692
702
  this.playerManager.close(idx);
703
+ this.opts.emit("pause");
693
704
  }
694
- this.opts.emit("pause");
695
705
  } catch {
696
706
  }
697
707
  }
@@ -731,6 +741,35 @@ var PlayerAdapter = class {
731
741
  }
732
742
  };
733
743
 
744
+ // src/sdk/PlaybackTime.ts
745
+ function extractPlaybackTimeMsFromFrameInfo(data) {
746
+ const vf = data && typeof data === "object" ? data.videoFrameInfo : void 0;
747
+ const utcMsRaw = vf && typeof vf === "object" ? vf.utcTimeStamp : void 0;
748
+ const secRaw = data && typeof data === "object" ? data.timeStamp : void 0;
749
+ const utcMs = typeof utcMsRaw === "number" && Number.isFinite(utcMsRaw) ? Math.floor(utcMsRaw) : null;
750
+ const sec = typeof secRaw === "number" && Number.isFinite(secRaw) ? Math.floor(secRaw) : null;
751
+ const baseMs = utcMs != null ? utcMs : sec != null ? sec * 1e3 : null;
752
+ if (baseMs == null) return null;
753
+ const shouldApplySubMs = utcMs == null ? true : utcMs % 1e3 === 0;
754
+ if (!shouldApplySubMs) return baseMs;
755
+ const nTimeStampRaw = vf && typeof vf === "object" ? vf.nTimeStamp : void 0;
756
+ if (typeof nTimeStampRaw !== "number" || !Number.isFinite(nTimeStampRaw)) return baseMs;
757
+ const sub = (Math.floor(nTimeStampRaw) % 1e3 + 1e3) % 1e3;
758
+ return baseMs + sub;
759
+ }
760
+ function buildPlaybackTimePayloadFromFrameInfo(data) {
761
+ var _a;
762
+ const timeMs = extractPlaybackTimeMsFromFrameInfo(data);
763
+ if (timeMs == null) return null;
764
+ const secRaw = data && typeof data === "object" ? data.timeStamp : void 0;
765
+ const timeSec = typeof secRaw === "number" && Number.isFinite(secRaw) ? Math.floor(secRaw) : Math.floor(timeMs / 1e3);
766
+ const idxRaw = data && typeof data === "object" ? data.selectIndex : void 0;
767
+ const windowIndex = typeof idxRaw === "number" && Number.isFinite(idxRaw) ? Math.floor(idxRaw) : void 0;
768
+ const channelCodeRaw = data && typeof data === "object" ? (_a = data.channelData) == null ? void 0 : _a.channelCode : void 0;
769
+ const channelCode = typeof channelCodeRaw === "string" ? channelCodeRaw : void 0;
770
+ return { timeMs, timeSec, windowIndex, channelCode, raw: data };
771
+ }
772
+
734
773
  // src/DahuaPlayer.ts
735
774
  function normalizeStaticPath(path) {
736
775
  const raw = (path || "").trim();
@@ -902,6 +941,8 @@ var DahuaPlayer = class {
902
941
  };
903
942
  let readyReject = () => {
904
943
  };
944
+ let lastPlaybackTimeMs = null;
945
+ let lastEmittedPlaybackTimeSec = null;
905
946
  const safeOnError = (e) => {
906
947
  var _a2;
907
948
  try {
@@ -983,11 +1024,24 @@ var DahuaPlayer = class {
983
1024
  playerOptions: opts.playerOptions,
984
1025
  debug: opts.debug,
985
1026
  onMessage: (type, data) => {
986
- var _a3;
1027
+ var _a3, _b2;
987
1028
  try {
988
1029
  (_a3 = opts.onSdkMessage) == null ? void 0 : _a3.call(opts, type, data);
989
1030
  } catch {
990
1031
  }
1032
+ if (type === "getVideoFrameInfo") {
1033
+ const payload = buildPlaybackTimePayloadFromFrameInfo(data);
1034
+ if (!payload) return;
1035
+ lastPlaybackTimeMs = payload.timeMs;
1036
+ if (payload.timeSec !== lastEmittedPlaybackTimeSec) {
1037
+ lastEmittedPlaybackTimeSec = payload.timeSec;
1038
+ try {
1039
+ (_b2 = opts.onPlaybackTime) == null ? void 0 : _b2.call(opts, payload);
1040
+ } catch {
1041
+ }
1042
+ emit(listeners, "playbackTime", payload);
1043
+ }
1044
+ }
991
1045
  },
992
1046
  emit: (event, payload) => {
993
1047
  var _a3, _b2, _c2;
@@ -1055,6 +1109,7 @@ var DahuaPlayer = class {
1055
1109
  readyReject(err);
1056
1110
  }
1057
1111
  })();
1112
+ const getPlaybackTimeMs = () => lastPlaybackTimeMs;
1058
1113
  const instance = {
1059
1114
  id,
1060
1115
  ready,
@@ -1067,6 +1122,7 @@ var DahuaPlayer = class {
1067
1122
  if (!adapter) return;
1068
1123
  adapter.pause();
1069
1124
  },
1125
+ getPlaybackTimeMs,
1070
1126
  /**
1071
1127
  * 销毁播放器实例并释放资源。
1072
1128
  *