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.
Files changed (175) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE.md +22 -0
  3. package/README.md +377 -0
  4. package/binding.gyp +78 -0
  5. package/dist/api/bitstream-filter.d.ts +246 -0
  6. package/dist/api/bitstream-filter.js +369 -0
  7. package/dist/api/bitstream-filter.js.map +1 -0
  8. package/dist/api/decoder.d.ts +257 -0
  9. package/dist/api/decoder.js +424 -0
  10. package/dist/api/decoder.js.map +1 -0
  11. package/dist/api/encoder.d.ts +298 -0
  12. package/dist/api/encoder.js +574 -0
  13. package/dist/api/encoder.js.map +1 -0
  14. package/dist/api/filter.d.ts +457 -0
  15. package/dist/api/filter.js +876 -0
  16. package/dist/api/filter.js.map +1 -0
  17. package/dist/api/hardware.d.ts +318 -0
  18. package/dist/api/hardware.js +558 -0
  19. package/dist/api/hardware.js.map +1 -0
  20. package/dist/api/index.d.ts +12 -0
  21. package/dist/api/index.js +20 -0
  22. package/dist/api/index.js.map +1 -0
  23. package/dist/api/io-stream.d.ts +109 -0
  24. package/dist/api/io-stream.js +124 -0
  25. package/dist/api/io-stream.js.map +1 -0
  26. package/dist/api/media-input.d.ts +295 -0
  27. package/dist/api/media-input.js +456 -0
  28. package/dist/api/media-input.js.map +1 -0
  29. package/dist/api/media-output.d.ts +274 -0
  30. package/dist/api/media-output.js +486 -0
  31. package/dist/api/media-output.js.map +1 -0
  32. package/dist/api/pipeline.d.ts +117 -0
  33. package/dist/api/pipeline.js +836 -0
  34. package/dist/api/pipeline.js.map +1 -0
  35. package/dist/api/types.d.ts +440 -0
  36. package/dist/api/types.js +2 -0
  37. package/dist/api/types.js.map +1 -0
  38. package/dist/api/utilities/audio-sample.d.ts +115 -0
  39. package/dist/api/utilities/audio-sample.js +110 -0
  40. package/dist/api/utilities/audio-sample.js.map +1 -0
  41. package/dist/api/utilities/channel-layout.d.ts +83 -0
  42. package/dist/api/utilities/channel-layout.js +87 -0
  43. package/dist/api/utilities/channel-layout.js.map +1 -0
  44. package/dist/api/utilities/image.d.ts +177 -0
  45. package/dist/api/utilities/image.js +183 -0
  46. package/dist/api/utilities/image.js.map +1 -0
  47. package/dist/api/utilities/index.d.ts +8 -0
  48. package/dist/api/utilities/index.js +17 -0
  49. package/dist/api/utilities/index.js.map +1 -0
  50. package/dist/api/utilities/media-type.d.ts +56 -0
  51. package/dist/api/utilities/media-type.js +60 -0
  52. package/dist/api/utilities/media-type.js.map +1 -0
  53. package/dist/api/utilities/pixel-format.d.ts +94 -0
  54. package/dist/api/utilities/pixel-format.js +102 -0
  55. package/dist/api/utilities/pixel-format.js.map +1 -0
  56. package/dist/api/utilities/sample-format.d.ts +132 -0
  57. package/dist/api/utilities/sample-format.js +144 -0
  58. package/dist/api/utilities/sample-format.js.map +1 -0
  59. package/dist/api/utilities/streaming.d.ts +104 -0
  60. package/dist/api/utilities/streaming.js +137 -0
  61. package/dist/api/utilities/streaming.js.map +1 -0
  62. package/dist/api/utilities/timestamp.d.ts +187 -0
  63. package/dist/api/utilities/timestamp.js +200 -0
  64. package/dist/api/utilities/timestamp.js.map +1 -0
  65. package/dist/api/utils.d.ts +61 -0
  66. package/dist/api/utils.js +330 -0
  67. package/dist/api/utils.js.map +1 -0
  68. package/dist/index.d.ts +2 -0
  69. package/dist/index.js +5 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/lib/audio-fifo.d.ts +339 -0
  72. package/dist/lib/audio-fifo.js +365 -0
  73. package/dist/lib/audio-fifo.js.map +1 -0
  74. package/dist/lib/binding.d.ts +192 -0
  75. package/dist/lib/binding.js +70 -0
  76. package/dist/lib/binding.js.map +1 -0
  77. package/dist/lib/bitstream-filter-context.d.ts +345 -0
  78. package/dist/lib/bitstream-filter-context.js +407 -0
  79. package/dist/lib/bitstream-filter-context.js.map +1 -0
  80. package/dist/lib/bitstream-filter.d.ts +124 -0
  81. package/dist/lib/bitstream-filter.js +138 -0
  82. package/dist/lib/bitstream-filter.js.map +1 -0
  83. package/dist/lib/channel-layouts.d.ts +51 -0
  84. package/dist/lib/channel-layouts.js +55 -0
  85. package/dist/lib/channel-layouts.js.map +1 -0
  86. package/dist/lib/codec-context.d.ts +763 -0
  87. package/dist/lib/codec-context.js +974 -0
  88. package/dist/lib/codec-context.js.map +1 -0
  89. package/dist/lib/codec-parameters.d.ts +362 -0
  90. package/dist/lib/codec-parameters.js +460 -0
  91. package/dist/lib/codec-parameters.js.map +1 -0
  92. package/dist/lib/codec-parser.d.ts +185 -0
  93. package/dist/lib/codec-parser.js +193 -0
  94. package/dist/lib/codec-parser.js.map +1 -0
  95. package/dist/lib/codec.d.ts +432 -0
  96. package/dist/lib/codec.js +492 -0
  97. package/dist/lib/codec.js.map +1 -0
  98. package/dist/lib/constants.d.ts +2037 -0
  99. package/dist/lib/constants.js +1659 -0
  100. package/dist/lib/constants.js.map +1 -0
  101. package/dist/lib/dictionary.d.ts +371 -0
  102. package/dist/lib/dictionary.js +406 -0
  103. package/dist/lib/dictionary.js.map +1 -0
  104. package/dist/lib/error.d.ts +216 -0
  105. package/dist/lib/error.js +254 -0
  106. package/dist/lib/error.js.map +1 -0
  107. package/dist/lib/filter-context.d.ts +445 -0
  108. package/dist/lib/filter-context.js +505 -0
  109. package/dist/lib/filter-context.js.map +1 -0
  110. package/dist/lib/filter-graph.d.ts +556 -0
  111. package/dist/lib/filter-graph.js +608 -0
  112. package/dist/lib/filter-graph.js.map +1 -0
  113. package/dist/lib/filter-inout.d.ts +205 -0
  114. package/dist/lib/filter-inout.js +264 -0
  115. package/dist/lib/filter-inout.js.map +1 -0
  116. package/dist/lib/filter.d.ts +231 -0
  117. package/dist/lib/filter.js +260 -0
  118. package/dist/lib/filter.js.map +1 -0
  119. package/dist/lib/format-context.d.ts +798 -0
  120. package/dist/lib/format-context.js +845 -0
  121. package/dist/lib/format-context.js.map +1 -0
  122. package/dist/lib/frame.d.ts +784 -0
  123. package/dist/lib/frame.js +933 -0
  124. package/dist/lib/frame.js.map +1 -0
  125. package/dist/lib/hardware-device-context.d.ts +407 -0
  126. package/dist/lib/hardware-device-context.js +429 -0
  127. package/dist/lib/hardware-device-context.js.map +1 -0
  128. package/dist/lib/hardware-frames-context.d.ts +374 -0
  129. package/dist/lib/hardware-frames-context.js +430 -0
  130. package/dist/lib/hardware-frames-context.js.map +1 -0
  131. package/dist/lib/index.d.ts +31 -0
  132. package/dist/lib/index.js +54 -0
  133. package/dist/lib/index.js.map +1 -0
  134. package/dist/lib/input-format.d.ts +216 -0
  135. package/dist/lib/input-format.js +246 -0
  136. package/dist/lib/input-format.js.map +1 -0
  137. package/dist/lib/io-context.d.ts +495 -0
  138. package/dist/lib/io-context.js +550 -0
  139. package/dist/lib/io-context.js.map +1 -0
  140. package/dist/lib/log.d.ts +201 -0
  141. package/dist/lib/log.js +219 -0
  142. package/dist/lib/log.js.map +1 -0
  143. package/dist/lib/native-types.d.ts +719 -0
  144. package/dist/lib/native-types.js +2 -0
  145. package/dist/lib/native-types.js.map +1 -0
  146. package/dist/lib/option.d.ts +589 -0
  147. package/dist/lib/option.js +853 -0
  148. package/dist/lib/option.js.map +1 -0
  149. package/dist/lib/output-format.d.ts +179 -0
  150. package/dist/lib/output-format.js +205 -0
  151. package/dist/lib/output-format.js.map +1 -0
  152. package/dist/lib/packet.d.ts +487 -0
  153. package/dist/lib/packet.js +558 -0
  154. package/dist/lib/packet.js.map +1 -0
  155. package/dist/lib/rational.d.ts +210 -0
  156. package/dist/lib/rational.js +233 -0
  157. package/dist/lib/rational.js.map +1 -0
  158. package/dist/lib/software-resample-context.d.ts +572 -0
  159. package/dist/lib/software-resample-context.js +610 -0
  160. package/dist/lib/software-resample-context.js.map +1 -0
  161. package/dist/lib/software-scale-context.d.ts +290 -0
  162. package/dist/lib/software-scale-context.js +308 -0
  163. package/dist/lib/software-scale-context.js.map +1 -0
  164. package/dist/lib/stream.d.ts +322 -0
  165. package/dist/lib/stream.js +408 -0
  166. package/dist/lib/stream.js.map +1 -0
  167. package/dist/lib/types.d.ts +59 -0
  168. package/dist/lib/types.js +8 -0
  169. package/dist/lib/types.js.map +1 -0
  170. package/dist/lib/utilities.d.ts +346 -0
  171. package/dist/lib/utilities.js +424 -0
  172. package/dist/lib/utilities.js.map +1 -0
  173. package/install/check.js +113 -0
  174. package/install/ffmpeg.js +163 -0
  175. package/package.json +107 -0
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Decoder - High-level wrapper for media decoding
3
+ *
4
+ * Simplifies FFmpeg's decoding API with automatic codec selection,
5
+ * parameter configuration, and frame management.
6
+ *
7
+ * Handles codec initialization, packet decoding, and frame output.
8
+ * Supports hardware acceleration and zero-copy transcoding.
9
+ *
10
+ * @module api/decoder
11
+ */
12
+ import { CodecContext, Frame } from '../lib/index.js';
13
+ import type { Packet, Stream } from '../lib/index.js';
14
+ import type { DecoderOptions } from './types.js';
15
+ /**
16
+ * High-level decoder for media streams.
17
+ *
18
+ * Handles codec initialization, packet decoding, and frame output.
19
+ * Designed for simple, efficient decoding workflows.
20
+ *
21
+ * Manages codec context lifecycle and provides automatic cleanup.
22
+ * Supports hardware acceleration with zero-copy frame sharing.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // Create decoder for video stream
27
+ * const media = await MediaInput.open('video.mp4');
28
+ * const stream = media.video(); // Get video stream
29
+ * const decoder = await Decoder.create(stream);
30
+ *
31
+ * // Decode packets
32
+ * for await (const packet of media.packets()) {
33
+ * if (packet.streamIndex === stream.index) {
34
+ * const frame = await decoder.decode(packet);
35
+ * if (frame) {
36
+ * console.log(`Decoded frame: ${frame.width}x${frame.height}`);
37
+ * // Process frame...
38
+ * }
39
+ * }
40
+ * }
41
+ *
42
+ * // Flush decoder
43
+ * const lastFrame = await decoder.flush();
44
+ * decoder.close();
45
+ * ```
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * // With hardware acceleration
50
+ * const hw = await HardwareContext.auto();
51
+ * const stream = media.video();
52
+ * const decoder = await Decoder.create(stream, {
53
+ * hardware: hw
54
+ * });
55
+ * // ... use decoder
56
+ * decoder.close();
57
+ * hw?.dispose(); // Safe to call again (no-op)
58
+ * ```
59
+ */
60
+ export declare class Decoder implements Disposable {
61
+ private codecContext;
62
+ private frame;
63
+ private streamIndex;
64
+ private stream;
65
+ private isOpen;
66
+ private hardware?;
67
+ /**
68
+ * Private constructor - use Decoder.create() instead.
69
+ *
70
+ * Initializes the decoder with a codec context and allocates a frame buffer.
71
+ *
72
+ * @param codecContext - Initialized codec context
73
+ * @param stream - The stream this decoder is for
74
+ * @param hardware - Optional hardware context for auto-sharing frames context
75
+ */
76
+ private constructor();
77
+ /**
78
+ * Create a decoder for a specific stream.
79
+ *
80
+ * Factory method that handles codec discovery, context setup,
81
+ * and initialization.
82
+ *
83
+ * Uses avcodec_find_decoder() to locate the appropriate codec,
84
+ * then initializes and opens the codec context.
85
+ *
86
+ * @param stream - Stream to decode
87
+ * @param options - Decoder configuration options
88
+ *
89
+ * @returns Promise resolving to configured Decoder
90
+ *
91
+ * @throws {Error} If codec unavailable
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const media = await MediaInput.open('video.mp4');
96
+ * const stream = media.video();
97
+ * const decoder = await Decoder.create(stream);
98
+ * ```
99
+ */
100
+ static create(stream: Stream, options?: DecoderOptions): Promise<Decoder>;
101
+ /**
102
+ * Check if decoder is open.
103
+ */
104
+ get isDecoderOpen(): boolean;
105
+ /**
106
+ * Decode a packet and return a frame if available.
107
+ *
108
+ * Sends packet to decoder and attempts to receive a frame.
109
+ * May return null if decoder needs more data.
110
+ *
111
+ * Uses avcodec_send_packet() and avcodec_receive_frame() internally.
112
+ * The decoder may buffer packets before producing frames.
113
+ *
114
+ * @param packet - Packet to decode
115
+ *
116
+ * @returns Promise resolving to Frame or null
117
+ *
118
+ * @throws {Error} If decoder is closed or decode fails
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const frame = await decoder.decode(packet);
123
+ * if (frame) {
124
+ * // Process frame
125
+ * }
126
+ * ```
127
+ */
128
+ decode(packet: Packet): Promise<Frame | null>;
129
+ /**
130
+ * Flush decoder and get remaining frames.
131
+ *
132
+ * Sends null packet to trigger flush mode.
133
+ * Call repeatedly until it returns null.
134
+ *
135
+ * Uses avcodec_send_packet(NULL) to signal end of stream.
136
+ * Retrieves buffered frames from the decoder.
137
+ *
138
+ * @returns Promise resolving to Frame or null
139
+ *
140
+ * @throws {Error} If decoder is closed
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * // Flush all remaining frames
145
+ * let frame;
146
+ * while ((frame = await decoder.flush()) !== null) {
147
+ * // Process final frames
148
+ * }
149
+ * ```
150
+ */
151
+ flush(): Promise<Frame | null>;
152
+ /**
153
+ * Flush decoder and yield all remaining frames as a generator.
154
+ *
155
+ * More convenient than calling flush() in a loop.
156
+ * Automatically sends flush signal and yields all buffered frames.
157
+ *
158
+ * IMPORTANT: The yielded frames MUST be freed by the caller!
159
+ * Use 'using' statement or manually call frame.free() to avoid memory leaks.
160
+ *
161
+ * @returns Async generator of remaining frames
162
+ *
163
+ * @throws {Error} If decoder is closed
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * // Process all remaining frames with generator
168
+ * for await (const frame of decoder.flushFrames()) {
169
+ * // Process final frame
170
+ * using _ = frame; // Auto cleanup
171
+ * }
172
+ * ```
173
+ */
174
+ flushFrames(): AsyncGenerator<Frame>;
175
+ /**
176
+ * Async iterator that decodes packets and yields frames.
177
+ *
178
+ * Filters packets for this decoder's stream and yields decoded frames.
179
+ * Automatically handles packet cleanup and decoder flushing.
180
+ *
181
+ * Processes packets in sequence, decoding each and yielding frames.
182
+ * After all packets are processed, flushes the decoder for remaining frames.
183
+ *
184
+ * IMPORTANT: The yielded frames MUST be freed by the caller!
185
+ * Use 'using' statement or manually call frame.free() to avoid memory leaks.
186
+ *
187
+ * @param packets - Async iterable of packets (e.g., from MediaInput.packets())
188
+ *
189
+ * @yields Decoded frames (ownership transferred to caller)
190
+ *
191
+ * @example
192
+ * ```typescript
193
+ * // RECOMMENDED: Use 'using' for automatic cleanup
194
+ * for await (using frame of decoder.frames(media.packets())) {
195
+ * console.log(`Frame: ${frame.width}x${frame.height}`);
196
+ * // Frame is automatically freed at end of iteration
197
+ * }
198
+ *
199
+ * // OR: Manual cleanup
200
+ * for await (const frame of decoder.frames(media.packets())) {
201
+ * console.log(`Frame: ${frame.width}x${frame.height}`);
202
+ * // Process frame...
203
+ * frame.free(); // MUST call free()!
204
+ * }
205
+ * ```
206
+ */
207
+ frames(packets: AsyncIterable<Packet>): AsyncGenerator<Frame>;
208
+ /**
209
+ * Close decoder and free resources.
210
+ *
211
+ * After closing, the decoder cannot be used again.
212
+ *
213
+ * Frees the frame buffer and codec context.
214
+ * Note: Does NOT dispose the HardwareContext - caller is responsible for that.
215
+ */
216
+ close(): void;
217
+ /**
218
+ * Get the stream index this decoder is for.
219
+ */
220
+ getStreamIndex(): number;
221
+ /**
222
+ * Get the original stream this decoder was created from.
223
+ * Used for stream-copy operations in pipeline.
224
+ */
225
+ getStream(): Stream;
226
+ /**
227
+ * Get codec context for advanced configuration.
228
+ *
229
+ * Use with caution - direct manipulation may cause issues.
230
+ *
231
+ * Provides access to the underlying AVCodecContext for advanced operations.
232
+ *
233
+ * @returns CodecContext or null if closed
234
+ *
235
+ * @internal
236
+ */
237
+ getCodecContext(): CodecContext | null;
238
+ /**
239
+ * Receive a frame from the decoder (internal).
240
+ *
241
+ * Internal method to receive decoded frames without conversion.
242
+ *
243
+ * Uses avcodec_receive_frame() to get decoded frames from the codec.
244
+ * Clones the frame for the user to prevent internal buffer corruption.
245
+ *
246
+ * @returns Frame or null if no frame available
247
+ * @internal
248
+ */
249
+ private receiveFrameInternal;
250
+ /**
251
+ * Symbol.dispose for automatic cleanup.
252
+ *
253
+ * Implements the Disposable interface for automatic resource management.
254
+ * Calls close() to free all resources.
255
+ */
256
+ [Symbol.dispose](): void;
257
+ }
@@ -0,0 +1,424 @@
1
+ /**
2
+ * Decoder - High-level wrapper for media decoding
3
+ *
4
+ * Simplifies FFmpeg's decoding API with automatic codec selection,
5
+ * parameter configuration, and frame management.
6
+ *
7
+ * Handles codec initialization, packet decoding, and frame output.
8
+ * Supports hardware acceleration and zero-copy transcoding.
9
+ *
10
+ * @module api/decoder
11
+ */
12
+ import { AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, AVERROR_EAGAIN, AVERROR_EOF, Codec, CodecContext, FFmpegError, Frame } from '../lib/index.js';
13
+ /**
14
+ * High-level decoder for media streams.
15
+ *
16
+ * Handles codec initialization, packet decoding, and frame output.
17
+ * Designed for simple, efficient decoding workflows.
18
+ *
19
+ * Manages codec context lifecycle and provides automatic cleanup.
20
+ * Supports hardware acceleration with zero-copy frame sharing.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * // Create decoder for video stream
25
+ * const media = await MediaInput.open('video.mp4');
26
+ * const stream = media.video(); // Get video stream
27
+ * const decoder = await Decoder.create(stream);
28
+ *
29
+ * // Decode packets
30
+ * for await (const packet of media.packets()) {
31
+ * if (packet.streamIndex === stream.index) {
32
+ * const frame = await decoder.decode(packet);
33
+ * if (frame) {
34
+ * console.log(`Decoded frame: ${frame.width}x${frame.height}`);
35
+ * // Process frame...
36
+ * }
37
+ * }
38
+ * }
39
+ *
40
+ * // Flush decoder
41
+ * const lastFrame = await decoder.flush();
42
+ * decoder.close();
43
+ * ```
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * // With hardware acceleration
48
+ * const hw = await HardwareContext.auto();
49
+ * const stream = media.video();
50
+ * const decoder = await Decoder.create(stream, {
51
+ * hardware: hw
52
+ * });
53
+ * // ... use decoder
54
+ * decoder.close();
55
+ * hw?.dispose(); // Safe to call again (no-op)
56
+ * ```
57
+ */
58
+ export class Decoder {
59
+ codecContext;
60
+ frame;
61
+ streamIndex;
62
+ stream;
63
+ isOpen = true;
64
+ hardware; // Reference to hardware context for auto-sharing frames context
65
+ /**
66
+ * Private constructor - use Decoder.create() instead.
67
+ *
68
+ * Initializes the decoder with a codec context and allocates a frame buffer.
69
+ *
70
+ * @param codecContext - Initialized codec context
71
+ * @param stream - The stream this decoder is for
72
+ * @param hardware - Optional hardware context for auto-sharing frames context
73
+ */
74
+ constructor(codecContext, stream, hardware) {
75
+ this.codecContext = codecContext;
76
+ this.stream = stream;
77
+ this.streamIndex = stream.index;
78
+ this.hardware = hardware;
79
+ this.frame = new Frame();
80
+ this.frame.alloc();
81
+ }
82
+ /**
83
+ * Create a decoder for a specific stream.
84
+ *
85
+ * Factory method that handles codec discovery, context setup,
86
+ * and initialization.
87
+ *
88
+ * Uses avcodec_find_decoder() to locate the appropriate codec,
89
+ * then initializes and opens the codec context.
90
+ *
91
+ * @param stream - Stream to decode
92
+ * @param options - Decoder configuration options
93
+ *
94
+ * @returns Promise resolving to configured Decoder
95
+ *
96
+ * @throws {Error} If codec unavailable
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * const media = await MediaInput.open('video.mp4');
101
+ * const stream = media.video();
102
+ * const decoder = await Decoder.create(stream);
103
+ * ```
104
+ */
105
+ static async create(stream, options = {}) {
106
+ if (!stream) {
107
+ throw new Error('Stream is required');
108
+ }
109
+ // Find decoder for this codec
110
+ const codec = Codec.findDecoder(stream.codecpar.codecId);
111
+ if (!codec) {
112
+ throw new Error(`Decoder not found for codec ${stream.codecpar.codecId}`);
113
+ }
114
+ // Allocate and configure codec context
115
+ const codecContext = new CodecContext();
116
+ codecContext.allocContext3(codec);
117
+ // Copy codec parameters to context
118
+ const ret = codecContext.parametersToContext(stream.codecpar);
119
+ if (ret < 0) {
120
+ codecContext.freeContext();
121
+ FFmpegError.throwIfError(ret, 'Failed to copy codec parameters');
122
+ }
123
+ // Set packet time base
124
+ codecContext.pktTimebase = stream.timeBase;
125
+ // Apply options
126
+ if (options.threads !== undefined) {
127
+ codecContext.threadCount = options.threads;
128
+ }
129
+ // Check if this decoder supports hardware acceleration
130
+ let supportsHardware = false;
131
+ if (options.hardware) {
132
+ // Check decoder's hardware configurations
133
+ for (let i = 0;; i++) {
134
+ const config = codec.getHwConfig(i);
135
+ if (!config)
136
+ break;
137
+ // Check if decoder supports HW_DEVICE_CTX method with matching device type
138
+ if ((config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) !== 0 && config.deviceType === options.hardware.deviceType) {
139
+ supportsHardware = true;
140
+ break;
141
+ }
142
+ }
143
+ // Only apply hardware acceleration if the decoder supports it
144
+ if (supportsHardware) {
145
+ codecContext.hwDeviceCtx = options.hardware.deviceContext;
146
+ }
147
+ // Silently ignore hardware for software decoders
148
+ }
149
+ // Apply codec-specific options via AVOptions
150
+ if (options.options) {
151
+ for (const [key, value] of Object.entries(options.options)) {
152
+ codecContext.setOption(key, value.toString());
153
+ }
154
+ }
155
+ // Open codec
156
+ const openRet = await codecContext.open2(codec, null);
157
+ if (openRet < 0) {
158
+ codecContext.freeContext();
159
+ FFmpegError.throwIfError(openRet, 'Failed to open codec');
160
+ }
161
+ const decoder = new Decoder(codecContext, stream, options.hardware);
162
+ return decoder;
163
+ }
164
+ /**
165
+ * Check if decoder is open.
166
+ */
167
+ get isDecoderOpen() {
168
+ return this.isOpen;
169
+ }
170
+ /**
171
+ * Decode a packet and return a frame if available.
172
+ *
173
+ * Sends packet to decoder and attempts to receive a frame.
174
+ * May return null if decoder needs more data.
175
+ *
176
+ * Uses avcodec_send_packet() and avcodec_receive_frame() internally.
177
+ * The decoder may buffer packets before producing frames.
178
+ *
179
+ * @param packet - Packet to decode
180
+ *
181
+ * @returns Promise resolving to Frame or null
182
+ *
183
+ * @throws {Error} If decoder is closed or decode fails
184
+ *
185
+ * @example
186
+ * ```typescript
187
+ * const frame = await decoder.decode(packet);
188
+ * if (frame) {
189
+ * // Process frame
190
+ * }
191
+ * ```
192
+ */
193
+ async decode(packet) {
194
+ if (!this.isOpen) {
195
+ throw new Error('Decoder is closed');
196
+ }
197
+ // Send packet to decoder
198
+ const sendRet = await this.codecContext.sendPacket(packet);
199
+ if (sendRet < 0 && sendRet !== AVERROR_EOF) {
200
+ // Decoder might be full, try to receive first
201
+ const frame = await this.receiveFrameInternal();
202
+ if (frame) {
203
+ return frame;
204
+ }
205
+ // If still failing, it's an error
206
+ if (sendRet !== AVERROR_EAGAIN) {
207
+ FFmpegError.throwIfError(sendRet, 'Failed to send packet');
208
+ }
209
+ }
210
+ // Try to receive frame
211
+ const frame = await this.receiveFrameInternal();
212
+ return frame;
213
+ }
214
+ /**
215
+ * Flush decoder and get remaining frames.
216
+ *
217
+ * Sends null packet to trigger flush mode.
218
+ * Call repeatedly until it returns null.
219
+ *
220
+ * Uses avcodec_send_packet(NULL) to signal end of stream.
221
+ * Retrieves buffered frames from the decoder.
222
+ *
223
+ * @returns Promise resolving to Frame or null
224
+ *
225
+ * @throws {Error} If decoder is closed
226
+ *
227
+ * @example
228
+ * ```typescript
229
+ * // Flush all remaining frames
230
+ * let frame;
231
+ * while ((frame = await decoder.flush()) !== null) {
232
+ * // Process final frames
233
+ * }
234
+ * ```
235
+ */
236
+ async flush() {
237
+ if (!this.isOpen) {
238
+ throw new Error('Decoder is closed');
239
+ }
240
+ // Send flush packet (null)
241
+ await this.codecContext.sendPacket(null);
242
+ // Receive frame
243
+ const frame = await this.receiveFrameInternal();
244
+ return frame;
245
+ }
246
+ /**
247
+ * Flush decoder and yield all remaining frames as a generator.
248
+ *
249
+ * More convenient than calling flush() in a loop.
250
+ * Automatically sends flush signal and yields all buffered frames.
251
+ *
252
+ * IMPORTANT: The yielded frames MUST be freed by the caller!
253
+ * Use 'using' statement or manually call frame.free() to avoid memory leaks.
254
+ *
255
+ * @returns Async generator of remaining frames
256
+ *
257
+ * @throws {Error} If decoder is closed
258
+ *
259
+ * @example
260
+ * ```typescript
261
+ * // Process all remaining frames with generator
262
+ * for await (const frame of decoder.flushFrames()) {
263
+ * // Process final frame
264
+ * using _ = frame; // Auto cleanup
265
+ * }
266
+ * ```
267
+ */
268
+ async *flushFrames() {
269
+ if (!this.isOpen) {
270
+ throw new Error('Decoder is closed');
271
+ }
272
+ let frame;
273
+ while ((frame = await this.flush()) !== null) {
274
+ yield frame;
275
+ }
276
+ }
277
+ /**
278
+ * Async iterator that decodes packets and yields frames.
279
+ *
280
+ * Filters packets for this decoder's stream and yields decoded frames.
281
+ * Automatically handles packet cleanup and decoder flushing.
282
+ *
283
+ * Processes packets in sequence, decoding each and yielding frames.
284
+ * After all packets are processed, flushes the decoder for remaining frames.
285
+ *
286
+ * IMPORTANT: The yielded frames MUST be freed by the caller!
287
+ * Use 'using' statement or manually call frame.free() to avoid memory leaks.
288
+ *
289
+ * @param packets - Async iterable of packets (e.g., from MediaInput.packets())
290
+ *
291
+ * @yields Decoded frames (ownership transferred to caller)
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * // RECOMMENDED: Use 'using' for automatic cleanup
296
+ * for await (using frame of decoder.frames(media.packets())) {
297
+ * console.log(`Frame: ${frame.width}x${frame.height}`);
298
+ * // Frame is automatically freed at end of iteration
299
+ * }
300
+ *
301
+ * // OR: Manual cleanup
302
+ * for await (const frame of decoder.frames(media.packets())) {
303
+ * console.log(`Frame: ${frame.width}x${frame.height}`);
304
+ * // Process frame...
305
+ * frame.free(); // MUST call free()!
306
+ * }
307
+ * ```
308
+ */
309
+ async *frames(packets) {
310
+ if (!this.isOpen) {
311
+ throw new Error('Decoder is closed');
312
+ }
313
+ // Process packets
314
+ for await (const packet of packets) {
315
+ try {
316
+ // Only process packets for our stream
317
+ if (packet.streamIndex === this.streamIndex) {
318
+ const frame = await this.decode(packet);
319
+ if (frame) {
320
+ yield frame;
321
+ }
322
+ }
323
+ }
324
+ finally {
325
+ // Free the input packet after processing
326
+ packet.free();
327
+ }
328
+ }
329
+ // Flush decoder after all packets
330
+ let frame;
331
+ while ((frame = await this.flush()) !== null) {
332
+ yield frame;
333
+ }
334
+ }
335
+ /**
336
+ * Close decoder and free resources.
337
+ *
338
+ * After closing, the decoder cannot be used again.
339
+ *
340
+ * Frees the frame buffer and codec context.
341
+ * Note: Does NOT dispose the HardwareContext - caller is responsible for that.
342
+ */
343
+ close() {
344
+ if (!this.isOpen)
345
+ return;
346
+ this.frame.free();
347
+ this.codecContext.freeContext();
348
+ // NOTE: We do NOT dispose the hardware context here
349
+ // The caller who created the HardwareContext is responsible for disposing it
350
+ // This allows reusing the same HardwareContext for multiple decoders
351
+ this.isOpen = false;
352
+ }
353
+ /**
354
+ * Get the stream index this decoder is for.
355
+ */
356
+ getStreamIndex() {
357
+ return this.streamIndex;
358
+ }
359
+ /**
360
+ * Get the original stream this decoder was created from.
361
+ * Used for stream-copy operations in pipeline.
362
+ */
363
+ getStream() {
364
+ return this.stream;
365
+ }
366
+ /**
367
+ * Get codec context for advanced configuration.
368
+ *
369
+ * Use with caution - direct manipulation may cause issues.
370
+ *
371
+ * Provides access to the underlying AVCodecContext for advanced operations.
372
+ *
373
+ * @returns CodecContext or null if closed
374
+ *
375
+ * @internal
376
+ */
377
+ getCodecContext() {
378
+ return this.isOpen ? this.codecContext : null;
379
+ }
380
+ /**
381
+ * Receive a frame from the decoder (internal).
382
+ *
383
+ * Internal method to receive decoded frames without conversion.
384
+ *
385
+ * Uses avcodec_receive_frame() to get decoded frames from the codec.
386
+ * Clones the frame for the user to prevent internal buffer corruption.
387
+ *
388
+ * @returns Frame or null if no frame available
389
+ * @internal
390
+ */
391
+ async receiveFrameInternal() {
392
+ // Clear previous frame data
393
+ this.frame.unref();
394
+ const ret = await this.codecContext.receiveFrame(this.frame);
395
+ if (ret === 0) {
396
+ // Set hw_frames_ctx from frame for other components to share
397
+ // This is THE moment when hw_frames_ctx becomes available
398
+ if (this.hardware && this.frame.hwFramesCtx) {
399
+ this.hardware.framesContext = this.frame.hwFramesCtx;
400
+ }
401
+ // Got a frame, clone it for the user
402
+ return this.frame.clone();
403
+ }
404
+ else if (ret === AVERROR_EAGAIN || ret === AVERROR_EOF) {
405
+ // Need more data or end of stream
406
+ return null;
407
+ }
408
+ else {
409
+ // Error
410
+ FFmpegError.throwIfError(ret, 'Failed to receive frame');
411
+ return null;
412
+ }
413
+ }
414
+ /**
415
+ * Symbol.dispose for automatic cleanup.
416
+ *
417
+ * Implements the Disposable interface for automatic resource management.
418
+ * Calls close() to free all resources.
419
+ */
420
+ [Symbol.dispose]() {
421
+ this.close();
422
+ }
423
+ }
424
+ //# sourceMappingURL=decoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decoder.js","sourceRoot":"","sources":["../../src/api/decoder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,uCAAuC,EAAE,cAAc,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAMhJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,OAAO,OAAO;IACV,YAAY,CAAe;IAC3B,KAAK,CAAQ;IACb,WAAW,CAAS;IACpB,MAAM,CAAS;IACf,MAAM,GAAG,IAAI,CAAC;IACd,QAAQ,CAA0B,CAAC,gEAAgE;IAE3G;;;;;;;;OAQG;IACH,YAAoB,YAA0B,EAAE,MAAc,EAAE,QAAiC;QAC/F,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC;QAChC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,UAA0B,EAAE;QAC9D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxC,CAAC;QAED,8BAA8B;QAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,+BAA+B,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,uCAAuC;QACvC,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;QACxC,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAElC,mCAAmC;QACnC,MAAM,GAAG,GAAG,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9D,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC;YACZ,YAAY,CAAC,WAAW,EAAE,CAAC;YAC3B,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,iCAAiC,CAAC,CAAC;QACnE,CAAC;QAED,uBAAuB;QACvB,YAAY,CAAC,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC;QAE3C,gBAAgB;QAChB,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAClC,YAAY,CAAC,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;QAC7C,CAAC;QAED,uDAAuD;QACvD,IAAI,gBAAgB,GAAG,KAAK,CAAC;QAC7B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,0CAA0C;YAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,GAAI,CAAC,EAAE,EAAE,CAAC;gBACtB,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;gBACpC,IAAI,CAAC,MAAM;oBAAE,MAAM;gBAEnB,2EAA2E;gBAC3E,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,uCAAuC,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;oBAC1H,gBAAgB,GAAG,IAAI,CAAC;oBACxB,MAAM;gBACR,CAAC;YACH,CAAC;YAED,8DAA8D;YAC9D,IAAI,gBAAgB,EAAE,CAAC;gBACrB,YAAY,CAAC,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;YAC5D,CAAC;YACD,iDAAiD;QACnD,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,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,sBAAsB,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;QACpE,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;OAEG;IACH,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,KAAK,CAAC,MAAM,CAAC,MAAc;QACzB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,yBAAyB;QACzB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC3D,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;YAC3C,8CAA8C;YAC9C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAChD,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,KAAK,CAAC;YACf,CAAC;YAED,kCAAkC;YAClC,IAAI,OAAO,KAAK,cAAc,EAAE,CAAC;gBAC/B,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAED,uBAAuB;QACvB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,2BAA2B;QAC3B,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAEzC,gBAAgB;QAChB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,CAAC,WAAW;QAChB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,KAAK,CAAC;QACV,OAAO,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;YAC7C,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,KAAK,CAAC,CAAC,MAAM,CAAC,OAA8B;QAC1C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACvC,CAAC;QAED,kBAAkB;QAClB,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,sCAAsC;gBACtC,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;oBAC5C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACxC,IAAI,KAAK,EAAE,CAAC;wBACV,MAAM,KAAK,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC;oBAAS,CAAC;gBACT,yCAAyC;gBACzC,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,IAAI,KAAK,CAAC;QACV,OAAO,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;YAC7C,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;QAEhC,oDAAoD;QACpD,6EAA6E;QAC7E,qEAAqE;QAErE,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;;;;;;;;;OAUG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAED;;;;;;;;;;OAUG;IACK,KAAK,CAAC,oBAAoB;QAChC,4BAA4B;QAC5B,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAEnB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE7D,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;YACd,6DAA6D;YAC7D,0DAA0D;YAC1D,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;gBAC5C,IAAI,CAAC,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;YACvD,CAAC;YAED,qCAAqC;YACrC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,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,yBAAyB,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,CAAC,MAAM,CAAC,OAAO,CAAC;QACd,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;CACF"}