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
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
import { isRtcp, RtpPacket } from 'werift';
|
|
2
|
+
import { AV_HWDEVICE_TYPE_NONE } from '../constants/constants.js';
|
|
3
|
+
import { FF_ENCODER_LIBOPUS, FF_ENCODER_LIBX264, FF_ENCODER_LIBX265 } from '../constants/encoders.js';
|
|
4
|
+
import { Codec } from '../lib/codec.js';
|
|
5
|
+
import { MAX_PACKET_SIZE } from './constants.js';
|
|
6
|
+
import { Decoder } from './decoder.js';
|
|
7
|
+
import { Demuxer } from './demuxer.js';
|
|
8
|
+
import { Encoder } from './encoder.js';
|
|
9
|
+
import { FilterPreset } from './filter-presets.js';
|
|
10
|
+
import { FilterAPI } from './filter.js';
|
|
11
|
+
import { HardwareContext } from './hardware.js';
|
|
12
|
+
import { Muxer } from './muxer.js';
|
|
13
|
+
import { pipeline } from './pipeline.js';
|
|
14
|
+
/**
|
|
15
|
+
* Generic RTP streaming with automatic codec detection and transcoding.
|
|
16
|
+
*
|
|
17
|
+
* Provides library-agnostic RTP streaming for various applications.
|
|
18
|
+
* Automatically detects input codecs and transcodes non-compatible formats.
|
|
19
|
+
* Supports hardware acceleration for video transcoding.
|
|
20
|
+
* Essential component for building RTP streaming servers.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { RTPStream } from 'node-av/api';
|
|
25
|
+
*
|
|
26
|
+
* // Create stream with RTP packet callbacks
|
|
27
|
+
* const stream = RTPStream.create('rtsp://camera.local/stream', {
|
|
28
|
+
* mtu: 1200,
|
|
29
|
+
* hardware: 'auto',
|
|
30
|
+
* onVideoPacket: (rtp) => {
|
|
31
|
+
* // Send RTP packet
|
|
32
|
+
* sendRtpPacket(rtp);
|
|
33
|
+
* },
|
|
34
|
+
* onAudioPacket: (rtp) => {
|
|
35
|
+
* sendRtpPacket(rtp);
|
|
36
|
+
* }
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // Start streaming
|
|
40
|
+
* await stream.start();
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @see {@link Demuxer} For input media handling
|
|
44
|
+
* @see {@link HardwareContext} For GPU acceleration
|
|
45
|
+
*/
|
|
46
|
+
export class RTPStream {
|
|
47
|
+
options;
|
|
48
|
+
inputUrl;
|
|
49
|
+
inputOptions;
|
|
50
|
+
input;
|
|
51
|
+
videoOutput;
|
|
52
|
+
audioOutput;
|
|
53
|
+
hardwareContext;
|
|
54
|
+
videoDecoder;
|
|
55
|
+
videoEncoder;
|
|
56
|
+
audioDecoder;
|
|
57
|
+
audioFilter;
|
|
58
|
+
audioEncoder;
|
|
59
|
+
pipeline;
|
|
60
|
+
supportedVideoCodecs;
|
|
61
|
+
supportedAudioCodecs;
|
|
62
|
+
/**
|
|
63
|
+
* @param inputUrl - Media input URL
|
|
64
|
+
*
|
|
65
|
+
* @param options - Stream configuration options
|
|
66
|
+
*
|
|
67
|
+
* Use {@link create} factory method
|
|
68
|
+
*
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
constructor(inputUrl, options) {
|
|
72
|
+
this.inputUrl = inputUrl;
|
|
73
|
+
this.inputOptions = {
|
|
74
|
+
...options.inputOptions,
|
|
75
|
+
options: {
|
|
76
|
+
flags: 'low_delay',
|
|
77
|
+
fflags: 'nobuffer',
|
|
78
|
+
analyzeduration: 0,
|
|
79
|
+
probesize: 32,
|
|
80
|
+
timeout: 5000000,
|
|
81
|
+
rtsp_transport: inputUrl.toLowerCase().startsWith('rtsp') ? 'tcp' : undefined,
|
|
82
|
+
...options.inputOptions?.options,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
options.supportedVideoCodecs = options.supportedVideoCodecs?.filter(Boolean);
|
|
86
|
+
options.supportedAudioCodecs = options.supportedAudioCodecs?.filter(Boolean);
|
|
87
|
+
// If no supported codecs specified, empty set means ALL codecs are supported (passthrough only)
|
|
88
|
+
this.supportedVideoCodecs = new Set(options.supportedVideoCodecs && options.supportedVideoCodecs.length > 0 ? options.supportedVideoCodecs : []);
|
|
89
|
+
this.supportedAudioCodecs = new Set(options.supportedAudioCodecs && options.supportedAudioCodecs.length > 0 ? options.supportedAudioCodecs : []);
|
|
90
|
+
this.options = {
|
|
91
|
+
onVideoPacket: options.onVideoPacket ?? (() => { }),
|
|
92
|
+
onAudioPacket: options.onAudioPacket ?? (() => { }),
|
|
93
|
+
onClose: options.onClose ?? (() => { }),
|
|
94
|
+
supportedVideoCodecs: Array.from(this.supportedVideoCodecs),
|
|
95
|
+
supportedAudioCodecs: Array.from(this.supportedAudioCodecs),
|
|
96
|
+
hardware: options.hardware ?? { deviceType: AV_HWDEVICE_TYPE_NONE },
|
|
97
|
+
inputOptions: options.inputOptions,
|
|
98
|
+
video: {
|
|
99
|
+
ssrc: options.video?.ssrc,
|
|
100
|
+
payloadType: options.video?.payloadType,
|
|
101
|
+
mtu: options.video?.mtu ?? MAX_PACKET_SIZE,
|
|
102
|
+
fps: options.video?.fps ?? 20,
|
|
103
|
+
encoderOptions: options.video?.encoderOptions ?? {},
|
|
104
|
+
},
|
|
105
|
+
audio: {
|
|
106
|
+
ssrc: options.audio?.ssrc,
|
|
107
|
+
payloadType: options.audio?.payloadType,
|
|
108
|
+
mtu: options.audio?.mtu ?? MAX_PACKET_SIZE,
|
|
109
|
+
sampleRate: options.audio?.sampleRate,
|
|
110
|
+
channels: options.audio?.channels,
|
|
111
|
+
encoderOptions: options.audio?.encoderOptions,
|
|
112
|
+
sampleFormat: options.audio?.sampleFormat,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Create an RTP stream from a media source.
|
|
118
|
+
*
|
|
119
|
+
* Configures the stream with input URL and options. The input is not opened
|
|
120
|
+
* until start() is called, allowing the stream to be reused after stop().
|
|
121
|
+
*
|
|
122
|
+
* @param inputUrl - Media source URL (RTSP, file path, HTTP, etc.)
|
|
123
|
+
*
|
|
124
|
+
* @param options - Stream configuration options
|
|
125
|
+
*
|
|
126
|
+
* @returns Configured RTP stream instance
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```typescript
|
|
130
|
+
* // Stream from RTSP camera
|
|
131
|
+
* const stream = RTPStream.create('rtsp://camera.local/stream', {
|
|
132
|
+
* mtu: 1200,
|
|
133
|
+
* onVideoPacket: (rtp) => sendPacket(rtp),
|
|
134
|
+
* onAudioPacket: (rtp) => sendPacket(rtp)
|
|
135
|
+
* });
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* // Stream file with auto hardware acceleration
|
|
141
|
+
* const stream = RTPStream.create('video.mp4', {
|
|
142
|
+
* hardware: 'auto'
|
|
143
|
+
* });
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
static create(inputUrl, options = {}) {
|
|
147
|
+
return new RTPStream(inputUrl, options);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Check if the stream is active.
|
|
151
|
+
*
|
|
152
|
+
* @returns True if the stream is active, false otherwise
|
|
153
|
+
*/
|
|
154
|
+
get isStreamActive() {
|
|
155
|
+
return this.pipeline !== undefined && !this.pipeline.isStopped();
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get the demuxer instance.
|
|
159
|
+
*
|
|
160
|
+
* Used for accessing the underlying demuxer.
|
|
161
|
+
* Only available after start() is called.
|
|
162
|
+
*
|
|
163
|
+
* @returns Demuxer instance or undefined if not started
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* const stream = RTPStream.create('input.mp4', {
|
|
168
|
+
* onVideoPacket: (rtp) => sendRtp(rtp)
|
|
169
|
+
* });
|
|
170
|
+
* await stream.start();
|
|
171
|
+
* const input = stream.getInput();
|
|
172
|
+
* console.log('Bitrate:', input?.bitRate);
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
getInput() {
|
|
176
|
+
return this.input;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Start streaming media to RTP packets.
|
|
180
|
+
*
|
|
181
|
+
* Begins the media processing pipeline, reading packets from input,
|
|
182
|
+
* transcoding if necessary, and invoking RTP packet callbacks.
|
|
183
|
+
* Automatically handles video and audio streams in parallel.
|
|
184
|
+
* This method returns immediately after starting the pipeline.
|
|
185
|
+
*
|
|
186
|
+
* @returns Promise that resolves when pipeline is started
|
|
187
|
+
*
|
|
188
|
+
* @throws {Error} If no video stream found in input
|
|
189
|
+
*
|
|
190
|
+
* @throws {FFmpegError} If setup fails
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const stream = RTPStream.create('rtsp://camera.local/stream', {
|
|
195
|
+
* onVideoPacket: (rtp) => sendRtp(rtp)
|
|
196
|
+
* });
|
|
197
|
+
*
|
|
198
|
+
* // Start streaming (returns immediately)
|
|
199
|
+
* await stream.start();
|
|
200
|
+
*
|
|
201
|
+
* // Later: stop streaming
|
|
202
|
+
* await stream.stop();
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
async start() {
|
|
206
|
+
if (this.pipeline) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
this.input ??= await Demuxer.open(this.inputUrl, this.inputOptions);
|
|
210
|
+
const videoStream = this.input.video();
|
|
211
|
+
const audioStream = this.input.audio();
|
|
212
|
+
// Setup video transcoding if needed
|
|
213
|
+
if (videoStream && !this.isVideoCodecSupported(videoStream.codecpar.codecId)) {
|
|
214
|
+
// Check if we need hardware acceleration
|
|
215
|
+
if (this.options.hardware === 'auto') {
|
|
216
|
+
this.hardwareContext = HardwareContext.auto();
|
|
217
|
+
}
|
|
218
|
+
else if (this.options.hardware.deviceType !== AV_HWDEVICE_TYPE_NONE) {
|
|
219
|
+
this.hardwareContext = HardwareContext.create(this.options.hardware.deviceType, this.options.hardware.device, this.options.hardware.options);
|
|
220
|
+
}
|
|
221
|
+
this.videoDecoder = await Decoder.create(videoStream, {
|
|
222
|
+
exitOnError: false,
|
|
223
|
+
hardware: this.hardwareContext,
|
|
224
|
+
});
|
|
225
|
+
// Get first supported codec
|
|
226
|
+
const targetCodecId = this.options.supportedVideoCodecs[0];
|
|
227
|
+
if (!targetCodecId) {
|
|
228
|
+
throw new Error('No supported video codec specified for transcoding');
|
|
229
|
+
}
|
|
230
|
+
let encoderCodec = null;
|
|
231
|
+
if (typeof targetCodecId === 'string') {
|
|
232
|
+
encoderCodec = Codec.findEncoderByName(targetCodecId);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
encoderCodec = this.hardwareContext?.getEncoderCodec(targetCodecId) ?? Codec.findEncoder(targetCodecId);
|
|
236
|
+
}
|
|
237
|
+
if (!encoderCodec) {
|
|
238
|
+
throw new Error(`No encoder found for codec ID ${targetCodecId}`);
|
|
239
|
+
}
|
|
240
|
+
let encoderOptions = {};
|
|
241
|
+
if (encoderCodec.name === FF_ENCODER_LIBX264 || encoderCodec.name === FF_ENCODER_LIBX265) {
|
|
242
|
+
encoderOptions.preset = 'ultrafast';
|
|
243
|
+
encoderOptions.tune = 'zerolatency';
|
|
244
|
+
}
|
|
245
|
+
encoderOptions = {
|
|
246
|
+
...encoderOptions,
|
|
247
|
+
...this.options.video.encoderOptions,
|
|
248
|
+
};
|
|
249
|
+
this.videoEncoder = await Encoder.create(encoderCodec, {
|
|
250
|
+
decoder: this.videoDecoder,
|
|
251
|
+
maxBFrames: 0,
|
|
252
|
+
options: encoderOptions,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
// Initialize RTP sequence numbers and timestamps
|
|
256
|
+
let videoSequenceNumber = Math.floor(Math.random() * 0xffff);
|
|
257
|
+
let videoTimestamp = Math.floor(Math.random() * 0xffffffff) >>> 0; // unsigned 32-bit
|
|
258
|
+
let audioSequenceNumber = Math.floor(Math.random() * 0xffff);
|
|
259
|
+
// Calculate video timestamp increment
|
|
260
|
+
const videoStreamFps = videoStream ? videoStream.avgFrameRate.num / videoStream.avgFrameRate.den : 20;
|
|
261
|
+
let fps = this.options.video.fps ?? videoStreamFps;
|
|
262
|
+
if (!isFinite(fps) || fps <= 0 || isNaN(fps)) {
|
|
263
|
+
fps = 20; // Default to 20 FPS if invalid
|
|
264
|
+
}
|
|
265
|
+
const videoTimestampIncrement = 90000 / fps;
|
|
266
|
+
// Setup video output
|
|
267
|
+
this.videoOutput = await Muxer.open({
|
|
268
|
+
write: (buffer) => {
|
|
269
|
+
if (isRtcp(buffer)) {
|
|
270
|
+
// Ignore RTCP packets
|
|
271
|
+
return buffer.length;
|
|
272
|
+
}
|
|
273
|
+
const rtpPacket = RtpPacket.deSerialize(buffer);
|
|
274
|
+
// Set SSRC (synchronization source identifier)
|
|
275
|
+
if (this.options.video.ssrc !== undefined) {
|
|
276
|
+
rtpPacket.header.ssrc = this.options.video.ssrc;
|
|
277
|
+
}
|
|
278
|
+
// Set payload type
|
|
279
|
+
if (this.options.video.payloadType !== undefined) {
|
|
280
|
+
rtpPacket.header.payloadType = this.options.video.payloadType;
|
|
281
|
+
}
|
|
282
|
+
// Fix sequence number - ensure continuous sequence
|
|
283
|
+
rtpPacket.header.sequenceNumber = videoSequenceNumber;
|
|
284
|
+
videoSequenceNumber = (videoSequenceNumber + 1) & 0xffff; // Wrap at 16-bit
|
|
285
|
+
// Fix timestamp - calculate based on FPS
|
|
286
|
+
// All packets in same frame have same timestamp (marker=false)
|
|
287
|
+
// Only increment timestamp when frame ends (marker=true)
|
|
288
|
+
rtpPacket.header.timestamp = videoTimestamp;
|
|
289
|
+
// Increment timestamp for next frame when current frame ends
|
|
290
|
+
if (rtpPacket.header.marker) {
|
|
291
|
+
videoTimestamp = (videoTimestamp + videoTimestampIncrement) >>> 0; // Unsigned 32-bit wrap
|
|
292
|
+
}
|
|
293
|
+
this.options.onVideoPacket(rtpPacket);
|
|
294
|
+
return buffer.length;
|
|
295
|
+
},
|
|
296
|
+
}, {
|
|
297
|
+
input: this.input,
|
|
298
|
+
copyInitialNonkeyframes: true,
|
|
299
|
+
format: 'rtp',
|
|
300
|
+
maxPacketSize: this.options.video.mtu,
|
|
301
|
+
options: {
|
|
302
|
+
pkt_size: this.options.video.mtu,
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
// Setup audio if available and needs transcoding
|
|
306
|
+
if (audioStream && !this.isAudioCodecSupported(audioStream.codecpar.codecId)) {
|
|
307
|
+
this.audioDecoder = await Decoder.create(audioStream, {
|
|
308
|
+
exitOnError: false,
|
|
309
|
+
});
|
|
310
|
+
// Get first supported audio codec
|
|
311
|
+
const targetCodecId = this.options.supportedAudioCodecs[0];
|
|
312
|
+
if (!targetCodecId) {
|
|
313
|
+
throw new Error('No supported audio codec specified for transcoding');
|
|
314
|
+
}
|
|
315
|
+
let encoderCodec = null;
|
|
316
|
+
if (typeof targetCodecId === 'string') {
|
|
317
|
+
encoderCodec = Codec.findEncoderByName(targetCodecId);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
encoderCodec = Codec.findEncoder(targetCodecId);
|
|
321
|
+
}
|
|
322
|
+
if (!encoderCodec) {
|
|
323
|
+
throw new Error(`No encoder found for codec ID ${targetCodecId}`);
|
|
324
|
+
}
|
|
325
|
+
// Determine target audio parameters from options
|
|
326
|
+
const desiredSampleFormat = this.options.audio?.sampleFormat ?? audioStream.codecpar.format;
|
|
327
|
+
const desiredSampleRate = this.options.audio?.sampleRate ?? (audioStream.codecpar.sampleRate > 0 ? audioStream.codecpar.sampleRate : 48000);
|
|
328
|
+
const desiredChannels = this.options.audio?.channels ?? (audioStream.codecpar.channels > 0 ? audioStream.codecpar.channels : 2);
|
|
329
|
+
// Select best supported parameters from codec
|
|
330
|
+
const targetSampleFormat = this.selectSampleFormat(encoderCodec, desiredSampleFormat);
|
|
331
|
+
const targetSampleRate = this.selectSampleRate(encoderCodec, desiredSampleRate);
|
|
332
|
+
const channelLayoutStr = this.selectChannelLayout(encoderCodec, desiredChannels);
|
|
333
|
+
// Create audio filter for resampling
|
|
334
|
+
const filterChain = FilterPreset.chain().aformat(targetSampleFormat, targetSampleRate, channelLayoutStr).build();
|
|
335
|
+
// FilterAPI now auto-calculates timeBase from first frame (FFmpeg behavior)
|
|
336
|
+
this.audioFilter = FilterAPI.create(filterChain);
|
|
337
|
+
let encoderOptions = {};
|
|
338
|
+
if (encoderCodec.name === FF_ENCODER_LIBOPUS) {
|
|
339
|
+
encoderOptions.application = 'lowdelay';
|
|
340
|
+
encoderOptions.frame_duration = 20;
|
|
341
|
+
}
|
|
342
|
+
encoderOptions = {
|
|
343
|
+
...encoderOptions,
|
|
344
|
+
...this.options.audio.encoderOptions,
|
|
345
|
+
};
|
|
346
|
+
this.audioEncoder = await Encoder.create(encoderCodec, {
|
|
347
|
+
decoder: this.audioDecoder,
|
|
348
|
+
filter: this.audioFilter,
|
|
349
|
+
options: encoderOptions,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
// Setup audio output if available
|
|
353
|
+
if (audioStream) {
|
|
354
|
+
this.audioOutput = await Muxer.open({
|
|
355
|
+
write: (buffer) => {
|
|
356
|
+
if (isRtcp(buffer)) {
|
|
357
|
+
// Ignore RTCP packets
|
|
358
|
+
return buffer.length;
|
|
359
|
+
}
|
|
360
|
+
const rtpPacket = RtpPacket.deSerialize(buffer);
|
|
361
|
+
// Set SSRC (synchronization source identifier)
|
|
362
|
+
if (this.options.audio.ssrc !== undefined) {
|
|
363
|
+
rtpPacket.header.ssrc = this.options.audio.ssrc;
|
|
364
|
+
}
|
|
365
|
+
// Set payload type
|
|
366
|
+
if (this.options.audio.payloadType !== undefined) {
|
|
367
|
+
rtpPacket.header.payloadType = this.options.audio.payloadType;
|
|
368
|
+
}
|
|
369
|
+
// Fix sequence number - ensure continuous sequence
|
|
370
|
+
rtpPacket.header.sequenceNumber = audioSequenceNumber;
|
|
371
|
+
audioSequenceNumber = (audioSequenceNumber + 1) & 0xffff; // Wrap at 16-bit
|
|
372
|
+
this.options.onAudioPacket(rtpPacket);
|
|
373
|
+
return buffer.length;
|
|
374
|
+
},
|
|
375
|
+
}, {
|
|
376
|
+
input: this.input,
|
|
377
|
+
copyInitialNonkeyframes: true,
|
|
378
|
+
format: 'rtp',
|
|
379
|
+
maxPacketSize: this.options.audio.mtu,
|
|
380
|
+
options: {
|
|
381
|
+
pkt_size: this.options.audio.mtu,
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
// Start pipeline in background (don't await)
|
|
386
|
+
this.runPipeline()
|
|
387
|
+
.then(() => {
|
|
388
|
+
// Pipeline completed successfully
|
|
389
|
+
this.options.onClose?.();
|
|
390
|
+
})
|
|
391
|
+
.catch(async (error) => {
|
|
392
|
+
console.error('[RTPStream] Pipeline error:', error);
|
|
393
|
+
await this.stop();
|
|
394
|
+
this.options.onClose?.(error);
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Run the streaming pipeline until completion or stopped.
|
|
399
|
+
*
|
|
400
|
+
* @internal
|
|
401
|
+
*/
|
|
402
|
+
async runPipeline() {
|
|
403
|
+
if (!this.input) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const hasVideo = this.input.video() !== undefined && this.videoOutput !== undefined;
|
|
407
|
+
const hasAudio = this.input.audio() !== undefined && this.audioOutput !== undefined;
|
|
408
|
+
if (hasAudio && hasVideo) {
|
|
409
|
+
this.pipeline = pipeline(this.input, {
|
|
410
|
+
video: [this.videoDecoder, this.videoEncoder],
|
|
411
|
+
audio: [this.audioDecoder, this.audioFilter, this.audioEncoder],
|
|
412
|
+
}, {
|
|
413
|
+
video: this.videoOutput,
|
|
414
|
+
audio: this.audioOutput,
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
else if (hasVideo) {
|
|
418
|
+
this.pipeline = pipeline(this.input, {
|
|
419
|
+
video: [this.videoDecoder, this.videoEncoder],
|
|
420
|
+
}, this.videoOutput);
|
|
421
|
+
}
|
|
422
|
+
else if (hasAudio) {
|
|
423
|
+
this.pipeline = pipeline(this.input, {
|
|
424
|
+
audio: [this.audioDecoder, this.audioFilter, this.audioEncoder],
|
|
425
|
+
}, this.audioOutput);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
throw new Error('No audio or video streams found in input');
|
|
429
|
+
}
|
|
430
|
+
await this.pipeline.completion;
|
|
431
|
+
this.pipeline = undefined;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Stop streaming gracefully and clean up all resources.
|
|
435
|
+
*
|
|
436
|
+
* Stops the pipeline, closes output, and releases all FFmpeg resources.
|
|
437
|
+
* Safe to call multiple times. After stopping, you can call start() again
|
|
438
|
+
* to restart the stream.
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```typescript
|
|
442
|
+
* const stream = RTPStream.create('input.mp4', {
|
|
443
|
+
* onVideoPacket: (rtp) => sendRtp(rtp)
|
|
444
|
+
* });
|
|
445
|
+
* await stream.start();
|
|
446
|
+
*
|
|
447
|
+
* // Stop after 10 seconds
|
|
448
|
+
* setTimeout(async () => await stream.stop(), 10000);
|
|
449
|
+
* ```
|
|
450
|
+
*/
|
|
451
|
+
async stop() {
|
|
452
|
+
// Stop pipeline if running and wait for completion
|
|
453
|
+
if (this.pipeline && !this.pipeline.isStopped()) {
|
|
454
|
+
this.pipeline.stop();
|
|
455
|
+
await this.pipeline.completion;
|
|
456
|
+
this.pipeline = undefined;
|
|
457
|
+
}
|
|
458
|
+
// Close all resources
|
|
459
|
+
await this.videoOutput?.close();
|
|
460
|
+
this.videoOutput = undefined;
|
|
461
|
+
await this.audioOutput?.close();
|
|
462
|
+
this.audioOutput = undefined;
|
|
463
|
+
this.videoEncoder?.close();
|
|
464
|
+
this.videoEncoder = undefined;
|
|
465
|
+
this.videoDecoder?.close();
|
|
466
|
+
this.videoDecoder = undefined;
|
|
467
|
+
this.audioEncoder?.close();
|
|
468
|
+
this.audioEncoder = undefined;
|
|
469
|
+
this.audioFilter?.close();
|
|
470
|
+
this.audioFilter = undefined;
|
|
471
|
+
this.audioDecoder?.close();
|
|
472
|
+
this.audioDecoder = undefined;
|
|
473
|
+
this.hardwareContext?.dispose();
|
|
474
|
+
this.hardwareContext = undefined;
|
|
475
|
+
await this.input?.close();
|
|
476
|
+
this.input = undefined;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Check if the given audio codec is supported.
|
|
480
|
+
*
|
|
481
|
+
* @param codecId - The AVCodecID to check
|
|
482
|
+
*
|
|
483
|
+
* @returns True if the codec is supported, false otherwise
|
|
484
|
+
*
|
|
485
|
+
* @internal
|
|
486
|
+
*/
|
|
487
|
+
isAudioCodecSupported(codecId) {
|
|
488
|
+
// Empty set means all codecs are supported (passthrough only)
|
|
489
|
+
if (this.supportedAudioCodecs.size === 0) {
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
const isSupported = this.supportedAudioCodecs.has(codecId);
|
|
493
|
+
if (!isSupported) {
|
|
494
|
+
try {
|
|
495
|
+
const ffEncoderCodecs = Array.from(this.supportedAudioCodecs).filter((c) => typeof c === 'string');
|
|
496
|
+
for (const encoderName of ffEncoderCodecs) {
|
|
497
|
+
const encoderCodec = Codec.findEncoderByName(encoderName);
|
|
498
|
+
if (encoderCodec?.id === codecId) {
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
catch {
|
|
504
|
+
// Ignore errors
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return isSupported;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Check if the given video codec is supported.
|
|
511
|
+
*
|
|
512
|
+
* @param codecId - The AVCodecID to check
|
|
513
|
+
*
|
|
514
|
+
* @returns True if the codec is supported, false otherwise
|
|
515
|
+
*
|
|
516
|
+
* @internal
|
|
517
|
+
*/
|
|
518
|
+
isVideoCodecSupported(codecId) {
|
|
519
|
+
// Empty set means all codecs are supported (passthrough only)
|
|
520
|
+
if (this.supportedVideoCodecs.size === 0) {
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
const isSupported = this.supportedVideoCodecs.has(codecId);
|
|
524
|
+
if (!isSupported) {
|
|
525
|
+
try {
|
|
526
|
+
const ffEncoderCodecs = Array.from(this.supportedVideoCodecs).filter((c) => typeof c === 'string');
|
|
527
|
+
for (const encoderName of ffEncoderCodecs) {
|
|
528
|
+
const encoderCodec = Codec.findEncoderByName(encoderName);
|
|
529
|
+
if (encoderCodec?.id === codecId) {
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
catch {
|
|
535
|
+
// Ignore errors
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return isSupported;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Select the best supported sample format from codec.
|
|
542
|
+
*
|
|
543
|
+
* Returns the first supported format, or null if none available.
|
|
544
|
+
* This follows FFmpeg's approach of using the first supported format.
|
|
545
|
+
*
|
|
546
|
+
* @param codec - Audio encoder codec
|
|
547
|
+
*
|
|
548
|
+
* @param desiredFormat - Desired sample format
|
|
549
|
+
*
|
|
550
|
+
* @returns First supported sample format or null
|
|
551
|
+
*
|
|
552
|
+
* @internal
|
|
553
|
+
*/
|
|
554
|
+
selectSampleFormat(codec, desiredFormat) {
|
|
555
|
+
const supportedFormats = codec.sampleFormats;
|
|
556
|
+
if (!supportedFormats || supportedFormats.length === 0) {
|
|
557
|
+
return desiredFormat; // should normally not happen
|
|
558
|
+
}
|
|
559
|
+
if (supportedFormats.includes(desiredFormat)) {
|
|
560
|
+
return desiredFormat;
|
|
561
|
+
}
|
|
562
|
+
return supportedFormats[0];
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Select the best supported sample rate from codec.
|
|
566
|
+
*
|
|
567
|
+
* Returns the closest supported rate to the desired rate.
|
|
568
|
+
* If no rates are specified by the codec, returns the desired rate.
|
|
569
|
+
*
|
|
570
|
+
* @param codec - Audio encoder codec
|
|
571
|
+
*
|
|
572
|
+
* @param desiredRate - Desired sample rate
|
|
573
|
+
*
|
|
574
|
+
* @returns Best matching sample rate
|
|
575
|
+
*
|
|
576
|
+
* @internal
|
|
577
|
+
*/
|
|
578
|
+
selectSampleRate(codec, desiredRate) {
|
|
579
|
+
const supportedRates = codec.supportedSamplerates;
|
|
580
|
+
if (!supportedRates || supportedRates.length === 0) {
|
|
581
|
+
return desiredRate; // should normally not happen
|
|
582
|
+
}
|
|
583
|
+
let bestSampleRate = supportedRates[0];
|
|
584
|
+
for (const rate of supportedRates) {
|
|
585
|
+
if (Math.abs(desiredRate - rate) < Math.abs(desiredRate - bestSampleRate)) {
|
|
586
|
+
bestSampleRate = rate;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return bestSampleRate;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Select the best supported channel layout from codec.
|
|
593
|
+
*
|
|
594
|
+
* Returns a layout matching the desired channel count, or the first supported layout.
|
|
595
|
+
*
|
|
596
|
+
* @param codec - Audio encoder codec
|
|
597
|
+
*
|
|
598
|
+
* @param desiredChannels - Desired number of channels
|
|
599
|
+
*
|
|
600
|
+
* @returns Best matching channel layout string
|
|
601
|
+
*
|
|
602
|
+
* @internal
|
|
603
|
+
*/
|
|
604
|
+
selectChannelLayout(codec, desiredChannels) {
|
|
605
|
+
const supportedLayouts = codec.channelLayouts;
|
|
606
|
+
if (!supportedLayouts || supportedLayouts.length === 0) {
|
|
607
|
+
return desiredChannels === 1 ? 'mono' : 'stereo'; // should normally not happen
|
|
608
|
+
}
|
|
609
|
+
// Try to find exact match
|
|
610
|
+
for (const layout of supportedLayouts) {
|
|
611
|
+
if (layout.nbChannels === desiredChannels) {
|
|
612
|
+
// Use standard names for common layouts
|
|
613
|
+
if (desiredChannels === 1)
|
|
614
|
+
return 'mono';
|
|
615
|
+
if (desiredChannels === 2)
|
|
616
|
+
return 'stereo';
|
|
617
|
+
// For other channel counts, use the mask
|
|
618
|
+
return layout.mask.toString();
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
// No exact match, return first supported
|
|
622
|
+
const firstLayout = supportedLayouts[0];
|
|
623
|
+
if (firstLayout.nbChannels === 1)
|
|
624
|
+
return 'mono';
|
|
625
|
+
if (firstLayout.nbChannels === 2)
|
|
626
|
+
return 'stereo';
|
|
627
|
+
return firstLayout.mask.toString();
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
//# sourceMappingURL=rtp-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rtp-stream.js","sourceRoot":"","sources":["../../src/api/rtp-stream.ts"],"names":[],"mappings":"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"}
|