node-av 3.1.3 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/README.md +88 -52
  2. package/binding.gyp +23 -11
  3. package/dist/api/audio-frame-buffer.d.ts +201 -0
  4. package/dist/api/audio-frame-buffer.js +275 -0
  5. package/dist/api/audio-frame-buffer.js.map +1 -0
  6. package/dist/api/bitstream-filter.d.ts +320 -78
  7. package/dist/api/bitstream-filter.js +684 -151
  8. package/dist/api/bitstream-filter.js.map +1 -1
  9. package/dist/api/constants.d.ts +44 -0
  10. package/dist/api/constants.js +45 -0
  11. package/dist/api/constants.js.map +1 -0
  12. package/dist/api/data/test_av1.ivf +0 -0
  13. package/dist/api/data/test_mjpeg.mjpeg +0 -0
  14. package/dist/api/data/test_vp8.ivf +0 -0
  15. package/dist/api/data/test_vp9.ivf +0 -0
  16. package/dist/api/decoder.d.ts +454 -77
  17. package/dist/api/decoder.js +1081 -271
  18. package/dist/api/decoder.js.map +1 -1
  19. package/dist/api/{media-input.d.ts → demuxer.d.ts} +295 -45
  20. package/dist/api/demuxer.js +1965 -0
  21. package/dist/api/demuxer.js.map +1 -0
  22. package/dist/api/encoder.d.ts +423 -132
  23. package/dist/api/encoder.js +1089 -240
  24. package/dist/api/encoder.js.map +1 -1
  25. package/dist/api/filter-complex.d.ts +769 -0
  26. package/dist/api/filter-complex.js +1596 -0
  27. package/dist/api/filter-complex.js.map +1 -0
  28. package/dist/api/filter-presets.d.ts +80 -5
  29. package/dist/api/filter-presets.js +117 -7
  30. package/dist/api/filter-presets.js.map +1 -1
  31. package/dist/api/filter.d.ts +561 -125
  32. package/dist/api/filter.js +1083 -274
  33. package/dist/api/filter.js.map +1 -1
  34. package/dist/api/{fmp4.d.ts → fmp4-stream.d.ts} +141 -140
  35. package/dist/api/fmp4-stream.js +539 -0
  36. package/dist/api/fmp4-stream.js.map +1 -0
  37. package/dist/api/hardware.d.ts +58 -6
  38. package/dist/api/hardware.js +127 -11
  39. package/dist/api/hardware.js.map +1 -1
  40. package/dist/api/index.d.ts +8 -4
  41. package/dist/api/index.js +17 -8
  42. package/dist/api/index.js.map +1 -1
  43. package/dist/api/io-stream.d.ts +6 -6
  44. package/dist/api/io-stream.js +5 -4
  45. package/dist/api/io-stream.js.map +1 -1
  46. package/dist/api/{media-output.d.ts → muxer.d.ts} +280 -66
  47. package/dist/api/muxer.js +1934 -0
  48. package/dist/api/muxer.js.map +1 -0
  49. package/dist/api/pipeline.d.ts +77 -29
  50. package/dist/api/pipeline.js +449 -439
  51. package/dist/api/pipeline.js.map +1 -1
  52. package/dist/api/rtp-stream.d.ts +312 -0
  53. package/dist/api/rtp-stream.js +630 -0
  54. package/dist/api/rtp-stream.js.map +1 -0
  55. package/dist/api/types.d.ts +533 -56
  56. package/dist/api/utilities/async-queue.d.ts +91 -0
  57. package/dist/api/utilities/async-queue.js +162 -0
  58. package/dist/api/utilities/async-queue.js.map +1 -0
  59. package/dist/api/utilities/audio-sample.d.ts +11 -1
  60. package/dist/api/utilities/audio-sample.js +10 -0
  61. package/dist/api/utilities/audio-sample.js.map +1 -1
  62. package/dist/api/utilities/channel-layout.d.ts +1 -0
  63. package/dist/api/utilities/channel-layout.js +1 -0
  64. package/dist/api/utilities/channel-layout.js.map +1 -1
  65. package/dist/api/utilities/image.d.ts +39 -1
  66. package/dist/api/utilities/image.js +38 -0
  67. package/dist/api/utilities/image.js.map +1 -1
  68. package/dist/api/utilities/index.d.ts +3 -0
  69. package/dist/api/utilities/index.js +6 -0
  70. package/dist/api/utilities/index.js.map +1 -1
  71. package/dist/api/utilities/media-type.d.ts +2 -1
  72. package/dist/api/utilities/media-type.js +1 -0
  73. package/dist/api/utilities/media-type.js.map +1 -1
  74. package/dist/api/utilities/pixel-format.d.ts +4 -1
  75. package/dist/api/utilities/pixel-format.js +3 -0
  76. package/dist/api/utilities/pixel-format.js.map +1 -1
  77. package/dist/api/utilities/sample-format.d.ts +6 -1
  78. package/dist/api/utilities/sample-format.js +5 -0
  79. package/dist/api/utilities/sample-format.js.map +1 -1
  80. package/dist/api/utilities/scheduler.d.ts +138 -0
  81. package/dist/api/utilities/scheduler.js +98 -0
  82. package/dist/api/utilities/scheduler.js.map +1 -0
  83. package/dist/api/utilities/streaming.d.ts +105 -15
  84. package/dist/api/utilities/streaming.js +201 -12
  85. package/dist/api/utilities/streaming.js.map +1 -1
  86. package/dist/api/utilities/timestamp.d.ts +15 -1
  87. package/dist/api/utilities/timestamp.js +14 -0
  88. package/dist/api/utilities/timestamp.js.map +1 -1
  89. package/dist/api/utilities/whisper-model.d.ts +310 -0
  90. package/dist/api/utilities/whisper-model.js +528 -0
  91. package/dist/api/utilities/whisper-model.js.map +1 -0
  92. package/dist/api/webrtc-stream.d.ts +288 -0
  93. package/dist/api/webrtc-stream.js +440 -0
  94. package/dist/api/webrtc-stream.js.map +1 -0
  95. package/dist/api/whisper.d.ts +324 -0
  96. package/dist/api/whisper.js +362 -0
  97. package/dist/api/whisper.js.map +1 -0
  98. package/dist/constants/constants.d.ts +54 -2
  99. package/dist/constants/constants.js +48 -1
  100. package/dist/constants/constants.js.map +1 -1
  101. package/dist/constants/encoders.d.ts +2 -1
  102. package/dist/constants/encoders.js +4 -3
  103. package/dist/constants/encoders.js.map +1 -1
  104. package/dist/constants/hardware.d.ts +26 -0
  105. package/dist/constants/hardware.js +27 -0
  106. package/dist/constants/hardware.js.map +1 -0
  107. package/dist/constants/index.d.ts +1 -0
  108. package/dist/constants/index.js +1 -0
  109. package/dist/constants/index.js.map +1 -1
  110. package/dist/ffmpeg/index.d.ts +3 -3
  111. package/dist/ffmpeg/index.js +3 -3
  112. package/dist/ffmpeg/utils.d.ts +27 -0
  113. package/dist/ffmpeg/utils.js +28 -16
  114. package/dist/ffmpeg/utils.js.map +1 -1
  115. package/dist/lib/binding.d.ts +22 -11
  116. package/dist/lib/binding.js.map +1 -1
  117. package/dist/lib/codec-context.d.ts +87 -0
  118. package/dist/lib/codec-context.js +125 -4
  119. package/dist/lib/codec-context.js.map +1 -1
  120. package/dist/lib/codec-parameters.d.ts +229 -1
  121. package/dist/lib/codec-parameters.js +264 -0
  122. package/dist/lib/codec-parameters.js.map +1 -1
  123. package/dist/lib/codec-parser.d.ts +23 -0
  124. package/dist/lib/codec-parser.js +25 -0
  125. package/dist/lib/codec-parser.js.map +1 -1
  126. package/dist/lib/codec.d.ts +26 -4
  127. package/dist/lib/codec.js +35 -0
  128. package/dist/lib/codec.js.map +1 -1
  129. package/dist/lib/dictionary.js +1 -0
  130. package/dist/lib/dictionary.js.map +1 -1
  131. package/dist/lib/error.js +1 -1
  132. package/dist/lib/error.js.map +1 -1
  133. package/dist/lib/fifo.d.ts +416 -0
  134. package/dist/lib/fifo.js +453 -0
  135. package/dist/lib/fifo.js.map +1 -0
  136. package/dist/lib/filter-context.d.ts +52 -11
  137. package/dist/lib/filter-context.js +56 -12
  138. package/dist/lib/filter-context.js.map +1 -1
  139. package/dist/lib/filter-graph.d.ts +9 -0
  140. package/dist/lib/filter-graph.js +13 -0
  141. package/dist/lib/filter-graph.js.map +1 -1
  142. package/dist/lib/filter.d.ts +21 -0
  143. package/dist/lib/filter.js +28 -0
  144. package/dist/lib/filter.js.map +1 -1
  145. package/dist/lib/format-context.d.ts +48 -14
  146. package/dist/lib/format-context.js +76 -7
  147. package/dist/lib/format-context.js.map +1 -1
  148. package/dist/lib/frame.d.ts +264 -1
  149. package/dist/lib/frame.js +351 -1
  150. package/dist/lib/frame.js.map +1 -1
  151. package/dist/lib/hardware-device-context.d.ts +3 -2
  152. package/dist/lib/hardware-device-context.js.map +1 -1
  153. package/dist/lib/index.d.ts +2 -0
  154. package/dist/lib/index.js +4 -0
  155. package/dist/lib/index.js.map +1 -1
  156. package/dist/lib/input-format.d.ts +21 -0
  157. package/dist/lib/input-format.js +42 -2
  158. package/dist/lib/input-format.js.map +1 -1
  159. package/dist/lib/native-types.d.ts +76 -27
  160. package/dist/lib/option.d.ts +25 -13
  161. package/dist/lib/option.js +28 -0
  162. package/dist/lib/option.js.map +1 -1
  163. package/dist/lib/output-format.d.ts +22 -1
  164. package/dist/lib/output-format.js +28 -0
  165. package/dist/lib/output-format.js.map +1 -1
  166. package/dist/lib/packet.d.ts +35 -0
  167. package/dist/lib/packet.js +52 -2
  168. package/dist/lib/packet.js.map +1 -1
  169. package/dist/lib/rational.d.ts +18 -0
  170. package/dist/lib/rational.js +19 -0
  171. package/dist/lib/rational.js.map +1 -1
  172. package/dist/lib/stream.d.ts +126 -0
  173. package/dist/lib/stream.js +188 -5
  174. package/dist/lib/stream.js.map +1 -1
  175. package/dist/lib/sync-queue.d.ts +179 -0
  176. package/dist/lib/sync-queue.js +197 -0
  177. package/dist/lib/sync-queue.js.map +1 -0
  178. package/dist/lib/types.d.ts +49 -1
  179. package/dist/lib/utilities.d.ts +281 -53
  180. package/dist/lib/utilities.js +298 -55
  181. package/dist/lib/utilities.js.map +1 -1
  182. package/install/check.js +2 -2
  183. package/package.json +37 -26
  184. package/dist/api/fmp4.js +0 -710
  185. package/dist/api/fmp4.js.map +0 -1
  186. package/dist/api/media-input.js +0 -1075
  187. package/dist/api/media-input.js.map +0 -1
  188. package/dist/api/media-output.js +0 -1040
  189. package/dist/api/media-output.js.map +0 -1
  190. package/dist/api/webrtc.d.ts +0 -664
  191. package/dist/api/webrtc.js +0 -1132
  192. package/dist/api/webrtc.js.map +0 -1
@@ -1,8 +1,9 @@
1
1
  import { HardwareFramesContext } from './hardware-frames-context.js';
2
2
  import { Rational } from './rational.js';
3
3
  import type { AVChromaLocation, AVColorPrimaries, AVColorRange, AVColorSpace, AVColorTransferCharacteristic, AVFrameSideDataType, AVMediaType, AVPictureType, AVPixelFormat, AVSampleFormat } from '../constants/constants.js';
4
+ import { Dictionary } from './dictionary.js';
4
5
  import type { NativeFrame, NativeWrapper } from './native-types.js';
5
- import type { ChannelLayout } from './types.js';
6
+ import type { AudioFrame, ChannelLayout, VideoFrame } from './types.js';
6
7
  /**
7
8
  * Container for uncompressed audio/video data.
8
9
  *
@@ -49,6 +50,63 @@ export declare class Frame implements Disposable, NativeWrapper<NativeFrame> {
49
50
  private native;
50
51
  private _hwFramesCtx?;
51
52
  constructor();
53
+ /**
54
+ * Create a video frame from a buffer with pixel data.
55
+ *
56
+ * Allocates frame buffers, sets properties, and copies buffer data.
57
+ * Convenience factory method that combines frame allocation and data copy.
58
+ *
59
+ * @param buffer - Buffer containing raw pixel data
60
+ *
61
+ * @param props - Video Frame properties
62
+ *
63
+ * @returns Allocated frame with data from buffer
64
+ *
65
+ * @throws {FFmpegError} If allocation or buffer copy fails
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * import { Frame, AV_PIX_FMT_RGBA, FFmpegError } from 'node-av';
70
+ *
71
+ * const rawPixels = Buffer.alloc(1920 * 1080 * 4); // RGBA data
72
+ * using frame = Frame.fromVideoBuffer(rawPixels, {
73
+ * width: 1920,
74
+ * height: 1080,
75
+ * format: AV_PIX_FMT_RGBA,
76
+ * timeBase: { num: 1, den: 30 }
77
+ * });
78
+ * ```
79
+ */
80
+ static fromVideoBuffer(buffer: Buffer, props: VideoFrame): Frame;
81
+ /**
82
+ * Create an audio frame from a buffer with sample data.
83
+ *
84
+ * Allocates frame buffers, sets properties, and copies buffer data.
85
+ * Convenience factory method that combines frame allocation and data copy.
86
+ *
87
+ * @param buffer - Buffer containing raw audio samples
88
+ *
89
+ * @param props - Frame properties
90
+ *
91
+ * @returns Allocated frame with data from buffer
92
+ *
93
+ * @throws {FFmpegError} If allocation or buffer copy fails
94
+ *
95
+ * @example
96
+ * ```typescript
97
+ * import { Frame, AV_SAMPLE_FMT_FLT, AV_CH_LAYOUT_STEREO, FFmpegError } from 'node-av';
98
+ *
99
+ * const samples = Buffer.alloc(960 * 2 * 4); // 960 samples, stereo, float32
100
+ * using frame = Frame.fromAudioBuffer(samples, {
101
+ * nbSamples: 960,
102
+ * format: AV_SAMPLE_FMT_FLT,
103
+ * sampleRate: 48000,
104
+ * channelLayout: AV_CH_LAYOUT_STEREO,
105
+ * timeBase: { num: 1, den: 48000 }
106
+ * });
107
+ * ```
108
+ */
109
+ static fromAudioBuffer(buffer: Buffer, props: AudioFrame): Frame;
52
110
  /**
53
111
  * Pixel format for video frames or sample format for audio.
54
112
  *
@@ -134,6 +192,17 @@ export declare class Frame implements Disposable, NativeWrapper<NativeFrame> {
134
192
  */
135
193
  get pictType(): AVPictureType;
136
194
  set pictType(value: AVPictureType);
195
+ /**
196
+ * Quality (between 1 (good) and FF_LAMBDA_MAX (bad)).
197
+ *
198
+ * Set by libavcodec for some coded frames.
199
+ * Can be set before encoding to specify desired quality for encoders that support it.
200
+ * Used by FFmpeg CLI's frame_encode() to propagate encoder's global_quality setting.
201
+ *
202
+ * Direct mapping to AVFrame->quality.
203
+ */
204
+ get quality(): number;
205
+ set quality(value: number);
137
206
  /**
138
207
  * Sample aspect ratio.
139
208
  *
@@ -254,6 +323,133 @@ export declare class Frame implements Disposable, NativeWrapper<NativeFrame> {
254
323
  */
255
324
  get hwFramesCtx(): HardwareFramesContext | null;
256
325
  set hwFramesCtx(value: HardwareFramesContext | null);
326
+ /**
327
+ * Frame flags.
328
+ *
329
+ * Combination of AVFrameFlags (e.g., AV_FRAME_FLAG_CORRUPT, AV_FRAME_FLAG_KEY).
330
+ *
331
+ * Direct mapping to AVFrame->flags.
332
+ */
333
+ get flags(): number;
334
+ set flags(value: number);
335
+ /**
336
+ * Decode error flags.
337
+ *
338
+ * Indicates errors detected during decoding.
339
+ * Non-zero value means the frame may be corrupted.
340
+ *
341
+ * Direct mapping to AVFrame->decode_error_flags.
342
+ */
343
+ get decodeErrorFlags(): number;
344
+ set decodeErrorFlags(value: number);
345
+ /**
346
+ * Frame duration.
347
+ *
348
+ * Duration of this frame in units of time_base.
349
+ * This is FFmpeg's best guess for how long the frame should be displayed.
350
+ * May be 0 if unknown or unavailable.
351
+ *
352
+ * Direct mapping to AVFrame->duration.
353
+ */
354
+ get duration(): bigint;
355
+ set duration(value: bigint);
356
+ /**
357
+ * Number of fields in this frame that should be repeated.
358
+ *
359
+ * For interlaced video, indicates how many times the frame should be repeated
360
+ * when displayed. For progressive video, this is typically 0.
361
+ * Formula: display_time = (repeat_pict / (2*fps))
362
+ *
363
+ * Direct mapping to AVFrame->repeat_pict.
364
+ */
365
+ get repeatPict(): number;
366
+ set repeatPict(value: number);
367
+ /**
368
+ * Set frame flags.
369
+ *
370
+ * Sets one or more flags using bitwise OR. Allows setting multiple flags
371
+ * without manually performing bitwise operations.
372
+ *
373
+ * @param flags - One or more flag values to set
374
+ *
375
+ * @example
376
+ * ```typescript
377
+ * import { AV_FRAME_FLAG_KEY } from 'node-av/constants';
378
+ *
379
+ * // Mark frame as key frame
380
+ * frame.setFlags(AV_FRAME_FLAG_KEY);
381
+ * ```
382
+ *
383
+ * @see {@link clearFlags} To unset flags
384
+ * @see {@link hasFlags} To check flags
385
+ * @see {@link flags} For direct flag access
386
+ */
387
+ setFlags(...flags: number[]): void;
388
+ /**
389
+ * Clear frame flags.
390
+ *
391
+ * Clears one or more flags using bitwise AND NOT. Allows clearing multiple
392
+ * flags without manually performing bitwise operations.
393
+ *
394
+ * @param flags - One or more flag values to clear
395
+ *
396
+ * @example
397
+ * ```typescript
398
+ * import { AV_FRAME_FLAG_CORRUPT } from 'node-av/constants';
399
+ *
400
+ * // Clear corrupt flag
401
+ * frame.clearFlags(AV_FRAME_FLAG_CORRUPT);
402
+ * ```
403
+ *
404
+ * @see {@link setFlags} To set flags
405
+ * @see {@link hasFlags} To check flags
406
+ * @see {@link flags} For direct flag access
407
+ */
408
+ clearFlags(...flags: number[]): void;
409
+ /**
410
+ * Check if frame has specific flags.
411
+ *
412
+ * Tests whether all specified flags are set using bitwise AND.
413
+ *
414
+ * @param flags - One or more flag values to check
415
+ *
416
+ * @returns true if all specified flags are set, false otherwise
417
+ *
418
+ * @example
419
+ * ```typescript
420
+ * import { AV_FRAME_FLAG_CORRUPT } from 'node-av/constants';
421
+ *
422
+ * if (frame.hasFlags(AV_FRAME_FLAG_CORRUPT)) {
423
+ * console.log('Frame is corrupted');
424
+ * }
425
+ * ```
426
+ *
427
+ * @see {@link setFlags} To set flags
428
+ * @see {@link clearFlags} To unset flags
429
+ * @see {@link flags} For direct flag access
430
+ */
431
+ hasFlags(...flags: number[]): boolean;
432
+ /**
433
+ * Check if frame has decode errors.
434
+ *
435
+ * Tests whether all specified decode error flags are set using bitwise AND.
436
+ *
437
+ * @param flags - One or more decode error flag values to check
438
+ *
439
+ * @returns true if all specified error flags are set, false otherwise
440
+ *
441
+ * @example
442
+ * ```typescript
443
+ * import { FF_DECODE_ERROR_INVALID_BITSTREAM } from 'node-av/constants';
444
+ *
445
+ * if (frame.hasDecodeErrorFlags(FF_DECODE_ERROR_INVALID_BITSTREAM)) {
446
+ * console.log('Frame has invalid bitstream error');
447
+ * }
448
+ * ```
449
+ *
450
+ * @see {@link decodeErrorFlags} For direct error flag access
451
+ */
452
+ hasDecodeErrorFlags(...flags: number[]): boolean;
257
453
  /**
258
454
  * Check if this is a video frame.
259
455
  *
@@ -783,6 +979,73 @@ export declare class Frame implements Disposable, NativeWrapper<NativeFrame> {
783
979
  * @see {@link newSideData} To add side data
784
980
  */
785
981
  removeSideData(type: AVFrameSideDataType): void;
982
+ /**
983
+ * Get frame metadata dictionary.
984
+ *
985
+ * Returns metadata attached to the frame by filters or demuxers.
986
+ * Metadata is stored as key-value pairs in a Dictionary.
987
+ * Useful for reading filter-generated metadata (e.g., whisper transcription).
988
+ *
989
+ * Direct mapping to AVFrame->metadata.
990
+ *
991
+ * @returns Dictionary containing frame metadata
992
+ *
993
+ * @example
994
+ * ```typescript
995
+ * // Read whisper filter metadata
996
+ * const metadata = frame.getMetadata();
997
+ * const text = metadata.get('lavfi.whisper.text');
998
+ * const duration = metadata.get('lavfi.whisper.duration');
999
+ *
1000
+ * if (text) {
1001
+ * console.log(`Transcribed: ${text}`);
1002
+ * console.log(`Duration: ${duration}s`);
1003
+ * }
1004
+ * ```
1005
+ *
1006
+ * @example
1007
+ * ```typescript
1008
+ * // Read scene detection metadata
1009
+ * const metadata = frame.getMetadata();
1010
+ * const score = metadata.get('lavfi.scene_score');
1011
+ * if (score) {
1012
+ * console.log(`Scene change score: ${score}`);
1013
+ * }
1014
+ * ```
1015
+ *
1016
+ * @see {@link Dictionary} For metadata dictionary operations
1017
+ */
1018
+ getMetadata(): Dictionary;
1019
+ /**
1020
+ * Apply cropping to the frame.
1021
+ *
1022
+ * Crops the frame according to its crop metadata (AVFrame crop fields).
1023
+ * This adjusts the frame dimensions and data pointers to reflect the cropped region.
1024
+ * The cropped-out area is discarded, reducing frame size.
1025
+ *
1026
+ * Direct mapping to av_frame_apply_cropping().
1027
+ *
1028
+ * @param flags - Cropping flags (default: AV_FRAME_CROP_UNALIGNED = 1)
1029
+ * AV_FRAME_CROP_UNALIGNED allows unaligned cropping for lavfi compatibility
1030
+ *
1031
+ * @returns 0 on success, negative error code on failure
1032
+ *
1033
+ * @example
1034
+ * ```typescript
1035
+ * import { Frame, FFmpegError } from 'node-av';
1036
+ *
1037
+ * const frame = new Frame();
1038
+ * // ... decode frame with crop metadata ...
1039
+ *
1040
+ * // Apply cropping based on metadata
1041
+ * const ret = frame.applyCropping();
1042
+ * FFmpegError.throwIfError(ret, 'Failed to apply cropping');
1043
+ *
1044
+ * // Frame dimensions are now updated to cropped size
1045
+ * console.log(`Cropped to ${frame.width}x${frame.height}`);
1046
+ * ```
1047
+ */
1048
+ applyCropping(flags?: number): number;
786
1049
  /**
787
1050
  * Get the underlying native Frame object.
788
1051
  *
package/dist/lib/frame.js CHANGED
@@ -1,7 +1,9 @@
1
- import { AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_UNKNOWN, AVMEDIA_TYPE_VIDEO } from '../constants/constants.js';
1
+ import { AV_NOPTS_VALUE, AV_TIME_BASE_Q, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_UNKNOWN, AVMEDIA_TYPE_VIDEO } from '../constants/constants.js';
2
2
  import { bindings } from './binding.js';
3
+ import { FFmpegError } from './error.js';
3
4
  import { HardwareFramesContext } from './hardware-frames-context.js';
4
5
  import { Rational } from './rational.js';
6
+ import { Dictionary } from './dictionary.js';
5
7
  /**
6
8
  * Container for uncompressed audio/video data.
7
9
  *
@@ -50,6 +52,103 @@ export class Frame {
50
52
  constructor() {
51
53
  this.native = new bindings.Frame();
52
54
  }
55
+ /**
56
+ * Create a video frame from a buffer with pixel data.
57
+ *
58
+ * Allocates frame buffers, sets properties, and copies buffer data.
59
+ * Convenience factory method that combines frame allocation and data copy.
60
+ *
61
+ * @param buffer - Buffer containing raw pixel data
62
+ *
63
+ * @param props - Video Frame properties
64
+ *
65
+ * @returns Allocated frame with data from buffer
66
+ *
67
+ * @throws {FFmpegError} If allocation or buffer copy fails
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * import { Frame, AV_PIX_FMT_RGBA, FFmpegError } from 'node-av';
72
+ *
73
+ * const rawPixels = Buffer.alloc(1920 * 1080 * 4); // RGBA data
74
+ * using frame = Frame.fromVideoBuffer(rawPixels, {
75
+ * width: 1920,
76
+ * height: 1080,
77
+ * format: AV_PIX_FMT_RGBA,
78
+ * timeBase: { num: 1, den: 30 }
79
+ * });
80
+ * ```
81
+ */
82
+ static fromVideoBuffer(buffer, props) {
83
+ const frame = new Frame();
84
+ frame.alloc();
85
+ frame.width = props.width;
86
+ frame.height = props.height;
87
+ frame.format = props.format;
88
+ frame.pts = props.pts ?? AV_NOPTS_VALUE;
89
+ if (props.timeBase) {
90
+ frame.timeBase = new Rational(props.timeBase.num, props.timeBase.den);
91
+ }
92
+ else {
93
+ frame.timeBase = Rational.fromObject(AV_TIME_BASE_Q);
94
+ }
95
+ if (props.sampleAspectRatio) {
96
+ frame.sampleAspectRatio = new Rational(props.sampleAspectRatio.num, props.sampleAspectRatio.den);
97
+ }
98
+ const ret = frame.getBuffer();
99
+ FFmpegError.throwIfError(ret, 'Failed to allocate frame buffers');
100
+ const copyRet = frame.fromBuffer(buffer);
101
+ FFmpegError.throwIfError(copyRet, 'Failed to copy buffer to frame');
102
+ return frame;
103
+ }
104
+ /**
105
+ * Create an audio frame from a buffer with sample data.
106
+ *
107
+ * Allocates frame buffers, sets properties, and copies buffer data.
108
+ * Convenience factory method that combines frame allocation and data copy.
109
+ *
110
+ * @param buffer - Buffer containing raw audio samples
111
+ *
112
+ * @param props - Frame properties
113
+ *
114
+ * @returns Allocated frame with data from buffer
115
+ *
116
+ * @throws {FFmpegError} If allocation or buffer copy fails
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * import { Frame, AV_SAMPLE_FMT_FLT, AV_CH_LAYOUT_STEREO, FFmpegError } from 'node-av';
121
+ *
122
+ * const samples = Buffer.alloc(960 * 2 * 4); // 960 samples, stereo, float32
123
+ * using frame = Frame.fromAudioBuffer(samples, {
124
+ * nbSamples: 960,
125
+ * format: AV_SAMPLE_FMT_FLT,
126
+ * sampleRate: 48000,
127
+ * channelLayout: AV_CH_LAYOUT_STEREO,
128
+ * timeBase: { num: 1, den: 48000 }
129
+ * });
130
+ * ```
131
+ */
132
+ static fromAudioBuffer(buffer, props) {
133
+ const frame = new Frame();
134
+ frame.alloc();
135
+ frame.nbSamples = props.nbSamples;
136
+ frame.format = props.format;
137
+ frame.sampleRate = props.sampleRate;
138
+ frame.channelLayout = props.channelLayout;
139
+ frame.pts = props.pts ?? AV_NOPTS_VALUE;
140
+ if (props.timeBase) {
141
+ frame.timeBase = new Rational(props.timeBase.num, props.timeBase.den);
142
+ }
143
+ else {
144
+ frame.timeBase = Rational.fromObject(AV_TIME_BASE_Q);
145
+ }
146
+ const ret = frame.getBuffer();
147
+ FFmpegError.throwIfError(ret, 'Failed to allocate frame buffers');
148
+ const copyRet = frame.fromBuffer(buffer);
149
+ FFmpegError.throwIfError(copyRet, 'Failed to copy buffer to frame');
150
+ return frame;
151
+ }
53
152
  /**
54
153
  * Pixel format for video frames or sample format for audio.
55
154
  *
@@ -176,6 +275,21 @@ export class Frame {
176
275
  set pictType(value) {
177
276
  this.native.pictType = value;
178
277
  }
278
+ /**
279
+ * Quality (between 1 (good) and FF_LAMBDA_MAX (bad)).
280
+ *
281
+ * Set by libavcodec for some coded frames.
282
+ * Can be set before encoding to specify desired quality for encoders that support it.
283
+ * Used by FFmpeg CLI's frame_encode() to propagate encoder's global_quality setting.
284
+ *
285
+ * Direct mapping to AVFrame->quality.
286
+ */
287
+ get quality() {
288
+ return this.native.quality;
289
+ }
290
+ set quality(value) {
291
+ this.native.quality = value;
292
+ }
179
293
  /**
180
294
  * Sample aspect ratio.
181
295
  *
@@ -358,6 +472,171 @@ export class Frame {
358
472
  // Clear the cache as the underlying context has changed
359
473
  this._hwFramesCtx = undefined;
360
474
  }
475
+ /**
476
+ * Frame flags.
477
+ *
478
+ * Combination of AVFrameFlags (e.g., AV_FRAME_FLAG_CORRUPT, AV_FRAME_FLAG_KEY).
479
+ *
480
+ * Direct mapping to AVFrame->flags.
481
+ */
482
+ get flags() {
483
+ return this.native.flags;
484
+ }
485
+ set flags(value) {
486
+ this.native.flags = value;
487
+ }
488
+ /**
489
+ * Decode error flags.
490
+ *
491
+ * Indicates errors detected during decoding.
492
+ * Non-zero value means the frame may be corrupted.
493
+ *
494
+ * Direct mapping to AVFrame->decode_error_flags.
495
+ */
496
+ get decodeErrorFlags() {
497
+ return this.native.decodeErrorFlags;
498
+ }
499
+ set decodeErrorFlags(value) {
500
+ this.native.decodeErrorFlags = value;
501
+ }
502
+ /**
503
+ * Frame duration.
504
+ *
505
+ * Duration of this frame in units of time_base.
506
+ * This is FFmpeg's best guess for how long the frame should be displayed.
507
+ * May be 0 if unknown or unavailable.
508
+ *
509
+ * Direct mapping to AVFrame->duration.
510
+ */
511
+ get duration() {
512
+ return this.native.duration;
513
+ }
514
+ set duration(value) {
515
+ this.native.duration = value;
516
+ }
517
+ /**
518
+ * Number of fields in this frame that should be repeated.
519
+ *
520
+ * For interlaced video, indicates how many times the frame should be repeated
521
+ * when displayed. For progressive video, this is typically 0.
522
+ * Formula: display_time = (repeat_pict / (2*fps))
523
+ *
524
+ * Direct mapping to AVFrame->repeat_pict.
525
+ */
526
+ get repeatPict() {
527
+ return this.native.repeatPict;
528
+ }
529
+ set repeatPict(value) {
530
+ this.native.repeatPict = value;
531
+ }
532
+ /**
533
+ * Set frame flags.
534
+ *
535
+ * Sets one or more flags using bitwise OR. Allows setting multiple flags
536
+ * without manually performing bitwise operations.
537
+ *
538
+ * @param flags - One or more flag values to set
539
+ *
540
+ * @example
541
+ * ```typescript
542
+ * import { AV_FRAME_FLAG_KEY } from 'node-av/constants';
543
+ *
544
+ * // Mark frame as key frame
545
+ * frame.setFlags(AV_FRAME_FLAG_KEY);
546
+ * ```
547
+ *
548
+ * @see {@link clearFlags} To unset flags
549
+ * @see {@link hasFlags} To check flags
550
+ * @see {@link flags} For direct flag access
551
+ */
552
+ setFlags(...flags) {
553
+ for (const flag of flags) {
554
+ this.native.flags |= flag;
555
+ }
556
+ }
557
+ /**
558
+ * Clear frame flags.
559
+ *
560
+ * Clears one or more flags using bitwise AND NOT. Allows clearing multiple
561
+ * flags without manually performing bitwise operations.
562
+ *
563
+ * @param flags - One or more flag values to clear
564
+ *
565
+ * @example
566
+ * ```typescript
567
+ * import { AV_FRAME_FLAG_CORRUPT } from 'node-av/constants';
568
+ *
569
+ * // Clear corrupt flag
570
+ * frame.clearFlags(AV_FRAME_FLAG_CORRUPT);
571
+ * ```
572
+ *
573
+ * @see {@link setFlags} To set flags
574
+ * @see {@link hasFlags} To check flags
575
+ * @see {@link flags} For direct flag access
576
+ */
577
+ clearFlags(...flags) {
578
+ for (const flag of flags) {
579
+ this.native.flags &= ~flag;
580
+ }
581
+ }
582
+ /**
583
+ * Check if frame has specific flags.
584
+ *
585
+ * Tests whether all specified flags are set using bitwise AND.
586
+ *
587
+ * @param flags - One or more flag values to check
588
+ *
589
+ * @returns true if all specified flags are set, false otherwise
590
+ *
591
+ * @example
592
+ * ```typescript
593
+ * import { AV_FRAME_FLAG_CORRUPT } from 'node-av/constants';
594
+ *
595
+ * if (frame.hasFlags(AV_FRAME_FLAG_CORRUPT)) {
596
+ * console.log('Frame is corrupted');
597
+ * }
598
+ * ```
599
+ *
600
+ * @see {@link setFlags} To set flags
601
+ * @see {@link clearFlags} To unset flags
602
+ * @see {@link flags} For direct flag access
603
+ */
604
+ hasFlags(...flags) {
605
+ for (const flag of flags) {
606
+ if ((this.native.flags & flag) !== flag) {
607
+ return false;
608
+ }
609
+ }
610
+ return true;
611
+ }
612
+ /**
613
+ * Check if frame has decode errors.
614
+ *
615
+ * Tests whether all specified decode error flags are set using bitwise AND.
616
+ *
617
+ * @param flags - One or more decode error flag values to check
618
+ *
619
+ * @returns true if all specified error flags are set, false otherwise
620
+ *
621
+ * @example
622
+ * ```typescript
623
+ * import { FF_DECODE_ERROR_INVALID_BITSTREAM } from 'node-av/constants';
624
+ *
625
+ * if (frame.hasDecodeErrorFlags(FF_DECODE_ERROR_INVALID_BITSTREAM)) {
626
+ * console.log('Frame has invalid bitstream error');
627
+ * }
628
+ * ```
629
+ *
630
+ * @see {@link decodeErrorFlags} For direct error flag access
631
+ */
632
+ hasDecodeErrorFlags(...flags) {
633
+ for (const flag of flags) {
634
+ if ((this.native.decodeErrorFlags & flag) !== flag) {
635
+ return false;
636
+ }
637
+ }
638
+ return true;
639
+ }
361
640
  /**
362
641
  * Check if this is a video frame.
363
642
  *
@@ -942,6 +1221,77 @@ export class Frame {
942
1221
  removeSideData(type) {
943
1222
  this.native.removeSideData(type);
944
1223
  }
1224
+ /**
1225
+ * Get frame metadata dictionary.
1226
+ *
1227
+ * Returns metadata attached to the frame by filters or demuxers.
1228
+ * Metadata is stored as key-value pairs in a Dictionary.
1229
+ * Useful for reading filter-generated metadata (e.g., whisper transcription).
1230
+ *
1231
+ * Direct mapping to AVFrame->metadata.
1232
+ *
1233
+ * @returns Dictionary containing frame metadata
1234
+ *
1235
+ * @example
1236
+ * ```typescript
1237
+ * // Read whisper filter metadata
1238
+ * const metadata = frame.getMetadata();
1239
+ * const text = metadata.get('lavfi.whisper.text');
1240
+ * const duration = metadata.get('lavfi.whisper.duration');
1241
+ *
1242
+ * if (text) {
1243
+ * console.log(`Transcribed: ${text}`);
1244
+ * console.log(`Duration: ${duration}s`);
1245
+ * }
1246
+ * ```
1247
+ *
1248
+ * @example
1249
+ * ```typescript
1250
+ * // Read scene detection metadata
1251
+ * const metadata = frame.getMetadata();
1252
+ * const score = metadata.get('lavfi.scene_score');
1253
+ * if (score) {
1254
+ * console.log(`Scene change score: ${score}`);
1255
+ * }
1256
+ * ```
1257
+ *
1258
+ * @see {@link Dictionary} For metadata dictionary operations
1259
+ */
1260
+ getMetadata() {
1261
+ return Dictionary.fromNative(this.native.getMetadata());
1262
+ }
1263
+ /**
1264
+ * Apply cropping to the frame.
1265
+ *
1266
+ * Crops the frame according to its crop metadata (AVFrame crop fields).
1267
+ * This adjusts the frame dimensions and data pointers to reflect the cropped region.
1268
+ * The cropped-out area is discarded, reducing frame size.
1269
+ *
1270
+ * Direct mapping to av_frame_apply_cropping().
1271
+ *
1272
+ * @param flags - Cropping flags (default: AV_FRAME_CROP_UNALIGNED = 1)
1273
+ * AV_FRAME_CROP_UNALIGNED allows unaligned cropping for lavfi compatibility
1274
+ *
1275
+ * @returns 0 on success, negative error code on failure
1276
+ *
1277
+ * @example
1278
+ * ```typescript
1279
+ * import { Frame, FFmpegError } from 'node-av';
1280
+ *
1281
+ * const frame = new Frame();
1282
+ * // ... decode frame with crop metadata ...
1283
+ *
1284
+ * // Apply cropping based on metadata
1285
+ * const ret = frame.applyCropping();
1286
+ * FFmpegError.throwIfError(ret, 'Failed to apply cropping');
1287
+ *
1288
+ * // Frame dimensions are now updated to cropped size
1289
+ * console.log(`Cropped to ${frame.width}x${frame.height}`);
1290
+ * ```
1291
+ */
1292
+ applyCropping(flags) {
1293
+ return this.native.applyCropping(flags);
1294
+ }
945
1295
  /**
946
1296
  * Get the underlying native Frame object.
947
1297
  *