@meframe/core 0.3.7 → 0.3.9
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/stages/encode/BaseEncoder.d.ts.map +1 -1
- package/dist/stages/encode/BaseEncoder.js +25 -6
- package/dist/stages/encode/BaseEncoder.js.map +1 -1
- package/dist/stages/encode/VideoChunkEncoder.d.ts.map +1 -1
- package/dist/workers/stages/export/{export.worker.BYttrqTQ.js → export.worker.DbrPlw6d.js} +45 -14
- package/dist/workers/stages/export/export.worker.DbrPlw6d.js.map +1 -0
- package/dist/workers/worker-manifest.json +1 -1
- package/package.json +1 -1
- package/dist/workers/stages/export/export.worker.BYttrqTQ.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseEncoder.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/BaseEncoder.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,iBAAiB,CAAC;IACzB,QAAQ,EAAE,yBAAyB,CAAC;CACrC;AAED,8BAAsB,WAAW,CAC/B,QAAQ,SAAS,YAAY,GAAG,YAAY,EAC5C,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,EACvD,MAAM,SAAS,UAAU,GAAG,SAAS,EACrC,MAAM,SAAS,iBAAiB,GAAG,iBAAiB,EACpD,SAAS,SAAS,yBAAyB,GAAG,yBAAyB;IAEvE,SAAS,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,UAAU,EAAE,gCAAgC,CAAC,YAAY,CAAC,GAAG,IAAI,CAAQ;gBAEvE,MAAM,EAAE,OAAO;IAI3B,SAAS,IAAI,OAAO;IAIpB,SAAS,KAAK,aAAa,IAAI,OAAO,CAErC;IAED,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO;IAW/D,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IAiBlD,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO;IAIjD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"BaseEncoder.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/BaseEncoder.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,iBAAiB,CAAC;IACzB,QAAQ,EAAE,yBAAyB,CAAC;CACrC;AAED,8BAAsB,WAAW,CAC/B,QAAQ,SAAS,YAAY,GAAG,YAAY,EAC5C,OAAO,SAAS,kBAAkB,GAAG,kBAAkB,EACvD,MAAM,SAAS,UAAU,GAAG,SAAS,EACrC,MAAM,SAAS,iBAAiB,GAAG,iBAAiB,EACpD,SAAS,SAAS,yBAAyB,GAAG,yBAAyB;IAEvE,SAAS,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,UAAU,EAAE,gCAAgC,CAAC,YAAY,CAAC,GAAG,IAAI,CAAQ;gBAEvE,MAAM,EAAE,OAAO;IAI3B,SAAS,IAAI,OAAO;IAIpB,SAAS,KAAK,aAAa,IAAI,OAAO,CAErC;IAED,SAAS,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO;IAW/D,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO;IAiBlD,SAAS,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO;IAIjD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB3B,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAe5B,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,SAAS,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,GAAG,IAAI;IAehE,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAiBhD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IACtF,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,QAAQ;IAC7D,SAAS,CAAC,QAAQ,CAAC,cAAc,IAAI,MAAM;IAG3C,SAAS,CAAC,OAAO,IAAI,IAAI;IAKzB,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAClD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAEzD;;;OAGG;IACH,YAAY,IAAI,eAAe,CAAC,MAAM,EAAE,YAAY,CAAC;IAoDrD,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CACrC;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC;IAC5C,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;CACtC"}
|
|
@@ -39,11 +39,14 @@ class BaseEncoder {
|
|
|
39
39
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
40
40
|
}
|
|
41
41
|
async initialize() {
|
|
42
|
+
console.info("Encoder is initializing...");
|
|
42
43
|
if (this.encoder?.state === "configured") {
|
|
44
|
+
console.warn("Encoder is already initialized, skipping initialization");
|
|
43
45
|
return;
|
|
44
46
|
}
|
|
45
47
|
const isSupported = await this.isConfigSupported(this.config);
|
|
46
48
|
if (!isSupported.supported) {
|
|
49
|
+
console.warn("Codec not supported:", JSON.stringify(this.config));
|
|
47
50
|
throw new Error(`Codec not supported: ${JSON.stringify(this.config)}`);
|
|
48
51
|
}
|
|
49
52
|
this.encoder = this.createEncoder({
|
|
@@ -51,8 +54,10 @@ class BaseEncoder {
|
|
|
51
54
|
error: this.handleError.bind(this)
|
|
52
55
|
});
|
|
53
56
|
this.encoder.configure(this.config);
|
|
57
|
+
console.info("Encoder is initialized");
|
|
54
58
|
}
|
|
55
59
|
async reconfigure(config) {
|
|
60
|
+
console.info("Encoder is reconfiguring...");
|
|
56
61
|
if (!config || Object.keys(config).length === 0) {
|
|
57
62
|
return;
|
|
58
63
|
}
|
|
@@ -74,6 +79,7 @@ class BaseEncoder {
|
|
|
74
79
|
}
|
|
75
80
|
this.config = nextConfig;
|
|
76
81
|
this.encoder.configure(this.config);
|
|
82
|
+
console.info("Encoder is reconfigured");
|
|
77
83
|
}
|
|
78
84
|
async flush() {
|
|
79
85
|
if (!this.encoder) {
|
|
@@ -82,13 +88,17 @@ class BaseEncoder {
|
|
|
82
88
|
await this.encoder.flush();
|
|
83
89
|
}
|
|
84
90
|
async reset() {
|
|
91
|
+
console.info("Encoder is resetting...");
|
|
85
92
|
if (!this.encoder) {
|
|
93
|
+
console.warn("Encoder is not initialized, skipping reset");
|
|
86
94
|
return;
|
|
87
95
|
}
|
|
88
96
|
this.encoder.reset();
|
|
89
97
|
this.onReset();
|
|
98
|
+
console.info("Encoder is resetted");
|
|
90
99
|
}
|
|
91
100
|
async close() {
|
|
101
|
+
console.info("Encoder is closing...");
|
|
92
102
|
if (!this.encoder) {
|
|
93
103
|
return;
|
|
94
104
|
}
|
|
@@ -97,6 +107,7 @@ class BaseEncoder {
|
|
|
97
107
|
}
|
|
98
108
|
this.encoder.close();
|
|
99
109
|
this.encoder = void 0;
|
|
110
|
+
console.info("Encoder is closed");
|
|
100
111
|
}
|
|
101
112
|
get isReady() {
|
|
102
113
|
return this.encoder?.state === "configured";
|
|
@@ -109,6 +120,7 @@ class BaseEncoder {
|
|
|
109
120
|
try {
|
|
110
121
|
this.controller.enqueue({ chunk, metadata });
|
|
111
122
|
} catch (error) {
|
|
123
|
+
console.error("Encoder output error:", error);
|
|
112
124
|
if (!(error instanceof TypeError && error.message.includes("closed"))) {
|
|
113
125
|
throw error;
|
|
114
126
|
}
|
|
@@ -116,6 +128,10 @@ class BaseEncoder {
|
|
|
116
128
|
}
|
|
117
129
|
}
|
|
118
130
|
handleError(error) {
|
|
131
|
+
if (error.message.includes("reclaimed")) {
|
|
132
|
+
console.warn("Encoder reclaimed by browser due to inactivity, skipping error handling");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
119
135
|
console.error(`[${this.getEncoderType()}Encoder] Encode error:`, {
|
|
120
136
|
name: error.name,
|
|
121
137
|
message: error.message,
|
|
@@ -137,15 +153,12 @@ class BaseEncoder {
|
|
|
137
153
|
{
|
|
138
154
|
start: async (controller) => {
|
|
139
155
|
this.controller = controller;
|
|
140
|
-
if (!this.isReady) {
|
|
141
|
-
await this.initialize();
|
|
142
|
-
}
|
|
143
156
|
},
|
|
144
157
|
transform: async (input) => {
|
|
145
|
-
if (!this.
|
|
146
|
-
|
|
158
|
+
if (!this.isReady) {
|
|
159
|
+
await this.initialize();
|
|
147
160
|
}
|
|
148
|
-
if (this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {
|
|
161
|
+
if (this.encoder && this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {
|
|
149
162
|
await new Promise((resolve) => {
|
|
150
163
|
const check = () => {
|
|
151
164
|
if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {
|
|
@@ -157,6 +170,12 @@ class BaseEncoder {
|
|
|
157
170
|
check();
|
|
158
171
|
});
|
|
159
172
|
}
|
|
173
|
+
if (!this.isReady) {
|
|
174
|
+
await this.initialize();
|
|
175
|
+
}
|
|
176
|
+
if (!this.encoder || this.encoder.state !== "configured") {
|
|
177
|
+
throw new Error("Encoder not configured");
|
|
178
|
+
}
|
|
160
179
|
const frame = input.frame || input;
|
|
161
180
|
this.encode(frame);
|
|
162
181
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseEncoder.js","sources":["../../../src/stages/encode/BaseEncoder.ts"],"sourcesContent":["// Base encoder implementation\n\n/**\n * Base encoder class for both video and audio encoding\n * Handles common WebCodecs encoder operations\n */\n\nexport interface EncoderChunk {\n chunk: EncodedVideoChunk;\n metadata: EncodedVideoChunkMetadata;\n}\n\nexport abstract class BaseEncoder<\n TEncoder extends VideoEncoder | AudioEncoder,\n TConfig extends VideoEncoderConfig | AudioEncoderConfig,\n TInput extends VideoFrame | AudioData,\n TChunk extends EncodedVideoChunk | EncodedAudioChunk,\n TMetadata extends EncodedVideoChunkMetadata | EncodedAudioChunkMetadata,\n> {\n protected encoder?: TEncoder;\n protected config: TConfig;\n protected controller: TransformStreamDefaultController<EncoderChunk> | null = null;\n\n constructor(config: TConfig) {\n this.config = config;\n }\n\n getConfig(): TConfig {\n return { ...this.config };\n }\n\n protected get currentConfig(): TConfig {\n return this.config;\n }\n\n protected shouldReconfigure(partial: Partial<TConfig>): boolean {\n const next = { ...this.config, ...partial } as TConfig;\n const keys = Object.keys(partial ?? {}) as Array<keyof TConfig>;\n for (const key of keys) {\n if (partial[key] !== undefined && next[key] !== this.config[key]) {\n return true;\n }\n }\n return false;\n }\n\n protected hasConfigChanged(next: TConfig): boolean {\n const currentEntries = Object.entries(this.config) as Array<[keyof TConfig, any]>;\n for (const [key, value] of currentEntries) {\n if (next[key] !== value) {\n return true;\n }\n }\n\n for (const key of Object.keys(next) as Array<keyof TConfig>) {\n if (this.config[key] !== next[key]) {\n return true;\n }\n }\n\n return false;\n }\n\n protected configsEqual(a: TConfig, b: TConfig): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n\n async initialize(): Promise<void> {\n if (this.encoder?.state === 'configured') {\n return;\n }\n\n const isSupported = await this.isConfigSupported(this.config);\n\n if (!isSupported.supported) {\n throw new Error(`Codec not supported: ${JSON.stringify(this.config)}`);\n }\n\n this.encoder = this.createEncoder({\n output: this.handleOutput.bind(this),\n error: this.handleError.bind(this),\n });\n\n (this.encoder as any).configure(this.config);\n }\n\n async reconfigure(config: Partial<TConfig>): Promise<void> {\n if (!config || Object.keys(config).length === 0) {\n return;\n }\n\n const nextConfig = { ...this.config, ...config } as TConfig;\n\n if (this.configsEqual(this.config, nextConfig)) {\n return;\n }\n\n if (!this.encoder) {\n this.config = nextConfig;\n await this.initialize();\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n const isSupported = await this.isConfigSupported(nextConfig);\n if (!isSupported.supported) {\n throw new Error(`New configuration not supported: ${nextConfig.codec}`);\n }\n\n this.config = nextConfig;\n (this.encoder as any).configure(this.config);\n }\n\n async flush(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n await this.encoder.flush();\n }\n\n async reset(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n this.encoder.reset();\n this.onReset();\n }\n\n async close(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n this.encoder.close();\n this.encoder = undefined;\n }\n\n get isReady(): boolean {\n return this.encoder?.state === 'configured';\n }\n\n get queueSize(): number {\n return this.encoder?.encodeQueueSize ?? 0;\n }\n\n protected handleOutput(chunk: TChunk, metadata: TMetadata): void {\n // Only enqueue if controller exists and stream is not closed\n if (this.controller) {\n try {\n this.controller.enqueue({ chunk, metadata });\n } catch (error) {\n // Stream may be closed during flush, ignore enqueue errors\n if (!(error instanceof TypeError && error.message.includes('closed'))) {\n throw error;\n }\n }\n }\n }\n\n protected handleError(error: DOMException): void {\n console.error(`[${this.getEncoderType()}Encoder] Encode error:`, {\n name: error.name,\n message: error.message,\n encoderState: this.encoder?.state,\n queueSize: this.queueSize,\n platform: typeof navigator !== 'undefined' ? navigator.platform : 'unknown',\n });\n this.controller?.error(error);\n }\n\n // Abstract methods to be implemented by subclasses\n protected abstract isConfigSupported(config: TConfig): Promise<{ supported: boolean }>;\n protected abstract createEncoder(init: EncoderInit): TEncoder;\n protected abstract getEncoderType(): string;\n\n // Hook for subclasses to handle reset\n protected onReset(): void {\n // Override in subclasses if needed\n }\n\n // Abstract properties for backpressure configuration\n protected abstract readonly highWaterMark: number;\n protected abstract readonly encodeQueueThreshold: number;\n\n /**\n * Create transform stream for encoding\n * Implements common stream logic with backpressure handling\n */\n createStream(): TransformStream<TInput, EncoderChunk> {\n return new TransformStream<TInput, EncoderChunk>(\n {\n start: async (controller) => {\n this.controller = controller;\n\n // Initialize encoder if not already initialized\n if (!this.isReady) {\n await this.initialize();\n }\n },\n\n transform: async (input) => {\n if (!this.encoder || this.encoder.state !== 'configured') {\n throw new Error('Encoder not configured');\n }\n\n // Check encoder queue pressure\n if (this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {\n // Wait for queue to drain\n await new Promise<void>((resolve) => {\n const check = () => {\n if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {\n resolve();\n } else {\n setTimeout(check, 10);\n }\n };\n check();\n });\n }\n\n // Encode the input\n const frame = (input as any).frame || input;\n this.encode(frame);\n },\n\n flush: async () => {\n await this.flush();\n },\n },\n // Queuing strategy with backpressure configuration\n {\n highWaterMark: this.highWaterMark,\n size: () => 1, // Count-based\n }\n );\n }\n\n // Abstract method for encoding\n abstract encode(input: TInput): void;\n}\n\ninterface EncoderInit {\n output: (chunk: any, metadata: any) => void;\n error: (error: DOMException) => void;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BaseEncoder.js","sources":["../../../src/stages/encode/BaseEncoder.ts"],"sourcesContent":["// Base encoder implementation\n\n/**\n * Base encoder class for both video and audio encoding\n * Handles common WebCodecs encoder operations\n */\n\nexport interface EncoderChunk {\n chunk: EncodedVideoChunk;\n metadata: EncodedVideoChunkMetadata;\n}\n\nexport abstract class BaseEncoder<\n TEncoder extends VideoEncoder | AudioEncoder,\n TConfig extends VideoEncoderConfig | AudioEncoderConfig,\n TInput extends VideoFrame | AudioData,\n TChunk extends EncodedVideoChunk | EncodedAudioChunk,\n TMetadata extends EncodedVideoChunkMetadata | EncodedAudioChunkMetadata,\n> {\n protected encoder?: TEncoder;\n protected config: TConfig;\n protected controller: TransformStreamDefaultController<EncoderChunk> | null = null;\n\n constructor(config: TConfig) {\n this.config = config;\n }\n\n getConfig(): TConfig {\n return { ...this.config };\n }\n\n protected get currentConfig(): TConfig {\n return this.config;\n }\n\n protected shouldReconfigure(partial: Partial<TConfig>): boolean {\n const next = { ...this.config, ...partial } as TConfig;\n const keys = Object.keys(partial ?? {}) as Array<keyof TConfig>;\n for (const key of keys) {\n if (partial[key] !== undefined && next[key] !== this.config[key]) {\n return true;\n }\n }\n return false;\n }\n\n protected hasConfigChanged(next: TConfig): boolean {\n const currentEntries = Object.entries(this.config) as Array<[keyof TConfig, any]>;\n for (const [key, value] of currentEntries) {\n if (next[key] !== value) {\n return true;\n }\n }\n\n for (const key of Object.keys(next) as Array<keyof TConfig>) {\n if (this.config[key] !== next[key]) {\n return true;\n }\n }\n\n return false;\n }\n\n protected configsEqual(a: TConfig, b: TConfig): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n }\n\n async initialize(): Promise<void> {\n console.info('Encoder is initializing...');\n if (this.encoder?.state === 'configured') {\n console.warn('Encoder is already initialized, skipping initialization');\n return;\n }\n\n const isSupported = await this.isConfigSupported(this.config);\n\n if (!isSupported.supported) {\n console.warn('Codec not supported:', JSON.stringify(this.config));\n throw new Error(`Codec not supported: ${JSON.stringify(this.config)}`);\n }\n\n this.encoder = this.createEncoder({\n output: this.handleOutput.bind(this),\n error: this.handleError.bind(this),\n });\n\n (this.encoder as any).configure(this.config);\n console.info('Encoder is initialized');\n }\n\n async reconfigure(config: Partial<TConfig>): Promise<void> {\n console.info('Encoder is reconfiguring...');\n if (!config || Object.keys(config).length === 0) {\n return;\n }\n\n const nextConfig = { ...this.config, ...config } as TConfig;\n\n if (this.configsEqual(this.config, nextConfig)) {\n return;\n }\n\n if (!this.encoder) {\n this.config = nextConfig;\n await this.initialize();\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n const isSupported = await this.isConfigSupported(nextConfig);\n if (!isSupported.supported) {\n throw new Error(`New configuration not supported: ${nextConfig.codec}`);\n }\n\n this.config = nextConfig;\n (this.encoder as any).configure(this.config);\n console.info('Encoder is reconfigured');\n }\n\n async flush(): Promise<void> {\n if (!this.encoder) {\n return;\n }\n\n await this.encoder.flush();\n }\n\n async reset(): Promise<void> {\n console.info('Encoder is resetting...');\n if (!this.encoder) {\n console.warn('Encoder is not initialized, skipping reset');\n return;\n }\n\n this.encoder.reset();\n this.onReset();\n console.info('Encoder is resetted');\n }\n\n async close(): Promise<void> {\n console.info('Encoder is closing...');\n if (!this.encoder) {\n return;\n }\n\n if (this.encoder.state === 'configured') {\n await this.encoder.flush();\n }\n\n this.encoder.close();\n this.encoder = undefined;\n console.info('Encoder is closed');\n }\n\n get isReady(): boolean {\n return this.encoder?.state === 'configured';\n }\n\n get queueSize(): number {\n return this.encoder?.encodeQueueSize ?? 0;\n }\n\n protected handleOutput(chunk: TChunk, metadata: TMetadata): void {\n // Only enqueue if controller exists and stream is not closed\n if (this.controller) {\n try {\n this.controller.enqueue({ chunk, metadata });\n } catch (error) {\n console.error('Encoder output error:', error);\n // Stream may be closed during flush, ignore enqueue errors\n if (!(error instanceof TypeError && error.message.includes('closed'))) {\n throw error;\n }\n }\n }\n }\n\n protected handleError(error: DOMException): void {\n // Codec reclaimed by browser due to inactivity, let transform re-initialize on next frame\n if (error.message.includes('reclaimed')) {\n console.warn('Encoder reclaimed by browser due to inactivity, skipping error handling');\n return;\n }\n console.error(`[${this.getEncoderType()}Encoder] Encode error:`, {\n name: error.name,\n message: error.message,\n encoderState: this.encoder?.state,\n queueSize: this.queueSize,\n platform: typeof navigator !== 'undefined' ? navigator.platform : 'unknown',\n });\n this.controller?.error(error);\n }\n\n // Abstract methods to be implemented by subclasses\n protected abstract isConfigSupported(config: TConfig): Promise<{ supported: boolean }>;\n protected abstract createEncoder(init: EncoderInit): TEncoder;\n protected abstract getEncoderType(): string;\n\n // Hook for subclasses to handle reset\n protected onReset(): void {\n // Override in subclasses if needed\n }\n\n // Abstract properties for backpressure configuration\n protected abstract readonly highWaterMark: number;\n protected abstract readonly encodeQueueThreshold: number;\n\n /**\n * Create transform stream for encoding\n * Implements common stream logic with backpressure handling\n */\n createStream(): TransformStream<TInput, EncoderChunk> {\n return new TransformStream<TInput, EncoderChunk>(\n {\n start: async (controller) => {\n this.controller = controller;\n },\n\n transform: async (input) => {\n // Lazy init: create encoder on first frame or re-create after codec reclaim\n if (!this.isReady) {\n await this.initialize();\n }\n\n // Backpressure: wait for encoder queue to drain\n if (this.encoder && this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {\n await new Promise<void>((resolve) => {\n const check = () => {\n if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {\n resolve();\n } else {\n setTimeout(check, 10);\n }\n };\n check();\n });\n }\n\n // Re-check after backpressure await: codec may be reclaimed during the wait\n if (!this.isReady) {\n await this.initialize();\n }\n if (!this.encoder || this.encoder.state !== 'configured') {\n throw new Error('Encoder not configured');\n }\n\n const frame = (input as any).frame || input;\n this.encode(frame);\n },\n\n flush: async () => {\n await this.flush();\n },\n },\n // Queuing strategy with backpressure configuration\n {\n highWaterMark: this.highWaterMark,\n size: () => 1, // Count-based\n }\n );\n }\n\n // Abstract method for encoding\n abstract encode(input: TInput): void;\n}\n\ninterface EncoderInit {\n output: (chunk: any, metadata: any) => void;\n error: (error: DOMException) => void;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoChunkEncoder.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/VideoChunkEncoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,WAAW,CAChD,YAAY,EACZ,kBAAkB,EAClB,UAAU,EACV,iBAAiB,EACjB,yBAAyB,CAC1B;IACC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAK;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAAK;IAE3D,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IACzC,SAAS,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAEhD,OAAO,CAAC,UAAU,CAAK;IAEvB,OAAO,CAAC,gBAAgB,CAAM;gBAElB,MAAM,EAAE,kBAAkB;
|
|
1
|
+
{"version":3,"file":"VideoChunkEncoder.d.ts","sourceRoot":"","sources":["../../../src/stages/encode/VideoChunkEncoder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,WAAW,CAChD,YAAY,EACZ,kBAAkB,EAClB,UAAU,EACV,iBAAiB,EACjB,yBAAyB,CAC1B;IACC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAK;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAAK;IAE3D,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IACzC,SAAS,CAAC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IAEhD,OAAO,CAAC,UAAU,CAAK;IAEvB,OAAO,CAAC,gBAAgB,CAAM;gBAElB,MAAM,EAAE,kBAAkB;cAuBtB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;IAK9F,SAAS,CAAC,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,YAAY;IAI7D,SAAS,CAAC,cAAc,IAAI,MAAM;cAIf,OAAO,IAAI,IAAI;IAIlC,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAc/B,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK3C,OAAO,CAAC,sBAAsB;CAM/B"}
|
|
@@ -2322,11 +2322,14 @@ class BaseEncoder {
|
|
|
2322
2322
|
return JSON.stringify(a) === JSON.stringify(b);
|
|
2323
2323
|
}
|
|
2324
2324
|
async initialize() {
|
|
2325
|
+
console.info("Encoder is initializing...");
|
|
2325
2326
|
if (this.encoder?.state === "configured") {
|
|
2327
|
+
console.warn("Encoder is already initialized, skipping initialization");
|
|
2326
2328
|
return;
|
|
2327
2329
|
}
|
|
2328
2330
|
const isSupported = await this.isConfigSupported(this.config);
|
|
2329
2331
|
if (!isSupported.supported) {
|
|
2332
|
+
console.warn("Codec not supported:", JSON.stringify(this.config));
|
|
2330
2333
|
throw new Error(`Codec not supported: ${JSON.stringify(this.config)}`);
|
|
2331
2334
|
}
|
|
2332
2335
|
this.encoder = this.createEncoder({
|
|
@@ -2334,8 +2337,10 @@ class BaseEncoder {
|
|
|
2334
2337
|
error: this.handleError.bind(this)
|
|
2335
2338
|
});
|
|
2336
2339
|
this.encoder.configure(this.config);
|
|
2340
|
+
console.info("Encoder is initialized");
|
|
2337
2341
|
}
|
|
2338
2342
|
async reconfigure(config) {
|
|
2343
|
+
console.info("Encoder is reconfiguring...");
|
|
2339
2344
|
if (!config || Object.keys(config).length === 0) {
|
|
2340
2345
|
return;
|
|
2341
2346
|
}
|
|
@@ -2357,6 +2362,7 @@ class BaseEncoder {
|
|
|
2357
2362
|
}
|
|
2358
2363
|
this.config = nextConfig;
|
|
2359
2364
|
this.encoder.configure(this.config);
|
|
2365
|
+
console.info("Encoder is reconfigured");
|
|
2360
2366
|
}
|
|
2361
2367
|
async flush() {
|
|
2362
2368
|
if (!this.encoder) {
|
|
@@ -2365,13 +2371,17 @@ class BaseEncoder {
|
|
|
2365
2371
|
await this.encoder.flush();
|
|
2366
2372
|
}
|
|
2367
2373
|
async reset() {
|
|
2374
|
+
console.info("Encoder is resetting...");
|
|
2368
2375
|
if (!this.encoder) {
|
|
2376
|
+
console.warn("Encoder is not initialized, skipping reset");
|
|
2369
2377
|
return;
|
|
2370
2378
|
}
|
|
2371
2379
|
this.encoder.reset();
|
|
2372
2380
|
this.onReset();
|
|
2381
|
+
console.info("Encoder is resetted");
|
|
2373
2382
|
}
|
|
2374
2383
|
async close() {
|
|
2384
|
+
console.info("Encoder is closing...");
|
|
2375
2385
|
if (!this.encoder) {
|
|
2376
2386
|
return;
|
|
2377
2387
|
}
|
|
@@ -2380,6 +2390,7 @@ class BaseEncoder {
|
|
|
2380
2390
|
}
|
|
2381
2391
|
this.encoder.close();
|
|
2382
2392
|
this.encoder = void 0;
|
|
2393
|
+
console.info("Encoder is closed");
|
|
2383
2394
|
}
|
|
2384
2395
|
get isReady() {
|
|
2385
2396
|
return this.encoder?.state === "configured";
|
|
@@ -2392,6 +2403,7 @@ class BaseEncoder {
|
|
|
2392
2403
|
try {
|
|
2393
2404
|
this.controller.enqueue({ chunk, metadata });
|
|
2394
2405
|
} catch (error) {
|
|
2406
|
+
console.error("Encoder output error:", error);
|
|
2395
2407
|
if (!(error instanceof TypeError && error.message.includes("closed"))) {
|
|
2396
2408
|
throw error;
|
|
2397
2409
|
}
|
|
@@ -2399,6 +2411,10 @@ class BaseEncoder {
|
|
|
2399
2411
|
}
|
|
2400
2412
|
}
|
|
2401
2413
|
handleError(error) {
|
|
2414
|
+
if (error.message.includes("reclaimed")) {
|
|
2415
|
+
console.warn("Encoder reclaimed by browser due to inactivity, skipping error handling");
|
|
2416
|
+
return;
|
|
2417
|
+
}
|
|
2402
2418
|
console.error(`[${this.getEncoderType()}Encoder] Encode error:`, {
|
|
2403
2419
|
name: error.name,
|
|
2404
2420
|
message: error.message,
|
|
@@ -2420,15 +2436,12 @@ class BaseEncoder {
|
|
|
2420
2436
|
{
|
|
2421
2437
|
start: async (controller) => {
|
|
2422
2438
|
this.controller = controller;
|
|
2423
|
-
if (!this.isReady) {
|
|
2424
|
-
await this.initialize();
|
|
2425
|
-
}
|
|
2426
2439
|
},
|
|
2427
2440
|
transform: async (input) => {
|
|
2428
|
-
if (!this.
|
|
2429
|
-
|
|
2441
|
+
if (!this.isReady) {
|
|
2442
|
+
await this.initialize();
|
|
2430
2443
|
}
|
|
2431
|
-
if (this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {
|
|
2444
|
+
if (this.encoder && this.encoder.encodeQueueSize >= this.encodeQueueThreshold) {
|
|
2432
2445
|
await new Promise((resolve) => {
|
|
2433
2446
|
const check = () => {
|
|
2434
2447
|
if (!this.encoder || this.encoder.encodeQueueSize < this.encodeQueueThreshold - 1) {
|
|
@@ -2440,6 +2453,12 @@ class BaseEncoder {
|
|
|
2440
2453
|
check();
|
|
2441
2454
|
});
|
|
2442
2455
|
}
|
|
2456
|
+
if (!this.isReady) {
|
|
2457
|
+
await this.initialize();
|
|
2458
|
+
}
|
|
2459
|
+
if (!this.encoder || this.encoder.state !== "configured") {
|
|
2460
|
+
throw new Error("Encoder not configured");
|
|
2461
|
+
}
|
|
2443
2462
|
const frame = input.frame || input;
|
|
2444
2463
|
this.encode(frame);
|
|
2445
2464
|
},
|
|
@@ -2471,6 +2490,14 @@ class VideoChunkEncoder extends BaseEncoder {
|
|
|
2471
2490
|
if (config.keyFrameInterval !== void 0) {
|
|
2472
2491
|
this.keyFrameInterval = Math.max(1, config.keyFrameInterval);
|
|
2473
2492
|
}
|
|
2493
|
+
console.info(
|
|
2494
|
+
"VideoChunkEncoder initialized with encodeQueueThreshold:",
|
|
2495
|
+
this.encodeQueueThreshold,
|
|
2496
|
+
" highWaterMark:",
|
|
2497
|
+
this.highWaterMark,
|
|
2498
|
+
" keyFrameInterval:",
|
|
2499
|
+
this.keyFrameInterval
|
|
2500
|
+
);
|
|
2474
2501
|
}
|
|
2475
2502
|
async isConfigSupported(config) {
|
|
2476
2503
|
const result = await VideoEncoder.isConfigSupported(config);
|
|
@@ -2486,16 +2513,20 @@ class VideoChunkEncoder extends BaseEncoder {
|
|
|
2486
2513
|
this.frameCount = 0;
|
|
2487
2514
|
}
|
|
2488
2515
|
encode(frame) {
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2516
|
+
try {
|
|
2517
|
+
const keyFrame = this.shouldGenerateKeyFrame();
|
|
2518
|
+
const encodeOptions = {
|
|
2519
|
+
keyFrame
|
|
2520
|
+
};
|
|
2521
|
+
this.encoder.encode(frame, encodeOptions);
|
|
2522
|
+
this.frameCount++;
|
|
2523
|
+
} finally {
|
|
2524
|
+
frame.close();
|
|
2525
|
+
}
|
|
2496
2526
|
}
|
|
2497
2527
|
setKeyFrameInterval(interval) {
|
|
2498
2528
|
this.keyFrameInterval = Math.max(1, interval);
|
|
2529
|
+
console.info("Key frame interval set to:", this.keyFrameInterval);
|
|
2499
2530
|
}
|
|
2500
2531
|
shouldGenerateKeyFrame() {
|
|
2501
2532
|
if (this.frameCount === 0) {
|
|
@@ -3209,4 +3240,4 @@ const export_worker = null;
|
|
|
3209
3240
|
export {
|
|
3210
3241
|
export_worker as default
|
|
3211
3242
|
};
|
|
3212
|
-
//# sourceMappingURL=export.worker.
|
|
3243
|
+
//# sourceMappingURL=export.worker.DbrPlw6d.js.map
|