@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,1260 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
53
+ import { join } from 'node:path';
54
+ import { AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, AV_CODEC_ID_AV1, AV_CODEC_ID_H263, AV_CODEC_ID_H264, AV_CODEC_ID_HEVC, AV_CODEC_ID_MJPEG, AV_CODEC_ID_MPEG2VIDEO, AV_CODEC_ID_MPEG4, AV_CODEC_ID_PRORES, AV_CODEC_ID_VP8, AV_CODEC_ID_VP9, AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_D3D12VA, AV_HWDEVICE_TYPE_DRM, AV_HWDEVICE_TYPE_DXVA2, AV_HWDEVICE_TYPE_MEDIACODEC, AV_HWDEVICE_TYPE_NONE, AV_HWDEVICE_TYPE_OPENCL, AV_HWDEVICE_TYPE_QSV, AV_HWDEVICE_TYPE_RKMPP, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VDPAU, AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_VULKAN, AV_PIX_FMT_CUDA, AV_PIX_FMT_D3D11, AV_PIX_FMT_D3D12, AV_PIX_FMT_DRM_PRIME, AV_PIX_FMT_DXVA2_VLD, AV_PIX_FMT_MEDIACODEC, AV_PIX_FMT_NV12, AV_PIX_FMT_OPENCL, AV_PIX_FMT_QSV, AV_PIX_FMT_VAAPI, AV_PIX_FMT_VIDEOTOOLBOX, AV_PIX_FMT_VULKAN, } from '../constants/constants.js';
55
+ import { Codec } from '../lib/codec.js';
56
+ import { Dictionary } from '../lib/dictionary.js';
57
+ import { FFmpegError } from '../lib/error.js';
58
+ import { HardwareDeviceContext } from '../lib/hardware-device-context.js';
59
+ import { Stream } from '../lib/stream.js';
60
+ import { avGetHardwareDeviceTypeFromName } from '../lib/utilities.js';
61
+ import { getDirname } from '../utils/electron.js';
62
+ import { Decoder } from './decoder.js';
63
+ import { Demuxer } from './demuxer.js';
64
+ import { Encoder } from './encoder.js';
65
+ import { FilterAPI } from './filter.js';
66
+ const __dirname = getDirname(import.meta.url);
67
+ const h264Data = join(__dirname, 'data', 'test_h264.h264');
68
+ const hevcData = join(__dirname, 'data', 'test_hevc.h265');
69
+ const vp8Data = join(__dirname, 'data', 'test_vp8.ivf');
70
+ const vp9Data = join(__dirname, 'data', 'test_vp9.ivf');
71
+ const av1Data = join(__dirname, 'data', 'test_av1.ivf');
72
+ const mjpegData = join(__dirname, 'data', 'test_mjpeg.mjpeg');
73
+ /**
74
+ * High-level hardware acceleration management.
75
+ *
76
+ * Provides automatic detection and configuration of hardware acceleration for media processing.
77
+ * Manages device contexts for GPU-accelerated encoding and decoding operations.
78
+ * Supports various hardware types including VideoToolbox, CUDA, VAAPI, D3D11VA, and more.
79
+ * Essential for high-performance video processing with reduced CPU usage.
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * import { HardwareContext } from 'node-av/api';
84
+ * import { AV_HWDEVICE_TYPE_CUDA } from 'node-av/constants';
85
+ *
86
+ * // Auto-detect best available hardware
87
+ * const hw = HardwareContext.auto();
88
+ * if (hw) {
89
+ * console.log(`Using hardware: ${hw.deviceTypeName}`);
90
+ * const decoder = await Decoder.create(stream, { hardware: hw });
91
+ * }
92
+ * ```
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * // Use specific hardware type
97
+ * const hw = HardwareContext.create(AV_HWDEVICE_TYPE_CUDA);
98
+ * const encoderCodec = hw?.getEncoderCodec('h264') ?? FF_ENCODER_LIBX264;
99
+ * const encoder = await Encoder.create(encoderCodec, { ... });
100
+ * hw.dispose();
101
+ * ```
102
+ *
103
+ * @see {@link Decoder} For hardware-accelerated decoding
104
+ * @see {@link Encoder} For hardware-accelerated encoding
105
+ */
106
+ export class HardwareContext {
107
+ static _autoTested = false;
108
+ static _autoCachedType = AV_HWDEVICE_TYPE_NONE;
109
+ _deviceContext;
110
+ _deviceType;
111
+ _deviceTypeName;
112
+ _devicePixelFormat;
113
+ _isDisposed = false;
114
+ /**
115
+ * @param deviceContext - Initialized hardware device context
116
+ *
117
+ * @param deviceType - Hardware device type enum
118
+ *
119
+ * @param deviceTypeName - Human-readable device type name
120
+ *
121
+ * @internal
122
+ */
123
+ constructor(deviceContext, deviceType, deviceTypeName) {
124
+ this._deviceContext = deviceContext;
125
+ this._deviceType = deviceType;
126
+ this._deviceTypeName = deviceTypeName;
127
+ this._devicePixelFormat = this.getHardwareDecoderPixelFormat();
128
+ }
129
+ /**
130
+ * Auto-detect and create the best available hardware context.
131
+ *
132
+ * Tries hardware types in order of preference based on platform.
133
+ * Returns null if no hardware acceleration is available.
134
+ * Platform-specific preference order ensures optimal performance.
135
+ *
136
+ * @param options - Optional hardware configuration
137
+ *
138
+ * @returns Hardware context or null if unavailable
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * const hw = HardwareContext.auto();
143
+ * if (hw) {
144
+ * console.log(`Auto-detected: ${hw.deviceTypeName}`);
145
+ * // Use for decoder/encoder
146
+ * }
147
+ * ```
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * // With specific device
152
+ * const hw = HardwareContext.auto({
153
+ * deviceName: '/dev/dri/renderD128'
154
+ * });
155
+ * ```
156
+ *
157
+ * @see {@link create} For specific hardware type
158
+ * @see {@link listAvailable} To check available types
159
+ */
160
+ static auto(options = {}) {
161
+ const hasOptions = options.device ?? options.options;
162
+ // Use cached device type if no custom options and already tested
163
+ if (!hasOptions && this._autoTested) {
164
+ // No hardware was found during testing
165
+ if (this._autoCachedType === AV_HWDEVICE_TYPE_NONE) {
166
+ return null;
167
+ }
168
+ // Create new instance using cached device type
169
+ return this.create(this._autoCachedType, options.device, options.options);
170
+ }
171
+ // Platform-specific preference order
172
+ const preferenceOrder = this.getPreferenceOrder();
173
+ for (const deviceType of preferenceOrder) {
174
+ try {
175
+ if (deviceType === AV_HWDEVICE_TYPE_VAAPI && !options.device) {
176
+ options.device = '/dev/dri/renderD128'; // Default VAAPI render node
177
+ }
178
+ const hwCtx = this.createFromType(deviceType, options.device, options.options);
179
+ const isSupported = hwCtx.testDecoder();
180
+ if (!isSupported) {
181
+ hwCtx.dispose();
182
+ continue;
183
+ }
184
+ // Cache device type if no custom options
185
+ if (!hasOptions) {
186
+ this._autoTested = true;
187
+ this._autoCachedType = deviceType;
188
+ }
189
+ return hwCtx;
190
+ }
191
+ catch {
192
+ // Try next device type
193
+ continue;
194
+ }
195
+ }
196
+ // Cache "no hardware" if no custom options
197
+ if (!hasOptions) {
198
+ this._autoTested = true;
199
+ this._autoCachedType = AV_HWDEVICE_TYPE_NONE;
200
+ }
201
+ return null;
202
+ }
203
+ /**
204
+ * Reset the auto-detection cache.
205
+ *
206
+ * Forces the next call to auto() to re-test hardware availability.
207
+ * Useful for testing or if hardware availability may have changed.
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * HardwareContext.resetAutoCache();
212
+ * const hw = HardwareContext.auto(); // Will re-test
213
+ * ```
214
+ */
215
+ static resetAutoCache() {
216
+ this._autoCachedType = AV_HWDEVICE_TYPE_NONE;
217
+ this._autoTested = false;
218
+ }
219
+ /**
220
+ * Create a hardware context for a specific device type.
221
+ *
222
+ * Creates and initializes a hardware device context.
223
+ * Throws if the device type is not supported or initialization fails.
224
+ *
225
+ * Direct mapping to av_hwdevice_ctx_create().
226
+ *
227
+ * @param deviceType - Hardware device type from AVHWDeviceType
228
+ *
229
+ * @param device - Optional device specifier (e.g., GPU index, device path)
230
+ *
231
+ * @param options - Optional device initialization options
232
+ *
233
+ * @returns Initialized hardware context or null if HardwareContext could not be created
234
+ *
235
+ * @example
236
+ * ```typescript
237
+ * import { AV_HWDEVICE_TYPE_CUDA } from 'node-av/constants';
238
+ *
239
+ * // CUDA with specific GPU
240
+ * const cuda = HardwareContext.create(AV_HWDEVICE_TYPE_CUDA, '0');
241
+ * ```
242
+ *
243
+ * @example
244
+ * ```typescript
245
+ * import { AV_HWDEVICE_TYPE_VAAPI } from 'node-av/constants';
246
+ *
247
+ * // VAAPI with render device
248
+ * const vaapi = HardwareContext.create(
249
+ * AV_HWDEVICE_TYPE_VAAPI,
250
+ * '/dev/dri/renderD128'
251
+ * );
252
+ * ```
253
+ *
254
+ * @see {@link auto} For automatic detection
255
+ * @see {@link HardwareDeviceContext} For low-level API
256
+ */
257
+ static create(deviceType, device, options) {
258
+ if (typeof deviceType === 'string') {
259
+ deviceType = avGetHardwareDeviceTypeFromName(deviceType);
260
+ }
261
+ if (deviceType === AV_HWDEVICE_TYPE_NONE) {
262
+ return null;
263
+ }
264
+ let hw;
265
+ try {
266
+ hw = this.createFromType(deviceType, device, options);
267
+ }
268
+ catch {
269
+ return null;
270
+ }
271
+ return hw;
272
+ }
273
+ /**
274
+ * Create a derived hardware device context.
275
+ *
276
+ * Creates a new hardware context derived from an existing one.
277
+ * Allows creating contexts on different device types that can share
278
+ * memory or resources with the source device. Useful for cross-device
279
+ * pipelines (e.g., VAAPI → OpenCL, CUDA → Vulkan).
280
+ *
281
+ * Direct mapping to av_hwdevice_ctx_create_derived().
282
+ *
283
+ * @param source - Source hardware context to derive from
284
+ *
285
+ * @param targetType - Target device type to create
286
+ *
287
+ * @returns New hardware context or null if derivation fails
288
+ *
289
+ * @example
290
+ * ```typescript
291
+ * import { AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_OPENCL } from 'node-av/constants';
292
+ *
293
+ * // Create VAAPI device for decoding
294
+ * const vaapi = HardwareContext.create(AV_HWDEVICE_TYPE_VAAPI);
295
+ *
296
+ * // Derive OpenCL device for filtering (shares memory with VAAPI)
297
+ * const opencl = HardwareContext.derive(vaapi, AV_HWDEVICE_TYPE_OPENCL);
298
+ *
299
+ * if (opencl) {
300
+ * // Decode with VAAPI
301
+ * const decoder = await Decoder.create(stream, { hardware: vaapi });
302
+ *
303
+ * // Filter with OpenCL (overrides frame's VAAPI context)
304
+ * const filter = FilterAPI.create('program_opencl=...', { hardware: opencl });
305
+ *
306
+ * for await (const frame of decoder.frames()) {
307
+ * // frame has VAAPI context, but filter uses OpenCL
308
+ * const filtered = await filter.apply(frame);
309
+ * }
310
+ * }
311
+ * ```
312
+ *
313
+ * @example
314
+ * ```typescript
315
+ * // CUDA → Vulkan derivation
316
+ * const cuda = HardwareContext.create(AV_HWDEVICE_TYPE_CUDA);
317
+ * const vulkan = HardwareContext.derive(cuda, AV_HWDEVICE_TYPE_VULKAN);
318
+ * ```
319
+ *
320
+ * @see {@link create} For creating independent device
321
+ */
322
+ static derive(source, targetType) {
323
+ if (!source || source.isDisposed) {
324
+ return null;
325
+ }
326
+ if (typeof targetType === 'string') {
327
+ targetType = avGetHardwareDeviceTypeFromName(targetType);
328
+ }
329
+ if (targetType === AV_HWDEVICE_TYPE_NONE) {
330
+ return null;
331
+ }
332
+ try {
333
+ const derivedDeviceCtx = new HardwareDeviceContext();
334
+ const ret = derivedDeviceCtx.createDerived(source.deviceContext, targetType);
335
+ if (FFmpegError.isFFmpegError(ret)) {
336
+ derivedDeviceCtx.free();
337
+ return null;
338
+ }
339
+ const deviceTypeName = HardwareDeviceContext.getTypeName(targetType);
340
+ if (!deviceTypeName) {
341
+ derivedDeviceCtx.free();
342
+ return null;
343
+ }
344
+ return new HardwareContext(derivedDeviceCtx, targetType, deviceTypeName);
345
+ }
346
+ catch {
347
+ return null;
348
+ }
349
+ }
350
+ /**
351
+ * List all available hardware device types.
352
+ *
353
+ * Enumerates all hardware types supported by the FFmpeg build.
354
+ * Useful for checking hardware capabilities at runtime.
355
+ *
356
+ * Direct mapping to av_hwdevice_iterate_types().
357
+ *
358
+ * @returns Array of available device type names
359
+ *
360
+ * @example
361
+ * ```typescript
362
+ * const available = HardwareContext.listAvailable();
363
+ * console.log('Available hardware:', available.join(', '));
364
+ * // Output: "cuda, vaapi, videotoolbox"
365
+ * ```
366
+ *
367
+ * @see {@link auto} For automatic selection
368
+ */
369
+ static listAvailable() {
370
+ const types = HardwareDeviceContext.iterateTypes();
371
+ const available = [];
372
+ for (const type of types) {
373
+ const name = HardwareDeviceContext.getTypeName(type);
374
+ if (name) {
375
+ available.push(name);
376
+ }
377
+ }
378
+ return available;
379
+ }
380
+ /**
381
+ * Get the hardware device context.
382
+ *
383
+ * Used internally by encoders and decoders for hardware acceleration.
384
+ * Can be assigned to CodecContext.hwDeviceCtx.
385
+ *
386
+ * @example
387
+ * ```typescript
388
+ * codecContext.hwDeviceCtx = hw.deviceContext;
389
+ * ```
390
+ */
391
+ get deviceContext() {
392
+ return this._deviceContext;
393
+ }
394
+ /**
395
+ * Get the device type enum value.
396
+ *
397
+ * @example
398
+ * ```typescript
399
+ * if (hw.deviceType === AV_HWDEVICE_TYPE_CUDA) {
400
+ * console.log('Using NVIDIA GPU');
401
+ * }
402
+ * ```
403
+ */
404
+ get deviceType() {
405
+ return this._deviceType;
406
+ }
407
+ /**
408
+ * Get the hardware device type name.
409
+ *
410
+ * Human-readable device type string.
411
+ *
412
+ * @example
413
+ * ```typescript
414
+ * console.log(`Hardware type: ${hw.deviceTypeName}`);
415
+ * // Output: "cuda" or "videotoolbox" etc.
416
+ * ```
417
+ */
418
+ get deviceTypeName() {
419
+ return this._deviceTypeName;
420
+ }
421
+ /**
422
+ * Get the device pixel format.
423
+ *
424
+ * Hardware-specific pixel format for frame allocation.
425
+ *
426
+ * @example
427
+ * ```typescript
428
+ * frame.format = hw.devicePixelFormat;
429
+ * ```
430
+ */
431
+ get devicePixelFormat() {
432
+ return this._devicePixelFormat;
433
+ }
434
+ /**
435
+ * Check if this hardware context has been disposed.
436
+ *
437
+ * @example
438
+ * ```typescript
439
+ * if (!hw.isDisposed) {
440
+ * hw.dispose();
441
+ * }
442
+ * ```
443
+ */
444
+ get isDisposed() {
445
+ return this._isDisposed;
446
+ }
447
+ /**
448
+ * Get hardware frame constraints.
449
+ *
450
+ * Returns the resolution limits and supported pixel formats for this hardware device.
451
+ * Essential for validating encoder/decoder parameters before initialization.
452
+ *
453
+ * Direct mapping to av_hwdevice_get_hwframe_constraints().
454
+ *
455
+ * @param hwconfig - Optional hardware configuration pointer
456
+ *
457
+ * @returns Constraints object with resolution limits and formats, or null if not available
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * const hw = HardwareContext.auto();
462
+ * if (hw) {
463
+ * const constraints = hw.getFrameConstraints();
464
+ * if (constraints) {
465
+ * console.log(`Resolution: ${constraints.minWidth}x${constraints.minHeight} to ${constraints.maxWidth}x${constraints.maxHeight}`);
466
+ * console.log('Hardware formats:', constraints.validHwFormats);
467
+ * console.log('Software formats:', constraints.validSwFormats);
468
+ * }
469
+ * }
470
+ * ```
471
+ *
472
+ * @example
473
+ * ```typescript
474
+ * import { AV_HWDEVICE_TYPE_VIDEOTOOLBOX } from 'node-av/constants';
475
+ *
476
+ * // VideoToolbox has resolution limits
477
+ * const hw = HardwareContext.create(AV_HWDEVICE_TYPE_VIDEOTOOLBOX);
478
+ * const constraints = hw?.getFrameConstraints();
479
+ * if (constraints && (width > constraints.maxWidth || height > constraints.maxHeight)) {
480
+ * console.log('Resolution exceeds hardware limits, falling back to software encoder');
481
+ * }
482
+ * ```
483
+ *
484
+ * @see {@link HardwareDeviceContext.getHwframeConstraints} For low-level API
485
+ */
486
+ getFrameConstraints(hwconfig) {
487
+ if (this._isDisposed) {
488
+ return null;
489
+ }
490
+ return this._deviceContext.getHwframeConstraints(hwconfig);
491
+ }
492
+ /**
493
+ * Check if this hardware type supports a specific codec.
494
+ *
495
+ * Queries FFmpeg's codec configurations to verify hardware support.
496
+ * Checks both decoder and encoder support based on parameters.
497
+ *
498
+ * Direct mapping to avcodec_get_hw_config().
499
+ *
500
+ * @param codecId - Codec ID from AVCodecID enum
501
+ *
502
+ * @param isEncoder - Check for encoder support (default: decoder)
503
+ *
504
+ * @returns true if codec is supported
505
+ *
506
+ * @example
507
+ * ```typescript
508
+ * import { AV_CODEC_ID_H264 } from 'node-av/constants';
509
+ *
510
+ * if (hw.supportsCodec(AV_CODEC_ID_H264, true)) {
511
+ * // Can use hardware H.264 encoder
512
+ * }
513
+ * ```
514
+ *
515
+ * @see {@link findSupportedCodecs} For all supported codecs
516
+ */
517
+ supportsCodec(codecId, isEncoder = false) {
518
+ const codecs = Codec.getCodecList();
519
+ for (const codec of codecs) {
520
+ if (codec.id !== codecId)
521
+ continue;
522
+ if (isEncoder && !codec.isEncoder())
523
+ continue;
524
+ if (!isEncoder && !codec.isDecoder())
525
+ continue;
526
+ if (isEncoder ? codec.isHardwareAcceleratedEncoder(this._deviceType) : codec.isHardwareAcceleratedDecoder(this._deviceType)) {
527
+ return true;
528
+ }
529
+ }
530
+ return false;
531
+ }
532
+ /**
533
+ * Check if this hardware supports a specific pixel format for a codec.
534
+ *
535
+ * Verifies pixel format compatibility with hardware codec.
536
+ * Important for ensuring format compatibility in pipelines.
537
+ *
538
+ * @param codecId - Codec ID from AVCodecID enum
539
+ *
540
+ * @param pixelFormat - Pixel format to check
541
+ *
542
+ * @param isEncoder - Check for encoder (default: decoder)
543
+ *
544
+ * @returns true if pixel format is supported
545
+ *
546
+ * @example
547
+ * ```typescript
548
+ * import { AV_CODEC_ID_H264, AV_PIX_FMT_NV12 } from 'node-av/constants';
549
+ *
550
+ * if (hw.supportsPixelFormat(AV_CODEC_ID_H264, AV_PIX_FMT_NV12)) {
551
+ * // Can use NV12 format with H.264
552
+ * }
553
+ * ```
554
+ *
555
+ * @see {@link supportsCodec} For basic codec support
556
+ */
557
+ supportsPixelFormat(codecId, pixelFormat, isEncoder = false) {
558
+ const codecs = Codec.getCodecList();
559
+ for (const codec of codecs) {
560
+ if (codec.id !== codecId)
561
+ continue;
562
+ if (isEncoder && !codec.isEncoder())
563
+ continue;
564
+ if (!isEncoder && !codec.isDecoder())
565
+ continue;
566
+ if (isEncoder ? codec.isHardwareAcceleratedEncoder(this._deviceType) : codec.isHardwareAcceleratedDecoder(this._deviceType)) {
567
+ const pixelFormats = codec.pixelFormats ?? [];
568
+ if (pixelFormats.some((fmt) => fmt === pixelFormat)) {
569
+ return true;
570
+ }
571
+ }
572
+ }
573
+ return false;
574
+ }
575
+ /**
576
+ * Get the appropriate encoder codec for a given base codec name.
577
+ *
578
+ * Maps generic codec names to hardware-specific encoder implementations.
579
+ * Returns null if no hardware encoder is available for the codec.
580
+ * Automatically tests encoder viability before returning.
581
+ *
582
+ * @param codecOrStream - Generic codec name (e.g., 'h264', 'hevc', 'av1'), AVCodecID or Stream
583
+ *
584
+ * @param validate - Whether to validate encoder by testing (default: false)
585
+ *
586
+ * @returns Hardware encoder codec or null if unsupported
587
+ *
588
+ * @example
589
+ * ```typescript
590
+ * const encoderCodec = hw.getEncoderCodec('h264');
591
+ * if (encoderCodec) {
592
+ * console.log(`Using encoder: ${encoderCodec.name}`);
593
+ * // e.g., "h264_nvenc" for CUDA
594
+ * }
595
+ * ```
596
+ *
597
+ * @example
598
+ * ```typescript
599
+ * // Use with Encoder.create
600
+ * const codec = hw.getEncoderCodec('hevc');
601
+ * if (codec) {
602
+ * const encoder = await Encoder.create(codec, { ... });
603
+ * }
604
+ * ```
605
+ *
606
+ * @see {@link Encoder.create} For using the codec
607
+ */
608
+ getEncoderCodec(codecOrStream, validate) {
609
+ // Build the encoder name
610
+ let codecBaseName = null;
611
+ let encoderSuffix = '';
612
+ if (codecOrStream instanceof Stream) {
613
+ const codecParams = codecOrStream.codecpar;
614
+ codecBaseName = this.getBaseCodecName(codecParams.codecId) ?? null;
615
+ }
616
+ else if (typeof codecOrStream === 'number') {
617
+ codecBaseName = this.getBaseCodecName(codecOrStream) ?? null;
618
+ }
619
+ else {
620
+ codecBaseName = codecOrStream;
621
+ }
622
+ if (!codecBaseName) {
623
+ return null;
624
+ }
625
+ const decoderCodecId = this.getCodecIDFromBaseName(codecBaseName);
626
+ // We might only have hardware decode capabilities (d3d11va, d3d12va etc)
627
+ // So we need to check for other hardware encoders
628
+ const getAlternativeEncoder = () => {
629
+ const nvencCodecName = `${codecBaseName}_nvenc`;
630
+ const qsvCodecName = `${codecBaseName}_qsv`;
631
+ const amfCodecName = `${codecBaseName}_amf`;
632
+ const codecNames = [nvencCodecName, qsvCodecName, amfCodecName];
633
+ let suffix = '';
634
+ for (const name of codecNames) {
635
+ const encoderCodec = Codec.findEncoderByName(name);
636
+ if (!encoderCodec) {
637
+ continue;
638
+ }
639
+ suffix = name.split('_')[1]; // Get suffix after underscore
640
+ if (!suffix) {
641
+ return null;
642
+ }
643
+ return suffix;
644
+ }
645
+ return null;
646
+ };
647
+ switch (this._deviceType) {
648
+ case AV_HWDEVICE_TYPE_CUDA:
649
+ // CUDA uses NVENC for encoding
650
+ encoderSuffix = 'nvenc';
651
+ break;
652
+ case AV_HWDEVICE_TYPE_D3D11VA:
653
+ case AV_HWDEVICE_TYPE_DXVA2:
654
+ encoderSuffix = getAlternativeEncoder() ?? '';
655
+ break;
656
+ case AV_HWDEVICE_TYPE_OPENCL:
657
+ case AV_HWDEVICE_TYPE_VDPAU:
658
+ case AV_HWDEVICE_TYPE_DRM:
659
+ encoderSuffix = getAlternativeEncoder() ?? '';
660
+ break;
661
+ default:
662
+ // Use the device type name as suffix
663
+ encoderSuffix = this._deviceTypeName;
664
+ }
665
+ if (!encoderSuffix) {
666
+ return null;
667
+ }
668
+ // Construct the encoder name
669
+ const encoderName = `${codecBaseName}_${encoderSuffix}`;
670
+ const encoderCodec = Codec.findEncoderByName(encoderName);
671
+ if (!encoderCodec?.isHardwareAcceleratedEncoder()) {
672
+ return null;
673
+ }
674
+ if (validate && decoderCodecId !== null) {
675
+ const isValid = this.testEncoder(decoderCodecId, encoderCodec);
676
+ if (!isValid) {
677
+ return null;
678
+ }
679
+ }
680
+ return encoderCodec;
681
+ }
682
+ /**
683
+ * Get the appropriate decoder codec for a given base codec name.
684
+ *
685
+ * Maps generic codec names to hardware-specific decoder implementations.
686
+ * Returns null if no hardware decoder is available for the codec.
687
+ * Automatically searches for decoders that support this hardware device type.
688
+ *
689
+ * @param codec - Generic codec name (e.g., 'h264', 'hevc', 'av1') or AVCodecID
690
+ *
691
+ * @returns Hardware decoder codec or null if unsupported
692
+ *
693
+ * @example
694
+ * ```typescript
695
+ * const decoderCodec = hw.getDecoderCodec('hevc');
696
+ * if (decoderCodec) {
697
+ * console.log(`Using decoder: ${decoderCodec.name}`);
698
+ * // e.g., "hevc_qsv" for QSV
699
+ * }
700
+ * ```
701
+ *
702
+ * @example
703
+ * ```typescript
704
+ * // Use with Decoder.create
705
+ * const codec = hw.getDecoderCodec(AV_CODEC_ID_H264);
706
+ * if (codec) {
707
+ * const decoder = await Decoder.create(stream, { hardware: hw });
708
+ * }
709
+ * ```
710
+ *
711
+ * @see {@link Decoder.create} For using the codec
712
+ * @see {@link getEncoderCodec} For hardware encoders
713
+ */
714
+ getDecoderCodec(codec) {
715
+ // Get codec ID
716
+ let codecId = null;
717
+ if (typeof codec === 'number') {
718
+ codecId = codec;
719
+ }
720
+ else {
721
+ codecId = this.getCodecIDFromBaseName(codec);
722
+ }
723
+ if (codecId === null) {
724
+ return null;
725
+ }
726
+ // Find all decoders for this codec
727
+ const codecs = Codec.getCodecList();
728
+ for (const decoderCodec of codecs) {
729
+ // Skip if not a decoder
730
+ if (!decoderCodec.isDecoder()) {
731
+ continue;
732
+ }
733
+ // Skip if wrong codec ID
734
+ if (decoderCodec.id !== codecId) {
735
+ continue;
736
+ }
737
+ // Check if this decoder supports our hardware device type
738
+ for (let i = 0;; i++) {
739
+ const config = decoderCodec.getHwConfig(i);
740
+ if (!config)
741
+ break;
742
+ // Accept both HW_DEVICE_CTX and HW_FRAMES_CTX methods
743
+ const supportsDeviceCtx = (config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) !== 0;
744
+ const supportsFramesCtx = (config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) !== 0;
745
+ if ((supportsDeviceCtx || supportsFramesCtx) && config.deviceType === this._deviceType) {
746
+ // Found a hardware decoder that supports this device type
747
+ return decoderCodec;
748
+ }
749
+ }
750
+ }
751
+ return null;
752
+ }
753
+ /**
754
+ * Test if hardware acceleration is working by decoding a test frame.
755
+ *
756
+ * Creates a simple decoder and attempts to decode with hardware acceleration.
757
+ * Returns true if hardware decoding succeeds, false otherwise.
758
+ * Useful for validating hardware setup before processing.
759
+ *
760
+ * @param codecId - Codec ID to test (default: H.264)
761
+ *
762
+ * @returns Promise that resolves to true if hardware works
763
+ *
764
+ * @example
765
+ * ```typescript
766
+ * const hw = HardwareContext.auto();
767
+ * if (hw && await hw.testDecoder()) {
768
+ * console.log('Hardware acceleration working!');
769
+ * // Proceed with hardware decoding/encoding
770
+ * } else {
771
+ * console.log('Hardware acceleration not available');
772
+ * // Fall back to software
773
+ * }
774
+ * ```
775
+ *
776
+ * @example
777
+ * ```typescript
778
+ * // Test specific hardware
779
+ * const cuda = HardwareContext.create(AV_HWDEVICE_TYPE_CUDA);
780
+ * if (cuda && await cuda.testDecoder()) {
781
+ * console.log('CUDA acceleration works');
782
+ * }
783
+ * ```
784
+ *
785
+ * @see {@link supportsCodec} For checking codec support
786
+ */
787
+ testDecoder(codecId = AV_CODEC_ID_H264) {
788
+ try {
789
+ if (!this.supportsCodec(codecId, false)) {
790
+ return false;
791
+ }
792
+ return this.testCodec(codecId);
793
+ }
794
+ catch {
795
+ return false;
796
+ }
797
+ }
798
+ /**
799
+ * Test if hardware encoding works with a specific codec pair.
800
+ *
801
+ * Attempts to decode and re-encode a test frame using hardware acceleration.
802
+ * Validates both decoding and encoding paths for the given codecs.
803
+ *
804
+ * @param decoderCodec - Codec name, ID, or instance to use for decoding
805
+ *
806
+ * @param encoderCodec - Codec name or instance to use for encoding
807
+ *
808
+ * @returns true if both decoding and encoding succeed
809
+ *
810
+ * @example
811
+ * ```typescript
812
+ * import { AV_CODEC_ID_H264 } from 'node-av/constants';
813
+ *
814
+ * const hw = HardwareContext.auto();
815
+ * if (hw && hw.testEncoder(AV_CODEC_ID_H264, AV_CODEC_ID_H264)) {
816
+ * console.log('Hardware H.264 encoding works!');
817
+ * }
818
+ * ```
819
+ *
820
+ * @see {@link getEncoderCodec} For obtaining hardware encoder codec
821
+ */
822
+ testEncoder(decoderCodec, encoderCodec) {
823
+ const isSupported = this.testCodec(decoderCodec, encoderCodec);
824
+ if (!isSupported) {
825
+ return false;
826
+ }
827
+ return true;
828
+ }
829
+ /**
830
+ * Find all codecs that support this hardware device.
831
+ *
832
+ * Iterates through all available codecs and checks hardware compatibility.
833
+ * Useful for discovering available hardware acceleration options.
834
+ *
835
+ * Direct mapping to av_codec_iterate() with hardware config checks.
836
+ *
837
+ * @param isEncoder - Find encoders (true) or decoders (false)
838
+ *
839
+ * @returns Array of codec names that support this hardware
840
+ *
841
+ * @example
842
+ * ```typescript
843
+ * const decoders = hw.findSupportedCodecs(false);
844
+ * console.log('Hardware decoders:', decoders);
845
+ * // ["h264_cuvid", "hevc_cuvid", ...]
846
+ *
847
+ * const encoders = hw.findSupportedCodecs(true);
848
+ * console.log('Hardware encoders:', encoders);
849
+ * // ["h264_nvenc", "hevc_nvenc", ...]
850
+ * ```
851
+ *
852
+ * @see {@link supportsCodec} For checking specific codec
853
+ */
854
+ findSupportedCodecs(isEncoder = false) {
855
+ const supportedCodecs = [];
856
+ const codecs = Codec.getCodecList();
857
+ for (const codec of codecs) {
858
+ // Skip if wrong type (encoder vs decoder)
859
+ if (isEncoder && !codec.isEncoder())
860
+ continue;
861
+ if (!isEncoder && !codec.isDecoder())
862
+ continue;
863
+ // Check if this codec supports our hardware device type
864
+ for (let i = 0;; i++) {
865
+ const config = codec.getHwConfig(i);
866
+ if (!config)
867
+ break;
868
+ // Accept both HW_DEVICE_CTX and HW_FRAMES_CTX methods
869
+ const supportsDeviceCtx = (config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) !== 0;
870
+ const supportsFramesCtx = (config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) !== 0;
871
+ if ((supportsDeviceCtx || supportsFramesCtx) && config.deviceType === this._deviceType) {
872
+ if (codec.name) {
873
+ supportedCodecs.push(codec.name);
874
+ }
875
+ break; // Found support, move to next codec
876
+ }
877
+ }
878
+ }
879
+ return supportedCodecs;
880
+ }
881
+ /**
882
+ * Clean up and free hardware resources.
883
+ *
884
+ * Releases the hardware device context.
885
+ * Safe to call multiple times.
886
+ * Automatically called by Symbol.dispose.
887
+ *
888
+ * @example
889
+ * ```typescript
890
+ * const hw = HardwareContext.auto();
891
+ * try {
892
+ * // Use hardware
893
+ * } finally {
894
+ * hw?.dispose();
895
+ * }
896
+ * ```
897
+ *
898
+ * @see {@link Symbol.dispose} For automatic cleanup
899
+ */
900
+ dispose() {
901
+ if (this._isDisposed) {
902
+ return;
903
+ }
904
+ this._deviceContext.free();
905
+ this._isDisposed = true;
906
+ }
907
+ /**
908
+ * Test hardware decoding with a specific codec.
909
+ *
910
+ * @param decoderCodec - Decoder codec name, ID, or instance to test
911
+ *
912
+ * @param encoderCodec - Optional encoder codec name or instance to test
913
+ *
914
+ * @param useFilter - Whether to test hwdownload filter (default: true)
915
+ *
916
+ * @returns true if decoding succeeds
917
+ *
918
+ * @internal
919
+ */
920
+ testCodec(decoderCodec, encoderCodec, useFilter = true) {
921
+ try {
922
+ const env_1 = { stack: [], error: void 0, hasError: false };
923
+ try {
924
+ let codecDecoder = null;
925
+ let codecEncoder = null;
926
+ if (decoderCodec instanceof Codec) {
927
+ codecDecoder = decoderCodec;
928
+ }
929
+ else if (typeof decoderCodec === 'string') {
930
+ codecDecoder = Codec.findDecoderByName(decoderCodec);
931
+ }
932
+ else {
933
+ codecDecoder = Codec.findDecoder(decoderCodec);
934
+ }
935
+ if (!codecDecoder) {
936
+ throw new Error('Decoder codec not found');
937
+ }
938
+ // Select appropriate test file based on codec
939
+ let testFilePath;
940
+ switch (codecDecoder.id) {
941
+ case AV_CODEC_ID_HEVC:
942
+ testFilePath = hevcData;
943
+ break;
944
+ case AV_CODEC_ID_VP8:
945
+ testFilePath = vp8Data;
946
+ break;
947
+ case AV_CODEC_ID_VP9:
948
+ testFilePath = vp9Data;
949
+ break;
950
+ case AV_CODEC_ID_AV1:
951
+ testFilePath = av1Data;
952
+ break;
953
+ case AV_CODEC_ID_MJPEG:
954
+ testFilePath = mjpegData;
955
+ break;
956
+ case AV_CODEC_ID_H264:
957
+ default:
958
+ testFilePath = h264Data;
959
+ break;
960
+ }
961
+ // Read test bitstream
962
+ const input = __addDisposableResource(env_1, Demuxer.openSync(testFilePath), false);
963
+ const videoStream = input.video();
964
+ const decoder = __addDisposableResource(env_1, Decoder.createSync(videoStream, {
965
+ hardware: this,
966
+ }), false);
967
+ const packetGenerator = input.packetsSync();
968
+ const hwFrameGenerator = decoder.framesSync(packetGenerator);
969
+ // Optionally create hwdownload filter to test hardware → software transfer
970
+ const filter = __addDisposableResource(env_1, useFilter
971
+ ? FilterAPI.create('hwdownload,format=nv12', {
972
+ framerate: videoStream.avgFrameRate,
973
+ hardware: this,
974
+ })
975
+ : null, false);
976
+ const frameGenerator = filter ? filter.framesSync(hwFrameGenerator) : hwFrameGenerator;
977
+ // Resolve encoder codec if provided
978
+ if (encoderCodec) {
979
+ if (encoderCodec instanceof Codec) {
980
+ codecEncoder = encoderCodec;
981
+ }
982
+ else if (typeof encoderCodec === 'string') {
983
+ codecEncoder = Codec.findEncoderByName(encoderCodec);
984
+ }
985
+ else {
986
+ codecEncoder = Codec.findEncoder(encoderCodec);
987
+ }
988
+ if (!codecEncoder) {
989
+ return false;
990
+ }
991
+ }
992
+ const encoder = __addDisposableResource(env_1, codecEncoder
993
+ ? Encoder.createSync(codecEncoder, {
994
+ decoder,
995
+ filter: filter ?? undefined,
996
+ })
997
+ : null, false);
998
+ const outputGenerator = encoder ? encoder.packetsSync(frameGenerator) : frameGenerator;
999
+ let hasData = false;
1000
+ for (const _1 of outputGenerator) {
1001
+ const env_2 = { stack: [], error: void 0, hasError: false };
1002
+ try {
1003
+ const _ = __addDisposableResource(env_2, _1, false);
1004
+ if (!_)
1005
+ continue;
1006
+ hasData = true;
1007
+ break;
1008
+ }
1009
+ catch (e_1) {
1010
+ env_2.error = e_1;
1011
+ env_2.hasError = true;
1012
+ }
1013
+ finally {
1014
+ __disposeResources(env_2);
1015
+ }
1016
+ }
1017
+ return hasData;
1018
+ }
1019
+ catch (e_2) {
1020
+ env_1.error = e_2;
1021
+ env_1.hasError = true;
1022
+ }
1023
+ finally {
1024
+ __disposeResources(env_1);
1025
+ }
1026
+ }
1027
+ catch {
1028
+ return false;
1029
+ }
1030
+ }
1031
+ /**
1032
+ * Map AVCodecID to base codec name for hardware encoder lookup.
1033
+ *
1034
+ * Converts codec IDs to generic codec names used for encoder naming.
1035
+ * Used internally to find hardware-specific encoder implementations.
1036
+ *
1037
+ * @param codecId - AVCodecID enum value
1038
+ *
1039
+ * @returns Base codec name or null if unsupported
1040
+ *
1041
+ * @internal
1042
+ */
1043
+ getBaseCodecName(codecId) {
1044
+ switch (codecId) {
1045
+ case AV_CODEC_ID_AV1:
1046
+ return 'av1';
1047
+ case AV_CODEC_ID_H264:
1048
+ return 'h264';
1049
+ case AV_CODEC_ID_HEVC:
1050
+ return 'hevc';
1051
+ case AV_CODEC_ID_H263:
1052
+ return 'h263';
1053
+ case AV_CODEC_ID_MPEG2VIDEO:
1054
+ return 'mpeg2';
1055
+ case AV_CODEC_ID_MPEG4:
1056
+ return 'mpeg4';
1057
+ case AV_CODEC_ID_VP8:
1058
+ return 'vp8';
1059
+ case AV_CODEC_ID_VP9:
1060
+ return 'vp9';
1061
+ case AV_CODEC_ID_MJPEG:
1062
+ return 'mjpeg';
1063
+ case AV_CODEC_ID_PRORES:
1064
+ return 'prores';
1065
+ default:
1066
+ return null;
1067
+ }
1068
+ }
1069
+ /**
1070
+ * Map base codec name to AVCodecID for internal use.
1071
+ *
1072
+ * Converts generic codec names to AVCodecID enum values.
1073
+ * Used internally for codec testing and validation.
1074
+ *
1075
+ * @param codecBaseName - Base codec name string
1076
+ *
1077
+ * @returns Corresponding AVCodecID or null if unsupported
1078
+ *
1079
+ * @internal
1080
+ */
1081
+ getCodecIDFromBaseName(codecBaseName) {
1082
+ switch (codecBaseName) {
1083
+ case 'av1':
1084
+ return AV_CODEC_ID_AV1;
1085
+ case 'h264':
1086
+ return AV_CODEC_ID_H264;
1087
+ case 'hevc':
1088
+ return AV_CODEC_ID_HEVC;
1089
+ case 'h263':
1090
+ return AV_CODEC_ID_H263;
1091
+ case 'mpeg2':
1092
+ return AV_CODEC_ID_MPEG2VIDEO;
1093
+ case 'mpeg4':
1094
+ return AV_CODEC_ID_MPEG4;
1095
+ case 'vp8':
1096
+ return AV_CODEC_ID_VP8;
1097
+ case 'vp9':
1098
+ return AV_CODEC_ID_VP9;
1099
+ case 'mjpeg':
1100
+ return AV_CODEC_ID_MJPEG;
1101
+ case 'prores':
1102
+ return AV_CODEC_ID_PRORES;
1103
+ default:
1104
+ return null;
1105
+ }
1106
+ }
1107
+ /**
1108
+ * Get the hardware decoder pixel format for this device type.
1109
+ *
1110
+ * Maps device types to their corresponding pixel formats.
1111
+ * Used internally for frame format configuration.
1112
+ *
1113
+ * @returns Hardware-specific pixel format
1114
+ *
1115
+ * @internal
1116
+ */
1117
+ getHardwareDecoderPixelFormat() {
1118
+ switch (this._deviceType) {
1119
+ case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
1120
+ return AV_PIX_FMT_VIDEOTOOLBOX;
1121
+ case AV_HWDEVICE_TYPE_VAAPI:
1122
+ return AV_PIX_FMT_VAAPI;
1123
+ case AV_HWDEVICE_TYPE_CUDA:
1124
+ return AV_PIX_FMT_CUDA;
1125
+ case AV_HWDEVICE_TYPE_QSV:
1126
+ return AV_PIX_FMT_QSV;
1127
+ case AV_HWDEVICE_TYPE_D3D11VA:
1128
+ return AV_PIX_FMT_D3D11;
1129
+ case AV_HWDEVICE_TYPE_DXVA2:
1130
+ return AV_PIX_FMT_DXVA2_VLD;
1131
+ case AV_HWDEVICE_TYPE_DRM:
1132
+ return AV_PIX_FMT_DRM_PRIME;
1133
+ case AV_HWDEVICE_TYPE_OPENCL:
1134
+ return AV_PIX_FMT_OPENCL;
1135
+ case AV_HWDEVICE_TYPE_MEDIACODEC:
1136
+ return AV_PIX_FMT_MEDIACODEC;
1137
+ case AV_HWDEVICE_TYPE_VULKAN:
1138
+ return AV_PIX_FMT_VULKAN;
1139
+ case AV_HWDEVICE_TYPE_D3D12VA:
1140
+ return AV_PIX_FMT_D3D12;
1141
+ case AV_HWDEVICE_TYPE_RKMPP:
1142
+ return AV_PIX_FMT_DRM_PRIME; // RKMPP uses DRM Prime buffers
1143
+ default:
1144
+ return AV_PIX_FMT_NV12; // Common hardware format
1145
+ }
1146
+ }
1147
+ /**
1148
+ * Create hardware context from device type.
1149
+ *
1150
+ * Internal factory method using av_hwdevice_ctx_create().
1151
+ *
1152
+ * @param deviceType - AVHWDeviceType enum value
1153
+ *
1154
+ * @param device - Optional device specifier
1155
+ *
1156
+ * @param options - Optional device options
1157
+ *
1158
+ * @returns Hardware context or null if creation fails
1159
+ *
1160
+ * @internal
1161
+ */
1162
+ static createFromType(deviceType, device, options) {
1163
+ // Set environment variables for Vulkan to enable video support on older gpus
1164
+ if (deviceType === AV_HWDEVICE_TYPE_VULKAN) {
1165
+ process.env.ANV_DEBUG ??= 'video-decode,video-encode';
1166
+ process.env.RADV_PERFTEST ??= 'video_decode,video_encode';
1167
+ }
1168
+ const deviceCtx = new HardwareDeviceContext();
1169
+ // Convert options to Dictionary if provided
1170
+ let optionsDict = null;
1171
+ if (options && Object.keys(options).length > 0) {
1172
+ optionsDict = Dictionary.fromObject(options);
1173
+ }
1174
+ const ret = deviceCtx.create(deviceType, device, optionsDict);
1175
+ // Clean up dictionary if used
1176
+ if (optionsDict) {
1177
+ optionsDict.free();
1178
+ }
1179
+ const deviceTypeName = HardwareDeviceContext.getTypeName(deviceType);
1180
+ if (ret < 0 || !deviceTypeName) {
1181
+ deviceCtx.free();
1182
+ FFmpegError.throwIfError(ret);
1183
+ throw new Error('Unknown error creating hardware device context');
1184
+ }
1185
+ return new HardwareContext(deviceCtx, deviceType, deviceTypeName);
1186
+ }
1187
+ /**
1188
+ * Get platform-specific preference order for hardware types.
1189
+ *
1190
+ * Returns available hardware types sorted by platform preference.
1191
+ * Ensures optimal hardware selection for each platform.
1192
+ *
1193
+ * @returns Array of AVHWDeviceType values in preference order
1194
+ *
1195
+ * @internal
1196
+ */
1197
+ static getPreferenceOrder() {
1198
+ // Get all available hardware types on this system
1199
+ const available = HardwareDeviceContext.iterateTypes();
1200
+ if (available.length === 0) {
1201
+ return [];
1202
+ }
1203
+ const platform = process.platform;
1204
+ let preferenceOrder;
1205
+ if (platform === 'darwin') {
1206
+ preferenceOrder = [AV_HWDEVICE_TYPE_VIDEOTOOLBOX];
1207
+ }
1208
+ else if (platform === 'win32') {
1209
+ preferenceOrder = [
1210
+ AV_HWDEVICE_TYPE_CUDA,
1211
+ AV_HWDEVICE_TYPE_QSV,
1212
+ AV_HWDEVICE_TYPE_D3D11VA,
1213
+ AV_HWDEVICE_TYPE_D3D12VA,
1214
+ AV_HWDEVICE_TYPE_DXVA2,
1215
+ AV_HWDEVICE_TYPE_VULKAN,
1216
+ AV_HWDEVICE_TYPE_OPENCL,
1217
+ ];
1218
+ }
1219
+ else {
1220
+ // Linux/Unix platforms
1221
+ const isARM = process.arch === 'arm64' || process.arch === 'arm';
1222
+ if (isARM) {
1223
+ preferenceOrder = [AV_HWDEVICE_TYPE_RKMPP, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_DRM, AV_HWDEVICE_TYPE_VULKAN, AV_HWDEVICE_TYPE_OPENCL];
1224
+ }
1225
+ else {
1226
+ preferenceOrder = [AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_QSV, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_DRM, AV_HWDEVICE_TYPE_VULKAN, AV_HWDEVICE_TYPE_OPENCL];
1227
+ }
1228
+ }
1229
+ // Filter preference order to only include available types
1230
+ const availableSet = new Set(available);
1231
+ const sortedAvailable = preferenceOrder.filter((type) => availableSet.has(type));
1232
+ // Add any available types not in our preference list at the end
1233
+ for (const type of available) {
1234
+ if (!preferenceOrder.includes(type)) {
1235
+ sortedAvailable.push(type);
1236
+ }
1237
+ }
1238
+ return sortedAvailable;
1239
+ }
1240
+ /**
1241
+ * Dispose of hardware context.
1242
+ *
1243
+ * Implements Disposable interface for automatic cleanup.
1244
+ * Equivalent to calling dispose().
1245
+ *
1246
+ * @example
1247
+ * ```typescript
1248
+ * {
1249
+ * using hw = HardwareContext.auto();
1250
+ * // Use hardware context...
1251
+ * } // Automatically disposed
1252
+ * ```
1253
+ *
1254
+ * @see {@link dispose} For manual cleanup
1255
+ */
1256
+ [Symbol.dispose]() {
1257
+ this.dispose();
1258
+ }
1259
+ }
1260
+ //# sourceMappingURL=hardware.js.map