@give-tech/ec-player 0.0.1-beta.32 → 0.0.1-beta.34
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/decoder/H264Decoder.d.ts +5 -0
- package/dist/decoder/H264Decoder.d.ts.map +1 -1
- package/dist/decoder/HEVCDecoder.d.ts +5 -0
- package/dist/decoder/HEVCDecoder.d.ts.map +1 -1
- package/dist/decoder/WASMLoader.d.ts +31 -2
- package/dist/decoder/WASMLoader.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +158 -17
- package/dist/index.js.map +1 -1
- package/dist/player/FLVPlayer.d.ts +4 -0
- package/dist/player/FLVPlayer.d.ts.map +1 -1
- package/dist/renderer/Canvas2DRenderer.d.ts +4 -0
- package/dist/renderer/Canvas2DRenderer.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -6,9 +6,14 @@ import { WASMLoader } from './WASMLoader';
|
|
|
6
6
|
export declare class H264Decoder {
|
|
7
7
|
private wasmModule;
|
|
8
8
|
private decoderContext;
|
|
9
|
+
private destroyed;
|
|
9
10
|
constructor(wasmLoader: WASMLoader);
|
|
10
11
|
init(): Promise<void>;
|
|
11
12
|
decode(nalUnit: NALUnit): VideoFrame | null;
|
|
13
|
+
/**
|
|
14
|
+
* 销毁解码器,释放 WASM 资源
|
|
15
|
+
*/
|
|
16
|
+
destroy(): void;
|
|
12
17
|
private yuv420pToRgba;
|
|
13
18
|
}
|
|
14
19
|
//# sourceMappingURL=H264Decoder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"H264Decoder.d.ts","sourceRoot":"","sources":["../../src/decoder/H264Decoder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAA8B,UAAU,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,qBAAa,WAAW;IACtB,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,cAAc,CAA8B;
|
|
1
|
+
{"version":3,"file":"H264Decoder.d.ts","sourceRoot":"","sources":["../../src/decoder/H264Decoder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAA8B,UAAU,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,qBAAa,WAAW;IACtB,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,SAAS,CAAQ;gBAEb,UAAU,EAAE,UAAU;IAI5B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI;IA4C3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAaf,OAAO,CAAC,aAAa;CAuCtB"}
|
|
@@ -13,9 +13,14 @@ export declare const HEVC_NAL_TYPE: {
|
|
|
13
13
|
export declare class HEVCDecoder {
|
|
14
14
|
private wasmModule;
|
|
15
15
|
private decoderContext;
|
|
16
|
+
private destroyed;
|
|
16
17
|
constructor(wasmLoader: WASMLoader);
|
|
17
18
|
init(): Promise<void>;
|
|
18
19
|
decode(nalUnit: NALUnit): VideoFrame | null;
|
|
20
|
+
/**
|
|
21
|
+
* 销毁解码器,释放 WASM 资源
|
|
22
|
+
*/
|
|
23
|
+
destroy(): void;
|
|
19
24
|
private yuv420pToRgba;
|
|
20
25
|
}
|
|
21
26
|
//# sourceMappingURL=HEVCDecoder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HEVCDecoder.d.ts","sourceRoot":"","sources":["../../src/decoder/HEVCDecoder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAA8B,UAAU,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAA;AAEV,qBAAa,WAAW;IACtB,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,cAAc,CAA8B;
|
|
1
|
+
{"version":3,"file":"HEVCDecoder.d.ts","sourceRoot":"","sources":["../../src/decoder/HEVCDecoder.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAA8B,UAAU,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAGzC,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAA;AAEV,qBAAa,WAAW;IACtB,OAAO,CAAC,UAAU,CAA0B;IAC5C,OAAO,CAAC,cAAc,CAA8B;IACpD,OAAO,CAAC,SAAS,CAAQ;gBAEb,UAAU,EAAE,UAAU;IAI5B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAe3B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI;IA4C3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAaf,OAAO,CAAC,aAAa;CAuCtB"}
|
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WASM
|
|
2
|
+
* WASM 加载器(多模块缓存)
|
|
3
|
+
*
|
|
4
|
+
* 支持同时缓存多个 WASM 模块(如 SIMD 和非 SIMD 版本)
|
|
5
|
+
* 使用懒加载,按需加载所需模块
|
|
6
|
+
* 解决快速切换源时的竞态条件问题
|
|
3
7
|
*/
|
|
4
8
|
import type { WASMModule } from '../types';
|
|
5
9
|
export declare class WASMLoader {
|
|
6
|
-
private
|
|
10
|
+
private localModule;
|
|
11
|
+
private localPath;
|
|
12
|
+
/**
|
|
13
|
+
* 加载 WASM 模块
|
|
14
|
+
*/
|
|
7
15
|
load(wasmPath: string): Promise<WASMModule>;
|
|
16
|
+
private doLoad;
|
|
8
17
|
getModule(): WASMModule | null;
|
|
18
|
+
/**
|
|
19
|
+
* 预加载 WASM 模块(后台加载,不阻塞)
|
|
20
|
+
*/
|
|
21
|
+
static preload(wasmPath: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* 批量预加载
|
|
24
|
+
*/
|
|
25
|
+
static preloadAll(wasmPaths: string[]): void;
|
|
26
|
+
/**
|
|
27
|
+
* 检查是否已加载
|
|
28
|
+
*/
|
|
29
|
+
static isLoaded(wasmPath?: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 获取已缓存的路径
|
|
32
|
+
*/
|
|
33
|
+
static getLoadedPaths(): string[];
|
|
34
|
+
/**
|
|
35
|
+
* 重置(仅用于测试)
|
|
36
|
+
*/
|
|
37
|
+
static reset(): void;
|
|
9
38
|
}
|
|
10
39
|
//# sourceMappingURL=WASMLoader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WASMLoader.d.ts","sourceRoot":"","sources":["../../src/decoder/WASMLoader.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"WASMLoader.d.ts","sourceRoot":"","sources":["../../src/decoder/WASMLoader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAQ1C,qBAAa,UAAU;IACrB,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,SAAS,CAAsB;IAEvC;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;YAsCnC,MAAM;IAuCpB,SAAS,IAAI,UAAU,GAAG,IAAI;IAI9B;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAWtC;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAI5C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAO3C;;OAEG;IACH,MAAM,CAAC,cAAc,IAAI,MAAM,EAAE;IAIjC;;OAEG;IACH,MAAM,CAAC,KAAK,IAAI,IAAI;CAIrB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { EcPlayerCore, type EcPlayerCoreConfig } from './player';
|
|
8
8
|
export { EnvDetector, type EnvInfo, type EnvCapabilities } from './env';
|
|
9
|
+
export { WASMLoader } from './decoder/WASMLoader';
|
|
9
10
|
export type { PlayerState as EcPlayerState, PlayerCallbacks as EcPlayerCallbacks } from './types';
|
|
10
11
|
export { LogLevel, setLogLevel } from './utils';
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAGhE,OAAO,EACL,WAAW,EACX,KAAK,OAAO,EACZ,KAAK,eAAe,EACrB,MAAM,OAAO,CAAA;AAGd,YAAY,EACV,WAAW,IAAI,aAAa,EAC5B,eAAe,IAAI,iBAAiB,EACrC,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAGhE,OAAO,EACL,WAAW,EACX,KAAK,OAAO,EACZ,KAAK,eAAe,EACrB,MAAM,OAAO,CAAA;AAGd,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAGjD,YAAY,EACV,WAAW,IAAI,aAAa,EAC5B,eAAe,IAAI,iBAAiB,EACrC,MAAM,SAAS,CAAA;AAGhB,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,43 @@
|
|
|
1
|
+
const moduleCache = /* @__PURE__ */ new Map();
|
|
2
|
+
const loadingPromises = /* @__PURE__ */ new Map();
|
|
1
3
|
class WASMLoader {
|
|
2
4
|
constructor() {
|
|
3
|
-
this.
|
|
5
|
+
this.localModule = null;
|
|
6
|
+
this.localPath = null;
|
|
4
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* 加载 WASM 模块
|
|
10
|
+
*/
|
|
5
11
|
async load(wasmPath) {
|
|
12
|
+
if (this.localModule && this.localPath === wasmPath) {
|
|
13
|
+
return this.localModule;
|
|
14
|
+
}
|
|
15
|
+
const cachedModule = moduleCache.get(wasmPath);
|
|
16
|
+
if (cachedModule) {
|
|
17
|
+
this.localModule = cachedModule;
|
|
18
|
+
this.localPath = wasmPath;
|
|
19
|
+
return cachedModule;
|
|
20
|
+
}
|
|
21
|
+
const loadingPromise = loadingPromises.get(wasmPath);
|
|
22
|
+
if (loadingPromise) {
|
|
23
|
+
const module = await loadingPromise;
|
|
24
|
+
this.localModule = module;
|
|
25
|
+
this.localPath = wasmPath;
|
|
26
|
+
return module;
|
|
27
|
+
}
|
|
28
|
+
const loadPromise = this.doLoad(wasmPath);
|
|
29
|
+
loadingPromises.set(wasmPath, loadPromise);
|
|
30
|
+
try {
|
|
31
|
+
const module = await loadPromise;
|
|
32
|
+
this.localModule = module;
|
|
33
|
+
this.localPath = wasmPath;
|
|
34
|
+
return module;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
loadingPromises.delete(wasmPath);
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async doLoad(wasmPath) {
|
|
6
41
|
return new Promise((resolve, reject) => {
|
|
7
42
|
const script = document.createElement("script");
|
|
8
43
|
script.src = wasmPath;
|
|
@@ -14,30 +49,75 @@ class WASMLoader {
|
|
|
14
49
|
reject(new Error("createFFmpegDecoder not found"));
|
|
15
50
|
return;
|
|
16
51
|
}
|
|
17
|
-
|
|
18
|
-
if (typeof
|
|
52
|
+
const module = await createFFmpegDecoder();
|
|
53
|
+
if (typeof module?._create_decoder !== "function") {
|
|
19
54
|
reject(new Error("Module initialization failed"));
|
|
20
55
|
return;
|
|
21
56
|
}
|
|
22
|
-
|
|
57
|
+
moduleCache.set(wasmPath, module);
|
|
58
|
+
loadingPromises.delete(wasmPath);
|
|
59
|
+
resolve(module);
|
|
23
60
|
} catch (e) {
|
|
61
|
+
loadingPromises.delete(wasmPath);
|
|
24
62
|
reject(new Error(`Failed to initialize decoder: ${e.message}`));
|
|
25
63
|
}
|
|
26
64
|
};
|
|
27
65
|
script.onerror = () => {
|
|
66
|
+
loadingPromises.delete(wasmPath);
|
|
28
67
|
reject(new Error(`Failed to load script: ${wasmPath}`));
|
|
29
68
|
};
|
|
30
69
|
document.head.appendChild(script);
|
|
31
70
|
});
|
|
32
71
|
}
|
|
33
72
|
getModule() {
|
|
34
|
-
return this.
|
|
73
|
+
return this.localModule;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 预加载 WASM 模块(后台加载,不阻塞)
|
|
77
|
+
*/
|
|
78
|
+
static preload(wasmPath) {
|
|
79
|
+
if (moduleCache.has(wasmPath) || loadingPromises.has(wasmPath)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const loader = new WASMLoader();
|
|
83
|
+
loader.load(wasmPath).catch((err) => {
|
|
84
|
+
console.warn(`[WASMLoader] Preload failed for ${wasmPath}:`, err.message);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 批量预加载
|
|
89
|
+
*/
|
|
90
|
+
static preloadAll(wasmPaths) {
|
|
91
|
+
wasmPaths.forEach((path) => this.preload(path));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 检查是否已加载
|
|
95
|
+
*/
|
|
96
|
+
static isLoaded(wasmPath) {
|
|
97
|
+
if (wasmPath) {
|
|
98
|
+
return moduleCache.has(wasmPath);
|
|
99
|
+
}
|
|
100
|
+
return moduleCache.size > 0;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 获取已缓存的路径
|
|
104
|
+
*/
|
|
105
|
+
static getLoadedPaths() {
|
|
106
|
+
return Array.from(moduleCache.keys());
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 重置(仅用于测试)
|
|
110
|
+
*/
|
|
111
|
+
static reset() {
|
|
112
|
+
moduleCache.clear();
|
|
113
|
+
loadingPromises.clear();
|
|
35
114
|
}
|
|
36
115
|
}
|
|
37
116
|
class H264Decoder {
|
|
38
117
|
constructor(wasmLoader) {
|
|
39
118
|
this.wasmModule = null;
|
|
40
119
|
this.decoderContext = null;
|
|
120
|
+
this.destroyed = false;
|
|
41
121
|
this.wasmModule = wasmLoader.getModule();
|
|
42
122
|
}
|
|
43
123
|
async init() {
|
|
@@ -50,7 +130,7 @@ class H264Decoder {
|
|
|
50
130
|
}
|
|
51
131
|
}
|
|
52
132
|
decode(nalUnit) {
|
|
53
|
-
if (this.decoderContext === null || !this.wasmModule) {
|
|
133
|
+
if (this.destroyed || this.decoderContext === null || !this.wasmModule) {
|
|
54
134
|
return null;
|
|
55
135
|
}
|
|
56
136
|
const dataPtr = this.wasmModule._malloc(nalUnit.size);
|
|
@@ -87,6 +167,18 @@ class H264Decoder {
|
|
|
87
167
|
}
|
|
88
168
|
return null;
|
|
89
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* 销毁解码器,释放 WASM 资源
|
|
172
|
+
*/
|
|
173
|
+
destroy() {
|
|
174
|
+
if (this.destroyed) return;
|
|
175
|
+
this.destroyed = true;
|
|
176
|
+
if (this.decoderContext !== null && this.wasmModule?._destroy_decoder) {
|
|
177
|
+
this.wasmModule._destroy_decoder(this.decoderContext);
|
|
178
|
+
}
|
|
179
|
+
this.decoderContext = null;
|
|
180
|
+
this.wasmModule = null;
|
|
181
|
+
}
|
|
90
182
|
yuv420pToRgba(yPtr, uPtr, vPtr, width, height, yLineSize, uLineSize, vLineSize) {
|
|
91
183
|
const rgba = new Uint8Array(width * height * 4);
|
|
92
184
|
for (let y = 0; y < height; y++) {
|
|
@@ -907,6 +999,7 @@ class HEVCDecoder {
|
|
|
907
999
|
constructor(wasmLoader) {
|
|
908
1000
|
this.wasmModule = null;
|
|
909
1001
|
this.decoderContext = null;
|
|
1002
|
+
this.destroyed = false;
|
|
910
1003
|
this.wasmModule = wasmLoader.getModule();
|
|
911
1004
|
}
|
|
912
1005
|
async init() {
|
|
@@ -920,7 +1013,7 @@ class HEVCDecoder {
|
|
|
920
1013
|
console.log("[HEVCDecoder] Initialized with codec_id=173");
|
|
921
1014
|
}
|
|
922
1015
|
decode(nalUnit) {
|
|
923
|
-
if (this.decoderContext === null || !this.wasmModule) {
|
|
1016
|
+
if (this.destroyed || this.decoderContext === null || !this.wasmModule) {
|
|
924
1017
|
return null;
|
|
925
1018
|
}
|
|
926
1019
|
const dataPtr = this.wasmModule._malloc(nalUnit.size);
|
|
@@ -957,6 +1050,18 @@ class HEVCDecoder {
|
|
|
957
1050
|
}
|
|
958
1051
|
return null;
|
|
959
1052
|
}
|
|
1053
|
+
/**
|
|
1054
|
+
* 销毁解码器,释放 WASM 资源
|
|
1055
|
+
*/
|
|
1056
|
+
destroy() {
|
|
1057
|
+
if (this.destroyed) return;
|
|
1058
|
+
this.destroyed = true;
|
|
1059
|
+
if (this.decoderContext !== null && this.wasmModule?._destroy_decoder) {
|
|
1060
|
+
this.wasmModule._destroy_decoder(this.decoderContext);
|
|
1061
|
+
}
|
|
1062
|
+
this.decoderContext = null;
|
|
1063
|
+
this.wasmModule = null;
|
|
1064
|
+
}
|
|
960
1065
|
yuv420pToRgba(yPtr, uPtr, vPtr, width, height, yLineSize, uLineSize, vLineSize) {
|
|
961
1066
|
const rgba = new Uint8Array(width * height * 4);
|
|
962
1067
|
for (let y = 0; y < height; y++) {
|
|
@@ -2926,18 +3031,27 @@ class FLVPlayer extends BasePlayer {
|
|
|
2926
3031
|
console.log("[FLVPlayer] RenderLoop initialized, firstFrameDts:", this.firstFrameDts, "isLive:", isLive);
|
|
2927
3032
|
}
|
|
2928
3033
|
if (isLive) {
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
3034
|
+
if (this.lastRenderedDts < 0 && this._timedFrameBuffer.length > 0) {
|
|
3035
|
+
const firstFrame = this._timedFrameBuffer.shift();
|
|
3036
|
+
this.renderFrame(firstFrame, now);
|
|
3037
|
+
this.firstFrameDts = firstFrame.dts;
|
|
3038
|
+
this.playStartTime = now;
|
|
3039
|
+
this.pausedTime = 0;
|
|
3040
|
+
console.log("[FLVPlayer] Live first frame rendered immediately, dts:", firstFrame.dts);
|
|
3041
|
+
} else {
|
|
3042
|
+
const elapsed = now - this.playStartTime - this.pausedTime;
|
|
3043
|
+
const currentTargetDts = this.firstFrameDts + elapsed;
|
|
3044
|
+
this.setCurrentTime(Math.floor(currentTargetDts));
|
|
3045
|
+
let frameToRender = null;
|
|
3046
|
+
while (this._timedFrameBuffer.length > 0 && this._timedFrameBuffer[0].dts <= currentTargetDts) {
|
|
3047
|
+
if (frameToRender) {
|
|
3048
|
+
this.droppedFrames++;
|
|
3049
|
+
}
|
|
3050
|
+
frameToRender = this._timedFrameBuffer.shift();
|
|
3051
|
+
}
|
|
2934
3052
|
if (frameToRender) {
|
|
2935
|
-
this.
|
|
3053
|
+
this.renderFrame(frameToRender, now);
|
|
2936
3054
|
}
|
|
2937
|
-
frameToRender = this._timedFrameBuffer.shift();
|
|
2938
|
-
}
|
|
2939
|
-
if (frameToRender) {
|
|
2940
|
-
this.renderFrame(frameToRender, now);
|
|
2941
3055
|
}
|
|
2942
3056
|
} else {
|
|
2943
3057
|
const nextFrame = this._timedFrameBuffer[0];
|
|
@@ -3161,6 +3275,25 @@ class FLVPlayer extends BasePlayer {
|
|
|
3161
3275
|
console.log("[FLVPlayer] Pausing live stream, keeping download running");
|
|
3162
3276
|
}
|
|
3163
3277
|
}
|
|
3278
|
+
/**
|
|
3279
|
+
* 销毁播放器,释放所有资源
|
|
3280
|
+
*/
|
|
3281
|
+
destroy() {
|
|
3282
|
+
this.stopLiveDownload();
|
|
3283
|
+
if (this.h264Decoder) {
|
|
3284
|
+
this.h264Decoder.destroy();
|
|
3285
|
+
this.h264Decoder = null;
|
|
3286
|
+
}
|
|
3287
|
+
if (this.hevcDecoder) {
|
|
3288
|
+
this.hevcDecoder.destroy();
|
|
3289
|
+
this.hevcDecoder = null;
|
|
3290
|
+
}
|
|
3291
|
+
if (this.prefetcher) {
|
|
3292
|
+
this.prefetcher.reset();
|
|
3293
|
+
this.prefetcher = null;
|
|
3294
|
+
}
|
|
3295
|
+
super.destroy();
|
|
3296
|
+
}
|
|
3164
3297
|
/**
|
|
3165
3298
|
* 处理预取缓冲区数据(供预取器调用)
|
|
3166
3299
|
*/
|
|
@@ -3731,6 +3864,13 @@ class Canvas2DRenderer {
|
|
|
3731
3864
|
if (!this.ctx) {
|
|
3732
3865
|
throw new Error("Invalid canvas element");
|
|
3733
3866
|
}
|
|
3867
|
+
this.clear();
|
|
3868
|
+
}
|
|
3869
|
+
/**
|
|
3870
|
+
* 清除 canvas 内容
|
|
3871
|
+
*/
|
|
3872
|
+
clear() {
|
|
3873
|
+
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
3734
3874
|
}
|
|
3735
3875
|
render(frame) {
|
|
3736
3876
|
const { width, height, data } = frame;
|
|
@@ -4254,6 +4394,7 @@ export {
|
|
|
4254
4394
|
EcPlayerCore,
|
|
4255
4395
|
EnvDetector,
|
|
4256
4396
|
LogLevel,
|
|
4397
|
+
WASMLoader,
|
|
4257
4398
|
setLogLevel
|
|
4258
4399
|
};
|
|
4259
4400
|
//# sourceMappingURL=index.js.map
|