node-av 3.1.3 → 5.0.0
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/README.md +88 -52
- package/binding.gyp +23 -11
- package/dist/api/audio-frame-buffer.d.ts +201 -0
- package/dist/api/audio-frame-buffer.js +275 -0
- package/dist/api/audio-frame-buffer.js.map +1 -0
- package/dist/api/bitstream-filter.d.ts +320 -78
- package/dist/api/bitstream-filter.js +684 -151
- package/dist/api/bitstream-filter.js.map +1 -1
- package/dist/api/constants.d.ts +44 -0
- package/dist/api/constants.js +45 -0
- package/dist/api/constants.js.map +1 -0
- package/dist/api/data/test_av1.ivf +0 -0
- package/dist/api/data/test_mjpeg.mjpeg +0 -0
- package/dist/api/data/test_vp8.ivf +0 -0
- package/dist/api/data/test_vp9.ivf +0 -0
- package/dist/api/decoder.d.ts +454 -77
- package/dist/api/decoder.js +1081 -271
- package/dist/api/decoder.js.map +1 -1
- package/dist/api/{media-input.d.ts → demuxer.d.ts} +295 -45
- package/dist/api/demuxer.js +1965 -0
- package/dist/api/demuxer.js.map +1 -0
- package/dist/api/encoder.d.ts +423 -132
- package/dist/api/encoder.js +1089 -240
- package/dist/api/encoder.js.map +1 -1
- package/dist/api/filter-complex.d.ts +769 -0
- package/dist/api/filter-complex.js +1596 -0
- package/dist/api/filter-complex.js.map +1 -0
- package/dist/api/filter-presets.d.ts +80 -5
- package/dist/api/filter-presets.js +117 -7
- package/dist/api/filter-presets.js.map +1 -1
- package/dist/api/filter.d.ts +561 -125
- package/dist/api/filter.js +1083 -274
- package/dist/api/filter.js.map +1 -1
- package/dist/api/{fmp4.d.ts → fmp4-stream.d.ts} +141 -140
- package/dist/api/fmp4-stream.js +539 -0
- package/dist/api/fmp4-stream.js.map +1 -0
- package/dist/api/hardware.d.ts +58 -6
- package/dist/api/hardware.js +127 -11
- package/dist/api/hardware.js.map +1 -1
- package/dist/api/index.d.ts +8 -4
- package/dist/api/index.js +17 -8
- package/dist/api/index.js.map +1 -1
- package/dist/api/io-stream.d.ts +6 -6
- package/dist/api/io-stream.js +5 -4
- package/dist/api/io-stream.js.map +1 -1
- package/dist/api/{media-output.d.ts → muxer.d.ts} +280 -66
- package/dist/api/muxer.js +1934 -0
- package/dist/api/muxer.js.map +1 -0
- package/dist/api/pipeline.d.ts +77 -29
- package/dist/api/pipeline.js +449 -439
- package/dist/api/pipeline.js.map +1 -1
- package/dist/api/rtp-stream.d.ts +312 -0
- package/dist/api/rtp-stream.js +630 -0
- package/dist/api/rtp-stream.js.map +1 -0
- package/dist/api/types.d.ts +533 -56
- package/dist/api/utilities/async-queue.d.ts +91 -0
- package/dist/api/utilities/async-queue.js +162 -0
- package/dist/api/utilities/async-queue.js.map +1 -0
- package/dist/api/utilities/audio-sample.d.ts +11 -1
- package/dist/api/utilities/audio-sample.js +10 -0
- package/dist/api/utilities/audio-sample.js.map +1 -1
- package/dist/api/utilities/channel-layout.d.ts +1 -0
- package/dist/api/utilities/channel-layout.js +1 -0
- package/dist/api/utilities/channel-layout.js.map +1 -1
- package/dist/api/utilities/image.d.ts +39 -1
- package/dist/api/utilities/image.js +38 -0
- package/dist/api/utilities/image.js.map +1 -1
- package/dist/api/utilities/index.d.ts +3 -0
- package/dist/api/utilities/index.js +6 -0
- package/dist/api/utilities/index.js.map +1 -1
- package/dist/api/utilities/media-type.d.ts +2 -1
- package/dist/api/utilities/media-type.js +1 -0
- package/dist/api/utilities/media-type.js.map +1 -1
- package/dist/api/utilities/pixel-format.d.ts +4 -1
- package/dist/api/utilities/pixel-format.js +3 -0
- package/dist/api/utilities/pixel-format.js.map +1 -1
- package/dist/api/utilities/sample-format.d.ts +6 -1
- package/dist/api/utilities/sample-format.js +5 -0
- package/dist/api/utilities/sample-format.js.map +1 -1
- package/dist/api/utilities/scheduler.d.ts +138 -0
- package/dist/api/utilities/scheduler.js +98 -0
- package/dist/api/utilities/scheduler.js.map +1 -0
- package/dist/api/utilities/streaming.d.ts +105 -15
- package/dist/api/utilities/streaming.js +201 -12
- package/dist/api/utilities/streaming.js.map +1 -1
- package/dist/api/utilities/timestamp.d.ts +15 -1
- package/dist/api/utilities/timestamp.js +14 -0
- package/dist/api/utilities/timestamp.js.map +1 -1
- package/dist/api/utilities/whisper-model.d.ts +310 -0
- package/dist/api/utilities/whisper-model.js +528 -0
- package/dist/api/utilities/whisper-model.js.map +1 -0
- package/dist/api/webrtc-stream.d.ts +288 -0
- package/dist/api/webrtc-stream.js +440 -0
- package/dist/api/webrtc-stream.js.map +1 -0
- package/dist/api/whisper.d.ts +324 -0
- package/dist/api/whisper.js +362 -0
- package/dist/api/whisper.js.map +1 -0
- package/dist/constants/constants.d.ts +54 -2
- package/dist/constants/constants.js +48 -1
- package/dist/constants/constants.js.map +1 -1
- package/dist/constants/encoders.d.ts +2 -1
- package/dist/constants/encoders.js +4 -3
- package/dist/constants/encoders.js.map +1 -1
- package/dist/constants/hardware.d.ts +26 -0
- package/dist/constants/hardware.js +27 -0
- package/dist/constants/hardware.js.map +1 -0
- package/dist/constants/index.d.ts +1 -0
- package/dist/constants/index.js +1 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/ffmpeg/index.d.ts +3 -3
- package/dist/ffmpeg/index.js +3 -3
- package/dist/ffmpeg/utils.d.ts +27 -0
- package/dist/ffmpeg/utils.js +28 -16
- package/dist/ffmpeg/utils.js.map +1 -1
- package/dist/lib/binding.d.ts +22 -11
- package/dist/lib/binding.js.map +1 -1
- package/dist/lib/codec-context.d.ts +87 -0
- package/dist/lib/codec-context.js +125 -4
- package/dist/lib/codec-context.js.map +1 -1
- package/dist/lib/codec-parameters.d.ts +229 -1
- package/dist/lib/codec-parameters.js +264 -0
- package/dist/lib/codec-parameters.js.map +1 -1
- package/dist/lib/codec-parser.d.ts +23 -0
- package/dist/lib/codec-parser.js +25 -0
- package/dist/lib/codec-parser.js.map +1 -1
- package/dist/lib/codec.d.ts +26 -4
- package/dist/lib/codec.js +35 -0
- package/dist/lib/codec.js.map +1 -1
- package/dist/lib/dictionary.js +1 -0
- package/dist/lib/dictionary.js.map +1 -1
- package/dist/lib/error.js +1 -1
- package/dist/lib/error.js.map +1 -1
- package/dist/lib/fifo.d.ts +416 -0
- package/dist/lib/fifo.js +453 -0
- package/dist/lib/fifo.js.map +1 -0
- package/dist/lib/filter-context.d.ts +52 -11
- package/dist/lib/filter-context.js +56 -12
- package/dist/lib/filter-context.js.map +1 -1
- package/dist/lib/filter-graph.d.ts +9 -0
- package/dist/lib/filter-graph.js +13 -0
- package/dist/lib/filter-graph.js.map +1 -1
- package/dist/lib/filter.d.ts +21 -0
- package/dist/lib/filter.js +28 -0
- package/dist/lib/filter.js.map +1 -1
- package/dist/lib/format-context.d.ts +48 -14
- package/dist/lib/format-context.js +76 -7
- package/dist/lib/format-context.js.map +1 -1
- package/dist/lib/frame.d.ts +264 -1
- package/dist/lib/frame.js +351 -1
- package/dist/lib/frame.js.map +1 -1
- package/dist/lib/hardware-device-context.d.ts +3 -2
- package/dist/lib/hardware-device-context.js.map +1 -1
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.js +4 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/input-format.d.ts +21 -0
- package/dist/lib/input-format.js +42 -2
- package/dist/lib/input-format.js.map +1 -1
- package/dist/lib/native-types.d.ts +76 -27
- package/dist/lib/option.d.ts +25 -13
- package/dist/lib/option.js +28 -0
- package/dist/lib/option.js.map +1 -1
- package/dist/lib/output-format.d.ts +22 -1
- package/dist/lib/output-format.js +28 -0
- package/dist/lib/output-format.js.map +1 -1
- package/dist/lib/packet.d.ts +35 -0
- package/dist/lib/packet.js +52 -2
- package/dist/lib/packet.js.map +1 -1
- package/dist/lib/rational.d.ts +18 -0
- package/dist/lib/rational.js +19 -0
- package/dist/lib/rational.js.map +1 -1
- package/dist/lib/stream.d.ts +126 -0
- package/dist/lib/stream.js +188 -5
- package/dist/lib/stream.js.map +1 -1
- package/dist/lib/sync-queue.d.ts +179 -0
- package/dist/lib/sync-queue.js +197 -0
- package/dist/lib/sync-queue.js.map +1 -0
- package/dist/lib/types.d.ts +49 -1
- package/dist/lib/utilities.d.ts +281 -53
- package/dist/lib/utilities.js +298 -55
- package/dist/lib/utilities.js.map +1 -1
- package/install/check.js +2 -2
- package/package.json +37 -26
- package/dist/api/fmp4.js +0 -710
- package/dist/api/fmp4.js.map +0 -1
- package/dist/api/media-input.js +0 -1075
- package/dist/api/media-input.js.map +0 -1
- package/dist/api/media-output.js +0 -1040
- package/dist/api/media-output.js.map +0 -1
- package/dist/api/webrtc.d.ts +0 -664
- package/dist/api/webrtc.js +0 -1132
- package/dist/api/webrtc.js.map +0 -1
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ Native Node.js bindings for FFmpeg with full TypeScript support. Provides direct
|
|
|
22
22
|
- [Low-Level API](#low-level-api)
|
|
23
23
|
- [High-Level API](#high-level-api)
|
|
24
24
|
- [Pipeline API](#pipeline-api)
|
|
25
|
+
- [Key Features](#key-features)
|
|
25
26
|
- [Hardware Acceleration](#hardware-acceleration)
|
|
26
27
|
- [Auto-Detection](#auto-detection)
|
|
27
28
|
- [Specific Hardware](#specific-hardware)
|
|
@@ -90,10 +91,6 @@ decoderCtx.allocContext3(codec);
|
|
|
90
91
|
ret = decoderCtx.parametersToContext(videoStream.codecpar);
|
|
91
92
|
FFmpegError.throwIfError(ret, 'Could not copy codec parameters to decoder context');
|
|
92
93
|
|
|
93
|
-
// Inform the decoder about the timebase for packet timestamps and the frame rate
|
|
94
|
-
decoderCtx.pktTimebase = videoStream.timeBase;
|
|
95
|
-
decoderCtx.framerate = videoStream.rFrameRate || videoStream.avgFrameRate || new Rational(25, 1);
|
|
96
|
-
|
|
97
94
|
// Open decoder context
|
|
98
95
|
ret = await decoderCtx.open2(codec, null);
|
|
99
96
|
FFmpegError.throwIfError(ret, 'Could not open codec');
|
|
@@ -140,49 +137,45 @@ while (true) {
|
|
|
140
137
|
Higher-level abstractions for common tasks like decoding, encoding, filtering, and transcoding. Easier to use while still providing access to low-level details when needed.
|
|
141
138
|
|
|
142
139
|
```typescript
|
|
143
|
-
import { Decoder, Encoder,
|
|
140
|
+
import { Decoder, Demuxer, Encoder, HardwareContext, Muxer } from 'node-av/api';
|
|
144
141
|
import { FF_ENCODER_LIBX264 } from 'node-av/constants';
|
|
145
142
|
|
|
146
|
-
// Open
|
|
147
|
-
await using input = await
|
|
148
|
-
await using output = await MediaOutput.open('output.mp4');
|
|
143
|
+
// Open Demuxer
|
|
144
|
+
await using input = await Demuxer.open('input.mp4');
|
|
149
145
|
|
|
150
146
|
// Get video stream
|
|
151
147
|
const videoStream = input.video()!;
|
|
152
148
|
|
|
149
|
+
// Optional, setup hardware acceleration
|
|
150
|
+
using hw = HardwareContext.auto();
|
|
151
|
+
|
|
153
152
|
// Create decoder
|
|
154
|
-
using decoder = await Decoder.create(videoStream
|
|
153
|
+
using decoder = await Decoder.create(videoStream, {
|
|
154
|
+
hardware: hw, // Optional, use hardware acceleration if available
|
|
155
|
+
});
|
|
155
156
|
|
|
156
157
|
// Create encoder
|
|
157
158
|
using encoder = await Encoder.create(FF_ENCODER_LIBX264, {
|
|
158
|
-
|
|
159
|
-
frameRate: videoStream.avgFrameRate,
|
|
159
|
+
decoder, // Optional, copy settings from decoder
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
-
//
|
|
163
|
-
|
|
162
|
+
// Open Muxer
|
|
163
|
+
await using output = await Muxer.open('output.mp4', {
|
|
164
|
+
input, // Optional, used to copy global headers and metadata
|
|
165
|
+
});
|
|
164
166
|
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
using encoded = await encoder.encode(frame);
|
|
170
|
-
if (encoded) {
|
|
171
|
-
await output.writePacket(encoded, outputIndex);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
167
|
+
// Add stream to output
|
|
168
|
+
const outputIndex = output.addStream(encoder, {
|
|
169
|
+
inputStream: videoStream, // Optional, copy settings from input stream
|
|
170
|
+
});
|
|
175
171
|
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
await output.writePacket(encoded, outputIndex);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
172
|
+
// Create processing generators
|
|
173
|
+
const inputGenerator = input.packets(videoStream.index);
|
|
174
|
+
const decoderGenerator = decoder.frames(inputGenerator);
|
|
175
|
+
const encoderGenerator = encoder.packets(decoderGenerator);
|
|
183
176
|
|
|
184
|
-
//
|
|
185
|
-
for await (using packet of
|
|
177
|
+
// Process packets
|
|
178
|
+
for await (using packet of encoderGenerator) {
|
|
186
179
|
await output.writePacket(packet, outputIndex);
|
|
187
180
|
}
|
|
188
181
|
|
|
@@ -194,21 +187,57 @@ for await (using packet of encoder.flushPackets()) {
|
|
|
194
187
|
A simple way to chain together multiple processing steps like decoding, filtering, encoding, and muxing.
|
|
195
188
|
|
|
196
189
|
```typescript
|
|
197
|
-
import {
|
|
190
|
+
import { Decoder, Demuxer, Encoder, HardwareContext, Muxer, pipeline } from 'node-av/api';
|
|
191
|
+
import { FF_ENCODER_LIBX264 } from 'node-av/constants';
|
|
198
192
|
|
|
199
193
|
// Simple transcode pipeline: input → decoder → encoder → output
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
194
|
+
|
|
195
|
+
// Open Demuxer
|
|
196
|
+
await using input = await Demuxer.open('input.mp4');
|
|
197
|
+
|
|
198
|
+
// Get video stream
|
|
199
|
+
const videoStream = input.video()!;
|
|
200
|
+
|
|
201
|
+
// Optional, setup hardware acceleration
|
|
202
|
+
using hw = HardwareContext.auto();
|
|
203
|
+
|
|
204
|
+
// Create decoder
|
|
205
|
+
using decoder = await Decoder.create(videoStream, {
|
|
206
|
+
hardware: hw, // Optional, use hardware acceleration if available
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Create encoder
|
|
210
|
+
using encoder = await Encoder.create(FF_ENCODER_LIBX264, {
|
|
211
|
+
decoder, // Optional, copy settings from decoder
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Open Muxer
|
|
215
|
+
await using output = await Muxer.open('output.mp4', {
|
|
216
|
+
input, // Optional, used to copy global headers and metadata
|
|
206
217
|
});
|
|
207
218
|
|
|
208
219
|
const control = pipeline(input, decoder, encoder, output);
|
|
209
220
|
await control.completion;
|
|
210
221
|
```
|
|
211
222
|
|
|
223
|
+
## Key Features
|
|
224
|
+
|
|
225
|
+
Beyond basic transcoding, NodeAV provides advanced media processing capabilities:
|
|
226
|
+
|
|
227
|
+
**Speech Recognition with Whisper**
|
|
228
|
+
Integrate automatic speech-to-text transcription using OpenAI's Whisper model through the whisper.cpp implementation. The library handles automatic model downloading from HuggingFace, supports multiple model sizes (tiny, base, small, medium, large) for different accuracy/performance tradeoffs, and provides hardware-accelerated inference through Metal (macOS), Vulkan (cross-platform), or OpenCL backends. Transcription results include precise timestamps and can be processed in real-time from any audio source.
|
|
229
|
+
|
|
230
|
+
**Advanced Video Filtering with FilterComplexAPI**
|
|
231
|
+
Build sophisticated video processing pipelines using FFmpeg's complete filter ecosystem. The FilterComplexAPI provides direct access to complex filtergraphs with multiple inputs and outputs, enabling advanced operations like picture-in-picture overlays, multi-stream composition (side-by-side, grid layouts), real-time video effects, and custom processing chains. All filters support hardware acceleration where available, and filter configurations can be dynamically constructed based on runtime requirements.
|
|
232
|
+
|
|
233
|
+
**Browser Streaming**
|
|
234
|
+
Stream any media source directly to web browsers through fragmented MP4 (fMP4) or WebRTC protocols. The library can process inputs from RTSP cameras, local files, network streams, or custom sources and package them for browser consumption with minimal latency. Complete examples demonstrate both Media Source Extensions (MSE) based playback for on-demand content and WebRTC integration for real-time streaming scenarios.
|
|
235
|
+
|
|
236
|
+
**RTSP Backchannel / Talkback**
|
|
237
|
+
Implements bidirectional RTSP communication for IP camera integration. The library provides native support for RTSP backchannel streams, enabling audio transmission to camera devices. Transport is handled automatically with support for both TCP (interleaved mode) and UDP protocols, with proper RTP packet formatting and stream synchronization.
|
|
238
|
+
|
|
239
|
+
See the [Examples](#examples) section for complete implementations.
|
|
240
|
+
|
|
212
241
|
## Hardware Acceleration
|
|
213
242
|
|
|
214
243
|
The library supports all hardware acceleration methods available in FFmpeg. The specific hardware types available depend on your FFmpeg build and system configuration.
|
|
@@ -231,8 +260,7 @@ const decoder = await Decoder.create(stream, {
|
|
|
231
260
|
// Use with encoder (use hardware-specific codec)
|
|
232
261
|
const encoderCodec = hw?.getEncoderCodec('h264') ?? FF_ENCODER_LIBX264;
|
|
233
262
|
const encoder = await Encoder.create(encoderCodec, {
|
|
234
|
-
|
|
235
|
-
frameRate: videoStream.avgFrameRate,
|
|
263
|
+
decoder,
|
|
236
264
|
});
|
|
237
265
|
```
|
|
238
266
|
|
|
@@ -252,7 +280,7 @@ The library provides multiple entry points for optimal tree shaking:
|
|
|
252
280
|
|
|
253
281
|
```typescript
|
|
254
282
|
// High-Level API only - Recommended for most use cases
|
|
255
|
-
import {
|
|
283
|
+
import { Muxer, Muxer, Decoder, Encoder } from 'node-av/api';
|
|
256
284
|
|
|
257
285
|
// Low-Level API only - Direct FFmpeg bindings
|
|
258
286
|
import { FormatContext, CodecContext, Frame, Packet } from 'node-av/lib';
|
|
@@ -272,11 +300,11 @@ import * as ffmpeg from 'node-av';
|
|
|
272
300
|
### From Files or Network
|
|
273
301
|
|
|
274
302
|
```typescript
|
|
275
|
-
const media = await
|
|
303
|
+
const media = await Muxer.open('input.mp4');
|
|
276
304
|
|
|
277
305
|
// or
|
|
278
306
|
|
|
279
|
-
const media = await
|
|
307
|
+
const media = await Muxer.open('rtsp://example.com/stream');
|
|
280
308
|
```
|
|
281
309
|
|
|
282
310
|
### From Buffers
|
|
@@ -285,7 +313,7 @@ const media = await MediaInput.open('rtsp://example.com/stream');
|
|
|
285
313
|
import { readFile } from 'fs/promises';
|
|
286
314
|
|
|
287
315
|
const buffer = await readFile('input.mp4');
|
|
288
|
-
const media = await
|
|
316
|
+
const media = await Muxer.open(buffer);
|
|
289
317
|
```
|
|
290
318
|
|
|
291
319
|
### Custom I/O Callbacks
|
|
@@ -305,7 +333,7 @@ const inputCallbacks: IOInputCallbacks = {
|
|
|
305
333
|
}
|
|
306
334
|
};
|
|
307
335
|
|
|
308
|
-
await using input = await
|
|
336
|
+
await using input = await Muxer.open(inputCallbacks, {
|
|
309
337
|
format: 'mp4'
|
|
310
338
|
});
|
|
311
339
|
```
|
|
@@ -314,7 +342,7 @@ await using input = await MediaInput.open(inputCallbacks, {
|
|
|
314
342
|
|
|
315
343
|
```typescript
|
|
316
344
|
// Raw video input
|
|
317
|
-
const rawVideo = await
|
|
345
|
+
const rawVideo = await Muxer.open({
|
|
318
346
|
type: 'video',
|
|
319
347
|
input: 'input.yuv',
|
|
320
348
|
width: 1280,
|
|
@@ -324,7 +352,7 @@ const rawVideo = await MediaInput.open({
|
|
|
324
352
|
});
|
|
325
353
|
|
|
326
354
|
// Raw audio input
|
|
327
|
-
const rawAudio = await
|
|
355
|
+
const rawAudio = await Muxer.open({
|
|
328
356
|
type: 'audio',
|
|
329
357
|
input: 'input.pcm',
|
|
330
358
|
sampleRate: 48000,
|
|
@@ -342,13 +370,13 @@ The library supports automatic resource cleanup using the Disposable pattern:
|
|
|
342
370
|
```typescript
|
|
343
371
|
// Automatic cleanup with 'using'
|
|
344
372
|
{
|
|
345
|
-
await using media = await
|
|
373
|
+
await using media = await Muxer.open('input.mp4');
|
|
346
374
|
using decoder = await Decoder.create(media.video());
|
|
347
375
|
// Resources automatically cleaned up at end of scope
|
|
348
376
|
}
|
|
349
377
|
|
|
350
378
|
// Manual cleanup
|
|
351
|
-
const media = await
|
|
379
|
+
const media = await Muxer.open('input.mp4');
|
|
352
380
|
try {
|
|
353
381
|
// Process media
|
|
354
382
|
} finally {
|
|
@@ -420,21 +448,29 @@ NodeAV provides direct bindings to FFmpeg's C APIs, which work with raw memory p
|
|
|
420
448
|
| `browser-webrtc` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/browser/webrtc) |
|
|
421
449
|
| `api-dash` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-dash.ts) |
|
|
422
450
|
| `api-encode-decode` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-encode-decode.ts) |
|
|
451
|
+
| `api-filter-complex` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-filter-complex.ts) |
|
|
452
|
+
| `api-filter-complex-grid` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-filter-complex-grid.ts) |
|
|
453
|
+
| `api-fmp4` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-fmp4.ts) |
|
|
423
454
|
| `api-frame-extract` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-frame-extract.ts) |
|
|
455
|
+
| `api-hw-codecs` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-hw-codecs.ts) |
|
|
424
456
|
| `api-hw-decode-sw-encode` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-hw-decode-sw-encode.ts) |
|
|
425
457
|
| `api-hw-raw` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-hw-raw.ts) |
|
|
426
458
|
| `api-hw-raw-output` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-hw-raw-output.ts) |
|
|
427
|
-
| `api-hw-rtsp-custom-io` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-hw-rtsp-custom-io.ts) |
|
|
428
459
|
| `api-hw-rtsp` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-hw-rtsp.ts) |
|
|
460
|
+
| `api-hw-stream-custom-io` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-hw-stream-custom-io.ts) |
|
|
429
461
|
| `api-hw-transcode` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-hw-transcode.ts) |
|
|
430
462
|
| `api-hw-filter-sync` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-hw-filter-sync.ts) |
|
|
431
463
|
| `api-muxing` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-muxing.ts) |
|
|
432
464
|
| `api-pipeline-hw-rtsp` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-pipeline-hw-rtsp.ts) |
|
|
433
465
|
| `api-pipeline-raw-muxing` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-pipeline-raw-muxing.ts) |
|
|
434
|
-
| `api-
|
|
466
|
+
| `api-rtp` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-rtp.ts) |
|
|
467
|
+
| `api-sdp-custom` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-sdp-custom.ts) |
|
|
468
|
+
| `api-sdp-input` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-sdp-input.ts) |
|
|
435
469
|
| `api-stream-input` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-stream-input.ts) |
|
|
436
470
|
| `api-sw-decode-hw-encode` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-sw-decode-hw-encode.ts) |
|
|
437
471
|
| `api-sw-transcode` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-sw-transcode.ts) |
|
|
472
|
+
| `api-whisper-subtitles` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-whisper-subtitles.ts) |
|
|
473
|
+
| `api-whisper-transcribe` | | | [✓](https://github.com/seydx/node-av/tree/main/examples/api-whisper-transcribe.ts) |
|
|
438
474
|
| `frame-utils` | | [✓](https://github.com/seydx/node-av/tree/main/examples/frame-utils.ts) | |
|
|
439
475
|
| `avio-read-callback` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/avio_read_callback.c) | [✓](https://github.com/seydx/node-av/tree/main/examples/avio-read-callback.ts) | |
|
|
440
476
|
| `decode-audio` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/decode_audio.c) | [✓](https://github.com/seydx/node-av/tree/main/examples/decode-audio.ts) | |
|
package/binding.gyp
CHANGED
|
@@ -51,17 +51,23 @@
|
|
|
51
51
|
"src/bindings/audio_fifo.cc",
|
|
52
52
|
"src/bindings/audio_fifo_async.cc",
|
|
53
53
|
"src/bindings/audio_fifo_sync.cc",
|
|
54
|
+
"src/bindings/fifo.cc",
|
|
55
|
+
"src/bindings/fifo_async.cc",
|
|
56
|
+
"src/bindings/fifo_sync.cc",
|
|
54
57
|
"src/bindings/frame_utils.cc",
|
|
55
58
|
"src/bindings/bitstream_filter.cc",
|
|
56
59
|
"src/bindings/bitstream_filter_context.cc",
|
|
57
60
|
"src/bindings/bitstream_filter_context_async.cc",
|
|
58
61
|
"src/bindings/bitstream_filter_context_sync.cc",
|
|
59
62
|
"src/bindings/option.cc",
|
|
63
|
+
"src/bindings/sync_queue.cc",
|
|
64
|
+
"externals/jellyfin-ffmpeg/fftools/sync_queue.c",
|
|
60
65
|
],
|
|
61
66
|
"include_dirs": [
|
|
62
67
|
"<!@(node -p \"require('node-addon-api').include\")",
|
|
63
68
|
"/opt/ffbuild/prefix/include",
|
|
64
69
|
"<(module_root_dir)/externals/jellyfin-ffmpeg",
|
|
70
|
+
"<(module_root_dir)/externals/jellyfin-ffmpeg/libavcodec",
|
|
65
71
|
],
|
|
66
72
|
"library_dirs": ["/opt/ffbuild/prefix/lib"],
|
|
67
73
|
"dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
|
|
@@ -102,17 +108,21 @@
|
|
|
102
108
|
"/opt/ffbuild/prefix/lib/libudfread.a",
|
|
103
109
|
"/opt/ffbuild/prefix/lib/libz.a",
|
|
104
110
|
"/opt/ffbuild/prefix/lib/liblzma.a",
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
111
|
+
"/opt/ffbuild/prefix/lib/libfdk-aac.a",
|
|
112
|
+
"/opt/ffbuild/prefix/lib/libNE10.a",
|
|
113
|
+
"/opt/ffbuild/prefix/lib/libchromaprint.a",
|
|
114
|
+
"/opt/ffbuild/prefix/lib/libopenmpt.a",
|
|
115
|
+
"/opt/ffbuild/prefix/lib/libzvbi.a",
|
|
116
|
+
"/opt/ffbuild/prefix/lib/libzimg.a",
|
|
117
|
+
"/opt/ffbuild/prefix/lib/libgmp.a",
|
|
118
|
+
"/opt/ffbuild/prefix/lib/libssl.a",
|
|
119
|
+
"/opt/ffbuild/prefix/lib/libcrypto.a",
|
|
120
|
+
"/opt/ffbuild/prefix/lib/libwhisper.a",
|
|
121
|
+
"/opt/ffbuild/prefix/lib/libggml.a",
|
|
122
|
+
"/opt/ffbuild/prefix/lib/libggml-base.a",
|
|
123
|
+
"/opt/ffbuild/prefix/lib/libggml-cpu.a",
|
|
124
|
+
"/opt/ffbuild/prefix/lib/libggml-blas.a",
|
|
125
|
+
"/opt/ffbuild/prefix/lib/libggml-metal.a",
|
|
116
126
|
"-liconv",
|
|
117
127
|
"-lxml2",
|
|
118
128
|
"-lbz2",
|
|
@@ -129,6 +139,8 @@
|
|
|
129
139
|
"-framework IOKit",
|
|
130
140
|
"-framework OpenGL",
|
|
131
141
|
"-framework Metal",
|
|
142
|
+
"-framework MetalKit",
|
|
143
|
+
"-framework Foundation",
|
|
132
144
|
"-framework OpenCL",
|
|
133
145
|
],
|
|
134
146
|
"xcode_settings": {
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { Frame } from '../lib/frame.js';
|
|
2
|
+
import type { AVSampleFormat } from '../constants/index.js';
|
|
3
|
+
import type { ChannelLayout } from '../lib/types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Audio frame buffering utility for encoders with fixed frame size requirements.
|
|
6
|
+
*
|
|
7
|
+
* Many audio encoders (Opus, AAC, MP3, etc.) require frames with a specific number
|
|
8
|
+
* of samples (frame_size). This class buffers incoming frames and outputs frames
|
|
9
|
+
* with exactly the required size.
|
|
10
|
+
*
|
|
11
|
+
* Uses FFmpeg's AVAudioFifo internally for efficient sample buffering.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { AudioFrameBuffer } from 'node-av/api';
|
|
16
|
+
*
|
|
17
|
+
* // Create buffer for 480-sample frames (e.g., Opus at 24kHz)
|
|
18
|
+
* using buffer = AudioFrameBuffer.create(480, AV_SAMPLE_FMT_FLT, 48000, 'mono', 1);
|
|
19
|
+
*
|
|
20
|
+
* // Push variable-sized frames from filter
|
|
21
|
+
* for await (const frame of filterOutput) {
|
|
22
|
+
* await buffer.push(frame);
|
|
23
|
+
*
|
|
24
|
+
* // Pull fixed-size frames for encoder
|
|
25
|
+
* let outputFrame;
|
|
26
|
+
* while ((outputFrame = await buffer.pull()) !== null) {
|
|
27
|
+
* await encoder.encode(outputFrame);
|
|
28
|
+
* outputFrame.free();
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* // Flush remaining samples
|
|
33
|
+
* let outputFrame;
|
|
34
|
+
* while ((outputFrame = await buffer.pull()) !== null) {
|
|
35
|
+
* await encoder.encode(outputFrame);
|
|
36
|
+
* outputFrame.free();
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class AudioFrameBuffer implements Disposable {
|
|
41
|
+
private fifo;
|
|
42
|
+
private frame;
|
|
43
|
+
private frameSize;
|
|
44
|
+
private nextPts;
|
|
45
|
+
private firstFramePts;
|
|
46
|
+
/**
|
|
47
|
+
* @param fifo - Underlying AudioFifo instance
|
|
48
|
+
*
|
|
49
|
+
* @param frameSize - Number of samples per output frame
|
|
50
|
+
*
|
|
51
|
+
* @param sampleFormat - Audio sample format
|
|
52
|
+
*
|
|
53
|
+
* @param sampleRate - Sample rate in Hz
|
|
54
|
+
*
|
|
55
|
+
* @param channelLayout - Channel layout
|
|
56
|
+
*
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
private constructor();
|
|
60
|
+
/**
|
|
61
|
+
* Create an audio frame buffer.
|
|
62
|
+
*
|
|
63
|
+
* @param frameSize - Required frame size in samples
|
|
64
|
+
*
|
|
65
|
+
* @param sampleFormat - Audio sample format
|
|
66
|
+
*
|
|
67
|
+
* @param sampleRate - Sample rate in Hz
|
|
68
|
+
*
|
|
69
|
+
* @param channelLayout - Channel layout (e.g., 'mono', 'stereo')
|
|
70
|
+
*
|
|
71
|
+
* @param channels - Number of audio channels
|
|
72
|
+
*
|
|
73
|
+
* @returns Configured audio frame buffer
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* // For Opus encoder at 48kHz with 20ms frames
|
|
78
|
+
* const buffer = AudioFrameBuffer.create(960, AV_SAMPLE_FMT_FLT, 48000, 'mono', 1);
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
static create(frameSize: number, sampleFormat: AVSampleFormat, sampleRate: number, channelLayout: ChannelLayout, channels: number): AudioFrameBuffer;
|
|
82
|
+
/**
|
|
83
|
+
* Get number of samples currently in buffer.
|
|
84
|
+
*
|
|
85
|
+
* @returns Number of buffered samples
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* console.log(`Buffer contains ${buffer.size} samples`);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
get size(): number;
|
|
93
|
+
/**
|
|
94
|
+
* Check if a complete frame is available.
|
|
95
|
+
*
|
|
96
|
+
* Returns true if the FIFO contains at least frameSize samples.
|
|
97
|
+
*
|
|
98
|
+
* @returns True if a full frame can be pulled
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* while (buffer.hasFrame()) {
|
|
103
|
+
* const frame = buffer.pull();
|
|
104
|
+
* // Process frame...
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
hasFrame(): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Push an audio frame into the buffer asynchronously.
|
|
111
|
+
*
|
|
112
|
+
* The frame's samples are added to the internal FIFO.
|
|
113
|
+
* Call hasFrame() and pull() to retrieve fixed-size output frames.
|
|
114
|
+
*
|
|
115
|
+
* @param frame - Audio frame to buffer
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* await buffer.push(filterFrame);
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @see {@link pushSync} For synchronous version
|
|
123
|
+
*/
|
|
124
|
+
push(frame: Frame): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Push an audio frame into the buffer synchronously.
|
|
127
|
+
* Synchronous version of push.
|
|
128
|
+
*
|
|
129
|
+
* The frame's samples are added to the internal FIFO.
|
|
130
|
+
* Call hasFrame() and pullSync() to retrieve fixed-size output frames.
|
|
131
|
+
*
|
|
132
|
+
* @param frame - Audio frame to buffer
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* buffer.pushSync(filterFrame);
|
|
137
|
+
* ```
|
|
138
|
+
*
|
|
139
|
+
* @see {@link push} For async version
|
|
140
|
+
*/
|
|
141
|
+
pushSync(frame: Frame): void;
|
|
142
|
+
/**
|
|
143
|
+
* Pull a fixed-size audio frame from the buffer asynchronously.
|
|
144
|
+
*
|
|
145
|
+
* Reads exactly frameSize samples from the FIFO and returns a cloned Frame.
|
|
146
|
+
* Returns null if not enough samples are available.
|
|
147
|
+
* Reuses internal frame buffer for efficiency (like Decoder does).
|
|
148
|
+
*
|
|
149
|
+
* @returns Audio frame with exactly frameSize samples, or null if insufficient samples
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* using frame = await buffer.pull();
|
|
154
|
+
* if (frame) {
|
|
155
|
+
* await encoder.encode(frame);
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* @see {@link pullSync} For synchronous version
|
|
160
|
+
*/
|
|
161
|
+
pull(): Promise<Frame | null>;
|
|
162
|
+
/**
|
|
163
|
+
* Pull a fixed-size audio frame from the buffer synchronously.
|
|
164
|
+
* Synchronous version of pull.
|
|
165
|
+
*
|
|
166
|
+
* Reads exactly frameSize samples from the FIFO and returns a cloned Frame.
|
|
167
|
+
* Returns null if not enough samples are available.
|
|
168
|
+
* Reuses internal frame buffer for efficiency (like Decoder does).
|
|
169
|
+
*
|
|
170
|
+
* @returns Audio frame with exactly frameSize samples, or null if insufficient samples
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* using frame = buffer.pullSync();
|
|
175
|
+
* if (frame) {
|
|
176
|
+
* encoder.encodeSync(frame);
|
|
177
|
+
* }
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* @see {@link pull} For async version
|
|
181
|
+
*/
|
|
182
|
+
pullSync(): Frame | null;
|
|
183
|
+
/**
|
|
184
|
+
* Reset the buffer, discarding all buffered samples.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* buffer.reset();
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
reset(): void;
|
|
192
|
+
/**
|
|
193
|
+
* Free the buffer and all resources.
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* buffer.free();
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
[Symbol.dispose](): void;
|
|
201
|
+
}
|