@give-tech/ec-player 0.0.1-beta.33 → 0.0.1-beta.35

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.
@@ -52,6 +52,7 @@ export interface InitSegment {
52
52
  avcC?: Uint8Array;
53
53
  hvcC?: Uint8Array;
54
54
  isHevc?: boolean;
55
+ lengthSizeMinusOne?: number;
55
56
  }
56
57
  export declare class fMP4Demuxer {
57
58
  private timescale;
@@ -59,6 +60,7 @@ export declare class fMP4Demuxer {
59
60
  private avcC;
60
61
  private hvcC;
61
62
  private isHevc;
63
+ private lengthSizeMinusOne;
62
64
  private trackHandlers;
63
65
  /**
64
66
  * 解析初始化段 (ftyp + moov)
@@ -141,6 +143,10 @@ export declare class fMP4Demuxer {
141
143
  * 是否为 HEVC 编码
142
144
  */
143
145
  isHevcStream(): boolean;
146
+ /**
147
+ * 获取 NAL 长度字段大小 - 1
148
+ */
149
+ getLengthSizeMinusOne(): number;
144
150
  }
145
151
  /**
146
152
  * 检测是否为 fMP4 格式
@@ -1 +1 @@
1
- {"version":3,"file":"fMP4Demuxer.d.ts","sourceRoot":"","sources":["../../src/demuxer/fMP4Demuxer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fMP4Demuxer.d.ts","sourceRoot":"","sources":["../../src/demuxer/fMP4Demuxer.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -511,6 +511,7 @@ class fMP4Demuxer {
511
511
  this.avcC = null;
512
512
  this.hvcC = null;
513
513
  this.isHevc = false;
514
+ this.lengthSizeMinusOne = 3;
514
515
  this.trackHandlers = /* @__PURE__ */ new Map();
515
516
  }
516
517
  /**
@@ -532,7 +533,8 @@ class fMP4Demuxer {
532
533
  timescale: this.timescale,
533
534
  avcC: this.avcC || void 0,
534
535
  hvcC: this.hvcC || void 0,
535
- isHevc: this.isHevc
536
+ isHevc: this.isHevc,
537
+ lengthSizeMinusOne: this.lengthSizeMinusOne
536
538
  };
537
539
  }
538
540
  /**
@@ -685,6 +687,10 @@ class fMP4Demuxer {
685
687
  if (boxSize < 8) break;
686
688
  if (boxType === "avcC") {
687
689
  this.avcC = data.slice(offset, offset + boxSize);
690
+ if (boxSize > 12) {
691
+ this.lengthSizeMinusOne = data[offset + 8 + 4] & 3;
692
+ console.log("[fMP4Demuxer] avcC lengthSizeMinusOne:", this.lengthSizeMinusOne, "(NAL length size:", this.lengthSizeMinusOne + 1, "bytes)");
693
+ }
688
694
  return;
689
695
  }
690
696
  offset += boxSize;
@@ -703,6 +709,10 @@ class fMP4Demuxer {
703
709
  if (boxSize < 8) break;
704
710
  if (boxType === "hvcC") {
705
711
  this.hvcC = data.slice(offset, offset + boxSize);
712
+ if (boxSize > 12) {
713
+ this.lengthSizeMinusOne = data[offset + 8 + 21] & 3;
714
+ console.log("[fMP4Demuxer] hvcC lengthSizeMinusOne:", this.lengthSizeMinusOne, "(NAL length size:", this.lengthSizeMinusOne + 1, "bytes)");
715
+ }
706
716
  console.log("[fMP4Demuxer] Found hvcC, size:", boxSize);
707
717
  return;
708
718
  }
@@ -944,6 +954,12 @@ class fMP4Demuxer {
944
954
  isHevcStream() {
945
955
  return this.isHevc;
946
956
  }
957
+ /**
958
+ * 获取 NAL 长度字段大小 - 1
959
+ */
960
+ getLengthSizeMinusOne() {
961
+ return this.lengthSizeMinusOne;
962
+ }
947
963
  }
948
964
  class NALParser {
949
965
  /**
@@ -1901,7 +1917,7 @@ class HLSPlayer extends BasePlayer {
1901
1917
  if (this.isFMP4) {
1902
1918
  const queueSize = this.sampleQueue.length;
1903
1919
  if (queueSize > 0 || batchCount % 50 === 0) {
1904
- console.log("[DecodeLoop] fMP4: sampleQueue=", queueSize, "frameBuffer=", this.frameBuffer.length, "batch=", batchCount);
1920
+ console.log("[DecodeLoop] fMP4: sampleQueue=", queueSize, "frameBuffer=", this.frameBuffer.length, "batch=", batchCount, "decoderInit=", this.decoderInitialized);
1905
1921
  }
1906
1922
  while (this.sampleQueue.length > 0 && decodedInBatch < batchSize) {
1907
1923
  const queuedSample = this.sampleQueue.shift();
@@ -1916,6 +1932,8 @@ class HLSPlayer extends BasePlayer {
1916
1932
  this.droppedFrames++;
1917
1933
  }
1918
1934
  }
1935
+ } else {
1936
+ console.warn("[DecodeLoop] decodeSample returned null, remaining samples=", this.sampleQueue.length);
1919
1937
  }
1920
1938
  }
1921
1939
  } else {
@@ -2091,7 +2109,8 @@ class HLSPlayer extends BasePlayer {
2091
2109
  isHevc: initInfo?.isHevc,
2092
2110
  hasAvcC: !!initInfo?.avcC,
2093
2111
  hasHvcC: !!initInfo?.hvcC,
2094
- timescale: initInfo?.timescale
2112
+ timescale: initInfo?.timescale,
2113
+ lengthSizeMinusOne: initInfo?.lengthSizeMinusOne
2095
2114
  });
2096
2115
  this._isHevc = initInfo?.isHevc ?? false;
2097
2116
  if (initInfo?.hvcC && this._isHevc) {
@@ -2367,53 +2386,61 @@ class HLSPlayer extends BasePlayer {
2367
2386
  decodeSample(sample) {
2368
2387
  const decoder = this._isHevc ? this.hevcDecoder : this.decoder;
2369
2388
  if (!decoder) {
2370
- console.warn("[fMP4] Decoder not available");
2389
+ console.warn("[fMP4] Decoder not available, isHevc=", this._isHevc);
2371
2390
  return null;
2372
2391
  }
2373
2392
  if (!this.decoderInitialized) {
2374
- console.warn("[fMP4] Decoder not initialized, skipping sample");
2393
+ console.warn("[fMP4] Decoder not initialized, isHevc=", this._isHevc, ", sample size=", sample.data.length);
2375
2394
  return null;
2376
2395
  }
2377
2396
  const data = sample.data;
2378
- const looksLikeStartCode = data.length >= 4 && data[0] === 0 && data[1] === 0 && (data[2] === 1 || data[2] === 0 && data[3] === 1);
2379
- let hasStartCode = looksLikeStartCode;
2380
- if (looksLikeStartCode) {
2381
- const possibleAvccLength = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
2382
- if (possibleAvccLength > 0 && possibleAvccLength + 4 === data.length) {
2383
- hasStartCode = false;
2397
+ const lengthSize = this.fmp4Demuxer.getLengthSizeMinusOne() + 1;
2398
+ const readNalLength = (data2, offset2, size) => {
2399
+ switch (size) {
2400
+ case 1:
2401
+ return data2[offset2];
2402
+ case 2:
2403
+ return data2[offset2] << 8 | data2[offset2 + 1];
2404
+ case 4:
2405
+ default:
2406
+ return data2[offset2] << 24 | data2[offset2 + 1] << 16 | data2[offset2 + 2] << 8 | data2[offset2 + 3];
2384
2407
  }
2385
- }
2386
- if (hasStartCode) {
2387
- const nalType2 = this._isHevc ? sample.isSync ? HEVC_NAL_TYPE.IDR_W_RADL : 1 : sample.isSync ? 5 : 1;
2388
- return decoder.decode({
2389
- type: nalType2,
2390
- data,
2391
- size: data.length
2392
- });
2393
- }
2408
+ };
2409
+ const hasAnnexBStartCode = data.length >= 4 && data[0] === 0 && data[1] === 0 && (data[2] === 0 && data[3] === 1 || data[2] === 1);
2394
2410
  let nalCount = 0;
2395
2411
  let totalSize = 0;
2396
2412
  let offset = 0;
2397
- while (offset + 4 <= data.length) {
2398
- const nalLength = data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
2399
- if (nalLength <= 0 || offset + 4 + nalLength > data.length) {
2400
- console.warn(`[fMP4] Invalid NAL length: ${nalLength} at offset ${offset}`);
2413
+ let avccParseError = false;
2414
+ while (offset + lengthSize <= data.length) {
2415
+ const nalLength = readNalLength(data, offset, lengthSize);
2416
+ if (nalLength <= 0 || nalLength > 1e7 || offset + lengthSize + nalLength > data.length) {
2417
+ avccParseError = true;
2401
2418
  break;
2402
2419
  }
2403
2420
  totalSize += 4 + nalLength;
2404
- offset += 4 + nalLength;
2421
+ offset += lengthSize + nalLength;
2405
2422
  nalCount++;
2406
2423
  }
2424
+ if (avccParseError && hasAnnexBStartCode) {
2425
+ const nalType2 = this._isHevc ? sample.isSync ? HEVC_NAL_TYPE.IDR_W_RADL : 1 : sample.isSync ? 5 : 1;
2426
+ console.log("[fMP4] Sample appears to be Annex B format, isSync=", sample.isSync, "size=", data.length);
2427
+ return decoder.decode({
2428
+ type: nalType2,
2429
+ data,
2430
+ size: data.length
2431
+ });
2432
+ }
2407
2433
  if (nalCount === 0) {
2408
- console.warn("[fMP4] No valid NAL units found in sample");
2434
+ console.warn("[fMP4] No valid NAL units found in sample, data.length=", data.length, "lengthSize=", lengthSize, "firstBytes=", Array.from(data.slice(0, 8)).map((b) => b.toString(16).padStart(2, "0")).join(" "));
2409
2435
  return null;
2410
2436
  }
2437
+ console.log("[fMP4] AVCC sample: nalCount=", nalCount, "annexBSize=", totalSize, "isSync=", sample.isSync, "lengthSize=", lengthSize);
2411
2438
  const annexBData = new Uint8Array(totalSize);
2412
2439
  let writeOffset = 0;
2413
2440
  offset = 0;
2414
- while (offset + 4 <= data.length) {
2415
- const nalLength = data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
2416
- if (nalLength <= 0 || offset + 4 + nalLength > data.length) {
2441
+ while (offset + lengthSize <= data.length) {
2442
+ const nalLength = readNalLength(data, offset, lengthSize);
2443
+ if (nalLength <= 0 || offset + lengthSize + nalLength > data.length) {
2417
2444
  break;
2418
2445
  }
2419
2446
  annexBData[writeOffset] = 0;
@@ -2421,9 +2448,9 @@ class HLSPlayer extends BasePlayer {
2421
2448
  annexBData[writeOffset + 2] = 0;
2422
2449
  annexBData[writeOffset + 3] = 1;
2423
2450
  writeOffset += 4;
2424
- annexBData.set(data.slice(offset + 4, offset + 4 + nalLength), writeOffset);
2451
+ annexBData.set(data.slice(offset + lengthSize, offset + lengthSize + nalLength), writeOffset);
2425
2452
  writeOffset += nalLength;
2426
- offset += 4 + nalLength;
2453
+ offset += lengthSize + nalLength;
2427
2454
  }
2428
2455
  const nalType = this._isHevc ? sample.isSync ? HEVC_NAL_TYPE.IDR_W_RADL : 1 : sample.isSync ? 5 : 1;
2429
2456
  const frame = decoder.decode({
@@ -3031,18 +3058,27 @@ class FLVPlayer extends BasePlayer {
3031
3058
  console.log("[FLVPlayer] RenderLoop initialized, firstFrameDts:", this.firstFrameDts, "isLive:", isLive);
3032
3059
  }
3033
3060
  if (isLive) {
3034
- const elapsed = now - this.playStartTime - this.pausedTime;
3035
- const currentTargetDts = this.firstFrameDts + elapsed;
3036
- this.setCurrentTime(Math.floor(currentTargetDts));
3037
- let frameToRender = null;
3038
- while (this._timedFrameBuffer.length > 0 && this._timedFrameBuffer[0].dts <= currentTargetDts) {
3061
+ if (this.lastRenderedDts < 0 && this._timedFrameBuffer.length > 0) {
3062
+ const firstFrame = this._timedFrameBuffer.shift();
3063
+ this.renderFrame(firstFrame, now);
3064
+ this.firstFrameDts = firstFrame.dts;
3065
+ this.playStartTime = now;
3066
+ this.pausedTime = 0;
3067
+ console.log("[FLVPlayer] Live first frame rendered immediately, dts:", firstFrame.dts);
3068
+ } else {
3069
+ const elapsed = now - this.playStartTime - this.pausedTime;
3070
+ const currentTargetDts = this.firstFrameDts + elapsed;
3071
+ this.setCurrentTime(Math.floor(currentTargetDts));
3072
+ let frameToRender = null;
3073
+ while (this._timedFrameBuffer.length > 0 && this._timedFrameBuffer[0].dts <= currentTargetDts) {
3074
+ if (frameToRender) {
3075
+ this.droppedFrames++;
3076
+ }
3077
+ frameToRender = this._timedFrameBuffer.shift();
3078
+ }
3039
3079
  if (frameToRender) {
3040
- this.droppedFrames++;
3080
+ this.renderFrame(frameToRender, now);
3041
3081
  }
3042
- frameToRender = this._timedFrameBuffer.shift();
3043
- }
3044
- if (frameToRender) {
3045
- this.renderFrame(frameToRender, now);
3046
3082
  }
3047
3083
  } else {
3048
3084
  const nextFrame = this._timedFrameBuffer[0];
@@ -3855,6 +3891,13 @@ class Canvas2DRenderer {
3855
3891
  if (!this.ctx) {
3856
3892
  throw new Error("Invalid canvas element");
3857
3893
  }
3894
+ this.clear();
3895
+ }
3896
+ /**
3897
+ * 清除 canvas 内容
3898
+ */
3899
+ clear() {
3900
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
3858
3901
  }
3859
3902
  render(frame) {
3860
3903
  const { width, height, data } = frame;