@revizly/node-av 5.2.2-beta.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 (254) hide show
  1. package/BUILD_LINUX.md +61 -0
  2. package/LICENSE.md +22 -0
  3. package/README.md +662 -0
  4. package/build_mac_local.sh +69 -0
  5. package/dist/api/audio-frame-buffer.d.ts +205 -0
  6. package/dist/api/audio-frame-buffer.js +287 -0
  7. package/dist/api/audio-frame-buffer.js.map +1 -0
  8. package/dist/api/bitstream-filter.d.ts +820 -0
  9. package/dist/api/bitstream-filter.js +1242 -0
  10. package/dist/api/bitstream-filter.js.map +1 -0
  11. package/dist/api/constants.d.ts +44 -0
  12. package/dist/api/constants.js +45 -0
  13. package/dist/api/constants.js.map +1 -0
  14. package/dist/api/data/test_av1.ivf +0 -0
  15. package/dist/api/data/test_h264.h264 +0 -0
  16. package/dist/api/data/test_hevc.h265 +0 -0
  17. package/dist/api/data/test_mjpeg.mjpeg +0 -0
  18. package/dist/api/data/test_vp8.ivf +0 -0
  19. package/dist/api/data/test_vp9.ivf +0 -0
  20. package/dist/api/decoder.d.ts +1088 -0
  21. package/dist/api/decoder.js +1775 -0
  22. package/dist/api/decoder.js.map +1 -0
  23. package/dist/api/demuxer.d.ts +1219 -0
  24. package/dist/api/demuxer.js +2081 -0
  25. package/dist/api/demuxer.js.map +1 -0
  26. package/dist/api/device.d.ts +586 -0
  27. package/dist/api/device.js +961 -0
  28. package/dist/api/device.js.map +1 -0
  29. package/dist/api/encoder.d.ts +1132 -0
  30. package/dist/api/encoder.js +1988 -0
  31. package/dist/api/encoder.js.map +1 -0
  32. package/dist/api/filter-complex.d.ts +821 -0
  33. package/dist/api/filter-complex.js +1604 -0
  34. package/dist/api/filter-complex.js.map +1 -0
  35. package/dist/api/filter-presets.d.ts +1286 -0
  36. package/dist/api/filter-presets.js +2152 -0
  37. package/dist/api/filter-presets.js.map +1 -0
  38. package/dist/api/filter.d.ts +1234 -0
  39. package/dist/api/filter.js +1976 -0
  40. package/dist/api/filter.js.map +1 -0
  41. package/dist/api/fmp4-stream.d.ts +426 -0
  42. package/dist/api/fmp4-stream.js +739 -0
  43. package/dist/api/fmp4-stream.js.map +1 -0
  44. package/dist/api/hardware.d.ts +651 -0
  45. package/dist/api/hardware.js +1260 -0
  46. package/dist/api/hardware.js.map +1 -0
  47. package/dist/api/index.d.ts +17 -0
  48. package/dist/api/index.js +32 -0
  49. package/dist/api/index.js.map +1 -0
  50. package/dist/api/io-stream.d.ts +307 -0
  51. package/dist/api/io-stream.js +282 -0
  52. package/dist/api/io-stream.js.map +1 -0
  53. package/dist/api/muxer.d.ts +957 -0
  54. package/dist/api/muxer.js +2002 -0
  55. package/dist/api/muxer.js.map +1 -0
  56. package/dist/api/pipeline.d.ts +607 -0
  57. package/dist/api/pipeline.js +1145 -0
  58. package/dist/api/pipeline.js.map +1 -0
  59. package/dist/api/utilities/async-queue.d.ts +120 -0
  60. package/dist/api/utilities/async-queue.js +211 -0
  61. package/dist/api/utilities/async-queue.js.map +1 -0
  62. package/dist/api/utilities/audio-sample.d.ts +117 -0
  63. package/dist/api/utilities/audio-sample.js +112 -0
  64. package/dist/api/utilities/audio-sample.js.map +1 -0
  65. package/dist/api/utilities/channel-layout.d.ts +76 -0
  66. package/dist/api/utilities/channel-layout.js +80 -0
  67. package/dist/api/utilities/channel-layout.js.map +1 -0
  68. package/dist/api/utilities/electron-shared-texture.d.ts +328 -0
  69. package/dist/api/utilities/electron-shared-texture.js +503 -0
  70. package/dist/api/utilities/electron-shared-texture.js.map +1 -0
  71. package/dist/api/utilities/image.d.ts +207 -0
  72. package/dist/api/utilities/image.js +213 -0
  73. package/dist/api/utilities/image.js.map +1 -0
  74. package/dist/api/utilities/index.d.ts +12 -0
  75. package/dist/api/utilities/index.js +25 -0
  76. package/dist/api/utilities/index.js.map +1 -0
  77. package/dist/api/utilities/media-type.d.ts +49 -0
  78. package/dist/api/utilities/media-type.js +53 -0
  79. package/dist/api/utilities/media-type.js.map +1 -0
  80. package/dist/api/utilities/pixel-format.d.ts +89 -0
  81. package/dist/api/utilities/pixel-format.js +97 -0
  82. package/dist/api/utilities/pixel-format.js.map +1 -0
  83. package/dist/api/utilities/sample-format.d.ts +129 -0
  84. package/dist/api/utilities/sample-format.js +141 -0
  85. package/dist/api/utilities/sample-format.js.map +1 -0
  86. package/dist/api/utilities/scheduler.d.ts +138 -0
  87. package/dist/api/utilities/scheduler.js +98 -0
  88. package/dist/api/utilities/scheduler.js.map +1 -0
  89. package/dist/api/utilities/streaming.d.ts +186 -0
  90. package/dist/api/utilities/streaming.js +309 -0
  91. package/dist/api/utilities/streaming.js.map +1 -0
  92. package/dist/api/utilities/timestamp.d.ts +193 -0
  93. package/dist/api/utilities/timestamp.js +206 -0
  94. package/dist/api/utilities/timestamp.js.map +1 -0
  95. package/dist/api/utilities/whisper-model.d.ts +310 -0
  96. package/dist/api/utilities/whisper-model.js +528 -0
  97. package/dist/api/utilities/whisper-model.js.map +1 -0
  98. package/dist/api/utils.d.ts +19 -0
  99. package/dist/api/utils.js +39 -0
  100. package/dist/api/utils.js.map +1 -0
  101. package/dist/api/whisper.d.ts +324 -0
  102. package/dist/api/whisper.js +362 -0
  103. package/dist/api/whisper.js.map +1 -0
  104. package/dist/constants/channel-layouts.d.ts +53 -0
  105. package/dist/constants/channel-layouts.js +57 -0
  106. package/dist/constants/channel-layouts.js.map +1 -0
  107. package/dist/constants/constants.d.ts +2325 -0
  108. package/dist/constants/constants.js +1887 -0
  109. package/dist/constants/constants.js.map +1 -0
  110. package/dist/constants/decoders.d.ts +633 -0
  111. package/dist/constants/decoders.js +641 -0
  112. package/dist/constants/decoders.js.map +1 -0
  113. package/dist/constants/encoders.d.ts +295 -0
  114. package/dist/constants/encoders.js +308 -0
  115. package/dist/constants/encoders.js.map +1 -0
  116. package/dist/constants/hardware.d.ts +26 -0
  117. package/dist/constants/hardware.js +27 -0
  118. package/dist/constants/hardware.js.map +1 -0
  119. package/dist/constants/index.d.ts +5 -0
  120. package/dist/constants/index.js +6 -0
  121. package/dist/constants/index.js.map +1 -0
  122. package/dist/ffmpeg/index.d.ts +99 -0
  123. package/dist/ffmpeg/index.js +115 -0
  124. package/dist/ffmpeg/index.js.map +1 -0
  125. package/dist/ffmpeg/utils.d.ts +31 -0
  126. package/dist/ffmpeg/utils.js +68 -0
  127. package/dist/ffmpeg/utils.js.map +1 -0
  128. package/dist/ffmpeg/version.d.ts +6 -0
  129. package/dist/ffmpeg/version.js +7 -0
  130. package/dist/ffmpeg/version.js.map +1 -0
  131. package/dist/index.d.ts +4 -0
  132. package/dist/index.js +9 -0
  133. package/dist/index.js.map +1 -0
  134. package/dist/lib/audio-fifo.d.ts +399 -0
  135. package/dist/lib/audio-fifo.js +431 -0
  136. package/dist/lib/audio-fifo.js.map +1 -0
  137. package/dist/lib/binding.d.ts +228 -0
  138. package/dist/lib/binding.js +60 -0
  139. package/dist/lib/binding.js.map +1 -0
  140. package/dist/lib/bitstream-filter-context.d.ts +379 -0
  141. package/dist/lib/bitstream-filter-context.js +441 -0
  142. package/dist/lib/bitstream-filter-context.js.map +1 -0
  143. package/dist/lib/bitstream-filter.d.ts +140 -0
  144. package/dist/lib/bitstream-filter.js +154 -0
  145. package/dist/lib/bitstream-filter.js.map +1 -0
  146. package/dist/lib/codec-context.d.ts +1071 -0
  147. package/dist/lib/codec-context.js +1354 -0
  148. package/dist/lib/codec-context.js.map +1 -0
  149. package/dist/lib/codec-parameters.d.ts +616 -0
  150. package/dist/lib/codec-parameters.js +761 -0
  151. package/dist/lib/codec-parameters.js.map +1 -0
  152. package/dist/lib/codec-parser.d.ts +201 -0
  153. package/dist/lib/codec-parser.js +213 -0
  154. package/dist/lib/codec-parser.js.map +1 -0
  155. package/dist/lib/codec.d.ts +586 -0
  156. package/dist/lib/codec.js +713 -0
  157. package/dist/lib/codec.js.map +1 -0
  158. package/dist/lib/device.d.ts +291 -0
  159. package/dist/lib/device.js +324 -0
  160. package/dist/lib/device.js.map +1 -0
  161. package/dist/lib/dictionary.d.ts +333 -0
  162. package/dist/lib/dictionary.js +372 -0
  163. package/dist/lib/dictionary.js.map +1 -0
  164. package/dist/lib/error.d.ts +242 -0
  165. package/dist/lib/error.js +303 -0
  166. package/dist/lib/error.js.map +1 -0
  167. package/dist/lib/fifo.d.ts +416 -0
  168. package/dist/lib/fifo.js +453 -0
  169. package/dist/lib/fifo.js.map +1 -0
  170. package/dist/lib/filter-context.d.ts +712 -0
  171. package/dist/lib/filter-context.js +789 -0
  172. package/dist/lib/filter-context.js.map +1 -0
  173. package/dist/lib/filter-graph-segment.d.ts +160 -0
  174. package/dist/lib/filter-graph-segment.js +171 -0
  175. package/dist/lib/filter-graph-segment.js.map +1 -0
  176. package/dist/lib/filter-graph.d.ts +641 -0
  177. package/dist/lib/filter-graph.js +704 -0
  178. package/dist/lib/filter-graph.js.map +1 -0
  179. package/dist/lib/filter-inout.d.ts +198 -0
  180. package/dist/lib/filter-inout.js +257 -0
  181. package/dist/lib/filter-inout.js.map +1 -0
  182. package/dist/lib/filter.d.ts +243 -0
  183. package/dist/lib/filter.js +272 -0
  184. package/dist/lib/filter.js.map +1 -0
  185. package/dist/lib/format-context.d.ts +1254 -0
  186. package/dist/lib/format-context.js +1379 -0
  187. package/dist/lib/format-context.js.map +1 -0
  188. package/dist/lib/frame-utils.d.ts +116 -0
  189. package/dist/lib/frame-utils.js +98 -0
  190. package/dist/lib/frame-utils.js.map +1 -0
  191. package/dist/lib/frame.d.ts +1222 -0
  192. package/dist/lib/frame.js +1435 -0
  193. package/dist/lib/frame.js.map +1 -0
  194. package/dist/lib/hardware-device-context.d.ts +362 -0
  195. package/dist/lib/hardware-device-context.js +383 -0
  196. package/dist/lib/hardware-device-context.js.map +1 -0
  197. package/dist/lib/hardware-frames-context.d.ts +419 -0
  198. package/dist/lib/hardware-frames-context.js +477 -0
  199. package/dist/lib/hardware-frames-context.js.map +1 -0
  200. package/dist/lib/index.d.ts +35 -0
  201. package/dist/lib/index.js +60 -0
  202. package/dist/lib/index.js.map +1 -0
  203. package/dist/lib/input-format.d.ts +249 -0
  204. package/dist/lib/input-format.js +306 -0
  205. package/dist/lib/input-format.js.map +1 -0
  206. package/dist/lib/io-context.d.ts +696 -0
  207. package/dist/lib/io-context.js +769 -0
  208. package/dist/lib/io-context.js.map +1 -0
  209. package/dist/lib/log.d.ts +174 -0
  210. package/dist/lib/log.js +184 -0
  211. package/dist/lib/log.js.map +1 -0
  212. package/dist/lib/native-types.d.ts +946 -0
  213. package/dist/lib/native-types.js +2 -0
  214. package/dist/lib/native-types.js.map +1 -0
  215. package/dist/lib/option.d.ts +927 -0
  216. package/dist/lib/option.js +1583 -0
  217. package/dist/lib/option.js.map +1 -0
  218. package/dist/lib/output-format.d.ts +180 -0
  219. package/dist/lib/output-format.js +213 -0
  220. package/dist/lib/output-format.js.map +1 -0
  221. package/dist/lib/packet.d.ts +501 -0
  222. package/dist/lib/packet.js +590 -0
  223. package/dist/lib/packet.js.map +1 -0
  224. package/dist/lib/rational.d.ts +251 -0
  225. package/dist/lib/rational.js +278 -0
  226. package/dist/lib/rational.js.map +1 -0
  227. package/dist/lib/software-resample-context.d.ts +552 -0
  228. package/dist/lib/software-resample-context.js +592 -0
  229. package/dist/lib/software-resample-context.js.map +1 -0
  230. package/dist/lib/software-scale-context.d.ts +344 -0
  231. package/dist/lib/software-scale-context.js +366 -0
  232. package/dist/lib/software-scale-context.js.map +1 -0
  233. package/dist/lib/stream.d.ts +379 -0
  234. package/dist/lib/stream.js +526 -0
  235. package/dist/lib/stream.js.map +1 -0
  236. package/dist/lib/sync-queue.d.ts +179 -0
  237. package/dist/lib/sync-queue.js +197 -0
  238. package/dist/lib/sync-queue.js.map +1 -0
  239. package/dist/lib/types.d.ts +34 -0
  240. package/dist/lib/types.js +2 -0
  241. package/dist/lib/types.js.map +1 -0
  242. package/dist/lib/utilities.d.ts +1127 -0
  243. package/dist/lib/utilities.js +1225 -0
  244. package/dist/lib/utilities.js.map +1 -0
  245. package/dist/utils/electron.d.ts +49 -0
  246. package/dist/utils/electron.js +63 -0
  247. package/dist/utils/electron.js.map +1 -0
  248. package/dist/utils/index.d.ts +4 -0
  249. package/dist/utils/index.js +5 -0
  250. package/dist/utils/index.js.map +1 -0
  251. package/install/check.js +121 -0
  252. package/install/ffmpeg.js +66 -0
  253. package/jellyfin-ffmpeg.patch +181 -0
  254. package/package.json +129 -0
@@ -0,0 +1,69 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
5
+ BUILDER_DIR="$SCRIPT_DIR/externals/jellyfin-ffmpeg/builder"
6
+ BUILD_DIR="$BUILDER_DIR/build"
7
+
8
+ echo ""
9
+ echo "=== FFmpeg Local Build ==="
10
+ echo ""
11
+ echo " 1) Full build (clean + dependencies + FFmpeg)"
12
+ echo " 2) FFmpeg only (skip dependency builds)"
13
+ echo ""
14
+ read -rp "Choose [1/2]: " choice
15
+
16
+ case "$choice" in
17
+ 1)
18
+ echo ""
19
+ echo "=> Full build selected. Cleaning build + prefix directories..."
20
+ rm -rf "$BUILD_DIR"
21
+ sudo rm -rf /opt/ffbuild/prefix
22
+ SKIP_BUILD=""
23
+ ;;
24
+ 2)
25
+ echo ""
26
+ echo "=> FFmpeg-only build selected. Skipping dependencies..."
27
+ SKIP_BUILD="--skip-build"
28
+ ;;
29
+ *)
30
+ echo "Invalid choice."
31
+ exit 1
32
+ ;;
33
+ esac
34
+
35
+ # Ensure submodules are initialized
36
+ if [ ! -f "$SCRIPT_DIR/externals/jellyfin-ffmpeg/configure" ]; then
37
+ echo "=> Initializing git submodules..."
38
+ git -C "$SCRIPT_DIR" submodule update --init --recursive
39
+ fi
40
+
41
+ # Log everything to terminal and file
42
+ LOG_FILE="$SCRIPT_DIR/ffmpeg_build.log"
43
+ exec > >(tee "$LOG_FILE") 2>&1
44
+
45
+ # Ensure /opt/ffbuild exists with correct permissions
46
+ sudo mkdir -p /opt/ffbuild/prefix
47
+ sudo chown -R "$(whoami):staff" /opt/ffbuild
48
+ sudo chmod -R 755 /opt/ffbuild
49
+
50
+ cd "$SCRIPT_DIR"
51
+
52
+ # Apply FFmpeg patches (skips if already applied)
53
+ node scripts/patch-ffmpeg.js
54
+
55
+ cd "$BUILDER_DIR"
56
+
57
+ # Run Jellyfin build script
58
+ ./buildmac.sh arm64 $SKIP_BUILD
59
+
60
+ # The build script uses /ffbuild/prefix but we need /opt/ffbuild/prefix
61
+ cd ..
62
+ make install DESTDIR="" prefix="/opt/ffbuild/prefix"
63
+
64
+ # Fix permissions after install
65
+ sudo chown -R "$(whoami):staff" /opt/ffbuild
66
+
67
+ cd "$SCRIPT_DIR"
68
+
69
+ # npm run build:native
@@ -0,0 +1,205 @@
1
+ import { Frame } from '../lib/frame.js';
2
+ import type { AVSampleFormat } from '../constants/index.js';
3
+ import type { ChannelLayout } from '../lib/types.js';
4
+ /**
5
+ * Audio frame buffering utility for encoders with fixed frame size requirements.
6
+ *
7
+ * Many audio encoders (Opus, AAC, MP3, etc.) require frames with a specific number
8
+ * of samples (frame_size). This class buffers incoming frames and outputs frames
9
+ * with exactly the required size.
10
+ *
11
+ * Uses FFmpeg's AVAudioFifo internally for efficient sample buffering.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { AudioFrameBuffer } from 'node-av/api';
16
+ *
17
+ * // Create buffer for 480-sample frames (e.g., Opus at 24kHz)
18
+ * using buffer = AudioFrameBuffer.create(480, AV_SAMPLE_FMT_FLT, 48000, 'mono', 1);
19
+ *
20
+ * // Push variable-sized frames from filter
21
+ * for await (const frame of filterOutput) {
22
+ * await buffer.push(frame);
23
+ *
24
+ * // Pull fixed-size frames for encoder
25
+ * let outputFrame;
26
+ * while ((outputFrame = await buffer.pull()) !== null) {
27
+ * await encoder.encode(outputFrame);
28
+ * outputFrame.free();
29
+ * }
30
+ * }
31
+ *
32
+ * // Flush remaining samples
33
+ * let outputFrame;
34
+ * while ((outputFrame = await buffer.pull()) !== null) {
35
+ * await encoder.encode(outputFrame);
36
+ * outputFrame.free();
37
+ * }
38
+ * ```
39
+ */
40
+ export declare class AudioFrameBuffer implements Disposable {
41
+ private fifo;
42
+ private frame;
43
+ private frameSize;
44
+ private nextPts;
45
+ private firstFramePts;
46
+ /**
47
+ * @param fifo - Underlying AudioFifo instance
48
+ *
49
+ * @param frameSize - Number of samples per output frame
50
+ *
51
+ * @param sampleFormat - Audio sample format
52
+ *
53
+ * @param sampleRate - Sample rate in Hz
54
+ *
55
+ * @param channelLayout - Channel layout
56
+ *
57
+ * @internal
58
+ */
59
+ private constructor();
60
+ /**
61
+ * Create an audio frame buffer.
62
+ *
63
+ * @param frameSize - Required frame size in samples
64
+ *
65
+ * @param sampleFormat - Audio sample format
66
+ *
67
+ * @param sampleRate - Sample rate in Hz
68
+ *
69
+ * @param channelLayout - Channel layout (e.g., 'mono', 'stereo')
70
+ *
71
+ * @param channels - Number of audio channels
72
+ *
73
+ * @returns Configured audio frame buffer
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * // For Opus encoder at 48kHz with 20ms frames
78
+ * const buffer = AudioFrameBuffer.create(960, AV_SAMPLE_FMT_FLT, 48000, 'mono', 1);
79
+ * ```
80
+ */
81
+ static create(frameSize: number, sampleFormat: AVSampleFormat, sampleRate: number, channelLayout: ChannelLayout, channels: number): AudioFrameBuffer;
82
+ /**
83
+ * Get number of samples currently in buffer.
84
+ *
85
+ * @returns Number of buffered samples
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * console.log(`Buffer contains ${buffer.size} samples`);
90
+ * ```
91
+ */
92
+ get size(): number;
93
+ /**
94
+ * Check if a complete frame is available.
95
+ *
96
+ * Returns true if the FIFO contains at least frameSize samples.
97
+ *
98
+ * @returns True if a full frame can be pulled
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * while (buffer.hasFrame()) {
103
+ * const frame = buffer.pull();
104
+ * // Process frame...
105
+ * }
106
+ * ```
107
+ */
108
+ hasFrame(): boolean;
109
+ /**
110
+ * Push an audio frame into the buffer asynchronously.
111
+ *
112
+ * The frame's samples are added to the internal FIFO.
113
+ * Call hasFrame() and pull() to retrieve fixed-size output frames.
114
+ *
115
+ * @param frame - Audio frame to buffer
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * await buffer.push(filterFrame);
120
+ * ```
121
+ *
122
+ * @see {@link pushSync} For synchronous version
123
+ */
124
+ push(frame: Frame): Promise<void>;
125
+ /**
126
+ * Push an audio frame into the buffer synchronously.
127
+ * Synchronous version of push.
128
+ *
129
+ * The frame's samples are added to the internal FIFO.
130
+ * Call hasFrame() and pullSync() to retrieve fixed-size output frames.
131
+ *
132
+ * @param frame - Audio frame to buffer
133
+ *
134
+ * @example
135
+ * ```typescript
136
+ * buffer.pushSync(filterFrame);
137
+ * ```
138
+ *
139
+ * @see {@link push} For async version
140
+ */
141
+ pushSync(frame: Frame): void;
142
+ /**
143
+ * Pull a fixed-size audio frame from the buffer asynchronously.
144
+ *
145
+ * Reads exactly frameSize samples from the FIFO and returns a cloned Frame.
146
+ * Returns null if not enough samples are available.
147
+ * Reuses internal frame buffer for efficiency (like Decoder does).
148
+ *
149
+ * @returns Audio frame with exactly frameSize samples, or null if insufficient samples
150
+ *
151
+ * @throws {Error} If frame cloning fails (out of memory)
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * using frame = await buffer.pull();
156
+ * if (frame) {
157
+ * await encoder.encode(frame);
158
+ * }
159
+ * ```
160
+ *
161
+ * @see {@link pullSync} For synchronous version
162
+ */
163
+ pull(): Promise<Frame | null>;
164
+ /**
165
+ * Pull a fixed-size audio frame from the buffer synchronously.
166
+ * Synchronous version of pull.
167
+ *
168
+ * Reads exactly frameSize samples from the FIFO and returns a cloned Frame.
169
+ * Returns null if not enough samples are available.
170
+ * Reuses internal frame buffer for efficiency (like Decoder does).
171
+ *
172
+ * @returns Audio frame with exactly frameSize samples, or null if insufficient samples
173
+ *
174
+ * @throws {Error} If frame cloning fails (out of memory)
175
+ *
176
+ * @example
177
+ * ```typescript
178
+ * using frame = buffer.pullSync();
179
+ * if (frame) {
180
+ * encoder.encodeSync(frame);
181
+ * }
182
+ * ```
183
+ *
184
+ * @see {@link pull} For async version
185
+ */
186
+ pullSync(): Frame | null;
187
+ /**
188
+ * Reset the buffer, discarding all buffered samples.
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * buffer.reset();
193
+ * ```
194
+ */
195
+ reset(): void;
196
+ /**
197
+ * Free the buffer and all resources.
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * buffer.free();
202
+ * ```
203
+ */
204
+ [Symbol.dispose](): void;
205
+ }
@@ -0,0 +1,287 @@
1
+ import { AudioFifo } from '../lib/audio-fifo.js';
2
+ import { Frame } from '../lib/frame.js';
3
+ /**
4
+ * Audio frame buffering utility for encoders with fixed frame size requirements.
5
+ *
6
+ * Many audio encoders (Opus, AAC, MP3, etc.) require frames with a specific number
7
+ * of samples (frame_size). This class buffers incoming frames and outputs frames
8
+ * with exactly the required size.
9
+ *
10
+ * Uses FFmpeg's AVAudioFifo internally for efficient sample buffering.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { AudioFrameBuffer } from 'node-av/api';
15
+ *
16
+ * // Create buffer for 480-sample frames (e.g., Opus at 24kHz)
17
+ * using buffer = AudioFrameBuffer.create(480, AV_SAMPLE_FMT_FLT, 48000, 'mono', 1);
18
+ *
19
+ * // Push variable-sized frames from filter
20
+ * for await (const frame of filterOutput) {
21
+ * await buffer.push(frame);
22
+ *
23
+ * // Pull fixed-size frames for encoder
24
+ * let outputFrame;
25
+ * while ((outputFrame = await buffer.pull()) !== null) {
26
+ * await encoder.encode(outputFrame);
27
+ * outputFrame.free();
28
+ * }
29
+ * }
30
+ *
31
+ * // Flush remaining samples
32
+ * let outputFrame;
33
+ * while ((outputFrame = await buffer.pull()) !== null) {
34
+ * await encoder.encode(outputFrame);
35
+ * outputFrame.free();
36
+ * }
37
+ * ```
38
+ */
39
+ export class AudioFrameBuffer {
40
+ fifo;
41
+ frame;
42
+ frameSize;
43
+ nextPts = 0n;
44
+ firstFramePts = null;
45
+ /**
46
+ * @param fifo - Underlying AudioFifo instance
47
+ *
48
+ * @param frameSize - Number of samples per output frame
49
+ *
50
+ * @param sampleFormat - Audio sample format
51
+ *
52
+ * @param sampleRate - Sample rate in Hz
53
+ *
54
+ * @param channelLayout - Channel layout
55
+ *
56
+ * @internal
57
+ */
58
+ constructor(fifo, frameSize, sampleFormat, sampleRate, channelLayout) {
59
+ this.fifo = fifo;
60
+ this.frameSize = frameSize;
61
+ this.frame = new Frame();
62
+ this.frame.alloc();
63
+ this.frame.nbSamples = frameSize;
64
+ this.frame.format = sampleFormat;
65
+ this.frame.sampleRate = sampleRate;
66
+ this.frame.channelLayout = channelLayout;
67
+ this.frame.getBuffer(0); // Allocate buffer once
68
+ }
69
+ /**
70
+ * Create an audio frame buffer.
71
+ *
72
+ * @param frameSize - Required frame size in samples
73
+ *
74
+ * @param sampleFormat - Audio sample format
75
+ *
76
+ * @param sampleRate - Sample rate in Hz
77
+ *
78
+ * @param channelLayout - Channel layout (e.g., 'mono', 'stereo')
79
+ *
80
+ * @param channels - Number of audio channels
81
+ *
82
+ * @returns Configured audio frame buffer
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * // For Opus encoder at 48kHz with 20ms frames
87
+ * const buffer = AudioFrameBuffer.create(960, AV_SAMPLE_FMT_FLT, 48000, 'mono', 1);
88
+ * ```
89
+ */
90
+ static create(frameSize, sampleFormat, sampleRate, channelLayout, channels) {
91
+ const fifo = new AudioFifo();
92
+ // Allocate FIFO with capacity for multiple frames
93
+ fifo.alloc(sampleFormat, channels, frameSize * 4);
94
+ return new AudioFrameBuffer(fifo, frameSize, sampleFormat, sampleRate, channelLayout);
95
+ }
96
+ /**
97
+ * Get number of samples currently in buffer.
98
+ *
99
+ * @returns Number of buffered samples
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * console.log(`Buffer contains ${buffer.size} samples`);
104
+ * ```
105
+ */
106
+ get size() {
107
+ return this.fifo.size;
108
+ }
109
+ /**
110
+ * Check if a complete frame is available.
111
+ *
112
+ * Returns true if the FIFO contains at least frameSize samples.
113
+ *
114
+ * @returns True if a full frame can be pulled
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * while (buffer.hasFrame()) {
119
+ * const frame = buffer.pull();
120
+ * // Process frame...
121
+ * }
122
+ * ```
123
+ */
124
+ hasFrame() {
125
+ return this.fifo.size >= this.frameSize;
126
+ }
127
+ /**
128
+ * Push an audio frame into the buffer asynchronously.
129
+ *
130
+ * The frame's samples are added to the internal FIFO.
131
+ * Call hasFrame() and pull() to retrieve fixed-size output frames.
132
+ *
133
+ * @param frame - Audio frame to buffer
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * await buffer.push(filterFrame);
138
+ * ```
139
+ *
140
+ * @see {@link pushSync} For synchronous version
141
+ */
142
+ async push(frame) {
143
+ if (!frame.isAudio()) {
144
+ throw new Error('AudioFrameBuffer.push() requires an audio frame');
145
+ }
146
+ if (this.firstFramePts === null) {
147
+ // Always start PTS from 0 for encoder frames
148
+ // Input frames may be in different timebase than encoder expects
149
+ this.firstFramePts = 0n;
150
+ this.nextPts = 0n;
151
+ }
152
+ // Write frame data to FIFO
153
+ await this.fifo.write(frame.data, frame.nbSamples);
154
+ }
155
+ /**
156
+ * Push an audio frame into the buffer synchronously.
157
+ * Synchronous version of push.
158
+ *
159
+ * The frame's samples are added to the internal FIFO.
160
+ * Call hasFrame() and pullSync() to retrieve fixed-size output frames.
161
+ *
162
+ * @param frame - Audio frame to buffer
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * buffer.pushSync(filterFrame);
167
+ * ```
168
+ *
169
+ * @see {@link push} For async version
170
+ */
171
+ pushSync(frame) {
172
+ if (!frame.isAudio()) {
173
+ throw new Error('AudioFrameBuffer.pushSync() requires an audio frame');
174
+ }
175
+ if (this.firstFramePts === null) {
176
+ // Always start PTS from 0 for encoder frames
177
+ // Input frames may be in different timebase than encoder expects
178
+ this.firstFramePts = 0n;
179
+ this.nextPts = 0n;
180
+ }
181
+ // Write frame data to FIFO
182
+ this.fifo.writeSync(frame.data, frame.nbSamples);
183
+ }
184
+ /**
185
+ * Pull a fixed-size audio frame from the buffer asynchronously.
186
+ *
187
+ * Reads exactly frameSize samples from the FIFO and returns a cloned Frame.
188
+ * Returns null if not enough samples are available.
189
+ * Reuses internal frame buffer for efficiency (like Decoder does).
190
+ *
191
+ * @returns Audio frame with exactly frameSize samples, or null if insufficient samples
192
+ *
193
+ * @throws {Error} If frame cloning fails (out of memory)
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * using frame = await buffer.pull();
198
+ * if (frame) {
199
+ * await encoder.encode(frame);
200
+ * }
201
+ * ```
202
+ *
203
+ * @see {@link pullSync} For synchronous version
204
+ */
205
+ async pull() {
206
+ if (!this.hasFrame()) {
207
+ return null;
208
+ }
209
+ // Update PTS
210
+ this.frame.pts = this.nextPts;
211
+ // Read samples from FIFO into reusable frame
212
+ await this.fifo.read(this.frame.data, this.frameSize);
213
+ // Update PTS for next frame
214
+ this.nextPts += BigInt(this.frameSize);
215
+ // Clone frame for user (like Decoder does)
216
+ const cloned = this.frame.clone();
217
+ if (!cloned) {
218
+ throw new Error('Failed to clone frame (out of memory)');
219
+ }
220
+ return cloned;
221
+ }
222
+ /**
223
+ * Pull a fixed-size audio frame from the buffer synchronously.
224
+ * Synchronous version of pull.
225
+ *
226
+ * Reads exactly frameSize samples from the FIFO and returns a cloned Frame.
227
+ * Returns null if not enough samples are available.
228
+ * Reuses internal frame buffer for efficiency (like Decoder does).
229
+ *
230
+ * @returns Audio frame with exactly frameSize samples, or null if insufficient samples
231
+ *
232
+ * @throws {Error} If frame cloning fails (out of memory)
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * using frame = buffer.pullSync();
237
+ * if (frame) {
238
+ * encoder.encodeSync(frame);
239
+ * }
240
+ * ```
241
+ *
242
+ * @see {@link pull} For async version
243
+ */
244
+ pullSync() {
245
+ if (!this.hasFrame()) {
246
+ return null;
247
+ }
248
+ // Update PTS
249
+ this.frame.pts = this.nextPts;
250
+ // Read samples from FIFO into reusable frame
251
+ this.fifo.readSync(this.frame.data, this.frameSize);
252
+ // Update PTS for next frame
253
+ this.nextPts += BigInt(this.frameSize);
254
+ // Clone frame for user (like Decoder does)
255
+ const cloned = this.frame.clone();
256
+ if (!cloned) {
257
+ throw new Error('Failed to clone frame (out of memory)');
258
+ }
259
+ return cloned;
260
+ }
261
+ /**
262
+ * Reset the buffer, discarding all buffered samples.
263
+ *
264
+ * @example
265
+ * ```typescript
266
+ * buffer.reset();
267
+ * ```
268
+ */
269
+ reset() {
270
+ this.fifo.reset();
271
+ this.nextPts = 0n;
272
+ this.firstFramePts = null;
273
+ }
274
+ /**
275
+ * Free the buffer and all resources.
276
+ *
277
+ * @example
278
+ * ```typescript
279
+ * buffer.free();
280
+ * ```
281
+ */
282
+ [Symbol.dispose]() {
283
+ this.frame.free();
284
+ this.fifo[Symbol.dispose]();
285
+ }
286
+ }
287
+ //# sourceMappingURL=audio-frame-buffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-frame-buffer.js","sourceRoot":"","sources":["../../src/api/audio-frame-buffer.ts"],"names":[],"mappings":"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"}