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,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MediaInput - Unified Input Handler for FFmpeg
|
|
3
|
+
*
|
|
4
|
+
* Provides a high-level interface for opening and reading media from various sources.
|
|
5
|
+
* Supports files, URLs, and Buffers with automatic format detection.
|
|
6
|
+
*
|
|
7
|
+
* Central entry point for all media input operations.
|
|
8
|
+
* Manages FormatContext lifecycle and provides stream information.
|
|
9
|
+
*
|
|
10
|
+
* @module api/media-input
|
|
11
|
+
*/
|
|
12
|
+
import { open } from 'fs/promises';
|
|
13
|
+
import { AVFLAG_NONE, avGetPixFmtName, avGetSampleFmtName, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_VIDEO, Dictionary, FFmpegError, FormatContext, InputFormat, Packet, Rational, } from '../lib/index.js';
|
|
14
|
+
import { IOStream } from './io-stream.js';
|
|
15
|
+
/**
|
|
16
|
+
* MediaInput - High-level media input handler.
|
|
17
|
+
*
|
|
18
|
+
* Opens and provides access to media streams from various sources.
|
|
19
|
+
* Automatically detects format and finds stream information.
|
|
20
|
+
*
|
|
21
|
+
* Manages the FormatContext and provides convenient methods for
|
|
22
|
+
* accessing streams, metadata, and packets.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { MediaInput } from 'node-av/api';
|
|
27
|
+
*
|
|
28
|
+
* // Open from file
|
|
29
|
+
* const media = await MediaInput.open('video.mp4');
|
|
30
|
+
* console.log(`Found ${media.streams.length} streams`);
|
|
31
|
+
* console.log(`Duration: ${media.duration} seconds`);
|
|
32
|
+
*
|
|
33
|
+
* // Open from buffer
|
|
34
|
+
* const buffer = await fs.readFile('video.mp4');
|
|
35
|
+
* const media = await MediaInput.open(buffer);
|
|
36
|
+
*
|
|
37
|
+
* // Iterate packets
|
|
38
|
+
* for await (const packet of media.packets()) {
|
|
39
|
+
* console.log(`Packet from stream ${packet.streamIndex}`);
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export class MediaInput {
|
|
44
|
+
formatContext;
|
|
45
|
+
_streams = [];
|
|
46
|
+
ioContext; // Store IOContext for cleanup
|
|
47
|
+
/**
|
|
48
|
+
* Create a new MediaInput instance.
|
|
49
|
+
*
|
|
50
|
+
* Private constructor - use MediaInput.open() to create instances.
|
|
51
|
+
*
|
|
52
|
+
* Parses stream information immediately after construction.
|
|
53
|
+
*
|
|
54
|
+
* @param formatContext - Opened FormatContext
|
|
55
|
+
*/
|
|
56
|
+
constructor(formatContext) {
|
|
57
|
+
this.formatContext = formatContext;
|
|
58
|
+
// Streams will be set after findStreamInfo in the static factory
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Probe the format of media without fully opening it.
|
|
62
|
+
*
|
|
63
|
+
* Detects the container format and basic information without
|
|
64
|
+
* parsing all stream information. Useful for quick format validation.
|
|
65
|
+
*
|
|
66
|
+
* @param input - File path or Buffer to probe
|
|
67
|
+
*
|
|
68
|
+
* @returns Format information or null if unrecognized
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* // Probe a file
|
|
73
|
+
* const info = await MediaInput.probeFormat('video.mp4');
|
|
74
|
+
* if (info) {
|
|
75
|
+
* console.log(`Format: ${info.format}`);
|
|
76
|
+
* console.log(`Confidence: ${info.confidence}%`);
|
|
77
|
+
* }
|
|
78
|
+
*
|
|
79
|
+
* // Probe a buffer
|
|
80
|
+
* const buffer = await fs.readFile('video.mp4');
|
|
81
|
+
* const info = await MediaInput.probeFormat(buffer);
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
static async probeFormat(input) {
|
|
85
|
+
try {
|
|
86
|
+
if (Buffer.isBuffer(input)) {
|
|
87
|
+
// Probe from buffer
|
|
88
|
+
const format = InputFormat.probe(input);
|
|
89
|
+
if (!format) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
format: format.name ?? 'unknown',
|
|
94
|
+
longName: format.longName ?? undefined,
|
|
95
|
+
extensions: format.extensions ?? undefined,
|
|
96
|
+
mimeType: format.mimeType ?? undefined,
|
|
97
|
+
confidence: 100, // Direct probe always has high confidence
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// For files, read first part and probe
|
|
102
|
+
let fileHandle;
|
|
103
|
+
try {
|
|
104
|
+
fileHandle = await open(input, 'r');
|
|
105
|
+
// Read first 64KB for probing
|
|
106
|
+
const buffer = Buffer.alloc(65536);
|
|
107
|
+
const { bytesRead } = await fileHandle.read(buffer, 0, 65536, 0);
|
|
108
|
+
const probeBuffer = buffer.subarray(0, bytesRead);
|
|
109
|
+
const format = InputFormat.probe(probeBuffer, input);
|
|
110
|
+
if (!format) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
format: format.name ?? 'unknown',
|
|
115
|
+
longName: format.longName ?? undefined,
|
|
116
|
+
extensions: format.extensions ?? undefined,
|
|
117
|
+
mimeType: format.mimeType ?? undefined,
|
|
118
|
+
confidence: 90, // File-based probe with filename hint
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// If file reading fails, return null
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
await fileHandle?.close();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
static async open(input, options = {}) {
|
|
135
|
+
// Check if input is raw data
|
|
136
|
+
if (typeof input === 'object' && 'type' in input && ('width' in input || 'sampleRate' in input)) {
|
|
137
|
+
// Build options for raw data
|
|
138
|
+
const rawOptions = {
|
|
139
|
+
bufferSize: options.bufferSize,
|
|
140
|
+
format: options.format ?? (input.type === 'video' ? 'rawvideo' : 's16le'),
|
|
141
|
+
options: {
|
|
142
|
+
...options.options,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
if (input.type === 'video') {
|
|
146
|
+
rawOptions.options = {
|
|
147
|
+
...rawOptions.options,
|
|
148
|
+
video_size: `${input.width}x${input.height}`,
|
|
149
|
+
pixel_format: avGetPixFmtName(input.pixelFormat) ?? 'yuv420p',
|
|
150
|
+
framerate: new Rational(input.frameRate.num, input.frameRate.den).toString(),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
rawOptions.options = {
|
|
155
|
+
...rawOptions.options,
|
|
156
|
+
sample_rate: input.sampleRate,
|
|
157
|
+
channels: input.channels,
|
|
158
|
+
sample_fmt: avGetSampleFmtName(input.sampleFormat) ?? 's16le',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
// Open with the raw data source
|
|
162
|
+
return MediaInput.open(input.input, rawOptions);
|
|
163
|
+
}
|
|
164
|
+
// Original implementation for non-raw data
|
|
165
|
+
const formatContext = new FormatContext();
|
|
166
|
+
let ioContext;
|
|
167
|
+
let optionsDict = null;
|
|
168
|
+
let inputFormat = null;
|
|
169
|
+
try {
|
|
170
|
+
// Create options dictionary if options are provided
|
|
171
|
+
if (options.options && Object.keys(options.options).length > 0) {
|
|
172
|
+
// Convert all values to strings for FFmpeg
|
|
173
|
+
const stringOptions = {};
|
|
174
|
+
for (const [key, value] of Object.entries(options.options)) {
|
|
175
|
+
stringOptions[key] = String(value);
|
|
176
|
+
}
|
|
177
|
+
optionsDict = Dictionary.fromObject(stringOptions);
|
|
178
|
+
}
|
|
179
|
+
// Find input format if specified
|
|
180
|
+
if (options.format) {
|
|
181
|
+
inputFormat = InputFormat.findInputFormat(options.format);
|
|
182
|
+
if (!inputFormat) {
|
|
183
|
+
throw new Error(`Input format '${options.format}' not found`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (typeof input === 'string') {
|
|
187
|
+
// File path or URL
|
|
188
|
+
const ret = await formatContext.openInput(input, inputFormat, optionsDict);
|
|
189
|
+
FFmpegError.throwIfError(ret, 'Failed to open input');
|
|
190
|
+
}
|
|
191
|
+
else if (Buffer.isBuffer(input)) {
|
|
192
|
+
// Validate buffer is not empty
|
|
193
|
+
if (input.length === 0) {
|
|
194
|
+
throw new Error('Cannot open media from empty buffer');
|
|
195
|
+
}
|
|
196
|
+
// From buffer - allocate context first for custom I/O
|
|
197
|
+
formatContext.allocContext();
|
|
198
|
+
ioContext = IOStream.create(input, { bufferSize: options.bufferSize });
|
|
199
|
+
formatContext.pb = ioContext;
|
|
200
|
+
const ret = await formatContext.openInput('', inputFormat, optionsDict);
|
|
201
|
+
FFmpegError.throwIfError(ret, 'Failed to open input from buffer');
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
throw new TypeError('Invalid input type. Expected file path, URL, or Buffer');
|
|
205
|
+
}
|
|
206
|
+
// Find stream information
|
|
207
|
+
const ret = await formatContext.findStreamInfo(null);
|
|
208
|
+
FFmpegError.throwIfError(ret, 'Failed to find stream info');
|
|
209
|
+
const mediaInput = new MediaInput(formatContext);
|
|
210
|
+
mediaInput.ioContext = ioContext;
|
|
211
|
+
// After successful creation, streams should be available
|
|
212
|
+
mediaInput._streams = formatContext.streams ?? [];
|
|
213
|
+
return mediaInput;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
// Clean up only on error
|
|
217
|
+
if (ioContext) {
|
|
218
|
+
// Clear the pb reference first
|
|
219
|
+
formatContext.pb = null;
|
|
220
|
+
// Free the IOContext
|
|
221
|
+
ioContext.freeContext();
|
|
222
|
+
}
|
|
223
|
+
// Clean up FormatContext
|
|
224
|
+
await formatContext.closeInput();
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
// Clean up options dictionary
|
|
229
|
+
if (optionsDict) {
|
|
230
|
+
optionsDict.free();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get all streams in the container.
|
|
236
|
+
*
|
|
237
|
+
* @returns Array of stream information
|
|
238
|
+
*/
|
|
239
|
+
get streams() {
|
|
240
|
+
return this._streams;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Get media duration in seconds.
|
|
244
|
+
*
|
|
245
|
+
* Returns 0 if duration is not available.
|
|
246
|
+
*
|
|
247
|
+
* @returns Duration in seconds
|
|
248
|
+
*/
|
|
249
|
+
get duration() {
|
|
250
|
+
const duration = this.formatContext.duration;
|
|
251
|
+
if (!duration || duration <= 0)
|
|
252
|
+
return 0;
|
|
253
|
+
// Convert from AV_TIME_BASE (microseconds) to seconds
|
|
254
|
+
return Number(duration) / 1000000;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Get container metadata.
|
|
258
|
+
*
|
|
259
|
+
* @returns Metadata key-value pairs
|
|
260
|
+
*/
|
|
261
|
+
get metadata() {
|
|
262
|
+
return this.formatContext.metadata?.getAll() ?? {};
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Get container format name.
|
|
266
|
+
*
|
|
267
|
+
* @returns Format name (e.g., 'mov,mp4,m4a,3gp,3g2,mj2')
|
|
268
|
+
*/
|
|
269
|
+
get formatName() {
|
|
270
|
+
return this.formatContext.iformat?.name ?? 'unknown';
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get container format long name.
|
|
274
|
+
*
|
|
275
|
+
* @returns Format long name (e.g., 'QuickTime / MOV')
|
|
276
|
+
*/
|
|
277
|
+
get formatLongName() {
|
|
278
|
+
return this.formatContext.iformat?.longName ?? 'Unknown Format';
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Get the first video stream.
|
|
282
|
+
*
|
|
283
|
+
* @param index - Video stream index (0 for first, 1 for second, etc.)
|
|
284
|
+
*
|
|
285
|
+
* @returns Stream info or undefined if not found
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```typescript
|
|
289
|
+
* const videoStream = media.video();
|
|
290
|
+
* if (videoStream) {
|
|
291
|
+
* console.log(`Video: ${videoStream.width}x${videoStream.height}`);
|
|
292
|
+
* }
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
video(index = 0) {
|
|
296
|
+
const streams = this._streams.filter((s) => s.codecpar.codecType === AVMEDIA_TYPE_VIDEO);
|
|
297
|
+
return streams[index];
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Get the first audio stream.
|
|
301
|
+
*
|
|
302
|
+
* @param index - Audio stream index (0 for first, 1 for second, etc.)
|
|
303
|
+
*
|
|
304
|
+
* @returns Stream info or undefined if not found
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* ```typescript
|
|
308
|
+
* const audioStream = media.audio();
|
|
309
|
+
* if (audioStream) {
|
|
310
|
+
* console.log(`Audio: ${audioStream.sampleRate}Hz, ${audioStream.channels}ch`);
|
|
311
|
+
* }
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
audio(index = 0) {
|
|
315
|
+
const streams = this._streams.filter((s) => s.codecpar.codecType === AVMEDIA_TYPE_AUDIO);
|
|
316
|
+
return streams[index];
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Find the best stream of a given type.
|
|
320
|
+
*
|
|
321
|
+
* Uses FFmpeg's stream selection logic to find the most suitable stream.
|
|
322
|
+
*
|
|
323
|
+
* Uses av_find_best_stream() internally for optimal stream selection.
|
|
324
|
+
*
|
|
325
|
+
* @param type - Media type to search for
|
|
326
|
+
*
|
|
327
|
+
* @returns Stream info or undefined if not found
|
|
328
|
+
*/
|
|
329
|
+
findBestStream(type) {
|
|
330
|
+
const bestStreamIndex = this.formatContext.findBestStream(type);
|
|
331
|
+
return this._streams.find((s) => s.index === bestStreamIndex);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Iterate over all packets in the container.
|
|
335
|
+
*
|
|
336
|
+
* Allocates a single packet and reuses it for efficiency.
|
|
337
|
+
* Automatically unreferences the packet between iterations.
|
|
338
|
+
*
|
|
339
|
+
* Uses av_read_frame() internally.
|
|
340
|
+
*
|
|
341
|
+
* @yields Packet from the container
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```typescript
|
|
345
|
+
* for await (const packet of media.packets()) {
|
|
346
|
+
* if (packet.streamIndex === videoStream.index) {
|
|
347
|
+
* // Process video packet
|
|
348
|
+
* await decoder.decode(packet);
|
|
349
|
+
* }
|
|
350
|
+
* }
|
|
351
|
+
* ```
|
|
352
|
+
*/
|
|
353
|
+
async *packets(index) {
|
|
354
|
+
const packet = new Packet();
|
|
355
|
+
packet.alloc();
|
|
356
|
+
try {
|
|
357
|
+
while (true) {
|
|
358
|
+
const ret = await this.formatContext.readFrame(packet);
|
|
359
|
+
if (ret < 0) {
|
|
360
|
+
// End of file or error
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
if (index === undefined || packet.streamIndex === index) {
|
|
364
|
+
// Clone the packet for the user
|
|
365
|
+
// This creates a new Packet object that shares the same data buffer
|
|
366
|
+
// through reference counting. The data won't be freed until both
|
|
367
|
+
// the original and the clone are unreferenced.
|
|
368
|
+
const cloned = packet.clone();
|
|
369
|
+
if (!cloned) {
|
|
370
|
+
throw new Error('Failed to clone packet (out of memory)');
|
|
371
|
+
}
|
|
372
|
+
yield cloned;
|
|
373
|
+
}
|
|
374
|
+
// Unreference the original packet's data buffer
|
|
375
|
+
// This allows us to reuse the packet object for the next readFrame()
|
|
376
|
+
// The data itself is still alive because the clone has a reference
|
|
377
|
+
packet.unref();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
finally {
|
|
381
|
+
packet.free();
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Seek to a specific timestamp.
|
|
386
|
+
*
|
|
387
|
+
* Uses av_seek_frame() internally.
|
|
388
|
+
*
|
|
389
|
+
* Converts seconds to microseconds for FFmpeg's AV_TIME_BASE.
|
|
390
|
+
*
|
|
391
|
+
* @param timestamp - Target timestamp in seconds
|
|
392
|
+
* @param streamIndex - Stream to seek in (-1 for default)
|
|
393
|
+
* @param flags - Seek flags (0 for default)
|
|
394
|
+
*
|
|
395
|
+
* @returns 0 on success, negative error code on failure
|
|
396
|
+
*/
|
|
397
|
+
async seek(timestamp, streamIndex = -1, flags = AVFLAG_NONE) {
|
|
398
|
+
// Convert seconds to AV_TIME_BASE
|
|
399
|
+
const ts = BigInt(Math.floor(timestamp * 1000000));
|
|
400
|
+
return this.formatContext.seekFrame(streamIndex, ts, flags);
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Close the input and free resources.
|
|
404
|
+
*
|
|
405
|
+
* Uses avformat_close_input() internally.
|
|
406
|
+
*
|
|
407
|
+
* Properly cleans up IOContext references before closing to prevent
|
|
408
|
+
* use-after-free errors.
|
|
409
|
+
*/
|
|
410
|
+
async close() {
|
|
411
|
+
// IMPORTANT: Clear pb reference FIRST to prevent use-after-free
|
|
412
|
+
if (this.ioContext) {
|
|
413
|
+
this.formatContext.pb = null;
|
|
414
|
+
}
|
|
415
|
+
// Close FormatContext
|
|
416
|
+
await this.formatContext.closeInput();
|
|
417
|
+
// NOW we can safely free the IOContext
|
|
418
|
+
if (this.ioContext) {
|
|
419
|
+
this.ioContext.freeContext();
|
|
420
|
+
this.ioContext = undefined;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Get the low-level FormatContext.
|
|
425
|
+
*
|
|
426
|
+
* Internal method for advanced use cases.
|
|
427
|
+
*
|
|
428
|
+
* Provides direct access to the underlying AVFormatContext.
|
|
429
|
+
*
|
|
430
|
+
* @returns FFmpeg FormatContext
|
|
431
|
+
*
|
|
432
|
+
* @internal
|
|
433
|
+
*/
|
|
434
|
+
getFormatContext() {
|
|
435
|
+
return this.formatContext;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Async cleanup when using 'await using' statement.
|
|
439
|
+
*
|
|
440
|
+
* Implements the AsyncDisposable interface for automatic cleanup.
|
|
441
|
+
*
|
|
442
|
+
* Calls close() to free all resources.
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* ```typescript
|
|
446
|
+
* {
|
|
447
|
+
* await using media = await MediaInput.open('video.mp4');
|
|
448
|
+
* // Use media...
|
|
449
|
+
* } // Automatically closed
|
|
450
|
+
* ```
|
|
451
|
+
*/
|
|
452
|
+
async [Symbol.asyncDispose]() {
|
|
453
|
+
await this.close();
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
//# sourceMappingURL=media-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"media-input.js","sourceRoot":"","sources":["../../src/api/media-input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,OAAO,EACL,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,aAAa,EACb,WAAW,EACX,MAAM,EACN,QAAQ,GACT,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAK1C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,OAAO,UAAU;IACb,aAAa,CAAgB;IAC7B,QAAQ,GAAa,EAAE,CAAC;IACxB,SAAS,CAAa,CAAC,8BAA8B;IAE7D;;;;;;;;OAQG;IACH,YAAoB,aAA4B;QAC9C,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,iEAAiE;IACnE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,KAAsB;QAO7C,IAAI,CAAC;YACH,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3B,oBAAoB;gBACpB,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACxC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,OAAO;oBACL,MAAM,EAAE,MAAM,CAAC,IAAI,IAAI,SAAS;oBAChC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;oBACtC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,SAAS;oBAC1C,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;oBACtC,UAAU,EAAE,GAAG,EAAE,0CAA0C;iBAC5D,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,uCAAuC;gBACvC,IAAI,UAAU,CAAC;gBACf,IAAI,CAAC;oBACH,UAAU,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;oBACpC,8BAA8B;oBAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBACnC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;oBAEjE,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;oBAClD,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;oBAErD,IAAI,CAAC,MAAM,EAAE,CAAC;wBACZ,OAAO,IAAI,CAAC;oBACd,CAAC;oBAED,OAAO;wBACL,MAAM,EAAE,MAAM,CAAC,IAAI,IAAI,SAAS;wBAChC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;wBACtC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,SAAS;wBAC1C,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;wBACtC,UAAU,EAAE,EAAE,EAAE,sCAAsC;qBACvD,CAAC;gBACJ,CAAC;gBAAC,MAAM,CAAC;oBACP,qCAAqC;oBACrC,OAAO,IAAI,CAAC;gBACd,CAAC;wBAAS,CAAC;oBACT,MAAM,UAAU,EAAE,KAAK,EAAE,CAAC;gBAC5B,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IA+DD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAgC,EAAE,UAA6B,EAAE;QACjF,6BAA6B;QAC7B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,IAAI,CAAC,OAAO,IAAI,KAAK,IAAI,YAAY,IAAI,KAAK,CAAC,EAAE,CAAC;YAChG,6BAA6B;YAC7B,MAAM,UAAU,GAAsB;gBACpC,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;gBACzE,OAAO,EAAE;oBACP,GAAG,OAAO,CAAC,OAAO;iBACnB;aACF,CAAC;YAEF,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC3B,UAAU,CAAC,OAAO,GAAG;oBACnB,GAAG,UAAU,CAAC,OAAO;oBACrB,UAAU,EAAE,GAAG,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE;oBAC5C,YAAY,EAAE,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,SAAS;oBAC7D,SAAS,EAAE,IAAI,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;iBAC7E,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,OAAO,GAAG;oBACnB,GAAG,UAAU,CAAC,OAAO;oBACrB,WAAW,EAAE,KAAK,CAAC,UAAU;oBAC7B,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,UAAU,EAAE,kBAAkB,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,OAAO;iBAC9D,CAAC;YACJ,CAAC;YAED,gCAAgC;YAChC,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAClD,CAAC;QAED,2CAA2C;QAC3C,MAAM,aAAa,GAAG,IAAI,aAAa,EAAE,CAAC;QAC1C,IAAI,SAAgC,CAAC;QACrC,IAAI,WAAW,GAAsB,IAAI,CAAC;QAC1C,IAAI,WAAW,GAAuB,IAAI,CAAC;QAE3C,IAAI,CAAC;YACH,oDAAoD;YACpD,IAAI,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/D,2CAA2C;gBAC3C,MAAM,aAAa,GAA2B,EAAE,CAAC;gBACjD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC3D,aAAa,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;gBACrC,CAAC;gBACD,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;YACrD,CAAC;YAED,iCAAiC;YACjC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,WAAW,GAAG,WAAW,CAAC,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;gBAC1D,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,MAAM,IAAI,KAAK,CAAC,iBAAiB,OAAO,CAAC,MAAM,aAAa,CAAC,CAAC;gBAChE,CAAC;YACH,CAAC;YAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,mBAAmB;gBACnB,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;gBAC3E,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;YACxD,CAAC;iBAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClC,+BAA+B;gBAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACvB,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;gBACzD,CAAC;gBACD,sDAAsD;gBACtD,aAAa,CAAC,YAAY,EAAE,CAAC;gBAC7B,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;gBACvE,aAAa,CAAC,EAAE,GAAG,SAAS,CAAC;gBAC7B,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,SAAS,CAAC,EAAE,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;gBACxE,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,kCAAkC,CAAC,CAAC;YACpE,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,SAAS,CAAC,wDAAwD,CAAC,CAAC;YAChF,CAAC;YAED,0BAA0B;YAC1B,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YACrD,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,4BAA4B,CAAC,CAAC;YAE5D,MAAM,UAAU,GAAG,IAAI,UAAU,CAAC,aAAa,CAAC,CAAC;YACjD,UAAU,CAAC,SAAS,GAAG,SAAS,CAAC;YAEjC,yDAAyD;YACzD,UAAU,CAAC,QAAQ,GAAG,aAAa,CAAC,OAAO,IAAI,EAAE,CAAC;YAElD,OAAO,UAAU,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,yBAAyB;YACzB,IAAI,SAAS,EAAE,CAAC;gBACd,+BAA+B;gBAC/B,aAAa,CAAC,EAAE,GAAG,IAAI,CAAC;gBACxB,qBAAqB;gBACrB,SAAS,CAAC,WAAW,EAAE,CAAC;YAC1B,CAAC;YACD,yBAAyB;YACzB,MAAM,aAAa,CAAC,UAAU,EAAE,CAAC;YACjC,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,8BAA8B;YAC9B,IAAI,WAAW,EAAE,CAAC;gBAChB,WAAW,CAAC,IAAI,EAAE,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;OAIG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;;;;;OAMG;IACH,IAAI,QAAQ;QACV,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;QAC7C,IAAI,CAAC,QAAQ,IAAI,QAAQ,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;QACzC,sDAAsD;QACtD,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC;IACpC,CAAC;IAED;;;;OAIG;IACH,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;IAED;;;;OAIG;IACH,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,IAAI,SAAS,CAAC;IACvD,CAAC;IAED;;;;OAIG;IACH,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,QAAQ,IAAI,gBAAgB,CAAC;IAClE,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,KAAK,GAAG,CAAC;QACb,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,KAAK,kBAAkB,CAAC,CAAC;QACzF,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,KAAK,GAAG,CAAC;QACb,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,KAAK,kBAAkB,CAAC,CAAC;QACzF,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED;;;;;;;;;;OAUG;IACH,cAAc,CAAC,IAAiB;QAC9B,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,eAAe,CAAC,CAAC;IAChE,CAAC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,KAAK,CAAC,CAAC,OAAO,CAAC,KAAc;QAC3B,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC5B,MAAM,CAAC,KAAK,EAAE,CAAC;QAEf,IAAI,CAAC;YACH,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACvD,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;oBACZ,uBAAuB;oBACvB,MAAM;gBACR,CAAC;gBAED,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,WAAW,KAAK,KAAK,EAAE,CAAC;oBACxD,gCAAgC;oBAChC,oEAAoE;oBACpE,iEAAiE;oBACjE,+CAA+C;oBAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;oBAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;wBACZ,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;oBAC5D,CAAC;oBACD,MAAM,MAAM,CAAC;gBACf,CAAC;gBACD,gDAAgD;gBAChD,qEAAqE;gBACrE,mEAAmE;gBACnE,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,IAAI,CAAC,SAAiB,EAAE,WAAW,GAAG,CAAC,CAAC,EAAE,QAAoB,WAAW;QAC7E,kCAAkC;QAClC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;IAC9D,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,KAAK;QACT,gEAAgE;QAChE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC,aAAa,CAAC,EAAE,GAAG,IAAI,CAAC;QAC/B,CAAC;QAED,sBAAsB;QACtB,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;QAEtC,uCAAuC;QACvC,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACnB,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC7B,CAAC;IACH,CAAC;IAED;;;;;;;;;;OAUG;IACH,gBAAgB;QACd,OAAO,IAAI,CAAC,aAAa,CAAC;IAC5B,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF"}
|