@give-tech/ec-player 0.0.1-beta.53 → 0.0.1-beta.55
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 +233 -215
- package/dist/index.js.map +1 -1
- package/dist/player/BasePlayer.d.ts.map +1 -1
- package/dist/player/EcPlayerCore.d.ts.map +1 -1
- package/dist/player/FLVPlayer.d.ts.map +1 -1
- package/dist/player/HLSPlayer.d.ts.map +1 -1
- package/dist/renderer/Canvas2DRenderer.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -253,17 +253,21 @@ class BasePlayer {
|
|
|
253
253
|
};
|
|
254
254
|
this.renderLoop = () => {
|
|
255
255
|
if (!this.isPlaying) return;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
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
|
-
}
|
|
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
1872
|
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
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);
|
|
1898
1877
|
}
|
|
1899
|
-
const
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
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
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
}
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
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
|
-
|
|
1946
|
-
|
|
1947
|
-
}
|
|
1954
|
+
} catch (error) {
|
|
1955
|
+
console.error("[HLSPlayer] Render error:", error);
|
|
1948
1956
|
}
|
|
1949
1957
|
this.frameTimer = requestAnimationFrame(this.renderLoop);
|
|
1950
1958
|
};
|
|
@@ -2605,13 +2613,14 @@ class HLSPlayer extends BasePlayer {
|
|
|
2605
2613
|
try {
|
|
2606
2614
|
response = await fetch(url, { signal: this.abortController?.signal });
|
|
2607
2615
|
} catch (error) {
|
|
2608
|
-
if (error.name === "AbortError") {
|
|
2609
|
-
console.log("[HLSPlayer] Parse playlist aborted");
|
|
2610
|
-
return { isMaster: true, isFMP4: false, segments: [], fmp4Segments: [], variants: 0 };
|
|
2611
|
-
}
|
|
2612
2616
|
throw error;
|
|
2613
2617
|
}
|
|
2614
|
-
|
|
2618
|
+
let content;
|
|
2619
|
+
try {
|
|
2620
|
+
content = await response.text();
|
|
2621
|
+
} catch (error) {
|
|
2622
|
+
throw error;
|
|
2623
|
+
}
|
|
2615
2624
|
const lines = content.split("\n");
|
|
2616
2625
|
const segments = [];
|
|
2617
2626
|
const fmp4Segments = [];
|
|
@@ -3374,127 +3383,131 @@ class FLVPlayer extends BasePlayer {
|
|
|
3374
3383
|
this._frameIntervalSamples = [];
|
|
3375
3384
|
this.renderLoop = () => {
|
|
3376
3385
|
if (!this.isPlaying) return;
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
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);
|
|
3386
|
+
try {
|
|
3387
|
+
this.updateState({
|
|
3388
|
+
decoded: this._timedFrameBuffer.length,
|
|
3389
|
+
downloaded: this._videoTagQueue.length,
|
|
3390
|
+
droppedFrames: this.droppedFrames
|
|
3391
|
+
});
|
|
3392
|
+
const now = performance.now();
|
|
3393
|
+
const isLive = this.config.isLive;
|
|
3394
|
+
const BACKGROUND_PAUSE_THRESHOLD = 500;
|
|
3395
|
+
if (this._lastRafTime > 0 && now - this._lastRafTime > BACKGROUND_PAUSE_THRESHOLD) {
|
|
3396
|
+
const pauseDuration = now - this._lastRafTime;
|
|
3397
|
+
console.log("[FLVPlayer] Background pause detected, duration:", pauseDuration.toFixed(0), "ms, isLive:", isLive, "queue:", this._videoTagQueue.length, "buffer:", this._timedFrameBuffer.length);
|
|
3398
|
+
if (isLive) {
|
|
3399
|
+
const droppedDecoded = this._timedFrameBuffer.length;
|
|
3400
|
+
const droppedQueue = this._videoTagQueue.length;
|
|
3401
|
+
this._timedFrameBuffer = [];
|
|
3402
|
+
this._videoTagQueue = [];
|
|
3403
|
+
this.droppedFrames += droppedDecoded;
|
|
3404
|
+
this.playStartTime = 0;
|
|
3405
|
+
this.firstFrameDts = -1;
|
|
3406
|
+
this.pausedTime = 0;
|
|
3407
|
+
console.log("[FLVPlayer] Live resume: cleared all buffers (decoded:", droppedDecoded, ", queue:", droppedQueue, "), waiting for new data");
|
|
3408
|
+
} else {
|
|
3409
|
+
this.playStartTimeOffset += pauseDuration;
|
|
3410
|
+
}
|
|
3414
3411
|
}
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
this.
|
|
3419
|
-
|
|
3412
|
+
this._lastRafTime = now;
|
|
3413
|
+
if (this._timedFrameBuffer.length > 0 && this.renderer) {
|
|
3414
|
+
if (this.state.isBuffering) {
|
|
3415
|
+
this.updateState({ isBuffering: false, bufferingProgress: void 0 });
|
|
3416
|
+
}
|
|
3417
|
+
this.consecutiveEmptyBuffer = 0;
|
|
3418
|
+
if (this.playStartTime <= 0) {
|
|
3419
|
+
this.firstFrameDts = this._timedFrameBuffer[0].dts;
|
|
3420
3420
|
this.playStartTime = now;
|
|
3421
|
+
this.playStartTimeOffset = 0;
|
|
3421
3422
|
this.pausedTime = 0;
|
|
3422
|
-
console.log("[FLVPlayer]
|
|
3423
|
-
}
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3423
|
+
console.log("[FLVPlayer] RenderLoop initialized, firstFrameDts:", this.firstFrameDts, "isLive:", isLive);
|
|
3424
|
+
}
|
|
3425
|
+
if (isLive) {
|
|
3426
|
+
if (this.lastRenderedDts < 0 && this._timedFrameBuffer.length > 0) {
|
|
3427
|
+
const firstFrame = this._timedFrameBuffer.shift();
|
|
3428
|
+
this.renderFrame(firstFrame, now);
|
|
3429
|
+
this.firstFrameDts = firstFrame.dts;
|
|
3430
|
+
this.playStartTime = now;
|
|
3431
|
+
this.pausedTime = 0;
|
|
3432
|
+
console.log("[FLVPlayer] Live first frame rendered immediately, dts:", firstFrame.dts);
|
|
3433
|
+
} else {
|
|
3434
|
+
const elapsed = (now - this.playStartTime - this.pausedTime) * this._playbackRate;
|
|
3435
|
+
const currentTargetDts = this.firstFrameDts + elapsed;
|
|
3436
|
+
this.setCurrentTime(Math.floor(currentTargetDts));
|
|
3437
|
+
let frameToRender = null;
|
|
3438
|
+
while (this._timedFrameBuffer.length > 0 && this._timedFrameBuffer[0].dts <= currentTargetDts) {
|
|
3439
|
+
if (frameToRender) {
|
|
3440
|
+
this.droppedFrames++;
|
|
3441
|
+
}
|
|
3442
|
+
frameToRender = this._timedFrameBuffer.shift();
|
|
3443
|
+
}
|
|
3429
3444
|
if (frameToRender) {
|
|
3430
|
-
this.
|
|
3445
|
+
this.renderFrame(frameToRender, now);
|
|
3431
3446
|
}
|
|
3432
|
-
frameToRender = this._timedFrameBuffer.shift();
|
|
3433
3447
|
}
|
|
3434
|
-
|
|
3448
|
+
} else {
|
|
3449
|
+
const nextFrame = this._timedFrameBuffer[0];
|
|
3450
|
+
const elapsed = (now - this.playStartTime - this.playStartTimeOffset) * this._playbackRate;
|
|
3451
|
+
const currentTargetPts = this.firstFrameDts + elapsed;
|
|
3452
|
+
if (this.lastRenderedDts >= 0) {
|
|
3453
|
+
this.setCurrentTime(Math.floor(this.lastRenderedDts));
|
|
3454
|
+
}
|
|
3455
|
+
if (nextFrame.dts <= currentTargetPts) {
|
|
3456
|
+
const frameToRender = this._timedFrameBuffer.shift();
|
|
3435
3457
|
this.renderFrame(frameToRender, now);
|
|
3458
|
+
this.lastRenderedDts = frameToRender.dts;
|
|
3459
|
+
if (this._prevRenderDts >= 0) {
|
|
3460
|
+
this._frameIntervalSamples.push(frameToRender.dts - this._prevRenderDts);
|
|
3461
|
+
if (this._frameIntervalSamples.length >= 30) {
|
|
3462
|
+
const avg = this._frameIntervalSamples.reduce((a, b) => a + b, 0) / this._frameIntervalSamples.length;
|
|
3463
|
+
console.log("[FLVPlayer] 帧率诊断: 平均帧间隔", avg.toFixed(1), "ms, 约", (1e3 / avg).toFixed(1), "fps, 样本数:", this._frameIntervalSamples.length);
|
|
3464
|
+
this._frameIntervalSamples = [];
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
this._prevRenderDts = frameToRender.dts;
|
|
3468
|
+
const lag = currentTargetPts - frameToRender.dts;
|
|
3469
|
+
if (lag > 1e3) {
|
|
3470
|
+
this.playStartTime = now;
|
|
3471
|
+
this.playStartTimeOffset = 0;
|
|
3472
|
+
this.firstFrameDts = frameToRender.dts;
|
|
3473
|
+
this.resyncCount++;
|
|
3474
|
+
if (this.resyncCount <= 3) {
|
|
3475
|
+
console.log("[FLVPlayer] Major resync, lag:", Math.floor(lag), "ms");
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3436
3478
|
}
|
|
3437
3479
|
}
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3480
|
+
if (now - this.lastRenderLogTime > 5e3) {
|
|
3481
|
+
console.log("[FLVPlayer] RenderLoop stats:", {
|
|
3482
|
+
renderedFrames: this.renderedFrames,
|
|
3483
|
+
droppedFrames: this.droppedFrames,
|
|
3484
|
+
decoded: this._timedFrameBuffer.length,
|
|
3485
|
+
downloaded: this._videoTagQueue.length,
|
|
3486
|
+
mode: isLive ? "live" : "vod"
|
|
3487
|
+
});
|
|
3488
|
+
this.lastRenderLogTime = now;
|
|
3444
3489
|
}
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
this.
|
|
3448
|
-
|
|
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
|
-
}
|
|
3490
|
+
} else {
|
|
3491
|
+
if (this.isPlaying && !this.state.isBuffering) {
|
|
3492
|
+
if (this.consecutiveEmptyBuffer >= 15) {
|
|
3493
|
+
this.updateState({ isBuffering: true });
|
|
3467
3494
|
}
|
|
3468
3495
|
}
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
this.
|
|
3479
|
-
|
|
3480
|
-
} else {
|
|
3481
|
-
if (this.isPlaying && !this.state.isBuffering) {
|
|
3482
|
-
if (this.consecutiveEmptyBuffer >= 15) {
|
|
3483
|
-
this.updateState({ isBuffering: true });
|
|
3496
|
+
if (this.consecutiveEmptyBuffer === 0 && this.lastRenderedDts >= 0) {
|
|
3497
|
+
this.bufferEmptyStartTime = now;
|
|
3498
|
+
}
|
|
3499
|
+
this.consecutiveEmptyBuffer++;
|
|
3500
|
+
if (isLive && this.bufferEmptyStartTime > 0) {
|
|
3501
|
+
this.pausedTime = now - this.bufferEmptyStartTime;
|
|
3502
|
+
}
|
|
3503
|
+
if (this.consecutiveEmptyBuffer === 1) {
|
|
3504
|
+
console.warn("[FLVPlayer] Buffer empty, waiting for frames... queue:", this._videoTagQueue.length);
|
|
3505
|
+
} else if (this.consecutiveEmptyBuffer % 60 === 0) {
|
|
3506
|
+
console.warn("[FLVPlayer] Buffer still empty after", Math.floor(this.consecutiveEmptyBuffer / 60), "seconds");
|
|
3484
3507
|
}
|
|
3485
3508
|
}
|
|
3486
|
-
|
|
3487
|
-
|
|
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
|
-
}
|
|
3509
|
+
} catch (error) {
|
|
3510
|
+
console.error("[FLVPlayer] Render error:", error);
|
|
3498
3511
|
}
|
|
3499
3512
|
this.frameTimer = requestAnimationFrame(this.renderLoop);
|
|
3500
3513
|
};
|
|
@@ -4316,7 +4329,7 @@ class FLVPlayer extends BasePlayer {
|
|
|
4316
4329
|
* 渲染一帧
|
|
4317
4330
|
*/
|
|
4318
4331
|
renderFrame(frame, now) {
|
|
4319
|
-
if (!this.renderer) return;
|
|
4332
|
+
if (!this.renderer || !frame.frame) return;
|
|
4320
4333
|
this.renderer.render(frame.frame);
|
|
4321
4334
|
this.renderedFrames++;
|
|
4322
4335
|
this.lastRenderedDts = frame.dts;
|
|
@@ -4408,6 +4421,7 @@ class Canvas2DRenderer {
|
|
|
4408
4421
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
4409
4422
|
}
|
|
4410
4423
|
render(frame) {
|
|
4424
|
+
if (!frame || !frame.data) return;
|
|
4411
4425
|
const { width, height, data } = frame;
|
|
4412
4426
|
if (this.canvas.width !== width || this.canvas.height !== height) {
|
|
4413
4427
|
this.canvas.width = width;
|
|
@@ -4488,6 +4502,10 @@ class EcPlayerCore {
|
|
|
4488
4502
|
await this.player.finishInitDecoder(initResult);
|
|
4489
4503
|
this.callbacks.onStateChange?.({ isLoaded: true });
|
|
4490
4504
|
} catch (error) {
|
|
4505
|
+
if (error?.name === "AbortError") {
|
|
4506
|
+
console.log("[EcPlayerCore] Load aborted (expected)");
|
|
4507
|
+
return;
|
|
4508
|
+
}
|
|
4491
4509
|
console.error("[EcPlayerCore] Load failed:", error);
|
|
4492
4510
|
this.callbacks.onError?.(error);
|
|
4493
4511
|
throw error;
|