webcodecs-node 0.7.2 → 0.7.5

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.
Files changed (105) hide show
  1. package/README.md +94 -12
  2. package/dist/config/ffmpeg-quality.d.ts +10 -1
  3. package/dist/config/ffmpeg-quality.d.ts.map +1 -1
  4. package/dist/config/ffmpeg-quality.js +12 -38
  5. package/dist/config/ffmpeg-quality.js.map +1 -1
  6. package/dist/config/webcodecs-config.d.ts +58 -0
  7. package/dist/config/webcodecs-config.d.ts.map +1 -0
  8. package/dist/config/webcodecs-config.js +187 -0
  9. package/dist/config/webcodecs-config.js.map +1 -0
  10. package/dist/containers/Demuxer.d.ts +3 -1
  11. package/dist/containers/Demuxer.d.ts.map +1 -1
  12. package/dist/containers/Demuxer.js +26 -19
  13. package/dist/containers/Demuxer.js.map +1 -1
  14. package/dist/containers/FFmpegMuxer.d.ts +42 -0
  15. package/dist/containers/FFmpegMuxer.d.ts.map +1 -0
  16. package/dist/containers/FFmpegMuxer.js +311 -0
  17. package/dist/containers/FFmpegMuxer.js.map +1 -0
  18. package/dist/containers/FFmpegSpawnMuxer.d.ts +42 -0
  19. package/dist/containers/FFmpegSpawnMuxer.d.ts.map +1 -0
  20. package/dist/containers/FFmpegSpawnMuxer.js +311 -0
  21. package/dist/containers/FFmpegSpawnMuxer.js.map +1 -0
  22. package/dist/containers/FallbackMuxer.d.ts +42 -0
  23. package/dist/containers/FallbackMuxer.d.ts.map +1 -0
  24. package/dist/containers/FallbackMuxer.js +311 -0
  25. package/dist/containers/FallbackMuxer.js.map +1 -0
  26. package/dist/containers/Muxer.d.ts +75 -107
  27. package/dist/containers/Muxer.d.ts.map +1 -1
  28. package/dist/containers/Muxer.js +184 -243
  29. package/dist/containers/Muxer.js.map +1 -1
  30. package/dist/containers/MuxerWithFallback.d.ts +110 -0
  31. package/dist/containers/MuxerWithFallback.d.ts.map +1 -0
  32. package/dist/containers/MuxerWithFallback.js +239 -0
  33. package/dist/containers/MuxerWithFallback.js.map +1 -0
  34. package/dist/containers/NodeAvMuxer.d.ts +118 -0
  35. package/dist/containers/NodeAvMuxer.d.ts.map +1 -0
  36. package/dist/containers/NodeAvMuxer.js +338 -0
  37. package/dist/containers/NodeAvMuxer.js.map +1 -0
  38. package/dist/containers/extract.d.ts.map +1 -1
  39. package/dist/containers/extract.js +3 -1
  40. package/dist/containers/extract.js.map +1 -1
  41. package/dist/containers/index.d.ts +20 -14
  42. package/dist/containers/index.d.ts.map +1 -1
  43. package/dist/containers/index.js +21 -14
  44. package/dist/containers/index.js.map +1 -1
  45. package/dist/containers/muxer-types.d.ts +117 -0
  46. package/dist/containers/muxer-types.d.ts.map +1 -0
  47. package/dist/containers/muxer-types.js +45 -0
  48. package/dist/containers/muxer-types.js.map +1 -0
  49. package/dist/containers/transcode.d.ts.map +1 -1
  50. package/dist/containers/transcode.js +171 -150
  51. package/dist/containers/transcode.js.map +1 -1
  52. package/dist/core/VideoFrame.d.ts +19 -0
  53. package/dist/core/VideoFrame.d.ts.map +1 -1
  54. package/dist/core/VideoFrame.js +11 -0
  55. package/dist/core/VideoFrame.js.map +1 -1
  56. package/dist/decoders/VideoDecoder.d.ts +1 -0
  57. package/dist/decoders/VideoDecoder.d.ts.map +1 -1
  58. package/dist/decoders/VideoDecoder.js +6 -4
  59. package/dist/decoders/VideoDecoder.js.map +1 -1
  60. package/dist/demos/demo-audio-visualizer-mediabunny.d.ts +10 -0
  61. package/dist/demos/demo-audio-visualizer-mediabunny.d.ts.map +1 -0
  62. package/dist/demos/demo-audio-visualizer-mediabunny.js +357 -0
  63. package/dist/demos/demo-audio-visualizer-mediabunny.js.map +1 -0
  64. package/dist/demos/demo-audio-visualizer-nodeav.d.ts +10 -0
  65. package/dist/demos/demo-audio-visualizer-nodeav.d.ts.map +1 -0
  66. package/dist/demos/demo-audio-visualizer-nodeav.js +318 -0
  67. package/dist/demos/demo-audio-visualizer-nodeav.js.map +1 -0
  68. package/dist/demos/demo-muxer-fallback.d.ts +8 -0
  69. package/dist/demos/demo-muxer-fallback.d.ts.map +1 -0
  70. package/dist/demos/demo-muxer-fallback.js +165 -0
  71. package/dist/demos/demo-muxer-fallback.js.map +1 -0
  72. package/dist/encoders/AudioEncoder.d.ts +2 -0
  73. package/dist/encoders/AudioEncoder.d.ts.map +1 -1
  74. package/dist/encoders/AudioEncoder.js +7 -4
  75. package/dist/encoders/AudioEncoder.js.map +1 -1
  76. package/dist/hardware/decoder-args.d.ts.map +1 -1
  77. package/dist/hardware/decoder-args.js +35 -14
  78. package/dist/hardware/decoder-args.js.map +1 -1
  79. package/dist/hardware/detection.d.ts.map +1 -1
  80. package/dist/hardware/detection.js +39 -0
  81. package/dist/hardware/detection.js.map +1 -1
  82. package/dist/hardware/encoder-args.d.ts.map +1 -1
  83. package/dist/hardware/encoder-args.js +43 -5
  84. package/dist/hardware/encoder-args.js.map +1 -1
  85. package/dist/hardware/types.d.ts.map +1 -1
  86. package/dist/hardware/types.js +30 -28
  87. package/dist/hardware/types.js.map +1 -1
  88. package/dist/node-av/NodeAvVideoEncoder.d.ts +5 -0
  89. package/dist/node-av/NodeAvVideoEncoder.d.ts.map +1 -1
  90. package/dist/node-av/NodeAvVideoEncoder.js +76 -23
  91. package/dist/node-av/NodeAvVideoEncoder.js.map +1 -1
  92. package/dist/utils/avc.d.ts +2 -0
  93. package/dist/utils/avc.d.ts.map +1 -1
  94. package/dist/utils/avc.js +36 -8
  95. package/dist/utils/avc.js.map +1 -1
  96. package/dist/utils/codec-validation.d.ts.map +1 -1
  97. package/dist/utils/codec-validation.js +18 -8
  98. package/dist/utils/codec-validation.js.map +1 -1
  99. package/dist/utils/hevc.d.ts +2 -0
  100. package/dist/utils/hevc.d.ts.map +1 -1
  101. package/dist/utils/hevc.js +42 -8
  102. package/dist/utils/hevc.js.map +1 -1
  103. package/docs/api.md +20 -2
  104. package/docs/configuration.md +10 -7
  105. package/package.json +1 -1
@@ -0,0 +1,338 @@
1
+ /**
2
+ * Node-av Muxer - Fast muxer using node-av's FormatContext API
3
+ *
4
+ * Uses node-av's low-level FormatContext API to provide a WebCodecs-compatible interface
5
+ * that accepts EncodedVideoChunk and EncodedAudioChunk objects. This is the fast path
6
+ * (~5ms muxing time) used by the main Muxer class.
7
+ */
8
+ import { FormatContext, Packet, Rational, Demuxer as NodeAvDemuxerInternal, Muxer as NodeAvMuxerInternal, AV_CODEC_ID_H264, AV_CODEC_ID_HEVC, AV_CODEC_ID_VP8, AV_CODEC_ID_VP9, AV_CODEC_ID_AV1, AV_CODEC_ID_AAC, AV_CODEC_ID_OPUS, AV_CODEC_ID_MP3, AV_CODEC_ID_VORBIS, AV_CODEC_ID_FLAC, AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, } from 'node-av';
9
+ import { withTimeout, DEFAULT_TIMEOUTS } from '../utils/timeout.js';
10
+ import { Logger } from '../utils/logger.js';
11
+ import { inferFormat } from './muxer-types.js';
12
+ const logger = new Logger('NodeAvMuxer');
13
+ /**
14
+ * Maps WebCodecs codec strings to FFmpeg codec IDs
15
+ */
16
+ function mapVideoCodecId(codec) {
17
+ const codecLower = codec.toLowerCase();
18
+ if (codecLower.startsWith('avc1') || codecLower.startsWith('avc3') || codecLower === 'h264') {
19
+ return AV_CODEC_ID_H264;
20
+ }
21
+ else if (codecLower.startsWith('hvc1') || codecLower.startsWith('hev1') || codecLower === 'hevc') {
22
+ return AV_CODEC_ID_HEVC;
23
+ }
24
+ else if (codecLower === 'vp8') {
25
+ return AV_CODEC_ID_VP8;
26
+ }
27
+ else if (codecLower.startsWith('vp09') || codecLower === 'vp9') {
28
+ return AV_CODEC_ID_VP9;
29
+ }
30
+ else if (codecLower.startsWith('av01') || codecLower === 'av1') {
31
+ return AV_CODEC_ID_AV1;
32
+ }
33
+ throw new Error(`Unsupported video codec: ${codec}`);
34
+ }
35
+ function mapAudioCodecId(codec) {
36
+ const codecLower = codec.toLowerCase();
37
+ if (codecLower.startsWith('mp4a') || codecLower === 'aac') {
38
+ return AV_CODEC_ID_AAC;
39
+ }
40
+ else if (codecLower === 'mp3') {
41
+ return AV_CODEC_ID_MP3;
42
+ }
43
+ else if (codecLower === 'opus') {
44
+ return AV_CODEC_ID_OPUS;
45
+ }
46
+ else if (codecLower === 'vorbis') {
47
+ return AV_CODEC_ID_VORBIS;
48
+ }
49
+ else if (codecLower === 'flac') {
50
+ return AV_CODEC_ID_FLAC;
51
+ }
52
+ throw new Error(`Unsupported audio codec: ${codec}`);
53
+ }
54
+ /**
55
+ * Node-av based muxer that accepts WebCodecs-compatible chunks
56
+ *
57
+ * Uses node-av's low-level FormatContext API for direct packet writing.
58
+ * This is the fast implementation (~5ms) used internally by the main Muxer class.
59
+ *
60
+ * @example
61
+ * ```typescript
62
+ * const muxer = new NodeAvMuxer({ path: 'output.mp4' });
63
+ * await muxer.open();
64
+ * await muxer.addVideoTrack({
65
+ * codec: 'avc1.42001E',
66
+ * codedWidth: 640,
67
+ * codedHeight: 480,
68
+ * framerate: 30,
69
+ * description: spsNaluBuffer, // Optional: H.264 SPS/PPS
70
+ * });
71
+ *
72
+ * // Write encoded chunks from VideoEncoder
73
+ * await muxer.writeVideoChunk(chunk);
74
+ *
75
+ * await muxer.close();
76
+ * ```
77
+ */
78
+ export class NodeAvMuxer {
79
+ formatContext = null;
80
+ config;
81
+ _videoStreamIndex = -1;
82
+ _audioStreamIndex = -1;
83
+ _videoConfig = null;
84
+ _audioConfig = null;
85
+ _videoChunkCount = 0;
86
+ _audioChunkCount = 0;
87
+ _headerWritten = false;
88
+ constructor(config) {
89
+ this.config = config;
90
+ }
91
+ /**
92
+ * Open the muxer for writing
93
+ *
94
+ * @param timeout - Operation timeout in milliseconds (default: 15000)
95
+ */
96
+ async open(timeout = DEFAULT_TIMEOUTS.open) {
97
+ const format = this.config.format || inferFormat(this.config.path);
98
+ // Create and configure FormatContext
99
+ this.formatContext = new FormatContext();
100
+ this.formatContext.allocOutputContext2(null, format, this.config.path);
101
+ // Open output file
102
+ await withTimeout(this.formatContext.openOutput(this.config.path), timeout, `Muxer open (${this.config.path})`);
103
+ }
104
+ /**
105
+ * Add a video track to the output
106
+ *
107
+ * @param config - Video track configuration
108
+ * @returns Stream index for the video track
109
+ */
110
+ async addVideoTrack(config) {
111
+ if (!this.formatContext) {
112
+ throw new Error('Muxer not opened');
113
+ }
114
+ this._videoConfig = config;
115
+ const codecId = mapVideoCodecId(config.codec);
116
+ // Create a new stream
117
+ const stream = this.formatContext.newStream(null);
118
+ this._videoStreamIndex = stream.index;
119
+ // Set codec parameters on the stream
120
+ const cp = stream.codecpar;
121
+ cp.codecType = AVMEDIA_TYPE_VIDEO;
122
+ cp.codecId = codecId;
123
+ cp.width = config.codedWidth;
124
+ cp.height = config.codedHeight;
125
+ cp.bitRate = BigInt(config.bitrate || 1_000_000);
126
+ cp.format = 0; // YUV420P
127
+ // Set extradata if description is provided (SPS/PPS for H.264, etc.)
128
+ if (config.description && config.description.length > 0) {
129
+ cp.extradata = Buffer.from(config.description);
130
+ }
131
+ // Set stream time base to microseconds (WebCodecs uses microseconds)
132
+ stream.timeBase = new Rational(1, 1_000_000);
133
+ return this._videoStreamIndex;
134
+ }
135
+ /**
136
+ * Add an audio track to the output
137
+ *
138
+ * @param config - Audio track configuration
139
+ * @returns Stream index for the audio track
140
+ */
141
+ async addAudioTrack(config) {
142
+ if (!this.formatContext) {
143
+ throw new Error('Muxer not opened');
144
+ }
145
+ this._audioConfig = config;
146
+ const codecId = mapAudioCodecId(config.codec);
147
+ // Create a new stream
148
+ const stream = this.formatContext.newStream(null);
149
+ this._audioStreamIndex = stream.index;
150
+ // Set codec parameters on the stream
151
+ const cp = stream.codecpar;
152
+ cp.codecType = AVMEDIA_TYPE_AUDIO;
153
+ cp.codecId = codecId;
154
+ cp.sampleRate = config.sampleRate;
155
+ cp.channels = config.numberOfChannels;
156
+ cp.bitRate = BigInt(config.bitrate || 128_000);
157
+ // Set extradata if description is provided (AudioSpecificConfig for AAC, etc.)
158
+ if (config.description && config.description.length > 0) {
159
+ cp.extradata = Buffer.from(config.description);
160
+ }
161
+ // Set stream time base to microseconds (WebCodecs uses microseconds)
162
+ stream.timeBase = new Rational(1, 1_000_000);
163
+ return this._audioStreamIndex;
164
+ }
165
+ /**
166
+ * Write header if not already written
167
+ */
168
+ writeHeaderIfNeeded() {
169
+ if (!this._headerWritten && this.formatContext) {
170
+ const ret = this.formatContext.writeHeaderSync();
171
+ if (ret < 0) {
172
+ throw new Error(`Failed to write header: ${ret}`);
173
+ }
174
+ this._headerWritten = true;
175
+ }
176
+ }
177
+ /**
178
+ * Write an encoded video chunk to the output container
179
+ *
180
+ * @param chunk - EncodedVideoChunk from VideoEncoder
181
+ */
182
+ async writeVideoChunk(chunk) {
183
+ if (!this.formatContext || this._videoStreamIndex < 0) {
184
+ throw new Error('Video track not configured. Call addVideoTrack() first.');
185
+ }
186
+ // Write header on first chunk
187
+ this.writeHeaderIfNeeded();
188
+ // Get the output stream's actual time base (may differ from what we set)
189
+ const stream = this.formatContext.streams[this._videoStreamIndex];
190
+ const streamTimeBase = stream.timeBase;
191
+ // Create a proper node-av Packet from the chunk data
192
+ const packet = new Packet();
193
+ packet.alloc();
194
+ packet.data = Buffer.from(chunk._buffer);
195
+ // Convert timestamps from microseconds to stream timebase
196
+ const usToStreamTs = (us) => {
197
+ // ts_out = ts_in * (timebase_in / timebase_out)
198
+ // ts_out = us * (1/1000000) / (streamTimeBase.num / streamTimeBase.den)
199
+ // ts_out = us * streamTimeBase.den / (1000000 * streamTimeBase.num)
200
+ return BigInt(Math.round(us * streamTimeBase.den / (1_000_000 * streamTimeBase.num)));
201
+ };
202
+ packet.pts = usToStreamTs(chunk.timestamp);
203
+ packet.dts = usToStreamTs(chunk.timestamp);
204
+ if (chunk.duration) {
205
+ packet.duration = usToStreamTs(chunk.duration);
206
+ }
207
+ packet.streamIndex = this._videoStreamIndex;
208
+ packet.isKeyframe = chunk.type === 'key';
209
+ packet.timeBase = streamTimeBase;
210
+ const ret = this.formatContext.interleavedWriteFrameSync(packet);
211
+ packet.free();
212
+ if (ret < 0) {
213
+ throw new Error(`Failed to write video packet: ${ret}`);
214
+ }
215
+ this._videoChunkCount++;
216
+ }
217
+ /**
218
+ * Write an encoded audio chunk to the output container
219
+ *
220
+ * @param chunk - EncodedAudioChunk from AudioEncoder
221
+ */
222
+ async writeAudioChunk(chunk) {
223
+ if (!this.formatContext || this._audioStreamIndex < 0 || !this._audioConfig) {
224
+ throw new Error('Audio track not configured. Call addAudioTrack() first.');
225
+ }
226
+ // Write header on first chunk
227
+ this.writeHeaderIfNeeded();
228
+ // Get the output stream's actual time base (may differ from what we set)
229
+ const stream = this.formatContext.streams[this._audioStreamIndex];
230
+ const streamTimeBase = stream.timeBase;
231
+ // Create a proper node-av Packet from the chunk data
232
+ const packet = new Packet();
233
+ packet.alloc();
234
+ packet.data = Buffer.from(chunk._rawData);
235
+ // Convert timestamps from microseconds to stream timebase
236
+ // For audio, the stream timebase is typically 1/sampleRate
237
+ const usToStreamTs = (us) => {
238
+ // ts_out = ts_in * (timebase_in / timebase_out)
239
+ // ts_out = us * (1/1000000) / (streamTimeBase.num / streamTimeBase.den)
240
+ // ts_out = us * streamTimeBase.den / (1000000 * streamTimeBase.num)
241
+ return BigInt(Math.round(us * streamTimeBase.den / (1_000_000 * streamTimeBase.num)));
242
+ };
243
+ packet.pts = usToStreamTs(chunk.timestamp);
244
+ packet.dts = usToStreamTs(chunk.timestamp);
245
+ if (chunk.duration) {
246
+ packet.duration = usToStreamTs(chunk.duration);
247
+ }
248
+ packet.streamIndex = this._audioStreamIndex;
249
+ packet.isKeyframe = chunk.type === 'key';
250
+ packet.timeBase = streamTimeBase;
251
+ const ret = this.formatContext.interleavedWriteFrameSync(packet);
252
+ packet.free();
253
+ if (ret < 0) {
254
+ throw new Error(`Failed to write audio packet: ${ret}`);
255
+ }
256
+ this._audioChunkCount++;
257
+ }
258
+ /**
259
+ * Finalize and close the muxer
260
+ *
261
+ * @param timeout - Operation timeout in milliseconds (default: 10000)
262
+ */
263
+ async close(timeout = DEFAULT_TIMEOUTS.close) {
264
+ if (this.formatContext) {
265
+ // Write trailer
266
+ if (this._headerWritten) {
267
+ const ret = this.formatContext.writeTrailerSync();
268
+ if (ret < 0) {
269
+ logger.warn(`writeTrailer returned error code ${ret}`);
270
+ }
271
+ }
272
+ // Close output and free context
273
+ await withTimeout(this.formatContext.closeOutput(), timeout, 'Muxer close output');
274
+ this.formatContext.freeContext();
275
+ this.formatContext = null;
276
+ }
277
+ }
278
+ /**
279
+ * Get the underlying FormatContext (for advanced use)
280
+ */
281
+ get native() {
282
+ return this.formatContext;
283
+ }
284
+ /**
285
+ * Get number of video chunks written
286
+ */
287
+ get videoChunkCount() {
288
+ return this._videoChunkCount;
289
+ }
290
+ /**
291
+ * Get number of audio chunks written
292
+ */
293
+ get audioChunkCount() {
294
+ return this._audioChunkCount;
295
+ }
296
+ }
297
+ /**
298
+ * Helper class for stream copy (remux) operations
299
+ * This copies encoded data from one container to another without re-encoding
300
+ */
301
+ export class StreamCopier {
302
+ srcDemuxer = null;
303
+ dstMuxer = null;
304
+ /**
305
+ * Remux a file from one container format to another
306
+ * This performs a stream copy without re-encoding
307
+ */
308
+ static async remux(inputPath, outputPath, options) {
309
+ const demuxer = await NodeAvDemuxerInternal.open(inputPath);
310
+ const format = options?.format || inferFormat(outputPath);
311
+ const muxer = await NodeAvMuxerInternal.open(outputPath, { format });
312
+ const streamMap = new Map();
313
+ // Copy video stream
314
+ const videoStream = demuxer.video();
315
+ if (videoStream) {
316
+ const outIndex = muxer.addStream(videoStream);
317
+ streamMap.set(videoStream.index, outIndex);
318
+ }
319
+ // Copy audio stream
320
+ const audioStream = demuxer.audio();
321
+ if (audioStream) {
322
+ const outIndex = muxer.addStream(audioStream);
323
+ streamMap.set(audioStream.index, outIndex);
324
+ }
325
+ // Copy packets
326
+ for await (const packet of demuxer.packets()) {
327
+ if (!packet)
328
+ continue;
329
+ const outIndex = streamMap.get(packet.streamIndex);
330
+ if (outIndex !== undefined) {
331
+ await muxer.writePacket(packet, outIndex);
332
+ }
333
+ }
334
+ await demuxer.close();
335
+ await muxer.close();
336
+ }
337
+ }
338
+ //# sourceMappingURL=NodeAvMuxer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NodeAvMuxer.js","sourceRoot":"","sources":["../../src/containers/NodeAvMuxer.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/containers/extract.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAuB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CA8CvF"}
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/containers/extract.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAKnD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAuB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CA8CvF"}
@@ -5,6 +5,8 @@
5
5
  */
6
6
  import { Demuxer } from './Demuxer.js';
7
7
  import { VideoDecoder } from '../decoders/VideoDecoder.js';
8
+ import { Logger } from '../utils/logger.js';
9
+ const logger = new Logger('Extract');
8
10
  /**
9
11
  * Extract video frames from a container file as VideoFrame objects
10
12
  *
@@ -36,7 +38,7 @@ export async function* extractVideoFrames(inputPath) {
36
38
  output: (frame) => {
37
39
  frames.push(frame);
38
40
  },
39
- error: (err) => console.error('Decode error:', err),
41
+ error: (err) => logger.error('Decode error:', err),
40
42
  });
41
43
  decoder.configure({
42
44
  codec: videoConfig.codec,
@@ -1 +1 @@
1
- {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/containers/extract.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAG3D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,kBAAkB,CAAC,SAAiB;IACzD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACjD,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;IAErB,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACxC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO;IACT,CAAC;IAED,oCAAoC;IACpC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC;QAC/B,MAAM,EAAE,CAAC,KAAiB,EAAE,EAAE;YAC5B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QACD,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,CAAC;KACpD,CAAC,CAAC;IAEH,OAAO,CAAC,SAAS,CAAC;QAChB,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,UAAU,EAAE,WAAW,CAAC,UAAU;QAClC,WAAW,EAAE,WAAW,CAAC,WAAW;QACpC,WAAW,EAAE,WAAW,CAAC,WAAW;KACrC,CAAC,CAAC;IAEH,0BAA0B;IAC1B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;QAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEtB,2BAA2B;QAC3B,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,MAAM,CAAC,KAAK,EAAG,CAAC;QACxB,CAAC;IACH,CAAC;IAED,wCAAwC;IACxC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACtB,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IAEtB,6BAA6B;IAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../src/containers/extract.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC;AAErC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,kBAAkB,CAAC,SAAiB;IACzD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACjD,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;IAErB,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACxC,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO;IACT,CAAC;IAED,oCAAoC;IACpC,MAAM,MAAM,GAAiB,EAAE,CAAC;IAEhC,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC;QAC/B,MAAM,EAAE,CAAC,KAAiB,EAAE,EAAE;YAC5B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QACD,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,CAAC;KACnD,CAAC,CAAC;IAEH,OAAO,CAAC,SAAS,CAAC;QAChB,KAAK,EAAE,WAAW,CAAC,KAAK;QACxB,UAAU,EAAE,WAAW,CAAC,UAAU;QAClC,WAAW,EAAE,WAAW,CAAC,WAAW;QACpC,WAAW,EAAE,WAAW,CAAC,WAAW;KACrC,CAAC,CAAC;IAEH,0BAA0B;IAC1B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;QAChD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEtB,2BAA2B;QAC3B,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,MAAM,CAAC,KAAK,EAAG,CAAC;QACxB,CAAC;IACH,CAAC;IAED,wCAAwC;IACxC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACtB,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IAEtB,6BAA6B;IAC7B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -6,11 +6,7 @@
6
6
  *
7
7
  * @example
8
8
  * ```typescript
9
- * import { Demuxer, transcode, getMediaInfo } from 'webcodecs-node/containers';
10
- *
11
- * // Get media info
12
- * const info = await getMediaInfo('video.mp4');
13
- * console.log(info.video.codec, info.video.width, info.video.height);
9
+ * import { Demuxer, Muxer, muxChunks } from 'webcodecs-node/containers';
14
10
  *
15
11
  * // Demux video chunks for WebCodecs processing
16
12
  * const demuxer = new Demuxer({ path: 'video.mp4' });
@@ -20,20 +16,30 @@
20
16
  * }
21
17
  * await demuxer.close();
22
18
  *
23
- * // Transcode to different codec/settings
24
- * await transcode('input.mp4', 'output.mp4', {
25
- * videoCodec: 'h264',
26
- * videoBitrate: 1_000_000,
27
- * });
19
+ * // Mux encoded chunks to a file (with automatic fallback)
20
+ * const muxer = new Muxer({ path: 'output.mp4' });
21
+ * await muxer.open();
22
+ * await muxer.addVideoTrack({ codec: 'avc1.64001E', ... });
23
+ * // ... write chunks
24
+ * const result = await muxer.closeWithResult();
25
+ * console.log(`Used ${result.backend} in ${result.durationMs}ms`);
28
26
  *
29
- * // Remux to different container (no re-encoding)
30
- * await remux('input.mp4', 'output.mkv');
27
+ * // Or use the convenience function
28
+ * const result = await muxChunks({
29
+ * path: 'output.mp4',
30
+ * video: { config, chunks },
31
+ * audio: { config, chunks },
32
+ * });
31
33
  * ```
32
34
  */
33
35
  export { Demuxer } from './Demuxer.js';
34
36
  export type { DemuxerConfig, VideoStreamConfig, AudioStreamConfig, VideoChunkCallback, AudioChunkCallback, } from './Demuxer.js';
35
- export { Muxer, StreamCopier } from './Muxer.js';
36
- export type { MuxerConfig, VideoTrackConfig, AudioTrackConfig } from './Muxer.js';
37
+ export type { IMuxer, MuxerConfig, VideoTrackConfig, AudioTrackConfig, MuxResult, } from './muxer-types.js';
38
+ export { MuxerError, inferFormat } from './muxer-types.js';
39
+ export { Muxer, muxChunks } from './Muxer.js';
40
+ export type { MuxerOptions } from './Muxer.js';
41
+ export { NodeAvMuxer, StreamCopier } from './NodeAvMuxer.js';
42
+ export { FFmpegMuxer } from './FFmpegMuxer.js';
37
43
  export { remux, transcode, getMediaInfo } from './transcode.js';
38
44
  export type { TranscodeOptions, TranscodeProgress, TranscodeResult, MediaInfo, VideoCodec, AudioCodec, HardwareAcceleration, } from './transcode.js';
39
45
  export { extractVideoFrames } from './extract.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/containers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGlF,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,UAAU,EACV,UAAU,EACV,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/containers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAGtB,YAAY,EACV,MAAM,EACN,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG3D,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAChE,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,UAAU,EACV,UAAU,EACV,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
@@ -6,11 +6,7 @@
6
6
  *
7
7
  * @example
8
8
  * ```typescript
9
- * import { Demuxer, transcode, getMediaInfo } from 'webcodecs-node/containers';
10
- *
11
- * // Get media info
12
- * const info = await getMediaInfo('video.mp4');
13
- * console.log(info.video.codec, info.video.width, info.video.height);
9
+ * import { Demuxer, Muxer, muxChunks } from 'webcodecs-node/containers';
14
10
  *
15
11
  * // Demux video chunks for WebCodecs processing
16
12
  * const demuxer = new Demuxer({ path: 'video.mp4' });
@@ -20,20 +16,31 @@
20
16
  * }
21
17
  * await demuxer.close();
22
18
  *
23
- * // Transcode to different codec/settings
24
- * await transcode('input.mp4', 'output.mp4', {
25
- * videoCodec: 'h264',
26
- * videoBitrate: 1_000_000,
27
- * });
19
+ * // Mux encoded chunks to a file (with automatic fallback)
20
+ * const muxer = new Muxer({ path: 'output.mp4' });
21
+ * await muxer.open();
22
+ * await muxer.addVideoTrack({ codec: 'avc1.64001E', ... });
23
+ * // ... write chunks
24
+ * const result = await muxer.closeWithResult();
25
+ * console.log(`Used ${result.backend} in ${result.durationMs}ms`);
28
26
  *
29
- * // Remux to different container (no re-encoding)
30
- * await remux('input.mp4', 'output.mkv');
27
+ * // Or use the convenience function
28
+ * const result = await muxChunks({
29
+ * path: 'output.mp4',
30
+ * video: { config, chunks },
31
+ * audio: { config, chunks },
32
+ * });
31
33
  * ```
32
34
  */
33
35
  // Demuxer
34
36
  export { Demuxer } from './Demuxer.js';
35
- // Muxer
36
- export { Muxer, StreamCopier } from './Muxer.js';
37
+ export { MuxerError, inferFormat } from './muxer-types.js';
38
+ // Main Muxer (with automatic fallback - recommended)
39
+ export { Muxer, muxChunks } from './Muxer.js';
40
+ // Node-av Muxer (fast, direct implementation)
41
+ export { NodeAvMuxer, StreamCopier } from './NodeAvMuxer.js';
42
+ // FFmpeg Muxer (subprocess-based, more compatible)
43
+ export { FFmpegMuxer } from './FFmpegMuxer.js';
37
44
  // Transcoding utilities
38
45
  export { remux, transcode, getMediaInfo } from './transcode.js';
39
46
  // Frame extraction
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/containers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,UAAU;AACV,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AASvC,QAAQ;AACR,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAGjD,wBAAwB;AACxB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAWhE,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/containers/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,UAAU;AACV,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAiBvC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE3D,qDAAqD;AACrD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG9C,8CAA8C;AAC9C,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE7D,mDAAmD;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,wBAAwB;AACxB,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAWhE,mBAAmB;AACnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Shared types and interfaces for muxers
3
+ *
4
+ * This module defines common interfaces that both NodeAvMuxer and FFmpegSpawnMuxer
5
+ * implement, enabling a clean fallback mechanism.
6
+ */
7
+ import type { EncodedVideoChunk } from '../core/EncodedVideoChunk.js';
8
+ import type { EncodedAudioChunk } from '../core/EncodedAudioChunk.js';
9
+ /**
10
+ * Video track configuration for muxing
11
+ */
12
+ export interface VideoTrackConfig {
13
+ /** WebCodecs codec string (e.g., 'avc1.64001E', 'hvc1.1.6.L93.B0') */
14
+ codec: string;
15
+ /** Video width in pixels */
16
+ codedWidth: number;
17
+ /** Video height in pixels */
18
+ codedHeight: number;
19
+ /** Frame rate (optional, used for timing) */
20
+ framerate?: number;
21
+ /** Target bitrate in bits/second (optional, for container hints) */
22
+ bitrate?: number;
23
+ /** Codec-specific description (SPS/PPS for H.264, etc.) */
24
+ description?: Uint8Array;
25
+ }
26
+ /**
27
+ * Audio track configuration for muxing
28
+ */
29
+ export interface AudioTrackConfig {
30
+ /** WebCodecs codec string (e.g., 'mp4a.40.2', 'opus') */
31
+ codec: string;
32
+ /** Sample rate in Hz */
33
+ sampleRate: number;
34
+ /** Number of audio channels */
35
+ numberOfChannels: number;
36
+ /** Target bitrate in bits/second (optional) */
37
+ bitrate?: number;
38
+ /** Codec-specific description (AudioSpecificConfig for AAC, etc.) */
39
+ description?: Uint8Array;
40
+ }
41
+ /**
42
+ * Muxer configuration
43
+ */
44
+ export interface MuxerConfig {
45
+ /** Path to the output file */
46
+ path: string;
47
+ /** Container format (mp4, webm, mkv) - inferred from extension if not specified */
48
+ format?: string;
49
+ }
50
+ /**
51
+ * Result of a muxing operation
52
+ */
53
+ export interface MuxResult {
54
+ /** Path to the output file */
55
+ path: string;
56
+ /** Number of video chunks written */
57
+ videoChunkCount: number;
58
+ /** Number of audio chunks written */
59
+ audioChunkCount: number;
60
+ /** Time taken for muxing in milliseconds */
61
+ durationMs: number;
62
+ /** Which muxer backend was used */
63
+ backend: 'node-av' | 'ffmpeg-spawn';
64
+ }
65
+ /**
66
+ * Common interface for all muxer implementations
67
+ */
68
+ export interface IMuxer {
69
+ /**
70
+ * Open the muxer for writing
71
+ */
72
+ open(timeout?: number): Promise<void>;
73
+ /**
74
+ * Add a video track to the output
75
+ * @returns Stream index for the video track
76
+ */
77
+ addVideoTrack(config: VideoTrackConfig): Promise<number>;
78
+ /**
79
+ * Add an audio track to the output
80
+ * @returns Stream index for the audio track
81
+ */
82
+ addAudioTrack(config: AudioTrackConfig): Promise<number>;
83
+ /**
84
+ * Write an encoded video chunk
85
+ */
86
+ writeVideoChunk(chunk: EncodedVideoChunk): Promise<void>;
87
+ /**
88
+ * Write an encoded audio chunk
89
+ */
90
+ writeAudioChunk(chunk: EncodedAudioChunk): Promise<void>;
91
+ /**
92
+ * Finalize and close the muxer
93
+ */
94
+ close(timeout?: number): Promise<void>;
95
+ /**
96
+ * Get number of video chunks written
97
+ */
98
+ readonly videoChunkCount: number;
99
+ /**
100
+ * Get number of audio chunks written
101
+ */
102
+ readonly audioChunkCount: number;
103
+ }
104
+ /**
105
+ * Muxer error with additional context
106
+ */
107
+ export declare class MuxerError extends Error {
108
+ readonly backend: 'node-av' | 'ffmpeg-spawn';
109
+ readonly operation: 'open' | 'addTrack' | 'write' | 'close';
110
+ readonly cause?: Error | undefined;
111
+ constructor(message: string, backend: 'node-av' | 'ffmpeg-spawn', operation: 'open' | 'addTrack' | 'write' | 'close', cause?: Error | undefined);
112
+ }
113
+ /**
114
+ * Infer container format from file extension
115
+ */
116
+ export declare function inferFormat(path: string): string;
117
+ //# sourceMappingURL=muxer-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"muxer-types.d.ts","sourceRoot":"","sources":["../../src/containers/muxer-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,OAAO,EAAE,SAAS,GAAG,cAAc,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB;;OAEG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzD;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzD;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzD;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzD;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvC;;OAEG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAEjC;;OAEG;IACH,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;aAGjB,OAAO,EAAE,SAAS,GAAG,cAAc;aACnC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO;aAClD,KAAK,CAAC,EAAE,KAAK;gBAH7B,OAAO,EAAE,MAAM,EACC,OAAO,EAAE,SAAS,GAAG,cAAc,EACnC,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,EAClD,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmBhD"}