node-av 0.0.1
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/CHANGELOG.md +8 -0
- package/LICENSE.md +22 -0
- package/README.md +377 -0
- package/binding.gyp +78 -0
- package/dist/api/bitstream-filter.d.ts +246 -0
- package/dist/api/bitstream-filter.js +369 -0
- package/dist/api/bitstream-filter.js.map +1 -0
- package/dist/api/decoder.d.ts +257 -0
- package/dist/api/decoder.js +424 -0
- package/dist/api/decoder.js.map +1 -0
- package/dist/api/encoder.d.ts +298 -0
- package/dist/api/encoder.js +574 -0
- package/dist/api/encoder.js.map +1 -0
- package/dist/api/filter.d.ts +457 -0
- package/dist/api/filter.js +876 -0
- package/dist/api/filter.js.map +1 -0
- package/dist/api/hardware.d.ts +318 -0
- package/dist/api/hardware.js +558 -0
- package/dist/api/hardware.js.map +1 -0
- package/dist/api/index.d.ts +12 -0
- package/dist/api/index.js +20 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/io-stream.d.ts +109 -0
- package/dist/api/io-stream.js +124 -0
- package/dist/api/io-stream.js.map +1 -0
- package/dist/api/media-input.d.ts +295 -0
- package/dist/api/media-input.js +456 -0
- package/dist/api/media-input.js.map +1 -0
- package/dist/api/media-output.d.ts +274 -0
- package/dist/api/media-output.js +486 -0
- package/dist/api/media-output.js.map +1 -0
- package/dist/api/pipeline.d.ts +117 -0
- package/dist/api/pipeline.js +836 -0
- package/dist/api/pipeline.js.map +1 -0
- package/dist/api/types.d.ts +440 -0
- package/dist/api/types.js +2 -0
- package/dist/api/types.js.map +1 -0
- package/dist/api/utilities/audio-sample.d.ts +115 -0
- package/dist/api/utilities/audio-sample.js +110 -0
- package/dist/api/utilities/audio-sample.js.map +1 -0
- package/dist/api/utilities/channel-layout.d.ts +83 -0
- package/dist/api/utilities/channel-layout.js +87 -0
- package/dist/api/utilities/channel-layout.js.map +1 -0
- package/dist/api/utilities/image.d.ts +177 -0
- package/dist/api/utilities/image.js +183 -0
- package/dist/api/utilities/image.js.map +1 -0
- package/dist/api/utilities/index.d.ts +8 -0
- package/dist/api/utilities/index.js +17 -0
- package/dist/api/utilities/index.js.map +1 -0
- package/dist/api/utilities/media-type.d.ts +56 -0
- package/dist/api/utilities/media-type.js +60 -0
- package/dist/api/utilities/media-type.js.map +1 -0
- package/dist/api/utilities/pixel-format.d.ts +94 -0
- package/dist/api/utilities/pixel-format.js +102 -0
- package/dist/api/utilities/pixel-format.js.map +1 -0
- package/dist/api/utilities/sample-format.d.ts +132 -0
- package/dist/api/utilities/sample-format.js +144 -0
- package/dist/api/utilities/sample-format.js.map +1 -0
- package/dist/api/utilities/streaming.d.ts +104 -0
- package/dist/api/utilities/streaming.js +137 -0
- package/dist/api/utilities/streaming.js.map +1 -0
- package/dist/api/utilities/timestamp.d.ts +187 -0
- package/dist/api/utilities/timestamp.js +200 -0
- package/dist/api/utilities/timestamp.js.map +1 -0
- package/dist/api/utils.d.ts +61 -0
- package/dist/api/utils.js +330 -0
- package/dist/api/utils.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/audio-fifo.d.ts +339 -0
- package/dist/lib/audio-fifo.js +365 -0
- package/dist/lib/audio-fifo.js.map +1 -0
- package/dist/lib/binding.d.ts +192 -0
- package/dist/lib/binding.js +70 -0
- package/dist/lib/binding.js.map +1 -0
- package/dist/lib/bitstream-filter-context.d.ts +345 -0
- package/dist/lib/bitstream-filter-context.js +407 -0
- package/dist/lib/bitstream-filter-context.js.map +1 -0
- package/dist/lib/bitstream-filter.d.ts +124 -0
- package/dist/lib/bitstream-filter.js +138 -0
- package/dist/lib/bitstream-filter.js.map +1 -0
- package/dist/lib/channel-layouts.d.ts +51 -0
- package/dist/lib/channel-layouts.js +55 -0
- package/dist/lib/channel-layouts.js.map +1 -0
- package/dist/lib/codec-context.d.ts +763 -0
- package/dist/lib/codec-context.js +974 -0
- package/dist/lib/codec-context.js.map +1 -0
- package/dist/lib/codec-parameters.d.ts +362 -0
- package/dist/lib/codec-parameters.js +460 -0
- package/dist/lib/codec-parameters.js.map +1 -0
- package/dist/lib/codec-parser.d.ts +185 -0
- package/dist/lib/codec-parser.js +193 -0
- package/dist/lib/codec-parser.js.map +1 -0
- package/dist/lib/codec.d.ts +432 -0
- package/dist/lib/codec.js +492 -0
- package/dist/lib/codec.js.map +1 -0
- package/dist/lib/constants.d.ts +2037 -0
- package/dist/lib/constants.js +1659 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/dictionary.d.ts +371 -0
- package/dist/lib/dictionary.js +406 -0
- package/dist/lib/dictionary.js.map +1 -0
- package/dist/lib/error.d.ts +216 -0
- package/dist/lib/error.js +254 -0
- package/dist/lib/error.js.map +1 -0
- package/dist/lib/filter-context.d.ts +445 -0
- package/dist/lib/filter-context.js +505 -0
- package/dist/lib/filter-context.js.map +1 -0
- package/dist/lib/filter-graph.d.ts +556 -0
- package/dist/lib/filter-graph.js +608 -0
- package/dist/lib/filter-graph.js.map +1 -0
- package/dist/lib/filter-inout.d.ts +205 -0
- package/dist/lib/filter-inout.js +264 -0
- package/dist/lib/filter-inout.js.map +1 -0
- package/dist/lib/filter.d.ts +231 -0
- package/dist/lib/filter.js +260 -0
- package/dist/lib/filter.js.map +1 -0
- package/dist/lib/format-context.d.ts +798 -0
- package/dist/lib/format-context.js +845 -0
- package/dist/lib/format-context.js.map +1 -0
- package/dist/lib/frame.d.ts +784 -0
- package/dist/lib/frame.js +933 -0
- package/dist/lib/frame.js.map +1 -0
- package/dist/lib/hardware-device-context.d.ts +407 -0
- package/dist/lib/hardware-device-context.js +429 -0
- package/dist/lib/hardware-device-context.js.map +1 -0
- package/dist/lib/hardware-frames-context.d.ts +374 -0
- package/dist/lib/hardware-frames-context.js +430 -0
- package/dist/lib/hardware-frames-context.js.map +1 -0
- package/dist/lib/index.d.ts +31 -0
- package/dist/lib/index.js +54 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/input-format.d.ts +216 -0
- package/dist/lib/input-format.js +246 -0
- package/dist/lib/input-format.js.map +1 -0
- package/dist/lib/io-context.d.ts +495 -0
- package/dist/lib/io-context.js +550 -0
- package/dist/lib/io-context.js.map +1 -0
- package/dist/lib/log.d.ts +201 -0
- package/dist/lib/log.js +219 -0
- package/dist/lib/log.js.map +1 -0
- package/dist/lib/native-types.d.ts +719 -0
- package/dist/lib/native-types.js +2 -0
- package/dist/lib/native-types.js.map +1 -0
- package/dist/lib/option.d.ts +589 -0
- package/dist/lib/option.js +853 -0
- package/dist/lib/option.js.map +1 -0
- package/dist/lib/output-format.d.ts +179 -0
- package/dist/lib/output-format.js +205 -0
- package/dist/lib/output-format.js.map +1 -0
- package/dist/lib/packet.d.ts +487 -0
- package/dist/lib/packet.js +558 -0
- package/dist/lib/packet.js.map +1 -0
- package/dist/lib/rational.d.ts +210 -0
- package/dist/lib/rational.js +233 -0
- package/dist/lib/rational.js.map +1 -0
- package/dist/lib/software-resample-context.d.ts +572 -0
- package/dist/lib/software-resample-context.js +610 -0
- package/dist/lib/software-resample-context.js.map +1 -0
- package/dist/lib/software-scale-context.d.ts +290 -0
- package/dist/lib/software-scale-context.js +308 -0
- package/dist/lib/software-scale-context.js.map +1 -0
- package/dist/lib/stream.d.ts +322 -0
- package/dist/lib/stream.js +408 -0
- package/dist/lib/stream.js.map +1 -0
- package/dist/lib/types.d.ts +59 -0
- package/dist/lib/types.js +8 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/utilities.d.ts +346 -0
- package/dist/lib/utilities.js +424 -0
- package/dist/lib/utilities.js.map +1 -0
- package/install/check.js +113 -0
- package/install/ffmpeg.js +163 -0
- package/package.json +107 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
All notable changes to this project will be documented in this file.
|
|
2
|
+
|
|
3
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
4
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
|
+
|
|
6
|
+
## [1.0.0] - 2019-08-06
|
|
7
|
+
|
|
8
|
+
- Initial Release
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2025 seydx <dev@seydx.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
# NodeAV
|
|
2
|
+
|
|
3
|
+
> ⚠️ **Work in Progress**: This project is currently under active development and not yet ready for production use. APIs may change, and some features may be incomplete or unstable.
|
|
4
|
+
|
|
5
|
+
Node.js bindings for FFmpeg libraries, providing both low-level and high-level APIs for audio/video processing. Built from the ground up with TypeScript, NodeAV offers complete type safety and IntelliSense support throughout your media processing workflows. The library seamlessly bridges the gap between FFmpeg's powerful C APIs and modern JavaScript development, enabling developers to leverage the full capabilities of FFmpeg directly within Node.js applications without sacrificing performance or functionality. Whether you need direct control over codecs, formats, and filters through low-level bindings, or prefer the convenience of high-level abstractions with automatic resource management and async/await support, NodeAV provides a unified, type-safe interface for all your audio and video processing needs.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install node-av
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
**For Users**
|
|
16
|
+
- Node.js v20 or higher
|
|
17
|
+
- No FFmpeg installation required - all necessary libraries are bundled
|
|
18
|
+
|
|
19
|
+
**For Development**
|
|
20
|
+
- Node.js v20 or higher
|
|
21
|
+
- FFmpeg 7.1+ development headers
|
|
22
|
+
- TypeScript 5.0+ (for TypeScript development)
|
|
23
|
+
- C++ build tools (for building native bindings)
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### High-Level API
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { MediaInput, MediaOutput, Decoder, Encoder } from 'node-av/api';
|
|
31
|
+
import { AV_PIX_FMT_YUV420P } from 'node-av/constants';
|
|
32
|
+
|
|
33
|
+
// Open media
|
|
34
|
+
const input = await MediaInput.open('input.mp4');
|
|
35
|
+
const output = await MediaOutput.open('output.mp4');
|
|
36
|
+
|
|
37
|
+
// Get video stream
|
|
38
|
+
const videoStream = input.video();
|
|
39
|
+
|
|
40
|
+
// Create decoder/encoder
|
|
41
|
+
const decoder = await Decoder.create(videoStream);
|
|
42
|
+
const encoder = await Encoder.create('libx264', videoStream, {
|
|
43
|
+
bitrate: '2M',
|
|
44
|
+
gopSize: 60
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Add stream to output
|
|
48
|
+
const outputIndex = output.addStream(encoder);
|
|
49
|
+
await output.writeHeader();
|
|
50
|
+
|
|
51
|
+
// Process frames
|
|
52
|
+
for await (const packet of input.packets()) {
|
|
53
|
+
if (packet.streamIndex === videoStream.index) {
|
|
54
|
+
const frame = await decoder.decode(packet);
|
|
55
|
+
if (frame) {
|
|
56
|
+
const encoded = await encoder.encode(frame);
|
|
57
|
+
if (encoded) {
|
|
58
|
+
await output.writePacket(encoded, outputIndex);
|
|
59
|
+
encoded.free();
|
|
60
|
+
}
|
|
61
|
+
frame.free();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
packet.free();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Cleanup
|
|
68
|
+
await output.writeTrailer();
|
|
69
|
+
await output.close();
|
|
70
|
+
await input.close();
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Pipeline API
|
|
74
|
+
|
|
75
|
+
The Pipeline API provides streamlined media processing with automatic flow control. It supports two modes:
|
|
76
|
+
|
|
77
|
+
#### Simple Pipeline (single stream)
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { pipeline, MediaInput, MediaOutput, Decoder, Encoder, FilterAPI } from 'node-av/api';
|
|
81
|
+
|
|
82
|
+
// Full transcode pipeline: input → decoder → encoder → output
|
|
83
|
+
const input = await MediaInput.open('input.mp4');
|
|
84
|
+
const output = await MediaOutput.open('output.mp4');
|
|
85
|
+
const decoder = await Decoder.create(input.video());
|
|
86
|
+
const encoder = await Encoder.create('libx264', {
|
|
87
|
+
type: 'video',
|
|
88
|
+
width: 1920,
|
|
89
|
+
height: 1080,
|
|
90
|
+
pixelFormat: AV_PIX_FMT_YUV420P,
|
|
91
|
+
timeBase: { num: 1, den: 30 }
|
|
92
|
+
}, {
|
|
93
|
+
bitrate: '2M'
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const control = pipeline(input, decoder, encoder, output);
|
|
97
|
+
await control.completion;
|
|
98
|
+
|
|
99
|
+
// With filter: input → decoder → filter → encoder → output
|
|
100
|
+
const filter = await FilterAPI.create('scale=1280:720', input.video());
|
|
101
|
+
const control2 = pipeline(input, decoder, filter, encoder, output);
|
|
102
|
+
await control2.completion;
|
|
103
|
+
|
|
104
|
+
// Stream copy (no re-encoding): input → output
|
|
105
|
+
const control3 = pipeline(input, output);
|
|
106
|
+
await control3.completion;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
#### Named Pipeline (multiple streams)
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// Process multiple streams with named routing
|
|
113
|
+
const control = pipeline(
|
|
114
|
+
{ video: videoInput, audio: audioInput },
|
|
115
|
+
{
|
|
116
|
+
video: [videoDecoder, videoFilter, videoEncoder],
|
|
117
|
+
audio: [audioDecoder, audioFilter, audioEncoder]
|
|
118
|
+
},
|
|
119
|
+
{ video: videoOutput, audio: audioOutput }
|
|
120
|
+
);
|
|
121
|
+
await control.completion;
|
|
122
|
+
|
|
123
|
+
// With single output (muxing)
|
|
124
|
+
const control2 = pipeline(
|
|
125
|
+
{ video: videoInput, audio: audioInput },
|
|
126
|
+
{
|
|
127
|
+
video: [videoDecoder, videoEncoder],
|
|
128
|
+
audio: 'passthrough' // Stream copy
|
|
129
|
+
},
|
|
130
|
+
output
|
|
131
|
+
);
|
|
132
|
+
await control2.completion;
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### Partial Pipeline (returns generator)
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// Pipeline without output returns async generator
|
|
139
|
+
const frames = pipeline(input, decoder);
|
|
140
|
+
for await (const frame of frames) {
|
|
141
|
+
// Process frames
|
|
142
|
+
frame.free();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// With filter
|
|
146
|
+
const filteredFrames = pipeline(input, decoder, filter);
|
|
147
|
+
for await (const frame of filteredFrames) {
|
|
148
|
+
// Process filtered frames
|
|
149
|
+
frame.free();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Named partial pipeline
|
|
153
|
+
const generators = pipeline(
|
|
154
|
+
{ video: videoInput, audio: audioInput },
|
|
155
|
+
{
|
|
156
|
+
video: [videoDecoder, videoFilter],
|
|
157
|
+
audio: [audioDecoder]
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
// generators.video and generators.audio are async generators
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Hardware Acceleration
|
|
164
|
+
|
|
165
|
+
The library supports all hardware acceleration methods available in FFmpeg. The specific hardware types available depend on your FFmpeg build and system configuration.
|
|
166
|
+
|
|
167
|
+
### Auto-Detection
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { HardwareContext } from 'node-av/api';
|
|
171
|
+
|
|
172
|
+
// Automatically detect best available hardware
|
|
173
|
+
const hw = await HardwareContext.auto();
|
|
174
|
+
if (hw) {
|
|
175
|
+
console.log(`Using hardware: ${hw.deviceTypeName}`);
|
|
176
|
+
|
|
177
|
+
// Use with decoder
|
|
178
|
+
const decoder = await Decoder.create(stream, {
|
|
179
|
+
hardware: hw
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Use with encoder (use hardware-specific codec)
|
|
183
|
+
const encoder = await Encoder.create('h264_videotoolbox', videoStream, {
|
|
184
|
+
hardware: hw
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Specific Hardware
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import { AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_VAAPI } from 'node-av/constants';
|
|
193
|
+
|
|
194
|
+
// Use specific hardware type
|
|
195
|
+
const cuda = await HardwareContext.create(AV_HWDEVICE_TYPE_CUDA);
|
|
196
|
+
const vaapi = await HardwareContext.create(AV_HWDEVICE_TYPE_VAAPI, '/dev/dri/renderD128');
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Imports and Tree Shaking
|
|
200
|
+
|
|
201
|
+
The library provides multiple entry points for optimal tree shaking:
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
// High-Level API only - Recommended for most use cases
|
|
205
|
+
import { MediaInput, MediaOutput, Decoder, Encoder } from 'node-av/api';
|
|
206
|
+
|
|
207
|
+
// Low-Level API only - Direct FFmpeg bindings
|
|
208
|
+
import { FormatContext, CodecContext, Frame, Packet } from 'node-av/lib';
|
|
209
|
+
|
|
210
|
+
// Constants only - When you just need FFmpeg constants
|
|
211
|
+
import { AV_PIX_FMT_YUV420P, AV_CODEC_ID_H264 } from 'node-av/constants';
|
|
212
|
+
|
|
213
|
+
// Channel layouts only - For audio channel configurations
|
|
214
|
+
import { AV_CHANNEL_LAYOUT_STEREO, AV_CHANNEL_LAYOUT_5POINT1 } from 'node-av/layouts';
|
|
215
|
+
|
|
216
|
+
// Default export - Includes everything
|
|
217
|
+
import * as ffmpeg from 'node-av';
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Stream Processing
|
|
221
|
+
|
|
222
|
+
### From Files
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const media = await MediaInput.open('input.mp4');
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### From Network
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const media = await MediaInput.open('rtsp://example.com/stream');
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### From Buffers
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { readFile } from 'fs/promises';
|
|
238
|
+
|
|
239
|
+
const buffer = await readFile('input.mp4');
|
|
240
|
+
const media = await MediaInput.open(buffer);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Raw Media Processing
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
// Raw video input
|
|
247
|
+
const rawVideo = await MediaInput.open({
|
|
248
|
+
type: 'video',
|
|
249
|
+
input: 'input.yuv',
|
|
250
|
+
width: 1280,
|
|
251
|
+
height: 720,
|
|
252
|
+
pixelFormat: AV_PIX_FMT_YUV420P,
|
|
253
|
+
frameRate: { num: 30, den: 1 }
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Raw audio input
|
|
257
|
+
const rawAudio = await MediaInput.open({
|
|
258
|
+
type: 'audio',
|
|
259
|
+
input: 'input.pcm',
|
|
260
|
+
sampleRate: 48000,
|
|
261
|
+
channels: 2,
|
|
262
|
+
sampleFormat: AV_SAMPLE_FMT_S16
|
|
263
|
+
}, {
|
|
264
|
+
format: 's16le'
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Error Handling
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { FFmpegError } from 'node-av';
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
const media = await MediaInput.open('input.mp4');
|
|
275
|
+
} catch (error) {
|
|
276
|
+
if (error instanceof FFmpegError) {
|
|
277
|
+
console.error(`FFmpeg error ${error.code}: ${error.message}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Resource Management
|
|
283
|
+
|
|
284
|
+
The library supports automatic resource cleanup using the Disposable pattern:
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// Automatic cleanup with 'using'
|
|
288
|
+
{
|
|
289
|
+
await using media = await MediaInput.open('input.mp4');
|
|
290
|
+
using decoder = await Decoder.create(media.video());
|
|
291
|
+
// Resources automatically cleaned up at end of scope
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Manual cleanup
|
|
295
|
+
const media = await MediaInput.open('input.mp4');
|
|
296
|
+
try {
|
|
297
|
+
// Process media
|
|
298
|
+
} finally {
|
|
299
|
+
await media.close();
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Performance
|
|
304
|
+
|
|
305
|
+
NodeAV executes all computationally intensive operations directly through FFmpeg's native C libraries, ensuring performance characteristics virtually identical to FFmpeg's command-line tools. The Node.js bindings introduce minimal overhead, primarily affecting only the JavaScript-to-C boundary crossings. When performing typical media operations like transcoding, muxing, or filtering, the vast majority of processing time is spent within FFmpeg's optimized C code paths. This means you get the same hardware acceleration support, SIMD optimizations, and multi-threading capabilities that make FFmpeg the industry standard for media processing. The thin binding layer ensures that whether you're processing 4K video streams or handling real-time audio, the performance bottleneck remains where it should be - in the actual media processing algorithms, not in the language bindings.
|
|
306
|
+
|
|
307
|
+
## Memory Safety Considerations
|
|
308
|
+
|
|
309
|
+
NodeAV provides direct bindings to FFmpeg's low-level C APIs, which inherently operate with raw memory pointers and minimal safety checks. While the high-level API adds protective abstractions and automatic resource management, incorrect usage can still lead to crashes. For instance, mismatched video dimensions, incompatible pixel formats, or improper frame buffer handling may cause segmentation faults. The library implements safety measures where feasible, including type checking, parameter validation, and resource tracking, but achieving complete memory safety while maintaining FFmpeg's full power and performance would require compromising functionality. Users working with the low-level API should be particularly mindful of parameter consistency, proper resource cleanup, and format compatibility. When used correctly with validated parameters and following the documented patterns, NodeAV provides stable and reliable media processing without memory-related issues.
|
|
310
|
+
|
|
311
|
+
## Examples
|
|
312
|
+
|
|
313
|
+
| Example | FFmpeg | Low-Level API | High-Level API |
|
|
314
|
+
|---------|--------|---------------|----------------|
|
|
315
|
+
| `api-encode-decode` | | | [✓](examples/api-encode-decode.ts) |
|
|
316
|
+
| `api-frame-extract` | | | [✓](examples/api-frame-extract.ts) |
|
|
317
|
+
| `api-hw-decode-sw-encode` | | | [✓](examples/api-hw-decode-sw-encode.ts) |
|
|
318
|
+
| `api-hw-raw` | | | [✓](examples/api-hw-raw.ts) |
|
|
319
|
+
| `api-hw-rtsp-custom-io` | | | [✓](examples/api-hw-rtsp-custom-io.ts) |
|
|
320
|
+
| `api-hw-rtsp` | | | [✓](examples/api-hw-rtsp.ts) |
|
|
321
|
+
| `api-hw-transcode` | | | [✓](examples/api-hw-transcode.ts) |
|
|
322
|
+
| `api-muxing` | | | [✓](examples/api-muxing.ts) |
|
|
323
|
+
| `api-pipeline-hw-rtsp` | | | [✓](examples/api-pipeline-hw-rtsp.ts) |
|
|
324
|
+
| `api-pipeline-raw-muxing` | | | [✓](examples/api-pipeline-raw-muxing.ts) |
|
|
325
|
+
| `api-stream-input` | | | [✓](examples/api-stream-input.ts) |
|
|
326
|
+
| `api-sw-decode-hw-encode` | | | [✓](examples/api-sw-decode-hw-encode.ts) |
|
|
327
|
+
| `api-sw-transcode` | | | [✓](examples/api-sw-transcode.ts) |
|
|
328
|
+
| `avio-read-callback` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/avio_read_callback.c) | [✓](examples/avio-read-callback.ts) | |
|
|
329
|
+
| `decode-audio` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/decode_audio.c) | [✓](examples/decode-audio.ts) | |
|
|
330
|
+
| `decode-filter-audio` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/decode_filter_audio.c) | [✓](examples/decode-filter-audio.ts) | |
|
|
331
|
+
| `decode-filter-video` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/decode_filter_video.c) | [✓](examples/decode-filter-video.ts) | |
|
|
332
|
+
| `decode-video` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/decode_video.c) | [✓](examples/decode-video.ts) | |
|
|
333
|
+
| `demux-decode` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/demux_decode.c) | [✓](examples/demux-decode.ts) | |
|
|
334
|
+
| `encode-audio` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/encode_audio.c) | [✓](examples/encode-audio.ts) | |
|
|
335
|
+
| `encode-video` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/encode_video.c) | [✓](examples/encode-video.ts) | |
|
|
336
|
+
| `filter-audio` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/filter_audio.c) | [✓](examples/filter-audio.ts) | |
|
|
337
|
+
| `hw-decode` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/hw_decode.c) | [✓](examples/hw-decode.ts) | |
|
|
338
|
+
| `hw-encode` | | [✓](examples/hw-encode.ts) | |
|
|
339
|
+
| `hw-transcode` | | [✓](examples/hw-transcode.ts) | |
|
|
340
|
+
| `qsv-decode` | [✓](https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/qsv_decode.c) | | |
|
|
341
|
+
| `qsv-transcode` | [✓](https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/qsv_transcode.c) | | |
|
|
342
|
+
| `vaapi-encode` | [✓](https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/vaapi_encode.c) | | |
|
|
343
|
+
| `vaapi-transcode` | [✓](https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/vaapi_transcode.c) | | |
|
|
344
|
+
| `mux` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/mux.c) | [✓](examples/mux.ts) | |
|
|
345
|
+
| `remux` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/remux.c) | [✓](examples/remux.ts) | |
|
|
346
|
+
| `resample-audio` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/resample_audio.c) | [✓](examples/resample-audio.ts) | |
|
|
347
|
+
| `scale-video` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/scale_video.c) | [✓](examples/scale-video.ts) | |
|
|
348
|
+
| `show-metadata` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/show_metadata.c) | [✓](examples/show-metadata.ts) | |
|
|
349
|
+
| `transcode-aac` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/transcode_aac.c) | [✓](examples/transcode-aac.ts) | |
|
|
350
|
+
| `transcode` | [✓](https://github.com/FFmpeg/FFmpeg/tree/master/doc/examples/transcode.c) | [✓](examples/transcode.ts) | |
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
## Prebuilt Binaries
|
|
354
|
+
|
|
355
|
+
Prebuilt binaries are available for macOS, Linux, and Windows (x64/arm64). The package will automatically build from source if needed.
|
|
356
|
+
|
|
357
|
+
For detailed installation instructions, build requirements, and troubleshooting, see the **[Installation Guide](INSTALLATION.md)**.
|
|
358
|
+
|
|
359
|
+
## License
|
|
360
|
+
|
|
361
|
+
This project is licensed under the MIT License. See the LICENSE file for details.
|
|
362
|
+
|
|
363
|
+
**Important**: FFmpeg itself is licensed under LGPL/GPL. Please ensure compliance with FFmpeg's license terms when using this library. The FFmpeg libraries themselves retain their original licenses, and this wrapper library does not change those terms. See [FFmpeg License](https://ffmpeg.org/legal.html) for details.
|
|
364
|
+
|
|
365
|
+
## Contributing
|
|
366
|
+
|
|
367
|
+
Contributions are welcome! Please read [CONTRIBUTION.md](CONTRIBUTION.md) for development setup, code standards, and contribution guidelines before submitting pull requests.
|
|
368
|
+
|
|
369
|
+
## Support
|
|
370
|
+
|
|
371
|
+
For issues and questions, please use the GitHub issue tracker.
|
|
372
|
+
|
|
373
|
+
## See Also
|
|
374
|
+
|
|
375
|
+
- [FFmpeg Documentation](https://ffmpeg.org/documentation.html)
|
|
376
|
+
- [FFmpeg Doxygen](https://ffmpeg.org/doxygen/trunk/)
|
|
377
|
+
- [Jellyfin FFmpeg](https://github.com/jellyfin/jellyfin-ffmpeg)
|
package/binding.gyp
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": [
|
|
3
|
+
{
|
|
4
|
+
"target_name": "node-av",
|
|
5
|
+
"sources": [
|
|
6
|
+
"src/bindings/index.cc",
|
|
7
|
+
"src/bindings/packet.cc",
|
|
8
|
+
"src/bindings/frame.cc",
|
|
9
|
+
"src/bindings/frame_async.cc",
|
|
10
|
+
"src/bindings/codec.cc",
|
|
11
|
+
"src/bindings/codec_context.cc",
|
|
12
|
+
"src/bindings/codec_context_async.cc",
|
|
13
|
+
"src/bindings/codec_parameters.cc",
|
|
14
|
+
"src/bindings/codec_parser.cc",
|
|
15
|
+
"src/bindings/format_context.cc",
|
|
16
|
+
"src/bindings/format_context_async.cc",
|
|
17
|
+
"src/bindings/stream.cc",
|
|
18
|
+
"src/bindings/dictionary.cc",
|
|
19
|
+
"src/bindings/input_format.cc",
|
|
20
|
+
"src/bindings/input_format_async.cc",
|
|
21
|
+
"src/bindings/output_format.cc",
|
|
22
|
+
"src/bindings/io_context.cc",
|
|
23
|
+
"src/bindings/io_context_async.cc",
|
|
24
|
+
"src/bindings/error.cc",
|
|
25
|
+
"src/bindings/software_scale_context.cc",
|
|
26
|
+
"src/bindings/software_scale_context_async.cc",
|
|
27
|
+
"src/bindings/software_resample_context.cc",
|
|
28
|
+
"src/bindings/software_resample_context_async.cc",
|
|
29
|
+
"src/bindings/filter.cc",
|
|
30
|
+
"src/bindings/filter_context.cc",
|
|
31
|
+
"src/bindings/filter_context_async.cc",
|
|
32
|
+
"src/bindings/filter_graph.cc",
|
|
33
|
+
"src/bindings/filter_graph_async.cc",
|
|
34
|
+
"src/bindings/filter_inout.cc",
|
|
35
|
+
"src/bindings/hardware_device_context.cc",
|
|
36
|
+
"src/bindings/hardware_frames_context.cc",
|
|
37
|
+
"src/bindings/hardware_frames_context_async.cc",
|
|
38
|
+
"src/bindings/log.cc",
|
|
39
|
+
"src/bindings/utilities.cc",
|
|
40
|
+
"src/bindings/audio_fifo.cc",
|
|
41
|
+
"src/bindings/audio_fifo_async.cc",
|
|
42
|
+
"src/bindings/bitstream_filter.cc",
|
|
43
|
+
"src/bindings/bitstream_filter_context.cc",
|
|
44
|
+
"src/bindings/bitstream_filter_context_async.cc",
|
|
45
|
+
"src/bindings/option.cc"
|
|
46
|
+
],
|
|
47
|
+
"include_dirs": [
|
|
48
|
+
"<!@(node -p \"require('node-addon-api').include\")",
|
|
49
|
+
"<!@(pkg-config --cflags-only-I libavutil libavformat libavfilter | sed s/-I//g)"
|
|
50
|
+
],
|
|
51
|
+
"dependencies": [
|
|
52
|
+
"<!(node -p \"require('node-addon-api').gyp\")"
|
|
53
|
+
],
|
|
54
|
+
"libraries": [
|
|
55
|
+
"<!@(pkg-config --libs libavutil libavcodec libavformat libavfilter libswscale libswresample)"
|
|
56
|
+
],
|
|
57
|
+
"cflags!": [
|
|
58
|
+
"-fno-exceptions"
|
|
59
|
+
],
|
|
60
|
+
"cflags_cc!": [
|
|
61
|
+
"-fno-exceptions"
|
|
62
|
+
],
|
|
63
|
+
"xcode_settings": {
|
|
64
|
+
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
|
|
65
|
+
"CLANG_CXX_LIBRARY": "libc++",
|
|
66
|
+
"MACOSX_DEPLOYMENT_TARGET": "10.15"
|
|
67
|
+
},
|
|
68
|
+
"msvs_settings": {
|
|
69
|
+
"VCCLCompilerTool": {
|
|
70
|
+
"ExceptionHandling": 1
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"defines": [
|
|
74
|
+
"NAPI_DISABLE_CPP_EXCEPTIONS"
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|