@give-tech/ec-player 0.0.1-beta.53 → 0.0.1-beta.54

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
@@ -253,17 +253,21 @@ class BasePlayer {
253
253
  };
254
254
  this.renderLoop = () => {
255
255
  if (!this.isPlaying) return;
256
- this.updateState({
257
- decoded: this.frameBuffer.length,
258
- droppedFrames: this.droppedFrames
259
- });
260
- if (this.frameBuffer.length > 0 && this.renderer) {
261
- const frame = this.frameBuffer.shift();
262
- this.renderer.render(frame);
263
- this.updateState({ resolution: `${frame.width}x${frame.height}` });
264
- const fps = this.renderer.updateFps();
265
- this.updateState({ fps });
266
- this.callbacks.onFrameRender?.(frame);
256
+ try {
257
+ this.updateState({
258
+ decoded: this.frameBuffer.length,
259
+ droppedFrames: this.droppedFrames
260
+ });
261
+ if (this.frameBuffer.length > 0 && this.renderer) {
262
+ const frame = this.frameBuffer.shift();
263
+ this.renderer.render(frame);
264
+ this.updateState({ resolution: `${frame.width}x${frame.height}` });
265
+ const fps = this.renderer.updateFps();
266
+ this.updateState({ fps });
267
+ this.callbacks.onFrameRender?.(frame);
268
+ }
269
+ } catch (error) {
270
+ console.error("[BasePlayer] Render error:", error);
267
271
  }
268
272
  this.frameTimer = requestAnimationFrame(this.renderLoop);
269
273
  };
@@ -1846,105 +1850,109 @@ class HLSPlayer extends BasePlayer {
1846
1850
  this._lastRafTime = 0;
1847
1851
  this.renderLoop = (timestamp = 0) => {
1848
1852
  if (!this.isPlaying) return;
1849
- const now = performance.now();
1850
- const BACKGROUND_PAUSE_THRESHOLD = 500;
1851
- if (this._lastRafTime > 0 && now - this._lastRafTime > BACKGROUND_PAUSE_THRESHOLD) {
1852
- const pauseDuration = now - this._lastRafTime;
1853
- console.log("[renderLoop] Background pause detected, duration:", pauseDuration.toFixed(0), "ms");
1854
- if (this.config.isLive) {
1855
- const KEEP_FRAMES = 5;
1856
- if (this.frameBuffer.length > KEEP_FRAMES) {
1857
- const droppedCount = this.frameBuffer.length - KEEP_FRAMES;
1858
- this.frameBuffer = this.frameBuffer.slice(-KEEP_FRAMES);
1859
- this.droppedFrames += droppedCount;
1860
- console.log("[renderLoop] Live resume: dropped", droppedCount, "old frames, keeping latest", KEEP_FRAMES);
1853
+ try {
1854
+ const now = performance.now();
1855
+ const BACKGROUND_PAUSE_THRESHOLD = 500;
1856
+ if (this._lastRafTime > 0 && now - this._lastRafTime > BACKGROUND_PAUSE_THRESHOLD) {
1857
+ const pauseDuration = now - this._lastRafTime;
1858
+ console.log("[renderLoop] Background pause detected, duration:", pauseDuration.toFixed(0), "ms");
1859
+ if (this.config.isLive) {
1860
+ const KEEP_FRAMES = 5;
1861
+ if (this.frameBuffer.length > KEEP_FRAMES) {
1862
+ const droppedCount = this.frameBuffer.length - KEEP_FRAMES;
1863
+ this.frameBuffer = this.frameBuffer.slice(-KEEP_FRAMES);
1864
+ this.droppedFrames += droppedCount;
1865
+ console.log("[renderLoop] Live resume: dropped", droppedCount, "old frames, keeping latest", KEEP_FRAMES);
1866
+ }
1867
+ this.playStartTime = now;
1868
+ this.accumulatedMediaTime = 0;
1869
+ } else {
1870
+ this.playStartTime = now - this.accumulatedMediaTime;
1861
1871
  }
1862
- this.playStartTime = now;
1863
- this.accumulatedMediaTime = 0;
1864
- } else {
1865
- this.playStartTime = now - this.accumulatedMediaTime;
1866
1872
  }
1867
- }
1868
- this._lastRafTime = now;
1869
- if (!this._lastLogTime || now - this._lastLogTime > 1e3) {
1870
- this._lastLogTime = now;
1871
- console.log("[renderLoop] frameBuffer=", this.frameBuffer.length, "renderer=", !!this.renderer);
1872
- }
1873
- const downloaded = this.isFMP4 ? this.sampleQueue.length : this.nalQueue.length;
1874
- const segments = this.isFMP4 ? this.fmp4Segments : this.segments;
1875
- const totalSegments = segments.length;
1876
- this.updateState({
1877
- decoded: this.frameBuffer.length,
1878
- downloaded,
1879
- droppedFrames: this.droppedFrames,
1880
- segmentIndex: this.currentSegmentIndex,
1881
- totalSegments
1882
- });
1883
- if (this.frameBuffer.length > 0 && this.renderer) {
1884
- const wasBuffering = this.state.isBuffering;
1885
- if (this.state.isBuffering) {
1886
- this.updateState({ isBuffering: false, bufferingProgress: void 0 });
1887
- }
1888
- this._consecutiveEmptyBuffer = 0;
1889
- const timescale = this.fmp4Demuxer.getTimescale();
1890
- if (this.playStartTime === 0) {
1891
- this.playStartTime = now;
1892
- this.accumulatedMediaTime = 0;
1893
- console.log("[renderLoop] Init: timescale=", timescale);
1894
- }
1895
- if (wasBuffering && this.accumulatedMediaTime > 0) {
1896
- this.playStartTime = now - this.accumulatedMediaTime / this._playbackRate;
1897
- console.log("[renderLoop] Buffer recovered, reset playStartTime to continue from", Math.floor(this.accumulatedMediaTime), "ms");
1898
- }
1899
- const elapsedWallTime = (now - this.playStartTime) * this._playbackRate;
1900
- if (Math.floor(elapsedWallTime / 1e3) !== Math.floor((elapsedWallTime - 20 * this._playbackRate) / 1e3)) {
1901
- console.log("[renderLoop] elapsed=", Math.floor(elapsedWallTime), "accumulated=", Math.floor(this.accumulatedMediaTime), "rate=", this._playbackRate, "frameBuffer=", this.frameBuffer.length);
1873
+ this._lastRafTime = now;
1874
+ if (!this._lastLogTime || now - this._lastLogTime > 1e3) {
1875
+ this._lastLogTime = now;
1876
+ console.log("[renderLoop] frameBuffer=", this.frameBuffer.length, "renderer=", !!this.renderer);
1902
1877
  }
1903
- const getFrameDurationMs = (frame2) => {
1904
- return frame2.duration ? frame2.duration * 1e3 / timescale : 33.33;
1905
- };
1906
- const bufferMs = 50;
1907
- if (this._playbackRate > 1) {
1908
- const behindTime = elapsedWallTime - this.accumulatedMediaTime;
1909
- if (behindTime > 50 && this.frameBuffer.length > 1) {
1910
- const avgFrameDuration = getFrameDurationMs(this.frameBuffer[0]);
1911
- const framesToSkip = Math.min(
1912
- Math.floor(behindTime / avgFrameDuration),
1913
- this.frameBuffer.length - 1
1914
- // 保留至少 1
1915
- );
1916
- if (framesToSkip > 0) {
1917
- for (let i = 0; i < framesToSkip; i++) {
1918
- const skipFrame = this.frameBuffer.shift();
1919
- const skipDuration = getFrameDurationMs(skipFrame);
1920
- this.accumulatedMediaTime += skipDuration;
1878
+ const downloaded = this.isFMP4 ? this.sampleQueue.length : this.nalQueue.length;
1879
+ const segments = this.isFMP4 ? this.fmp4Segments : this.segments;
1880
+ const totalSegments = segments.length;
1881
+ this.updateState({
1882
+ decoded: this.frameBuffer.length,
1883
+ downloaded,
1884
+ droppedFrames: this.droppedFrames,
1885
+ segmentIndex: this.currentSegmentIndex,
1886
+ totalSegments
1887
+ });
1888
+ if (this.frameBuffer.length > 0 && this.renderer) {
1889
+ const wasBuffering = this.state.isBuffering;
1890
+ if (this.state.isBuffering) {
1891
+ this.updateState({ isBuffering: false, bufferingProgress: void 0 });
1892
+ }
1893
+ this._consecutiveEmptyBuffer = 0;
1894
+ const timescale = this.fmp4Demuxer.getTimescale();
1895
+ if (this.playStartTime === 0) {
1896
+ this.playStartTime = now;
1897
+ this.accumulatedMediaTime = 0;
1898
+ console.log("[renderLoop] Init: timescale=", timescale);
1899
+ }
1900
+ if (wasBuffering && this.accumulatedMediaTime > 0) {
1901
+ this.playStartTime = now - this.accumulatedMediaTime / this._playbackRate;
1902
+ console.log("[renderLoop] Buffer recovered, reset playStartTime to continue from", Math.floor(this.accumulatedMediaTime), "ms");
1903
+ }
1904
+ const elapsedWallTime = (now - this.playStartTime) * this._playbackRate;
1905
+ if (Math.floor(elapsedWallTime / 1e3) !== Math.floor((elapsedWallTime - 20 * this._playbackRate) / 1e3)) {
1906
+ console.log("[renderLoop] elapsed=", Math.floor(elapsedWallTime), "accumulated=", Math.floor(this.accumulatedMediaTime), "rate=", this._playbackRate, "frameBuffer=", this.frameBuffer.length);
1907
+ }
1908
+ const getFrameDurationMs = (frame2) => {
1909
+ return frame2.duration ? frame2.duration * 1e3 / timescale : 33.33;
1910
+ };
1911
+ const bufferMs = 50;
1912
+ if (this._playbackRate > 1) {
1913
+ const behindTime = elapsedWallTime - this.accumulatedMediaTime;
1914
+ if (behindTime > 50 && this.frameBuffer.length > 1) {
1915
+ const avgFrameDuration = getFrameDurationMs(this.frameBuffer[0]);
1916
+ const framesToSkip = Math.min(
1917
+ Math.floor(behindTime / avgFrameDuration),
1918
+ this.frameBuffer.length - 1
1919
+ // 保留至少 1 帧
1920
+ );
1921
+ if (framesToSkip > 0) {
1922
+ for (let i = 0; i < framesToSkip; i++) {
1923
+ const skipFrame = this.frameBuffer.shift();
1924
+ const skipDuration = getFrameDurationMs(skipFrame);
1925
+ this.accumulatedMediaTime += skipDuration;
1926
+ }
1927
+ console.log("[renderLoop] Skipped", framesToSkip, "frames at rate", this._playbackRate, ", behind=", Math.floor(behindTime));
1921
1928
  }
1922
- console.log("[renderLoop] Skipped", framesToSkip, "frames at rate", this._playbackRate, ", behind=", Math.floor(behindTime));
1923
1929
  }
1924
1930
  }
1925
- }
1926
- const frame = this.frameBuffer[0];
1927
- const frameDurationMs = getFrameDurationMs(frame);
1928
- if (elapsedWallTime >= this.accumulatedMediaTime - bufferMs) {
1929
- this.frameBuffer.shift();
1930
- this.renderer.render(frame);
1931
- this.accumulatedMediaTime += frameDurationMs;
1932
- this.setCurrentTime(this.accumulatedMediaTime);
1933
- this.updateState({ resolution: `${frame.width}x${frame.height}` });
1934
- const fps = this.renderer.updateFps();
1935
- this.updateState({ fps });
1936
- this.callbacks.onFrameRender?.(frame);
1937
- }
1938
- } else {
1939
- if (this.isPlaying && !this.state.isBuffering) {
1940
- this._consecutiveEmptyBuffer++;
1941
- if (this._consecutiveEmptyBuffer >= 15) {
1942
- this.updateState({ isBuffering: true });
1931
+ const frame = this.frameBuffer[0];
1932
+ const frameDurationMs = getFrameDurationMs(frame);
1933
+ if (elapsedWallTime >= this.accumulatedMediaTime - bufferMs) {
1934
+ this.frameBuffer.shift();
1935
+ this.renderer.render(frame);
1936
+ this.accumulatedMediaTime += frameDurationMs;
1937
+ this.setCurrentTime(this.accumulatedMediaTime);
1938
+ this.updateState({ resolution: `${frame.width}x${frame.height}` });
1939
+ const fps = this.renderer.updateFps();
1940
+ this.updateState({ fps });
1941
+ this.callbacks.onFrameRender?.(frame);
1942
+ }
1943
+ } else {
1944
+ if (this.isPlaying && !this.state.isBuffering) {
1945
+ this._consecutiveEmptyBuffer++;
1946
+ if (this._consecutiveEmptyBuffer >= 15) {
1947
+ this.updateState({ isBuffering: true });
1948
+ }
1949
+ }
1950
+ if (this.playStartTime === 0) {
1951
+ console.log("[renderLoop] Waiting for frames...");
1943
1952
  }
1944
1953
  }
1945
- if (this.playStartTime === 0) {
1946
- console.log("[renderLoop] Waiting for frames...");
1947
- }
1954
+ } catch (error) {
1955
+ console.error("[HLSPlayer] Render error:", error);
1948
1956
  }
1949
1957
  this.frameTimer = requestAnimationFrame(this.renderLoop);
1950
1958
  };
@@ -2611,7 +2619,16 @@ class HLSPlayer extends BasePlayer {
2611
2619
  }
2612
2620
  throw error;
2613
2621
  }
2614
- const content = await response.text();
2622
+ let content;
2623
+ try {
2624
+ content = await response.text();
2625
+ } catch (error) {
2626
+ if (error.name === "AbortError") {
2627
+ console.log("[HLSPlayer] Read playlist body aborted");
2628
+ return { isMaster: true, isFMP4: false, segments: [], fmp4Segments: [], variants: 0 };
2629
+ }
2630
+ throw error;
2631
+ }
2615
2632
  const lines = content.split("\n");
2616
2633
  const segments = [];
2617
2634
  const fmp4Segments = [];
@@ -3374,127 +3391,131 @@ class FLVPlayer extends BasePlayer {
3374
3391
  this._frameIntervalSamples = [];
3375
3392
  this.renderLoop = () => {
3376
3393
  if (!this.isPlaying) return;
3377
- this.updateState({
3378
- decoded: this._timedFrameBuffer.length,
3379
- downloaded: this._videoTagQueue.length,
3380
- droppedFrames: this.droppedFrames
3381
- });
3382
- const now = performance.now();
3383
- const isLive = this.config.isLive;
3384
- const BACKGROUND_PAUSE_THRESHOLD = 500;
3385
- if (this._lastRafTime > 0 && now - this._lastRafTime > BACKGROUND_PAUSE_THRESHOLD) {
3386
- const pauseDuration = now - this._lastRafTime;
3387
- console.log("[FLVPlayer] Background pause detected, duration:", pauseDuration.toFixed(0), "ms, isLive:", isLive, "queue:", this._videoTagQueue.length, "buffer:", this._timedFrameBuffer.length);
3388
- if (isLive) {
3389
- const droppedDecoded = this._timedFrameBuffer.length;
3390
- const droppedQueue = this._videoTagQueue.length;
3391
- this._timedFrameBuffer = [];
3392
- this._videoTagQueue = [];
3393
- this.droppedFrames += droppedDecoded;
3394
- this.playStartTime = 0;
3395
- this.firstFrameDts = -1;
3396
- this.pausedTime = 0;
3397
- console.log("[FLVPlayer] Live resume: cleared all buffers (decoded:", droppedDecoded, ", queue:", droppedQueue, "), waiting for new data");
3398
- } else {
3399
- this.playStartTimeOffset += pauseDuration;
3400
- }
3401
- }
3402
- this._lastRafTime = now;
3403
- if (this._timedFrameBuffer.length > 0 && this.renderer) {
3404
- if (this.state.isBuffering) {
3405
- this.updateState({ isBuffering: false, bufferingProgress: void 0 });
3406
- }
3407
- this.consecutiveEmptyBuffer = 0;
3408
- if (this.playStartTime <= 0) {
3409
- this.firstFrameDts = this._timedFrameBuffer[0].dts;
3410
- this.playStartTime = now;
3411
- this.playStartTimeOffset = 0;
3412
- this.pausedTime = 0;
3413
- console.log("[FLVPlayer] RenderLoop initialized, firstFrameDts:", this.firstFrameDts, "isLive:", isLive);
3394
+ try {
3395
+ this.updateState({
3396
+ decoded: this._timedFrameBuffer.length,
3397
+ downloaded: this._videoTagQueue.length,
3398
+ droppedFrames: this.droppedFrames
3399
+ });
3400
+ const now = performance.now();
3401
+ const isLive = this.config.isLive;
3402
+ const BACKGROUND_PAUSE_THRESHOLD = 500;
3403
+ if (this._lastRafTime > 0 && now - this._lastRafTime > BACKGROUND_PAUSE_THRESHOLD) {
3404
+ const pauseDuration = now - this._lastRafTime;
3405
+ console.log("[FLVPlayer] Background pause detected, duration:", pauseDuration.toFixed(0), "ms, isLive:", isLive, "queue:", this._videoTagQueue.length, "buffer:", this._timedFrameBuffer.length);
3406
+ if (isLive) {
3407
+ const droppedDecoded = this._timedFrameBuffer.length;
3408
+ const droppedQueue = this._videoTagQueue.length;
3409
+ this._timedFrameBuffer = [];
3410
+ this._videoTagQueue = [];
3411
+ this.droppedFrames += droppedDecoded;
3412
+ this.playStartTime = 0;
3413
+ this.firstFrameDts = -1;
3414
+ this.pausedTime = 0;
3415
+ console.log("[FLVPlayer] Live resume: cleared all buffers (decoded:", droppedDecoded, ", queue:", droppedQueue, "), waiting for new data");
3416
+ } else {
3417
+ this.playStartTimeOffset += pauseDuration;
3418
+ }
3414
3419
  }
3415
- if (isLive) {
3416
- if (this.lastRenderedDts < 0 && this._timedFrameBuffer.length > 0) {
3417
- const firstFrame = this._timedFrameBuffer.shift();
3418
- this.renderFrame(firstFrame, now);
3419
- this.firstFrameDts = firstFrame.dts;
3420
+ this._lastRafTime = now;
3421
+ if (this._timedFrameBuffer.length > 0 && this.renderer) {
3422
+ if (this.state.isBuffering) {
3423
+ this.updateState({ isBuffering: false, bufferingProgress: void 0 });
3424
+ }
3425
+ this.consecutiveEmptyBuffer = 0;
3426
+ if (this.playStartTime <= 0) {
3427
+ this.firstFrameDts = this._timedFrameBuffer[0].dts;
3420
3428
  this.playStartTime = now;
3429
+ this.playStartTimeOffset = 0;
3421
3430
  this.pausedTime = 0;
3422
- console.log("[FLVPlayer] Live first frame rendered immediately, dts:", firstFrame.dts);
3423
- } else {
3424
- const elapsed = (now - this.playStartTime - this.pausedTime) * this._playbackRate;
3425
- const currentTargetDts = this.firstFrameDts + elapsed;
3426
- this.setCurrentTime(Math.floor(currentTargetDts));
3427
- let frameToRender = null;
3428
- while (this._timedFrameBuffer.length > 0 && this._timedFrameBuffer[0].dts <= currentTargetDts) {
3431
+ console.log("[FLVPlayer] RenderLoop initialized, firstFrameDts:", this.firstFrameDts, "isLive:", isLive);
3432
+ }
3433
+ if (isLive) {
3434
+ if (this.lastRenderedDts < 0 && this._timedFrameBuffer.length > 0) {
3435
+ const firstFrame = this._timedFrameBuffer.shift();
3436
+ this.renderFrame(firstFrame, now);
3437
+ this.firstFrameDts = firstFrame.dts;
3438
+ this.playStartTime = now;
3439
+ this.pausedTime = 0;
3440
+ console.log("[FLVPlayer] Live first frame rendered immediately, dts:", firstFrame.dts);
3441
+ } else {
3442
+ const elapsed = (now - this.playStartTime - this.pausedTime) * this._playbackRate;
3443
+ const currentTargetDts = this.firstFrameDts + elapsed;
3444
+ this.setCurrentTime(Math.floor(currentTargetDts));
3445
+ let frameToRender = null;
3446
+ while (this._timedFrameBuffer.length > 0 && this._timedFrameBuffer[0].dts <= currentTargetDts) {
3447
+ if (frameToRender) {
3448
+ this.droppedFrames++;
3449
+ }
3450
+ frameToRender = this._timedFrameBuffer.shift();
3451
+ }
3429
3452
  if (frameToRender) {
3430
- this.droppedFrames++;
3453
+ this.renderFrame(frameToRender, now);
3431
3454
  }
3432
- frameToRender = this._timedFrameBuffer.shift();
3433
3455
  }
3434
- if (frameToRender) {
3456
+ } else {
3457
+ const nextFrame = this._timedFrameBuffer[0];
3458
+ const elapsed = (now - this.playStartTime - this.playStartTimeOffset) * this._playbackRate;
3459
+ const currentTargetPts = this.firstFrameDts + elapsed;
3460
+ if (this.lastRenderedDts >= 0) {
3461
+ this.setCurrentTime(Math.floor(this.lastRenderedDts));
3462
+ }
3463
+ if (nextFrame.dts <= currentTargetPts) {
3464
+ const frameToRender = this._timedFrameBuffer.shift();
3435
3465
  this.renderFrame(frameToRender, now);
3466
+ this.lastRenderedDts = frameToRender.dts;
3467
+ if (this._prevRenderDts >= 0) {
3468
+ this._frameIntervalSamples.push(frameToRender.dts - this._prevRenderDts);
3469
+ if (this._frameIntervalSamples.length >= 30) {
3470
+ const avg = this._frameIntervalSamples.reduce((a, b) => a + b, 0) / this._frameIntervalSamples.length;
3471
+ console.log("[FLVPlayer] 帧率诊断: 平均帧间隔", avg.toFixed(1), "ms, 约", (1e3 / avg).toFixed(1), "fps, 样本数:", this._frameIntervalSamples.length);
3472
+ this._frameIntervalSamples = [];
3473
+ }
3474
+ }
3475
+ this._prevRenderDts = frameToRender.dts;
3476
+ const lag = currentTargetPts - frameToRender.dts;
3477
+ if (lag > 1e3) {
3478
+ this.playStartTime = now;
3479
+ this.playStartTimeOffset = 0;
3480
+ this.firstFrameDts = frameToRender.dts;
3481
+ this.resyncCount++;
3482
+ if (this.resyncCount <= 3) {
3483
+ console.log("[FLVPlayer] Major resync, lag:", Math.floor(lag), "ms");
3484
+ }
3485
+ }
3436
3486
  }
3437
3487
  }
3438
- } else {
3439
- const nextFrame = this._timedFrameBuffer[0];
3440
- const elapsed = (now - this.playStartTime - this.playStartTimeOffset) * this._playbackRate;
3441
- const currentTargetPts = this.firstFrameDts + elapsed;
3442
- if (this.lastRenderedDts >= 0) {
3443
- this.setCurrentTime(Math.floor(this.lastRenderedDts));
3488
+ if (now - this.lastRenderLogTime > 5e3) {
3489
+ console.log("[FLVPlayer] RenderLoop stats:", {
3490
+ renderedFrames: this.renderedFrames,
3491
+ droppedFrames: this.droppedFrames,
3492
+ decoded: this._timedFrameBuffer.length,
3493
+ downloaded: this._videoTagQueue.length,
3494
+ mode: isLive ? "live" : "vod"
3495
+ });
3496
+ this.lastRenderLogTime = now;
3444
3497
  }
3445
- if (nextFrame.dts <= currentTargetPts) {
3446
- const frameToRender = this._timedFrameBuffer.shift();
3447
- this.renderFrame(frameToRender, now);
3448
- this.lastRenderedDts = frameToRender.dts;
3449
- if (this._prevRenderDts >= 0) {
3450
- this._frameIntervalSamples.push(frameToRender.dts - this._prevRenderDts);
3451
- if (this._frameIntervalSamples.length >= 30) {
3452
- const avg = this._frameIntervalSamples.reduce((a, b) => a + b, 0) / this._frameIntervalSamples.length;
3453
- console.log("[FLVPlayer] 帧率诊断: 平均帧间隔", avg.toFixed(1), "ms, 约", (1e3 / avg).toFixed(1), "fps, 样本数:", this._frameIntervalSamples.length);
3454
- this._frameIntervalSamples = [];
3455
- }
3456
- }
3457
- this._prevRenderDts = frameToRender.dts;
3458
- const lag = currentTargetPts - frameToRender.dts;
3459
- if (lag > 1e3) {
3460
- this.playStartTime = now;
3461
- this.playStartTimeOffset = 0;
3462
- this.firstFrameDts = frameToRender.dts;
3463
- this.resyncCount++;
3464
- if (this.resyncCount <= 3) {
3465
- console.log("[FLVPlayer] Major resync, lag:", Math.floor(lag), "ms");
3466
- }
3498
+ } else {
3499
+ if (this.isPlaying && !this.state.isBuffering) {
3500
+ if (this.consecutiveEmptyBuffer >= 15) {
3501
+ this.updateState({ isBuffering: true });
3467
3502
  }
3468
3503
  }
3469
- }
3470
- if (now - this.lastRenderLogTime > 5e3) {
3471
- console.log("[FLVPlayer] RenderLoop stats:", {
3472
- renderedFrames: this.renderedFrames,
3473
- droppedFrames: this.droppedFrames,
3474
- decoded: this._timedFrameBuffer.length,
3475
- downloaded: this._videoTagQueue.length,
3476
- mode: isLive ? "live" : "vod"
3477
- });
3478
- this.lastRenderLogTime = now;
3479
- }
3480
- } else {
3481
- if (this.isPlaying && !this.state.isBuffering) {
3482
- if (this.consecutiveEmptyBuffer >= 15) {
3483
- this.updateState({ isBuffering: true });
3504
+ if (this.consecutiveEmptyBuffer === 0 && this.lastRenderedDts >= 0) {
3505
+ this.bufferEmptyStartTime = now;
3506
+ }
3507
+ this.consecutiveEmptyBuffer++;
3508
+ if (isLive && this.bufferEmptyStartTime > 0) {
3509
+ this.pausedTime = now - this.bufferEmptyStartTime;
3510
+ }
3511
+ if (this.consecutiveEmptyBuffer === 1) {
3512
+ console.warn("[FLVPlayer] Buffer empty, waiting for frames... queue:", this._videoTagQueue.length);
3513
+ } else if (this.consecutiveEmptyBuffer % 60 === 0) {
3514
+ console.warn("[FLVPlayer] Buffer still empty after", Math.floor(this.consecutiveEmptyBuffer / 60), "seconds");
3484
3515
  }
3485
3516
  }
3486
- if (this.consecutiveEmptyBuffer === 0 && this.lastRenderedDts >= 0) {
3487
- this.bufferEmptyStartTime = now;
3488
- }
3489
- this.consecutiveEmptyBuffer++;
3490
- if (isLive && this.bufferEmptyStartTime > 0) {
3491
- this.pausedTime = now - this.bufferEmptyStartTime;
3492
- }
3493
- if (this.consecutiveEmptyBuffer === 1) {
3494
- console.warn("[FLVPlayer] Buffer empty, waiting for frames... queue:", this._videoTagQueue.length);
3495
- } else if (this.consecutiveEmptyBuffer % 60 === 0) {
3496
- console.warn("[FLVPlayer] Buffer still empty after", Math.floor(this.consecutiveEmptyBuffer / 60), "seconds");
3497
- }
3517
+ } catch (error) {
3518
+ console.error("[FLVPlayer] Render error:", error);
3498
3519
  }
3499
3520
  this.frameTimer = requestAnimationFrame(this.renderLoop);
3500
3521
  };
@@ -4316,7 +4337,7 @@ class FLVPlayer extends BasePlayer {
4316
4337
  * 渲染一帧
4317
4338
  */
4318
4339
  renderFrame(frame, now) {
4319
- if (!this.renderer) return;
4340
+ if (!this.renderer || !frame.frame) return;
4320
4341
  this.renderer.render(frame.frame);
4321
4342
  this.renderedFrames++;
4322
4343
  this.lastRenderedDts = frame.dts;
@@ -4408,6 +4429,7 @@ class Canvas2DRenderer {
4408
4429
  this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
4409
4430
  }
4410
4431
  render(frame) {
4432
+ if (!frame || !frame.data) return;
4411
4433
  const { width, height, data } = frame;
4412
4434
  if (this.canvas.width !== width || this.canvas.height !== height) {
4413
4435
  this.canvas.width = width;
@@ -4488,6 +4510,10 @@ class EcPlayerCore {
4488
4510
  await this.player.finishInitDecoder(initResult);
4489
4511
  this.callbacks.onStateChange?.({ isLoaded: true });
4490
4512
  } catch (error) {
4513
+ if (error?.name === "AbortError") {
4514
+ console.log("[EcPlayerCore] Load aborted (expected)");
4515
+ return;
4516
+ }
4491
4517
  console.error("[EcPlayerCore] Load failed:", error);
4492
4518
  this.callbacks.onError?.(error);
4493
4519
  throw error;