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
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encoder - High-level wrapper for media encoding
|
|
3
|
+
*
|
|
4
|
+
* Simplifies FFmpeg's encoding API with automatic codec selection,
|
|
5
|
+
* parameter configuration, and packet management.
|
|
6
|
+
*
|
|
7
|
+
* Handles codec initialization, frame encoding, and packet output.
|
|
8
|
+
* Supports hardware acceleration and zero-copy transcoding.
|
|
9
|
+
*
|
|
10
|
+
* @module api/encoder
|
|
11
|
+
*/
|
|
12
|
+
import { AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, AVERROR_EAGAIN, AVERROR_EOF, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_VIDEO, Codec, CodecContext, FFmpegError, Packet, Rational, } from '../lib/index.js';
|
|
13
|
+
import { Stream } from '../lib/stream.js';
|
|
14
|
+
import { parseBitrate } from './utils.js';
|
|
15
|
+
/**
|
|
16
|
+
* High-level encoder for media streams.
|
|
17
|
+
*
|
|
18
|
+
* Handles codec initialization, frame encoding, and packet output.
|
|
19
|
+
* Supports various codecs with flexible configuration options.
|
|
20
|
+
*
|
|
21
|
+
* Manages codec context lifecycle and provides automatic cleanup.
|
|
22
|
+
* Supports hardware acceleration with shared frames context for zero-copy.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // Create H.264 encoder
|
|
27
|
+
* const encoder = await Encoder.create('libx264', {
|
|
28
|
+
* width: 1920,
|
|
29
|
+
* height: 1080,
|
|
30
|
+
* pixelFormat: 'yuv420p',
|
|
31
|
+
* bitrate: '5M',
|
|
32
|
+
* gopSize: 60,
|
|
33
|
+
* options: {
|
|
34
|
+
* preset: 'fast',
|
|
35
|
+
* crf: 23
|
|
36
|
+
* }
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // Encode frames
|
|
40
|
+
* const packet = await encoder.encode(frame);
|
|
41
|
+
* if (packet) {
|
|
42
|
+
* // Write packet to output
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* // Flush encoder
|
|
46
|
+
* let packet;
|
|
47
|
+
* while ((packet = await encoder.flush()) !== null) {
|
|
48
|
+
* // Process final packets
|
|
49
|
+
* }
|
|
50
|
+
* encoder.close();
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* // With hardware acceleration
|
|
56
|
+
* const hw = await HardwareContext.auto();
|
|
57
|
+
* const encoder = await Encoder.create('h264_videotoolbox', {
|
|
58
|
+
* width: 1920,
|
|
59
|
+
* height: 1080,
|
|
60
|
+
* pixelFormat: 'nv12',
|
|
61
|
+
* bitrate: '5M',
|
|
62
|
+
* hardware: hw
|
|
63
|
+
* });
|
|
64
|
+
* // ... use encoder
|
|
65
|
+
* encoder.close(); // Also disposes hardware
|
|
66
|
+
* hw?.dispose(); // Safe to call again (no-op)
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export class Encoder {
|
|
70
|
+
codecContext;
|
|
71
|
+
packet;
|
|
72
|
+
codecName;
|
|
73
|
+
isOpen = true;
|
|
74
|
+
supportedFormats = [];
|
|
75
|
+
preferredFormat;
|
|
76
|
+
hardware; // Store reference to check for late framesContext
|
|
77
|
+
isHardwareEncoder = false; // Track if this is a hardware encoder
|
|
78
|
+
/**
|
|
79
|
+
* Private constructor - use Encoder.create() instead.
|
|
80
|
+
*
|
|
81
|
+
* Initializes the encoder with a codec context and allocates a packet buffer.
|
|
82
|
+
*
|
|
83
|
+
* @param codecContext - Initialized codec context
|
|
84
|
+
* @param codecName - Name of the codec
|
|
85
|
+
* @param hardware - Optional hardware context for late framesContext binding
|
|
86
|
+
*/
|
|
87
|
+
constructor(codecContext, codecName, hardware) {
|
|
88
|
+
this.codecContext = codecContext;
|
|
89
|
+
this.codecName = codecName;
|
|
90
|
+
this.hardware = hardware;
|
|
91
|
+
this.packet = new Packet();
|
|
92
|
+
this.packet.alloc();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Create an encoder with specified codec and options.
|
|
96
|
+
*
|
|
97
|
+
* Factory method that handles codec discovery, context setup,
|
|
98
|
+
* and initialization.
|
|
99
|
+
*
|
|
100
|
+
* Uses avcodec_find_encoder_by_name() to locate the codec,
|
|
101
|
+
* configures the context with provided options, and opens it.
|
|
102
|
+
* Handles hardware setup including shared frames context for zero-copy.
|
|
103
|
+
*
|
|
104
|
+
* @param codecName - Name of codec (e.g., 'libx264', 'aac', 'libopus')
|
|
105
|
+
* @param input - Stream or StreamInfo to copy parameters from
|
|
106
|
+
* @param options - Encoder configuration options
|
|
107
|
+
*
|
|
108
|
+
* @returns Promise resolving to configured Encoder
|
|
109
|
+
*
|
|
110
|
+
* @throws {Error} If codec not found or configuration fails
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // Video encoder from stream
|
|
115
|
+
* const videoStream = media.video();
|
|
116
|
+
* const videoEncoder = await Encoder.create('libx264', videoStream, {
|
|
117
|
+
* bitrate: '5M',
|
|
118
|
+
* gopSize: 60
|
|
119
|
+
* });
|
|
120
|
+
*
|
|
121
|
+
* // Audio encoder from stream
|
|
122
|
+
* const audioStream = media.audio();
|
|
123
|
+
* const audioEncoder = await Encoder.create('aac', audioStream, {
|
|
124
|
+
* bitrate: '192k'
|
|
125
|
+
* });
|
|
126
|
+
*
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
static async create(codecName, input, options = {}) {
|
|
130
|
+
const actualCodecName = codecName;
|
|
131
|
+
// Find encoder by name
|
|
132
|
+
const codec = Codec.findEncoderByName(actualCodecName);
|
|
133
|
+
if (!codec) {
|
|
134
|
+
throw new Error(`Encoder ${actualCodecName} not found`);
|
|
135
|
+
}
|
|
136
|
+
// Allocate codec context
|
|
137
|
+
const codecContext = new CodecContext();
|
|
138
|
+
codecContext.allocContext3(codec);
|
|
139
|
+
// Apply parameters based on input type
|
|
140
|
+
if (input instanceof Stream) {
|
|
141
|
+
// It's a Stream - copy ONLY the essential parameters
|
|
142
|
+
// DO NOT use parametersToContext as it copies everything including decoder-specific settings
|
|
143
|
+
if (codec.type === AVMEDIA_TYPE_VIDEO) {
|
|
144
|
+
// Set required video parameters from input stream
|
|
145
|
+
codecContext.width = input.codecpar.width;
|
|
146
|
+
codecContext.height = input.codecpar.height;
|
|
147
|
+
codecContext.pixelFormat = input.codecpar.format;
|
|
148
|
+
// Set timing information
|
|
149
|
+
codecContext.pktTimebase = input.timeBase;
|
|
150
|
+
codecContext.timeBase = input.timeBase;
|
|
151
|
+
// Set framerate if available
|
|
152
|
+
if (input.avgFrameRate && input.avgFrameRate.num > 0 && input.avgFrameRate.den > 0) {
|
|
153
|
+
codecContext.framerate = new Rational(input.avgFrameRate.num, input.avgFrameRate.den);
|
|
154
|
+
}
|
|
155
|
+
else if (input.rFrameRate && input.rFrameRate.num > 0 && input.rFrameRate.den > 0) {
|
|
156
|
+
codecContext.framerate = new Rational(input.rFrameRate.num, input.rFrameRate.den);
|
|
157
|
+
}
|
|
158
|
+
// Copy sample aspect ratio if present
|
|
159
|
+
if (input.sampleAspectRatio && input.sampleAspectRatio.num > 0) {
|
|
160
|
+
codecContext.sampleAspectRatio = new Rational(input.sampleAspectRatio.num, input.sampleAspectRatio.den);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else if (codec.type === AVMEDIA_TYPE_AUDIO) {
|
|
164
|
+
// Set required audio parameters from input stream
|
|
165
|
+
codecContext.sampleRate = input.codecpar.sampleRate;
|
|
166
|
+
codecContext.sampleFormat = input.codecpar.format;
|
|
167
|
+
// Copy channel layout from input
|
|
168
|
+
// NOTE: This means the encoder will use the same channel configuration as the input
|
|
169
|
+
// If you need different channels, use an audio filter or pass StreamInfo instead
|
|
170
|
+
codecContext.channelLayout = input.codecpar.channelLayout;
|
|
171
|
+
// Set timing information
|
|
172
|
+
codecContext.pktTimebase = input.timeBase;
|
|
173
|
+
codecContext.timeBase = input.timeBase;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
codecContext.freeContext();
|
|
177
|
+
throw new Error('Unsupported codec type for encoder');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
// It's StreamInfo - apply manually
|
|
182
|
+
if (input.type === 'video' && codec.type === AVMEDIA_TYPE_VIDEO) {
|
|
183
|
+
const videoInfo = input;
|
|
184
|
+
codecContext.width = videoInfo.width;
|
|
185
|
+
codecContext.height = videoInfo.height;
|
|
186
|
+
// Only set pixelFormat if provided (might be omitted for hardware encoders)
|
|
187
|
+
if (videoInfo.pixelFormat !== undefined) {
|
|
188
|
+
codecContext.pixelFormat = videoInfo.pixelFormat;
|
|
189
|
+
}
|
|
190
|
+
// Set pkt_timebase and timeBase to input timebase
|
|
191
|
+
codecContext.pktTimebase = new Rational(videoInfo.timeBase.num, videoInfo.timeBase.den);
|
|
192
|
+
codecContext.timeBase = new Rational(videoInfo.timeBase.num, videoInfo.timeBase.den);
|
|
193
|
+
if (videoInfo.frameRate) {
|
|
194
|
+
codecContext.framerate = new Rational(videoInfo.frameRate.num, videoInfo.frameRate.den);
|
|
195
|
+
}
|
|
196
|
+
if (videoInfo.sampleAspectRatio) {
|
|
197
|
+
codecContext.sampleAspectRatio = new Rational(videoInfo.sampleAspectRatio.num, videoInfo.sampleAspectRatio.den);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (input.type === 'audio' && codec.type === AVMEDIA_TYPE_AUDIO) {
|
|
201
|
+
const audioInfo = input;
|
|
202
|
+
codecContext.sampleRate = audioInfo.sampleRate;
|
|
203
|
+
codecContext.sampleFormat = audioInfo.sampleFormat;
|
|
204
|
+
codecContext.channelLayout = audioInfo.channelLayout;
|
|
205
|
+
// Set both pkt_timebase and timeBase for audio
|
|
206
|
+
codecContext.pktTimebase = new Rational(audioInfo.timeBase.num, audioInfo.timeBase.den);
|
|
207
|
+
codecContext.timeBase = new Rational(audioInfo.timeBase.num, audioInfo.timeBase.den);
|
|
208
|
+
if (audioInfo.frameSize) {
|
|
209
|
+
codecContext.frameSize = audioInfo.frameSize;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
throw new Error(`Codec type mismatch: ${input.type} info but ${codec.type === AVMEDIA_TYPE_VIDEO ? 'video' : 'audio'} codec`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
// Apply encoder-specific options
|
|
217
|
+
if (options.gopSize !== undefined) {
|
|
218
|
+
codecContext.gopSize = options.gopSize;
|
|
219
|
+
}
|
|
220
|
+
if (options.maxBFrames !== undefined) {
|
|
221
|
+
codecContext.maxBFrames = options.maxBFrames;
|
|
222
|
+
}
|
|
223
|
+
// Apply common options
|
|
224
|
+
if (options.bitrate !== undefined) {
|
|
225
|
+
const bitrate = typeof options.bitrate === 'string' ? parseBitrate(options.bitrate) : BigInt(options.bitrate);
|
|
226
|
+
codecContext.bitRate = bitrate;
|
|
227
|
+
}
|
|
228
|
+
if (options.threads !== undefined) {
|
|
229
|
+
codecContext.threadCount = options.threads;
|
|
230
|
+
}
|
|
231
|
+
// Override timeBase if explicitly specified in options
|
|
232
|
+
if (options.timeBase) {
|
|
233
|
+
codecContext.timeBase = new Rational(options.timeBase.num, options.timeBase.den);
|
|
234
|
+
}
|
|
235
|
+
// Apply codec-specific options via AVOptions
|
|
236
|
+
if (options.options) {
|
|
237
|
+
for (const [key, value] of Object.entries(options.options)) {
|
|
238
|
+
codecContext.setOption(key, value.toString());
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// Check if this encoder supports hardware acceleration
|
|
242
|
+
let supportsHardware = false;
|
|
243
|
+
let isHardwareEncoder = false;
|
|
244
|
+
// Check encoder's hardware configurations
|
|
245
|
+
for (let i = 0;; i++) {
|
|
246
|
+
const config = codec.getHwConfig(i);
|
|
247
|
+
if (!config)
|
|
248
|
+
break;
|
|
249
|
+
// Check if encoder supports HW_FRAMES_CTX method
|
|
250
|
+
if ((config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) !== 0) {
|
|
251
|
+
supportsHardware = true;
|
|
252
|
+
// If hardware context provided, check if it matches this encoder
|
|
253
|
+
if (options.hardware && config.deviceType === options.hardware.deviceType) {
|
|
254
|
+
isHardwareEncoder = true;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Validation: Hardware encoder MUST have HardwareContext
|
|
260
|
+
if (supportsHardware && !options.hardware) {
|
|
261
|
+
throw new Error(`Hardware encoder '${actualCodecName}' requires a hardware context. ` + 'Please provide one via options.hardware');
|
|
262
|
+
}
|
|
263
|
+
// Apply hardware acceleration if provided and encoder supports it
|
|
264
|
+
if (options.hardware && isHardwareEncoder) {
|
|
265
|
+
// For hardware encoders, always set the hardware pixel format
|
|
266
|
+
// (overrides what was copied from stream parameters)
|
|
267
|
+
codecContext.pixelFormat = options.hardware.getHardwarePixelFormat();
|
|
268
|
+
// Check if frames context already available (shared from decoder)
|
|
269
|
+
if (options.hardware.framesContext) {
|
|
270
|
+
codecContext.hwFramesCtx = options.hardware.framesContext;
|
|
271
|
+
}
|
|
272
|
+
// Else: Will set hwFramesCtx later in encode() when first frame arrives
|
|
273
|
+
// DO NOT create frames context here - wait for first frame!
|
|
274
|
+
}
|
|
275
|
+
// Note: Software encoder silently ignores hardware context
|
|
276
|
+
// Open codec
|
|
277
|
+
const openRet = await codecContext.open2(codec, null);
|
|
278
|
+
if (openRet < 0) {
|
|
279
|
+
codecContext.freeContext();
|
|
280
|
+
FFmpegError.throwIfError(openRet, 'Failed to open encoder');
|
|
281
|
+
}
|
|
282
|
+
const encoder = new Encoder(codecContext, codecName, isHardwareEncoder ? options.hardware : undefined);
|
|
283
|
+
encoder.isHardwareEncoder = isHardwareEncoder;
|
|
284
|
+
// Get supported formats from codec (for validation and helpers)
|
|
285
|
+
if (codec.pixelFormats) {
|
|
286
|
+
encoder.supportedFormats = codec.pixelFormats;
|
|
287
|
+
encoder.preferredFormat = encoder.supportedFormats[0];
|
|
288
|
+
}
|
|
289
|
+
return encoder;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Check if encoder is open.
|
|
293
|
+
*/
|
|
294
|
+
get isEncoderOpen() {
|
|
295
|
+
return this.isOpen;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Encode a frame and return a packet if available.
|
|
299
|
+
*
|
|
300
|
+
* Sends frame to encoder and attempts to receive a packet.
|
|
301
|
+
* May return null if encoder needs more data.
|
|
302
|
+
*
|
|
303
|
+
* Uses avcodec_send_frame() and avcodec_receive_packet() internally.
|
|
304
|
+
* The encoder may buffer frames before producing packets.
|
|
305
|
+
*
|
|
306
|
+
* @param frame - Frame to encode (or null to flush)
|
|
307
|
+
*
|
|
308
|
+
* @returns Promise resolving to Packet or null
|
|
309
|
+
*
|
|
310
|
+
* @throws {Error} If encoder is closed or encode fails
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```typescript
|
|
314
|
+
* const packet = await encoder.encode(frame);
|
|
315
|
+
* if (packet) {
|
|
316
|
+
* // Write packet to output
|
|
317
|
+
* await output.writePacket(packet);
|
|
318
|
+
* }
|
|
319
|
+
* ```
|
|
320
|
+
*/
|
|
321
|
+
async encode(frame) {
|
|
322
|
+
if (!this.isOpen) {
|
|
323
|
+
throw new Error('Encoder is closed');
|
|
324
|
+
}
|
|
325
|
+
// Late binding of hw_frames_ctx ONLY for hardware encoders
|
|
326
|
+
if (this.hardware && this.isHardwareEncoder && !this.codecContext.hwFramesCtx) {
|
|
327
|
+
if (this.hardware.framesContext) {
|
|
328
|
+
// Use shared frames context from decoder
|
|
329
|
+
this.codecContext.hwFramesCtx = this.hardware.framesContext;
|
|
330
|
+
}
|
|
331
|
+
else if (frame?.width && frame.height) {
|
|
332
|
+
// First frame - create frames context for upload
|
|
333
|
+
this.hardware.ensureFramesContext(frame.width, frame.height);
|
|
334
|
+
this.codecContext.hwFramesCtx = this.hardware.framesContext ?? null;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// Software encoder completely ignores hardware context
|
|
338
|
+
// NO MANUAL RESCALING! FFmpeg's avcodec_send_frame() does this internally
|
|
339
|
+
// The encoder needs pkt_timebase to be set for proper rescaling
|
|
340
|
+
// Send frame to encoder
|
|
341
|
+
const sendRet = await this.codecContext.sendFrame(frame);
|
|
342
|
+
if (sendRet < 0 && sendRet !== AVERROR_EOF) {
|
|
343
|
+
// Encoder might be full, try to receive first
|
|
344
|
+
const packet = await this.receivePacket();
|
|
345
|
+
if (packet)
|
|
346
|
+
return packet;
|
|
347
|
+
// If still failing, it's an error
|
|
348
|
+
if (sendRet !== AVERROR_EAGAIN) {
|
|
349
|
+
FFmpegError.throwIfError(sendRet, 'Failed to send frame');
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// Try to receive packet
|
|
353
|
+
return this.receivePacket();
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Async iterator that encodes frames and yields packets.
|
|
357
|
+
*
|
|
358
|
+
* Encodes all provided frames and yields resulting packets.
|
|
359
|
+
* Automatically handles encoder flushing at the end.
|
|
360
|
+
* Input frames are automatically freed after encoding.
|
|
361
|
+
*
|
|
362
|
+
* Processes frames in sequence, encoding each and yielding packets.
|
|
363
|
+
* After all frames are processed, flushes the encoder for remaining packets.
|
|
364
|
+
*
|
|
365
|
+
* IMPORTANT: The yielded packets MUST be freed by the caller!
|
|
366
|
+
* Input frames are automatically freed after processing.
|
|
367
|
+
*
|
|
368
|
+
* @param frames - Async iterable of frames to encode (will be freed automatically)
|
|
369
|
+
*
|
|
370
|
+
* @yields Encoded packets (ownership transferred to caller)
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```typescript
|
|
374
|
+
* // Transcode video
|
|
375
|
+
* for await (const packet of encoder.packets(decoder.frames(media.packets()))) {
|
|
376
|
+
* await output.writePacket(packet);
|
|
377
|
+
* packet.free(); // Must free output packet
|
|
378
|
+
* }
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
async *packets(frames) {
|
|
382
|
+
if (!this.isOpen) {
|
|
383
|
+
throw new Error('Encoder is closed');
|
|
384
|
+
}
|
|
385
|
+
// Process frames
|
|
386
|
+
for await (const frame of frames) {
|
|
387
|
+
try {
|
|
388
|
+
const packet = await this.encode(frame);
|
|
389
|
+
if (packet) {
|
|
390
|
+
yield packet;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
finally {
|
|
394
|
+
// Free the input frame after encoding
|
|
395
|
+
frame.free();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
// Flush encoder after all frames
|
|
399
|
+
let packet;
|
|
400
|
+
while ((packet = await this.flush()) !== null) {
|
|
401
|
+
yield packet;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Flush encoder and get remaining packets.
|
|
406
|
+
*
|
|
407
|
+
* Sends null frame to trigger flush mode.
|
|
408
|
+
* Call repeatedly until it returns null.
|
|
409
|
+
*
|
|
410
|
+
* Uses avcodec_send_frame(NULL) to signal end of stream.
|
|
411
|
+
* Retrieves buffered packets from the encoder.
|
|
412
|
+
*
|
|
413
|
+
* @returns Promise resolving to Packet or null
|
|
414
|
+
*
|
|
415
|
+
* @throws {Error} If encoder is closed
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```typescript
|
|
419
|
+
* // Flush all remaining packets
|
|
420
|
+
* let packet;
|
|
421
|
+
* while ((packet = await encoder.flush()) !== null) {
|
|
422
|
+
* // Write final packets
|
|
423
|
+
* await output.writePacket(packet);
|
|
424
|
+
* }
|
|
425
|
+
* ```
|
|
426
|
+
*/
|
|
427
|
+
async flush() {
|
|
428
|
+
if (!this.isOpen) {
|
|
429
|
+
throw new Error('Encoder is closed');
|
|
430
|
+
}
|
|
431
|
+
// Send flush frame (null)
|
|
432
|
+
await this.codecContext.sendFrame(null);
|
|
433
|
+
// Receive packet
|
|
434
|
+
return this.receivePacket();
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Flush encoder and yield all remaining packets as a generator.
|
|
438
|
+
*
|
|
439
|
+
* More convenient than calling flush() in a loop.
|
|
440
|
+
* Automatically sends flush signal and yields all buffered packets.
|
|
441
|
+
*
|
|
442
|
+
* @returns Async generator of remaining packets
|
|
443
|
+
*
|
|
444
|
+
* @throws {Error} If encoder is closed
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```typescript
|
|
448
|
+
* // Process all remaining packets with generator
|
|
449
|
+
* for await (const packet of encoder.flushPackets()) {
|
|
450
|
+
* await output.writePacket(packet, streamIdx);
|
|
451
|
+
* using _ = packet; // Auto cleanup
|
|
452
|
+
* }
|
|
453
|
+
* ```
|
|
454
|
+
*/
|
|
455
|
+
async *flushPackets() {
|
|
456
|
+
if (!this.isOpen) {
|
|
457
|
+
throw new Error('Encoder is closed');
|
|
458
|
+
}
|
|
459
|
+
let packet;
|
|
460
|
+
while ((packet = await this.flush()) !== null) {
|
|
461
|
+
yield packet;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Close encoder and free resources.
|
|
466
|
+
*
|
|
467
|
+
* After closing, the encoder cannot be used again.
|
|
468
|
+
*
|
|
469
|
+
* Frees the packet buffer and codec context.
|
|
470
|
+
* Note: Does NOT dispose the HardwareContext - caller is responsible for that.
|
|
471
|
+
*/
|
|
472
|
+
close() {
|
|
473
|
+
if (!this.isOpen)
|
|
474
|
+
return;
|
|
475
|
+
this.packet.free();
|
|
476
|
+
this.codecContext.freeContext();
|
|
477
|
+
// NOTE: We do NOT dispose the hardware context here anymore
|
|
478
|
+
// The caller who created the HardwareContext is responsible for disposing it
|
|
479
|
+
// This allows reusing the same HardwareContext for multiple encoders
|
|
480
|
+
this.isOpen = false;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Get the codec name.
|
|
484
|
+
*/
|
|
485
|
+
getCodecName() {
|
|
486
|
+
return this.codecName;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Get codec context for advanced configuration.
|
|
490
|
+
*
|
|
491
|
+
* Use with caution - direct manipulation may cause issues.
|
|
492
|
+
*
|
|
493
|
+
* Provides access to the underlying AVCodecContext for advanced operations.
|
|
494
|
+
*
|
|
495
|
+
* @returns CodecContext or null if closed
|
|
496
|
+
*
|
|
497
|
+
* @internal
|
|
498
|
+
*/
|
|
499
|
+
getCodecContext() {
|
|
500
|
+
return this.isOpen ? this.codecContext : null;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Get the preferred pixel format for this encoder.
|
|
504
|
+
*
|
|
505
|
+
* Returns the first supported format, which is usually the most efficient.
|
|
506
|
+
*
|
|
507
|
+
* @returns Preferred pixel format or null if not available
|
|
508
|
+
*
|
|
509
|
+
* @example
|
|
510
|
+
* ```typescript
|
|
511
|
+
* const format = encoder.getPreferredPixelFormat();
|
|
512
|
+
* if (format) {
|
|
513
|
+
* console.log(`Encoder prefers format: ${format}`);
|
|
514
|
+
* }
|
|
515
|
+
* ```
|
|
516
|
+
*/
|
|
517
|
+
getPreferredPixelFormat() {
|
|
518
|
+
return this.preferredFormat ?? null;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Get all supported pixel formats for this encoder.
|
|
522
|
+
*
|
|
523
|
+
* Returns a list of pixel formats that this encoder can accept.
|
|
524
|
+
*
|
|
525
|
+
* @returns Array of supported pixel formats
|
|
526
|
+
*
|
|
527
|
+
* @example
|
|
528
|
+
* ```typescript
|
|
529
|
+
* const formats = encoder.getSupportedPixelFormats();
|
|
530
|
+
* console.log(`Encoder supports: ${formats.join(', ')}`);
|
|
531
|
+
* ```
|
|
532
|
+
*/
|
|
533
|
+
getSupportedPixelFormats() {
|
|
534
|
+
return this.supportedFormats;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Receive a packet from the encoder.
|
|
538
|
+
*
|
|
539
|
+
* Internal method to receive encoded packets.
|
|
540
|
+
*
|
|
541
|
+
* Uses avcodec_receive_packet() to get encoded packets from the codec.
|
|
542
|
+
* Clones the packet for the user to prevent internal buffer corruption.
|
|
543
|
+
*
|
|
544
|
+
* @returns Packet or null if no packet available
|
|
545
|
+
*/
|
|
546
|
+
async receivePacket() {
|
|
547
|
+
// Clear previous packet data
|
|
548
|
+
this.packet.unref();
|
|
549
|
+
const ret = await this.codecContext.receivePacket(this.packet);
|
|
550
|
+
if (ret === 0) {
|
|
551
|
+
// Got a packet, clone it for the user
|
|
552
|
+
return this.packet.clone();
|
|
553
|
+
}
|
|
554
|
+
else if (ret === AVERROR_EAGAIN || ret === AVERROR_EOF) {
|
|
555
|
+
// Need more data or end of stream
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
// Error
|
|
560
|
+
FFmpegError.throwIfError(ret, 'Failed to receive packet');
|
|
561
|
+
return null;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Symbol.dispose for automatic cleanup.
|
|
566
|
+
*
|
|
567
|
+
* Implements the Disposable interface for automatic resource management.
|
|
568
|
+
* Calls close() to free all resources.
|
|
569
|
+
*/
|
|
570
|
+
[Symbol.dispose]() {
|
|
571
|
+
this.close();
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
//# sourceMappingURL=encoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"encoder.js","sourceRoot":"","sources":["../../src/api/encoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,uCAAuC,EACvC,cAAc,EACd,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,EACL,YAAY,EACZ,WAAW,EACX,MAAM,EACN,QAAQ,GACT,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,MAAM,OAAO,OAAO;IACV,YAAY,CAAe;IAC3B,MAAM,CAAS;IACf,SAAS,CAAS;IAClB,MAAM,GAAG,IAAI,CAAC;IACd,gBAAgB,GAAoB,EAAE,CAAC;IACvC,eAAe,CAAiB;IAChC,QAAQ,CAA0B,CAAC,kDAAkD;IACrF,iBAAiB,GAAG,KAAK,CAAC,CAAC,sCAAsC;IAEzE;;;;;;;;OAQG;IACH,YAAoB,YAA0B,EAAE,SAAiB,EAAE,QAAiC;QAClG,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAiB,EAAE,KAA0B,EAAE,UAA0B,EAAE;QAC7F,MAAM,eAAe,GAAG,SAAS,CAAC;QAElC,uBAAuB;QACvB,MAAM,KAAK,GAAG,KAAK,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,WAAW,eAAe,YAAY,CAAC,CAAC;QAC1D,CAAC;QAED,yBAAyB;QACzB,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;QACxC,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAElC,uCAAuC;QACvC,IAAI,KAAK,YAAY,MAAM,EAAE,CAAC;YAC5B,qDAAqD;YACrD,6FAA6F;YAE7F,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBACtC,kDAAkD;gBAClD,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAC1C,YAAY,CAAC,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC5C,YAAY,CAAC,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAuB,CAAC;gBAElE,yBAAyB;gBACzB,YAAY,CAAC,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC;gBAC1C,YAAY,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;gBAEvC,6BAA6B;gBAC7B,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,YAAY,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;oBACnF,YAAY,CAAC,SAAS,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;gBACxF,CAAC;qBAAM,IAAI,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;oBACpF,YAAY,CAAC,SAAS,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;gBACpF,CAAC;gBAED,sCAAsC;gBACtC,IAAI,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,iBAAiB,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;oBAC/D,YAAY,CAAC,iBAAiB,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;gBAC1G,CAAC;YACH,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBAC7C,kDAAkD;gBAClD,YAAY,CAAC,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC;gBACpD,YAAY,CAAC,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAwB,CAAC;gBAEpE,iCAAiC;gBACjC,oFAAoF;gBACpF,iFAAiF;gBACjF,YAAY,CAAC,aAAa,GAAG,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAE1D,yBAAyB;gBACzB,YAAY,CAAC,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC;gBAC1C,YAAY,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,YAAY,CAAC,WAAW,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACxD,CAAC;QACH,CAAC;aAAM,CAAC;YACN,mCAAmC;YACnC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBAChE,MAAM,SAAS,GAAG,KAAK,CAAC;gBACxB,YAAY,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;gBACrC,YAAY,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC;gBACvC,4EAA4E;gBAC5E,IAAI,SAAS,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;oBACxC,YAAY,CAAC,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC;gBACnD,CAAC;gBAED,kDAAkD;gBAClD,YAAY,CAAC,WAAW,GAAG,IAAI,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACxF,YAAY,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAErF,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;oBACxB,YAAY,CAAC,SAAS,GAAG,IAAI,QAAQ,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;gBAC1F,CAAC;gBACD,IAAI,SAAS,CAAC,iBAAiB,EAAE,CAAC;oBAChC,YAAY,CAAC,iBAAiB,GAAG,IAAI,QAAQ,CAAC,SAAS,CAAC,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;gBAClH,CAAC;YACH,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBACvE,MAAM,SAAS,GAAG,KAAK,CAAC;gBACxB,YAAY,CAAC,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;gBAC/C,YAAY,CAAC,YAAY,GAAG,SAAS,CAAC,YAAY,CAAC;gBACnD,YAAY,CAAC,aAAa,GAAG,SAAS,CAAC,aAAa,CAAC;gBACrD,+CAA+C;gBAC/C,YAAY,CAAC,WAAW,GAAG,IAAI,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACxF,YAAY,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAErF,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;oBACxB,YAAY,CAAC,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;gBAC/C,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,CAAC,IAAI,aAAa,KAAK,CAAC,IAAI,KAAK,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC;YAChI,CAAC;QACH,CAAC;QAED,iCAAiC;QACjC,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAClC,YAAY,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QACzC,CAAC;QACD,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACrC,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QAC/C,CAAC;QAED,uBAAuB;QACvB,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC9G,YAAY,CAAC,OAAO,GAAG,OAAO,CAAC;QACjC,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAClC,YAAY,CAAC,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;QAC7C,CAAC;QAED,uDAAuD;QACvD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,YAAY,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACnF,CAAC;QAED,6CAA6C;QAC7C,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC3D,YAAY,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QAED,uDAAuD;QACvD,IAAI,gBAAgB,GAAG,KAAK,CAAC;QAC7B,IAAI,iBAAiB,GAAG,KAAK,CAAC;QAE9B,0CAA0C;QAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,GAAI,CAAC,EAAE,EAAE,CAAC;YACtB,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;YACpC,IAAI,CAAC,MAAM;gBAAE,MAAM;YAEnB,iDAAiD;YACjD,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,uCAAuC,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrE,gBAAgB,GAAG,IAAI,CAAC;gBAExB,iEAAiE;gBACjE,IAAI,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;oBAC1E,iBAAiB,GAAG,IAAI,CAAC;oBACzB,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,yDAAyD;QACzD,IAAI,gBAAgB,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,qBAAqB,eAAe,iCAAiC,GAAG,yCAAyC,CAAC,CAAC;QACrI,CAAC;QAED,kEAAkE;QAClE,IAAI,OAAO,CAAC,QAAQ,IAAI,iBAAiB,EAAE,CAAC;YAC1C,8DAA8D;YAC9D,qDAAqD;YACrD,YAAY,CAAC,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,sBAAsB,EAAE,CAAC;YAErE,kEAAkE;YAClE,IAAI,OAAO,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;gBACnC,YAAY,CAAC,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC5D,CAAC;YACD,wEAAwE;YACxE,4DAA4D;QAC9D,CAAC;QACD,2DAA2D;QAE3D,aAAa;QACb,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACtD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,YAAY,CAAC,WAAW,EAAE,CAAC;YAC3B,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,YAAY,EAAE,SAAS,EAAE,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACvG,OAAO,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAE9C,gEAAgE;QAChE,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YACvB,OAAO,CAAC,gBAAgB,GAAG,KAAK,CAAC,YAAY,CAAC;YAC9C,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACxD,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,KAAK,CAAC,MAAM,CAAC,KAAmB;QAC9B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,2DAA2D;QAC3D,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,iBAAiB,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;YAC9E,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;gBAChC,yCAAyC;gBACzC,IAAI,CAAC,YAAY,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC9D,CAAC;iBAAM,IAAI,KAAK,EAAE,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACxC,iDAAiD;gBACjD,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC7D,IAAI,CAAC,YAAY,CAAC,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,IAAI,IAAI,CAAC;YACtE,CAAC;QACH,CAAC;QACD,uDAAuD;QAEvD,0EAA0E;QAC1E,gEAAgE;QAEhE,wBAAwB;QACxB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACzD,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;YAC3C,8CAA8C;YAC9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;YAC1C,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;YAE1B,kCAAkC;YAClC,IAAI,OAAO,KAAK,cAAc,EAAE,CAAC;gBAC/B,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC;IAC9B,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,KAAK,CAAC,CAAC,OAAO,CAAC,MAA4B;QACzC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,iBAAiB;QACjB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACxC,IAAI,MAAM,EAAE,CAAC;oBACX,MAAM,MAAM,CAAC;gBACf,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,sCAAsC;gBACtC,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,CAAC;QACH,CAAC;QAED,iCAAiC;QACjC,IAAI,MAAM,CAAC;QACX,OAAO,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;YAC9C,MAAM,MAAM,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,0BAA0B;QAC1B,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAExC,iBAAiB;QACjB,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC;IAC9B,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,CAAC,CAAC,YAAY;QACjB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,MAAM,CAAC;QACX,OAAO,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;YAC9C,MAAM,MAAM,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzB,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACnB,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;QAEhC,4DAA4D;QAC5D,6EAA6E;QAC7E,qEAAqE;QAErE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;;;;;;;;;OAUG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,uBAAuB;QACrB,OAAO,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC;IACtC,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,wBAAwB;QACtB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED;;;;;;;;;OASG;IACK,KAAK,CAAC,aAAa;QACzB,6BAA6B;QAC7B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAEpB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE/D,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;YACd,sCAAsC;YACtC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC7B,CAAC;aAAM,IAAI,GAAG,KAAK,cAAc,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACzD,kCAAkC;YAClC,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,CAAC;YACN,QAAQ;YACR,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,0BAA0B,CAAC,CAAC;YAC1D,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC;QACd,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;CACF"}
|