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
@@ -1,298 +1,239 @@
1
1
  /**
2
- * Container Muxer - Writes encoded chunks to container files (MP4, WebM, MKV)
2
+ * Muxer - Primary muxer with automatic fallback
3
3
  *
4
- * Wraps node-av's Muxer to provide a WebCodecs-compatible interface that accepts
5
- * EncodedVideoChunk and EncodedAudioChunk objects.
4
+ * This muxer attempts to use the fast node-av muxer first, and automatically
5
+ * falls back to FFmpeg spawn if it fails. This provides the best of both worlds:
6
+ * fast muxing when possible, with reliable fallback for edge cases.
6
7
  */
7
- import { Muxer as NodeAvMuxer, Demuxer as NodeAvDemuxer, Encoder as NodeAvEncoder, 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, AV_PIX_FMT_YUV420P, AV_SAMPLE_FMT_FLTP, } from 'node-av';
8
- import { withTimeout, DEFAULT_TIMEOUTS } from '../utils/timeout.js';
8
+ import { MuxerError } from './muxer-types.js';
9
+ import { NodeAvMuxer } from './NodeAvMuxer.js';
10
+ import { FFmpegMuxer } from './FFmpegMuxer.js';
9
11
  /**
10
- * Maps WebCodecs codec strings to FFmpeg codec IDs
11
- */
12
- function mapVideoCodecId(codec) {
13
- const codecLower = codec.toLowerCase();
14
- if (codecLower.startsWith('avc1') || codecLower.startsWith('avc3') || codecLower === 'h264') {
15
- return AV_CODEC_ID_H264;
16
- }
17
- else if (codecLower.startsWith('hvc1') || codecLower.startsWith('hev1') || codecLower === 'hevc') {
18
- return AV_CODEC_ID_HEVC;
19
- }
20
- else if (codecLower === 'vp8') {
21
- return AV_CODEC_ID_VP8;
22
- }
23
- else if (codecLower.startsWith('vp09') || codecLower === 'vp9') {
24
- return AV_CODEC_ID_VP9;
25
- }
26
- else if (codecLower.startsWith('av01') || codecLower === 'av1') {
27
- return AV_CODEC_ID_AV1;
28
- }
29
- throw new Error(`Unsupported video codec: ${codec}`);
30
- }
31
- function mapAudioCodecId(codec) {
32
- const codecLower = codec.toLowerCase();
33
- if (codecLower.startsWith('mp4a') || codecLower === 'aac') {
34
- return AV_CODEC_ID_AAC;
35
- }
36
- else if (codecLower === 'mp3') {
37
- return AV_CODEC_ID_MP3;
38
- }
39
- else if (codecLower === 'opus') {
40
- return AV_CODEC_ID_OPUS;
41
- }
42
- else if (codecLower === 'vorbis') {
43
- return AV_CODEC_ID_VORBIS;
44
- }
45
- else if (codecLower === 'flac') {
46
- return AV_CODEC_ID_FLAC;
47
- }
48
- throw new Error(`Unsupported audio codec: ${codec}`);
49
- }
50
- /**
51
- * Infer container format from file extension
52
- */
53
- function inferFormat(path) {
54
- const ext = path.split('.').pop()?.toLowerCase();
55
- switch (ext) {
56
- case 'mp4':
57
- case 'm4v':
58
- return 'mp4';
59
- case 'webm':
60
- return 'webm';
61
- case 'mkv':
62
- return 'matroska';
63
- case 'mov':
64
- return 'mov';
65
- case 'avi':
66
- return 'avi';
67
- case 'ts':
68
- return 'mpegts';
69
- default:
70
- return 'mp4';
71
- }
72
- }
73
- /**
74
- * Container muxer that accepts WebCodecs-compatible chunks
12
+ * Muxer that tries node-av first, then falls back to FFmpeg spawn
13
+ *
14
+ * This implementation buffers all chunks and only performs the actual
15
+ * muxing when close() is called. This allows seamless fallback if the
16
+ * primary muxer fails at any point.
75
17
  *
76
18
  * @example
77
19
  * ```typescript
78
- * const muxer = new Muxer({ path: 'output.mp4' });
79
- * await muxer.open();
80
- * await muxer.addVideoTrack({
81
- * codec: 'avc1.42001E',
82
- * codedWidth: 640,
83
- * codedHeight: 480,
84
- * framerate: 30,
85
- * description: spsNaluBuffer, // Optional: H.264 SPS/PPS
20
+ * const muxer = new Muxer({
21
+ * path: 'output.mp4',
22
+ * onFallback: (err) => console.warn('Using FFmpeg fallback:', err.message),
86
23
  * });
87
24
  *
88
- * // Write encoded chunks from VideoEncoder
89
- * encoder.configure({ codec: 'avc1.42001E', ... });
90
- * encoder.encode(frame);
91
- * // In output callback:
92
- * await muxer.writeVideoChunk(chunk);
25
+ * await muxer.open();
26
+ * await muxer.addVideoTrack({ codec: 'avc1.64001E', ... });
27
+ * await muxer.addAudioTrack({ codec: 'mp4a.40.2', ... });
28
+ *
29
+ * for (const chunk of videoChunks) await muxer.writeVideoChunk(chunk);
30
+ * for (const chunk of audioChunks) await muxer.writeAudioChunk(chunk);
93
31
  *
94
- * await muxer.close();
32
+ * const result = await muxer.closeWithResult();
33
+ * console.log(`Muxed with ${result.backend} in ${result.durationMs}ms`);
95
34
  * ```
96
35
  */
97
36
  export class Muxer {
98
- muxer = null;
99
37
  config;
100
- _videoStreamIndex = -1;
101
- _audioStreamIndex = -1;
102
- _videoEncoder = null;
103
- _audioEncoder = null;
104
- _videoConfig = null;
105
- _audioConfig = null;
38
+ videoConfig = null;
39
+ audioConfig = null;
40
+ videoChunks = [];
41
+ audioChunks = [];
106
42
  _videoChunkCount = 0;
107
43
  _audioChunkCount = 0;
44
+ isOpen = false;
45
+ usedBackend = null;
108
46
  constructor(config) {
109
47
  this.config = config;
110
48
  }
111
- /**
112
- * Open the muxer for writing
113
- *
114
- * @param timeout - Operation timeout in milliseconds (default: 15000)
115
- */
116
- async open(timeout = DEFAULT_TIMEOUTS.open) {
117
- const format = this.config.format || inferFormat(this.config.path);
118
- this.muxer = await withTimeout(NodeAvMuxer.open(this.config.path, { format }), timeout, `Muxer open (${this.config.path})`);
49
+ async open(timeout) {
50
+ this.isOpen = true;
51
+ // We don't actually open anything yet - we buffer chunks
52
+ // and open the muxer during close()
119
53
  }
120
- /**
121
- * Add a video track to the output
122
- *
123
- * @param config - Video track configuration
124
- * @returns Stream index for the video track
125
- */
126
54
  async addVideoTrack(config) {
127
- if (!this.muxer) {
128
- throw new Error('Muxer not opened');
55
+ if (!this.isOpen) {
56
+ throw new MuxerError('Muxer not opened', 'node-av', 'addTrack');
129
57
  }
130
- this._videoConfig = config;
131
- const codecId = mapVideoCodecId(config.codec);
132
- // Create an encoder to properly configure the output stream
133
- // The encoder sets up codec parameters that the muxer needs
134
- // Use microsecond timeBase (1/1000000) to match WebCodecs timestamp units
135
- this._videoEncoder = await NodeAvEncoder.create(codecId, {
136
- width: config.codedWidth,
137
- height: config.codedHeight,
138
- pixelFormat: AV_PIX_FMT_YUV420P,
139
- timeBase: { num: 1, den: 1_000_000 }, // Microseconds - matches WebCodecs
140
- frameRate: { num: config.framerate || 30, den: 1 },
141
- bitrate: config.bitrate || 1_000_000,
142
- gopSize: 30,
143
- // Set extradata from description (SPS/PPS for H.264, etc.)
144
- extradata: config.description ? Buffer.from(config.description) : undefined,
145
- });
146
- // Add the encoder's stream to the muxer
147
- this._videoStreamIndex = this.muxer.addStream(this._videoEncoder);
148
- return this._videoStreamIndex;
58
+ this.videoConfig = config;
59
+ return 0;
149
60
  }
150
- /**
151
- * Add an audio track to the output
152
- *
153
- * @param config - Audio track configuration
154
- * @returns Stream index for the audio track
155
- */
156
61
  async addAudioTrack(config) {
157
- if (!this.muxer) {
158
- throw new Error('Muxer not opened');
62
+ if (!this.isOpen) {
63
+ throw new MuxerError('Muxer not opened', 'node-av', 'addTrack');
159
64
  }
160
- this._audioConfig = config;
161
- const codecId = mapAudioCodecId(config.codec);
162
- // Create an encoder to properly configure the output stream
163
- // Use microsecond timeBase (1/1000000) to match WebCodecs timestamp units
164
- this._audioEncoder = await NodeAvEncoder.create(codecId, {
165
- sampleRate: config.sampleRate,
166
- channels: config.numberOfChannels,
167
- sampleFormat: AV_SAMPLE_FMT_FLTP,
168
- timeBase: { num: 1, den: 1_000_000 }, // Microseconds - matches WebCodecs
169
- bitrate: config.bitrate || 128_000,
170
- // Set extradata from description (AudioSpecificConfig for AAC, etc.)
171
- extradata: config.description ? Buffer.from(config.description) : undefined,
172
- });
173
- // Add the encoder's stream to the muxer
174
- this._audioStreamIndex = this.muxer.addStream(this._audioEncoder);
175
- return this._audioStreamIndex;
65
+ this.audioConfig = config;
66
+ return this.videoConfig ? 1 : 0;
176
67
  }
177
- /**
178
- * Write an encoded video chunk to the output container
179
- *
180
- * @param chunk - EncodedVideoChunk from VideoEncoder
181
- */
182
68
  async writeVideoChunk(chunk) {
183
- if (!this.muxer || this._videoStreamIndex < 0) {
184
- throw new Error('Video track not configured. Call addVideoTrack() first.');
69
+ if (!this.isOpen || !this.videoConfig) {
70
+ throw new MuxerError('Video track not configured', 'node-av', 'write');
185
71
  }
186
- // Create a packet from the chunk data
187
- const packetData = {
188
- data: Buffer.from(chunk._buffer),
189
- pts: BigInt(Math.round(chunk.timestamp)), // microseconds
190
- dts: BigInt(Math.round(chunk.timestamp)),
191
- duration: chunk.duration ? BigInt(Math.round(chunk.duration)) : undefined,
192
- isKeyframe: chunk.type === 'key',
193
- };
194
- await this.muxer.writePacket(packetData, this._videoStreamIndex);
72
+ this.videoChunks.push(chunk);
195
73
  this._videoChunkCount++;
196
74
  }
197
- /**
198
- * Write an encoded audio chunk to the output container
199
- *
200
- * @param chunk - EncodedAudioChunk from AudioEncoder
201
- */
202
75
  async writeAudioChunk(chunk) {
203
- if (!this.muxer || this._audioStreamIndex < 0) {
204
- throw new Error('Audio track not configured. Call addAudioTrack() first.');
76
+ if (!this.isOpen || !this.audioConfig) {
77
+ throw new MuxerError('Audio track not configured', 'node-av', 'write');
205
78
  }
206
- // Create a packet from the chunk data
207
- const packetData = {
208
- data: Buffer.from(chunk._rawData),
209
- pts: BigInt(Math.round(chunk.timestamp)), // microseconds
210
- dts: BigInt(Math.round(chunk.timestamp)),
211
- duration: chunk.duration ? BigInt(Math.round(chunk.duration)) : undefined,
212
- isKeyframe: chunk.type === 'key',
213
- };
214
- await this.muxer.writePacket(packetData, this._audioStreamIndex);
79
+ this.audioChunks.push(chunk);
215
80
  this._audioChunkCount++;
216
81
  }
217
82
  /**
218
- * Finalize and close the muxer
219
- *
220
- * @param timeout - Operation timeout in milliseconds (default: 10000)
83
+ * Close the muxer and finalize the output file
221
84
  */
222
- async close(timeout = DEFAULT_TIMEOUTS.close) {
223
- // Close encoders (sync)
224
- if (this._videoEncoder) {
225
- this._videoEncoder.close();
226
- this._videoEncoder = null;
85
+ async close(timeout) {
86
+ await this.closeWithResult(timeout);
87
+ }
88
+ /**
89
+ * Close the muxer and return detailed result including which backend was used
90
+ */
91
+ async closeWithResult(timeout) {
92
+ if (!this.isOpen) {
93
+ return {
94
+ path: this.config.path,
95
+ videoChunkCount: 0,
96
+ audioChunkCount: 0,
97
+ durationMs: 0,
98
+ backend: 'node-av',
99
+ };
227
100
  }
228
- if (this._audioEncoder) {
229
- this._audioEncoder.close();
230
- this._audioEncoder = null;
101
+ const startTime = Date.now();
102
+ // If force backend is specified, use only that
103
+ if (this.config.forceBackend === 'ffmpeg-spawn') {
104
+ await this.muxWithFFmpeg();
105
+ this.usedBackend = 'ffmpeg-spawn';
231
106
  }
232
- // Close muxer (async with timeout)
233
- if (this.muxer) {
234
- await withTimeout(this.muxer.close(), timeout, 'Muxer close');
235
- this.muxer = null;
107
+ else if (this.config.forceBackend === 'node-av') {
108
+ await this.muxWithNodeAv(timeout);
109
+ this.usedBackend = 'node-av';
236
110
  }
111
+ else {
112
+ // Try node-av first, fallback to FFmpeg
113
+ try {
114
+ await this.muxWithNodeAv(timeout);
115
+ this.usedBackend = 'node-av';
116
+ }
117
+ catch (error) {
118
+ // Notify about fallback
119
+ if (this.config.onFallback) {
120
+ this.config.onFallback(error);
121
+ }
122
+ // Fall back to FFmpeg
123
+ await this.muxWithFFmpeg();
124
+ this.usedBackend = 'ffmpeg-spawn';
125
+ }
126
+ }
127
+ this.isOpen = false;
128
+ const durationMs = Date.now() - startTime;
129
+ return {
130
+ path: this.config.path,
131
+ videoChunkCount: this._videoChunkCount,
132
+ audioChunkCount: this._audioChunkCount,
133
+ durationMs,
134
+ backend: this.usedBackend,
135
+ };
237
136
  }
238
- /**
239
- * Get the underlying node-av muxer (for advanced use)
240
- */
241
- get native() {
242
- return this.muxer;
137
+ async muxWithNodeAv(timeout) {
138
+ const muxer = new NodeAvMuxer({
139
+ path: this.config.path,
140
+ format: this.config.format,
141
+ });
142
+ try {
143
+ await muxer.open(timeout);
144
+ if (this.videoConfig) {
145
+ await muxer.addVideoTrack(this.videoConfig);
146
+ }
147
+ if (this.audioConfig) {
148
+ await muxer.addAudioTrack(this.audioConfig);
149
+ }
150
+ // Write all buffered chunks
151
+ for (const chunk of this.videoChunks) {
152
+ await muxer.writeVideoChunk(chunk);
153
+ }
154
+ for (const chunk of this.audioChunks) {
155
+ await muxer.writeAudioChunk(chunk);
156
+ }
157
+ await muxer.close(timeout);
158
+ }
159
+ catch (error) {
160
+ // Try to clean up partial file
161
+ try {
162
+ await muxer.close(1000);
163
+ }
164
+ catch {
165
+ // Ignore cleanup errors
166
+ }
167
+ throw error;
168
+ }
169
+ }
170
+ async muxWithFFmpeg() {
171
+ const muxer = new FFmpegMuxer({
172
+ path: this.config.path,
173
+ format: this.config.format,
174
+ });
175
+ await muxer.open();
176
+ if (this.videoConfig) {
177
+ await muxer.addVideoTrack(this.videoConfig);
178
+ }
179
+ if (this.audioConfig) {
180
+ await muxer.addAudioTrack(this.audioConfig);
181
+ }
182
+ // Write all buffered chunks
183
+ for (const chunk of this.videoChunks) {
184
+ await muxer.writeVideoChunk(chunk);
185
+ }
186
+ for (const chunk of this.audioChunks) {
187
+ await muxer.writeAudioChunk(chunk);
188
+ }
189
+ await muxer.close();
243
190
  }
244
- /**
245
- * Get number of video chunks written
246
- */
247
191
  get videoChunkCount() {
248
192
  return this._videoChunkCount;
249
193
  }
250
- /**
251
- * Get number of audio chunks written
252
- */
253
194
  get audioChunkCount() {
254
195
  return this._audioChunkCount;
255
196
  }
197
+ /**
198
+ * Get which backend was used for muxing (available after close)
199
+ */
200
+ get backend() {
201
+ return this.usedBackend;
202
+ }
256
203
  }
257
204
  /**
258
- * Helper class for stream copy (remux) operations
259
- * This copies encoded data from one container to another without re-encoding
205
+ * Convenience function to mux video and audio chunks to a file
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * const result = await muxChunks({
210
+ * path: 'output.mp4',
211
+ * video: { config: videoTrackConfig, chunks: videoChunks },
212
+ * audio: { config: audioTrackConfig, chunks: audioChunks },
213
+ * });
214
+ * console.log(`Created ${result.path} using ${result.backend}`);
215
+ * ```
260
216
  */
261
- export class StreamCopier {
262
- srcDemuxer = null;
263
- dstMuxer = null;
264
- /**
265
- * Remux a file from one container format to another
266
- * This performs a stream copy without re-encoding
267
- */
268
- static async remux(inputPath, outputPath, options) {
269
- const demuxer = await NodeAvDemuxer.open(inputPath);
270
- const format = options?.format || inferFormat(outputPath);
271
- const muxer = await NodeAvMuxer.open(outputPath, { format });
272
- const streamMap = new Map();
273
- // Copy video stream
274
- const videoStream = demuxer.video();
275
- if (videoStream) {
276
- const outIndex = muxer.addStream(videoStream);
277
- streamMap.set(videoStream.index, outIndex);
217
+ export async function muxChunks(options) {
218
+ const muxer = new Muxer({
219
+ path: options.path,
220
+ format: options.format,
221
+ onFallback: options.onFallback,
222
+ forceBackend: options.forceBackend,
223
+ });
224
+ await muxer.open();
225
+ if (options.video) {
226
+ await muxer.addVideoTrack(options.video.config);
227
+ for (const chunk of options.video.chunks) {
228
+ await muxer.writeVideoChunk(chunk);
278
229
  }
279
- // Copy audio stream
280
- const audioStream = demuxer.audio();
281
- if (audioStream) {
282
- const outIndex = muxer.addStream(audioStream);
283
- streamMap.set(audioStream.index, outIndex);
284
- }
285
- // Copy packets
286
- for await (const packet of demuxer.packets()) {
287
- if (!packet)
288
- continue;
289
- const outIndex = streamMap.get(packet.streamIndex);
290
- if (outIndex !== undefined) {
291
- await muxer.writePacket(packet, outIndex);
292
- }
230
+ }
231
+ if (options.audio) {
232
+ await muxer.addAudioTrack(options.audio.config);
233
+ for (const chunk of options.audio.chunks) {
234
+ await muxer.writeAudioChunk(chunk);
293
235
  }
294
- await demuxer.close();
295
- await muxer.close();
296
236
  }
237
+ return muxer.closeWithResult();
297
238
  }
298
239
  //# sourceMappingURL=Muxer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Muxer.js","sourceRoot":"","sources":["../../src/containers/Muxer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Muxer.js","sourceRoot":"","sources":["../../src/containers/Muxer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Muxer with Fallback - Primary node-av muxer with FFmpeg spawn fallback
3
+ *
4
+ * This muxer attempts to use the fast node-av muxer first, and automatically
5
+ * falls back to FFmpeg spawn if it fails. This provides the best of both worlds:
6
+ * fast muxing when possible, with reliable fallback for edge cases.
7
+ */
8
+ import type { EncodedVideoChunk } from '../core/EncodedVideoChunk.js';
9
+ import type { EncodedAudioChunk } from '../core/EncodedAudioChunk.js';
10
+ import type { IMuxer, MuxerConfig, VideoTrackConfig, AudioTrackConfig, MuxResult } from './muxer-types.js';
11
+ /**
12
+ * Options for MuxerWithFallback
13
+ */
14
+ export interface MuxerWithFallbackOptions extends MuxerConfig {
15
+ /**
16
+ * Callback when fallback is triggered
17
+ * Useful for logging or metrics
18
+ */
19
+ onFallback?: (error: Error) => void;
20
+ /**
21
+ * Force using a specific backend (skip fallback logic)
22
+ */
23
+ forceBackend?: 'node-av' | 'ffmpeg-spawn';
24
+ }
25
+ /**
26
+ * Muxer that tries node-av first, then falls back to FFmpeg spawn
27
+ *
28
+ * This implementation buffers all chunks and only performs the actual
29
+ * muxing when close() is called. This allows seamless fallback if the
30
+ * primary muxer fails at any point.
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const muxer = new MuxerWithFallback({
35
+ * path: 'output.mp4',
36
+ * onFallback: (err) => console.warn('Using FFmpeg fallback:', err.message),
37
+ * });
38
+ *
39
+ * await muxer.open();
40
+ * await muxer.addVideoTrack({ codec: 'avc1.64001E', ... });
41
+ * await muxer.addAudioTrack({ codec: 'mp4a.40.2', ... });
42
+ *
43
+ * for (const chunk of videoChunks) await muxer.writeVideoChunk(chunk);
44
+ * for (const chunk of audioChunks) await muxer.writeAudioChunk(chunk);
45
+ *
46
+ * const result = await muxer.closeWithResult();
47
+ * console.log(`Muxed with ${result.backend} in ${result.durationMs}ms`);
48
+ * ```
49
+ */
50
+ export declare class MuxerWithFallback implements IMuxer {
51
+ private config;
52
+ private videoConfig;
53
+ private audioConfig;
54
+ private videoChunks;
55
+ private audioChunks;
56
+ private _videoChunkCount;
57
+ private _audioChunkCount;
58
+ private isOpen;
59
+ private usedBackend;
60
+ constructor(config: MuxerWithFallbackOptions);
61
+ open(timeout?: number): Promise<void>;
62
+ addVideoTrack(config: VideoTrackConfig): Promise<number>;
63
+ addAudioTrack(config: AudioTrackConfig): Promise<number>;
64
+ writeVideoChunk(chunk: EncodedVideoChunk): Promise<void>;
65
+ writeAudioChunk(chunk: EncodedAudioChunk): Promise<void>;
66
+ /**
67
+ * Close the muxer and finalize the output file
68
+ */
69
+ close(timeout?: number): Promise<void>;
70
+ /**
71
+ * Close the muxer and return detailed result including which backend was used
72
+ */
73
+ closeWithResult(timeout?: number): Promise<MuxResult>;
74
+ private muxWithNodeAv;
75
+ private muxWithFFmpeg;
76
+ get videoChunkCount(): number;
77
+ get audioChunkCount(): number;
78
+ /**
79
+ * Get which backend was used for muxing (available after close)
80
+ */
81
+ get backend(): 'node-av' | 'ffmpeg-spawn' | null;
82
+ }
83
+ /**
84
+ * Convenience function to mux video and audio chunks to a file
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const result = await muxChunks({
89
+ * path: 'output.mp4',
90
+ * video: { config: videoTrackConfig, chunks: videoChunks },
91
+ * audio: { config: audioTrackConfig, chunks: audioChunks },
92
+ * });
93
+ * console.log(`Created ${result.path} using ${result.backend}`);
94
+ * ```
95
+ */
96
+ export declare function muxChunks(options: {
97
+ path: string;
98
+ format?: string;
99
+ video?: {
100
+ config: VideoTrackConfig;
101
+ chunks: EncodedVideoChunk[];
102
+ };
103
+ audio?: {
104
+ config: AudioTrackConfig;
105
+ chunks: EncodedAudioChunk[];
106
+ };
107
+ onFallback?: (error: Error) => void;
108
+ forceBackend?: 'node-av' | 'ffmpeg-spawn';
109
+ }): Promise<MuxResult>;
110
+ //# sourceMappingURL=MuxerWithFallback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MuxerWithFallback.d.ts","sourceRoot":"","sources":["../../src/containers/MuxerWithFallback.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,KAAK,EACV,MAAM,EACN,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,SAAS,EACV,MAAM,kBAAkB,CAAC;AAK1B;;GAEG;AACH,MAAM,WAAW,wBAAyB,SAAQ,WAAW;IAC3D;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEpC;;OAEG;IACH,YAAY,CAAC,EAAE,SAAS,GAAG,cAAc,CAAC;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,iBAAkB,YAAW,MAAM;IAC9C,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAA2C;gBAElD,MAAM,EAAE,wBAAwB;IAItC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrC,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAQxD,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAQxD,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxD,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9D;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C;;OAEG;IACG,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;YAiD7C,aAAa;YAoCb,aAAa;IA0B3B,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,SAAS,GAAG,cAAc,GAAG,IAAI,CAE/C;CACF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE;QACN,MAAM,EAAE,gBAAgB,CAAC;QACzB,MAAM,EAAE,iBAAiB,EAAE,CAAC;KAC7B,CAAC;IACF,KAAK,CAAC,EAAE;QACN,MAAM,EAAE,gBAAgB,CAAC;QACzB,MAAM,EAAE,iBAAiB,EAAE,CAAC;KAC7B,CAAC;IACF,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACpC,YAAY,CAAC,EAAE,SAAS,GAAG,cAAc,CAAC;CAC3C,GAAG,OAAO,CAAC,SAAS,CAAC,CAyBrB"}