@give-tech/ec-player 0.0.1-beta.30 → 0.0.1-beta.32

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/dist/index.js CHANGED
@@ -118,9 +118,11 @@ class H264Decoder {
118
118
  }
119
119
  const DEFAULT_PLAYER_CONFIG = {
120
120
  wasmPath: "/wasm/decoder-simd.js",
121
- targetBufferSize: 60,
121
+ targetBufferSize: 90,
122
+ // 90 帧(约 3.6 秒 @25fps),适应高分辨率视频
122
123
  decodeBatchSize: 2,
123
- maxQueueSize: 200,
124
+ maxQueueSize: 300,
125
+ // 增加 sample 队列上限
124
126
  isLive: false
125
127
  };
126
128
  class BasePlayer {
@@ -1236,7 +1238,8 @@ class SegmentPrefetcher extends BasePrefetcher {
1236
1238
  this.prefetchQueue.push({
1237
1239
  data,
1238
1240
  segmentIndex: nextIndex,
1239
- fetchTime
1241
+ fetchTime,
1242
+ segmentDuration: segment.duration
1240
1243
  });
1241
1244
  this.fetchedSegmentCount++;
1242
1245
  this.updateStatus({
@@ -1274,7 +1277,7 @@ class SegmentPrefetcher extends BasePrefetcher {
1274
1277
  this.prefetchQueue.shift();
1275
1278
  this.updateStatus({ prefetchQueueSize: this.prefetchQueue.length });
1276
1279
  const parseStart = performance.now();
1277
- const itemCount = this.parseSegment(item.data, item.segmentIndex);
1280
+ const itemCount = this.parseSegment(item.data, item.segmentIndex, item.segmentDuration);
1278
1281
  const parseTime = performance.now() - parseStart;
1279
1282
  this.currentSegmentIndex++;
1280
1283
  this.updateStatus({ currentSegmentIndex: this.currentSegmentIndex });
@@ -1510,7 +1513,8 @@ const HLS_PREFETCHER_CONFIG = {
1510
1513
  ...DEFAULT_SEGMENT_PREFETCHER_CONFIG,
1511
1514
  lowWaterMark: 30,
1512
1515
  highWaterMark: 100,
1513
- prefetchAhead: 2,
1516
+ prefetchAhead: 6,
1517
+ // 预载 6 个分片(约 30 秒),适应高分辨率视频
1514
1518
  prefetchInterval: 10,
1515
1519
  dynamicInterval: true
1516
1520
  };
@@ -1545,11 +1549,11 @@ class HLSSegmentPrefetcher extends SegmentPrefetcher {
1545
1549
  /**
1546
1550
  * 解析分片数据
1547
1551
  */
1548
- parseSegment(data, index) {
1552
+ parseSegment(data, index, segmentDuration) {
1549
1553
  if (this.player.isFMP4) {
1550
1554
  return this.player.parseFMP4Data(data);
1551
1555
  } else {
1552
- return this.player.parseTSData(data);
1556
+ return this.player.parseTSData(data, segmentDuration);
1553
1557
  }
1554
1558
  }
1555
1559
  /**
@@ -1581,14 +1585,36 @@ class HLSPlayer extends BasePlayer {
1581
1585
  this.currentPlaylistUrl = "";
1582
1586
  this._nalQueue = [];
1583
1587
  this._sampleQueue = [];
1588
+ this._currentSegmentDuration = 0;
1584
1589
  this.prefetcher = null;
1590
+ this._nalCountInCurrentSegment = 0;
1585
1591
  this.lastRenderTime = 0;
1586
1592
  this.playStartTime = 0;
1587
1593
  this.accumulatedMediaTime = 0;
1588
1594
  this._lastLogTime = 0;
1595
+ this._lastRafTime = 0;
1589
1596
  this.renderLoop = (timestamp = 0) => {
1590
1597
  if (!this.isPlaying) return;
1591
1598
  const now = performance.now();
1599
+ const BACKGROUND_PAUSE_THRESHOLD = 500;
1600
+ if (this._lastRafTime > 0 && now - this._lastRafTime > BACKGROUND_PAUSE_THRESHOLD) {
1601
+ const pauseDuration = now - this._lastRafTime;
1602
+ console.log("[renderLoop] Background pause detected, duration:", pauseDuration.toFixed(0), "ms");
1603
+ if (this.config.isLive) {
1604
+ const KEEP_FRAMES = 5;
1605
+ if (this.frameBuffer.length > KEEP_FRAMES) {
1606
+ const droppedCount = this.frameBuffer.length - KEEP_FRAMES;
1607
+ this.frameBuffer = this.frameBuffer.slice(-KEEP_FRAMES);
1608
+ this.droppedFrames += droppedCount;
1609
+ console.log("[renderLoop] Live resume: dropped", droppedCount, "old frames, keeping latest", KEEP_FRAMES);
1610
+ }
1611
+ this.playStartTime = now;
1612
+ this.accumulatedMediaTime = 0;
1613
+ } else {
1614
+ this.playStartTime = now - this.accumulatedMediaTime;
1615
+ }
1616
+ }
1617
+ this._lastRafTime = now;
1592
1618
  if (!this._lastLogTime || now - this._lastLogTime > 1e3) {
1593
1619
  this._lastLogTime = now;
1594
1620
  console.log("[renderLoop] frameBuffer=", this.frameBuffer.length, "renderer=", !!this.renderer);
@@ -1693,6 +1719,8 @@ class HLSPlayer extends BasePlayer {
1693
1719
  isLoaded: true,
1694
1720
  totalSegments: segments.length
1695
1721
  });
1722
+ this.initPrefetcher();
1723
+ this.prefetcher.start();
1696
1724
  }
1697
1725
  /**
1698
1726
  * 初始化解码器(覆盖基类方法,添加 fMP4 支持)
@@ -1789,11 +1817,12 @@ class HLSPlayer extends BasePlayer {
1789
1817
  while (this.nalQueue.length > 0 && decodedInBatch < batchSize) {
1790
1818
  const queuedNal = this.nalQueue.shift();
1791
1819
  const nalUnit = queuedNal.nalUnit;
1820
+ const segmentDuration = queuedNal.segmentDuration;
1792
1821
  if (!this.decoderInitialized && (nalUnit.type === 7 || nalUnit.type === 8)) {
1793
1822
  this.initDecoderParamsSync([nalUnit]);
1794
1823
  }
1795
1824
  if (nalUnit.type === 5 || nalUnit.type === 1) {
1796
- const frame = this.decodeNAL(nalUnit);
1825
+ const frame = this.decodeNAL(nalUnit, segmentDuration);
1797
1826
  if (frame) {
1798
1827
  this.frameBuffer.push(frame);
1799
1828
  decodedInBatch++;
@@ -1907,7 +1936,7 @@ class HLSPlayer extends BasePlayer {
1907
1936
  /**
1908
1937
  * 解析 TS 数据
1909
1938
  */
1910
- parseTSData(tsData) {
1939
+ parseTSData(tsData, segmentDuration) {
1911
1940
  const packets = this.tsDemuxer.parse(tsData);
1912
1941
  let nalCount = 0;
1913
1942
  if (packets.video.length > 0) {
@@ -1917,8 +1946,15 @@ class HLSPlayer extends BasePlayer {
1917
1946
  if (!this.decoderInitialized) {
1918
1947
  this.initDecoderParamsSync(nalUnits);
1919
1948
  }
1949
+ if (segmentDuration !== void 0) {
1950
+ this._currentSegmentDuration = segmentDuration;
1951
+ }
1920
1952
  for (const nalUnit of nalUnits) {
1921
- this._nalQueue.push({ nalUnit, pts: 0 });
1953
+ this._nalQueue.push({
1954
+ nalUnit,
1955
+ pts: 0,
1956
+ segmentDuration: this._currentSegmentDuration
1957
+ });
1922
1958
  }
1923
1959
  nalCount = nalUnits.length;
1924
1960
  }
@@ -1975,7 +2011,13 @@ class HLSPlayer extends BasePlayer {
1975
2011
  this._sampleQueue.length = 0;
1976
2012
  this._nalQueue.length = 0;
1977
2013
  const url = uri.startsWith("http") ? uri : this.currentPlaylistUrl.substring(0, this.currentPlaylistUrl.lastIndexOf("/") + 1) + uri;
1978
- const response = await fetch(url);
2014
+ const headers = {};
2015
+ if (this.initSegment?.uri === uri && this.initSegment.byteRange) {
2016
+ const { start, end } = this.initSegment.byteRange;
2017
+ headers["Range"] = `bytes=${start}-${end}`;
2018
+ console.log("[fMP4] Using byte range for init segment:", { start, end });
2019
+ }
2020
+ const response = await fetch(url, { headers });
1979
2021
  const data = new Uint8Array(await response.arrayBuffer());
1980
2022
  console.log("[fMP4] New init segment data size:", data.length, "bytes");
1981
2023
  const initInfo = this.fmp4Demuxer.parseInitSegment(data);
@@ -2294,16 +2336,22 @@ class HLSPlayer extends BasePlayer {
2294
2336
  /**
2295
2337
  * 解码单个 NAL 单元
2296
2338
  */
2297
- decodeNAL(nalUnit) {
2339
+ decodeNAL(nalUnit, segmentDuration) {
2298
2340
  if (!this.decoder) return null;
2299
2341
  const nalWithStartCode = new Uint8Array(nalUnit.size + 4);
2300
2342
  nalWithStartCode.set([0, 0, 0, 1], 0);
2301
2343
  nalWithStartCode.set(nalUnit.data, 4);
2302
- return this.decoder.decode({
2344
+ const frame = this.decoder.decode({
2303
2345
  type: nalUnit.type,
2304
2346
  data: nalWithStartCode,
2305
2347
  size: nalWithStartCode.length
2306
2348
  });
2349
+ if (frame && segmentDuration && segmentDuration > 0) {
2350
+ const timescale = 1e3;
2351
+ const frameDuration = timescale / 60;
2352
+ frame.duration = frameDuration;
2353
+ }
2354
+ return frame;
2307
2355
  }
2308
2356
  }
2309
2357
  const FLV_SIGNATURE = [70, 76, 86];
@@ -2839,6 +2887,7 @@ class FLVPlayer extends BasePlayer {
2839
2887
  this.bufferEmptyStartTime = 0;
2840
2888
  this.playStartTimeOffset = 0;
2841
2889
  this.resyncCount = 0;
2890
+ this._lastRafTime = 0;
2842
2891
  this.renderLoop = () => {
2843
2892
  if (!this.isPlaying) return;
2844
2893
  this.updateState({
@@ -2848,12 +2897,32 @@ class FLVPlayer extends BasePlayer {
2848
2897
  });
2849
2898
  const now = performance.now();
2850
2899
  const isLive = this.config.isLive;
2900
+ const BACKGROUND_PAUSE_THRESHOLD = 500;
2901
+ if (this._lastRafTime > 0 && now - this._lastRafTime > BACKGROUND_PAUSE_THRESHOLD) {
2902
+ const pauseDuration = now - this._lastRafTime;
2903
+ console.log("[FLVPlayer] Background pause detected, duration:", pauseDuration.toFixed(0), "ms, isLive:", isLive, "queue:", this._videoTagQueue.length, "buffer:", this._timedFrameBuffer.length);
2904
+ if (isLive) {
2905
+ const droppedDecoded = this._timedFrameBuffer.length;
2906
+ const droppedQueue = this._videoTagQueue.length;
2907
+ this._timedFrameBuffer = [];
2908
+ this._videoTagQueue = [];
2909
+ this.droppedFrames += droppedDecoded;
2910
+ this.playStartTime = 0;
2911
+ this.firstFrameDts = -1;
2912
+ this.pausedTime = 0;
2913
+ console.log("[FLVPlayer] Live resume: cleared all buffers (decoded:", droppedDecoded, ", queue:", droppedQueue, "), waiting for new data");
2914
+ } else {
2915
+ this.playStartTimeOffset += pauseDuration;
2916
+ }
2917
+ }
2918
+ this._lastRafTime = now;
2851
2919
  if (this._timedFrameBuffer.length > 0 && this.renderer) {
2852
2920
  this.consecutiveEmptyBuffer = 0;
2853
2921
  if (this.playStartTime <= 0) {
2854
2922
  this.firstFrameDts = this._timedFrameBuffer[0].dts;
2855
2923
  this.playStartTime = now;
2856
2924
  this.playStartTimeOffset = 0;
2925
+ this.pausedTime = 0;
2857
2926
  console.log("[FLVPlayer] RenderLoop initialized, firstFrameDts:", this.firstFrameDts, "isLive:", isLive);
2858
2927
  }
2859
2928
  if (isLive) {