node-av 1.0.3 → 1.2.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 (162) hide show
  1. package/README.md +56 -41
  2. package/dist/api/bitstream-filter.d.ts +180 -123
  3. package/dist/api/bitstream-filter.js +182 -126
  4. package/dist/api/bitstream-filter.js.map +1 -1
  5. package/dist/api/decoder.d.ts +286 -130
  6. package/dist/api/decoder.js +321 -159
  7. package/dist/api/decoder.js.map +1 -1
  8. package/dist/api/encoder.d.ts +254 -158
  9. package/dist/api/encoder.js +326 -298
  10. package/dist/api/encoder.js.map +1 -1
  11. package/dist/api/filter-presets.d.ts +912 -0
  12. package/dist/api/filter-presets.js +1407 -0
  13. package/dist/api/filter-presets.js.map +1 -0
  14. package/dist/api/filter.d.ts +280 -284
  15. package/dist/api/filter.js +435 -509
  16. package/dist/api/filter.js.map +1 -1
  17. package/dist/api/hardware.d.ts +226 -159
  18. package/dist/api/hardware.js +405 -287
  19. package/dist/api/hardware.js.map +1 -1
  20. package/dist/api/index.d.ts +3 -2
  21. package/dist/api/index.js +1 -0
  22. package/dist/api/index.js.map +1 -1
  23. package/dist/api/io-stream.d.ts +65 -61
  24. package/dist/api/io-stream.js +45 -47
  25. package/dist/api/io-stream.js.map +1 -1
  26. package/dist/api/media-input.d.ts +244 -141
  27. package/dist/api/media-input.js +207 -104
  28. package/dist/api/media-input.js.map +1 -1
  29. package/dist/api/media-output.d.ts +206 -128
  30. package/dist/api/media-output.js +212 -129
  31. package/dist/api/media-output.js.map +1 -1
  32. package/dist/api/pipeline.d.ts +168 -38
  33. package/dist/api/pipeline.js +238 -14
  34. package/dist/api/pipeline.js.map +1 -1
  35. package/dist/api/types.d.ts +22 -182
  36. package/dist/api/utilities/audio-sample.d.ts +1 -1
  37. package/dist/api/utilities/image.d.ts +1 -1
  38. package/dist/api/utilities/media-type.d.ts +1 -1
  39. package/dist/api/utilities/pixel-format.d.ts +1 -1
  40. package/dist/api/utilities/sample-format.d.ts +1 -1
  41. package/dist/api/utilities/timestamp.d.ts +1 -1
  42. package/dist/api/utils.d.ts +1 -2
  43. package/dist/api/utils.js +9 -0
  44. package/dist/api/utils.js.map +1 -1
  45. package/dist/{lib → constants}/channel-layouts.d.ts +1 -1
  46. package/dist/constants/channel-layouts.js.map +1 -0
  47. package/dist/{lib → constants}/constants.d.ts +19 -4
  48. package/dist/{lib → constants}/constants.js +15 -1
  49. package/dist/constants/constants.js.map +1 -0
  50. package/dist/constants/decoders.d.ts +609 -0
  51. package/dist/constants/decoders.js +617 -0
  52. package/dist/constants/decoders.js.map +1 -0
  53. package/dist/constants/encoders.d.ts +285 -0
  54. package/dist/constants/encoders.js +298 -0
  55. package/dist/constants/encoders.js.map +1 -0
  56. package/dist/constants/index.d.ts +4 -0
  57. package/dist/constants/index.js +5 -0
  58. package/dist/constants/index.js.map +1 -0
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.js +2 -0
  61. package/dist/index.js.map +1 -1
  62. package/dist/lib/audio-fifo.d.ts +128 -171
  63. package/dist/lib/audio-fifo.js +130 -173
  64. package/dist/lib/audio-fifo.js.map +1 -1
  65. package/dist/lib/binding.d.ts +7 -5
  66. package/dist/lib/binding.js +5 -0
  67. package/dist/lib/binding.js.map +1 -1
  68. package/dist/lib/bitstream-filter-context.d.ts +139 -184
  69. package/dist/lib/bitstream-filter-context.js +139 -188
  70. package/dist/lib/bitstream-filter-context.js.map +1 -1
  71. package/dist/lib/bitstream-filter.d.ts +69 -55
  72. package/dist/lib/bitstream-filter.js +68 -54
  73. package/dist/lib/bitstream-filter.js.map +1 -1
  74. package/dist/lib/codec-context.d.ts +317 -381
  75. package/dist/lib/codec-context.js +316 -381
  76. package/dist/lib/codec-context.js.map +1 -1
  77. package/dist/lib/codec-parameters.d.ts +161 -171
  78. package/dist/lib/codec-parameters.js +162 -172
  79. package/dist/lib/codec-parameters.js.map +1 -1
  80. package/dist/lib/codec-parser.d.ts +92 -105
  81. package/dist/lib/codec-parser.js +92 -103
  82. package/dist/lib/codec-parser.js.map +1 -1
  83. package/dist/lib/codec.d.ts +328 -217
  84. package/dist/lib/codec.js +392 -218
  85. package/dist/lib/codec.js.map +1 -1
  86. package/dist/lib/dictionary.d.ts +150 -204
  87. package/dist/lib/dictionary.js +159 -213
  88. package/dist/lib/dictionary.js.map +1 -1
  89. package/dist/lib/error.d.ts +97 -131
  90. package/dist/lib/error.js +98 -128
  91. package/dist/lib/error.js.map +1 -1
  92. package/dist/lib/filter-context.d.ts +317 -194
  93. package/dist/lib/filter-context.js +335 -200
  94. package/dist/lib/filter-context.js.map +1 -1
  95. package/dist/lib/filter-graph.d.ts +252 -293
  96. package/dist/lib/filter-graph.js +253 -294
  97. package/dist/lib/filter-graph.js.map +1 -1
  98. package/dist/lib/filter-inout.d.ts +87 -95
  99. package/dist/lib/filter-inout.js +87 -95
  100. package/dist/lib/filter-inout.js.map +1 -1
  101. package/dist/lib/filter.d.ts +93 -111
  102. package/dist/lib/filter.js +94 -112
  103. package/dist/lib/filter.js.map +1 -1
  104. package/dist/lib/format-context.d.ts +321 -429
  105. package/dist/lib/format-context.js +314 -386
  106. package/dist/lib/format-context.js.map +1 -1
  107. package/dist/lib/frame.d.ts +263 -406
  108. package/dist/lib/frame.js +263 -408
  109. package/dist/lib/frame.js.map +1 -1
  110. package/dist/lib/hardware-device-context.d.ts +150 -204
  111. package/dist/lib/hardware-device-context.js +149 -203
  112. package/dist/lib/hardware-device-context.js.map +1 -1
  113. package/dist/lib/hardware-frames-context.d.ts +171 -181
  114. package/dist/lib/hardware-frames-context.js +171 -181
  115. package/dist/lib/hardware-frames-context.js.map +1 -1
  116. package/dist/lib/index.d.ts +2 -3
  117. package/dist/lib/index.js +2 -5
  118. package/dist/lib/index.js.map +1 -1
  119. package/dist/lib/input-format.d.ts +90 -118
  120. package/dist/lib/input-format.js +89 -117
  121. package/dist/lib/input-format.js.map +1 -1
  122. package/dist/lib/io-context.d.ts +210 -242
  123. package/dist/lib/io-context.js +221 -253
  124. package/dist/lib/io-context.js.map +1 -1
  125. package/dist/lib/log.d.ts +86 -120
  126. package/dist/lib/log.js +85 -122
  127. package/dist/lib/log.js.map +1 -1
  128. package/dist/lib/native-types.d.ts +127 -112
  129. package/dist/lib/native-types.js +9 -0
  130. package/dist/lib/native-types.js.map +1 -1
  131. package/dist/lib/option.d.ts +285 -242
  132. package/dist/lib/option.js +310 -250
  133. package/dist/lib/option.js.map +1 -1
  134. package/dist/lib/output-format.d.ts +78 -102
  135. package/dist/lib/output-format.js +77 -101
  136. package/dist/lib/output-format.js.map +1 -1
  137. package/dist/lib/packet.d.ts +173 -241
  138. package/dist/lib/packet.js +172 -241
  139. package/dist/lib/packet.js.map +1 -1
  140. package/dist/lib/rational.d.ts +0 -2
  141. package/dist/lib/rational.js +0 -2
  142. package/dist/lib/rational.js.map +1 -1
  143. package/dist/lib/software-resample-context.d.ts +242 -326
  144. package/dist/lib/software-resample-context.js +242 -326
  145. package/dist/lib/software-resample-context.js.map +1 -1
  146. package/dist/lib/software-scale-context.d.ts +130 -174
  147. package/dist/lib/software-scale-context.js +132 -176
  148. package/dist/lib/software-scale-context.js.map +1 -1
  149. package/dist/lib/stream.d.ts +88 -198
  150. package/dist/lib/stream.js +87 -197
  151. package/dist/lib/stream.js.map +1 -1
  152. package/dist/lib/types.d.ts +1 -1
  153. package/dist/lib/utilities.d.ts +372 -181
  154. package/dist/lib/utilities.js +373 -182
  155. package/dist/lib/utilities.js.map +1 -1
  156. package/install/check.js +0 -1
  157. package/package.json +32 -24
  158. package/release_notes.md +43 -13
  159. package/CHANGELOG.md +0 -8
  160. package/dist/lib/channel-layouts.js.map +0 -1
  161. package/dist/lib/constants.js.map +0 -1
  162. /package/dist/{lib → constants}/channel-layouts.js +0 -0
@@ -1,101 +1,108 @@
1
+ import { AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, 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';
2
+ import { Codec, CodecContext, Dictionary, HardwareDeviceContext, Rational } from '../lib/index.js';
3
+ import { HardwareFilterPresets } from './filter-presets.js';
1
4
  /**
2
- * HardwareContext - High-level Hardware Acceleration API
5
+ * High-level hardware acceleration management.
3
6
  *
4
- * Provides simplified access to hardware acceleration features.
5
- * Automatically detects and configures hardware devices for encoding/decoding.
6
- *
7
- * Wraps the low-level HardwareDeviceContext and HardwareFramesContext.
8
- * Manages lifecycle of hardware resources with automatic cleanup.
9
- *
10
- * @module api/hardware
11
- */
12
- import { AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, 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_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, Codec, Dictionary, FFmpegError, HardwareDeviceContext, HardwareFramesContext, } from '../lib/index.js';
13
- /**
14
- * HardwareContext - Simplified hardware acceleration management.
15
- *
16
- * Provides automatic detection and configuration of hardware acceleration.
17
- * Manages device contexts and frame contexts for hardware encoding/decoding.
18
- *
19
- * Supports various hardware types including VideoToolbox (macOS), CUDA,
20
- * VAAPI (Linux), D3D11VA/D3D12VA (Windows), and more.
7
+ * Provides automatic detection and configuration of hardware acceleration for media processing.
8
+ * Manages device contexts for GPU-accelerated encoding and decoding operations.
9
+ * Supports various hardware types including VideoToolbox, CUDA, VAAPI, D3D11VA, and more.
10
+ * Essential for high-performance video processing with reduced CPU usage.
21
11
  *
22
12
  * @example
23
13
  * ```typescript
24
14
  * import { HardwareContext } from 'node-av/api';
15
+ * import { AV_HWDEVICE_TYPE_CUDA } from 'node-av/constants';
25
16
  *
26
17
  * // Auto-detect best available hardware
27
- * const hw = await HardwareContext.auto();
18
+ * const hw = HardwareContext.auto();
28
19
  * if (hw) {
29
- * console.log(`Using hardware: ${hw.deviceType}`);
30
- * decoder.hwDeviceCtx = hw.deviceContext;
20
+ * console.log(`Using hardware: ${hw.deviceTypeName}`);
21
+ * const decoder = await Decoder.create(stream, { hardware: hw });
31
22
  * }
23
+ * ```
32
24
  *
33
- * // Use specific hardware
34
- * const cuda = await HardwareContext.create(AV_HWDEVICE_TYPE_CUDA);
35
- * encoder.hwDeviceCtx = cuda.deviceContext;
36
- *
37
- * // Clean up when done
38
- * hw?.dispose();
25
+ * @example
26
+ * ```typescript
27
+ * // Use specific hardware type
28
+ * const cuda = HardwareContext.create(AV_HWDEVICE_TYPE_CUDA);
29
+ * const encoder = await Encoder.create('h264_nvenc', streamInfo, {
30
+ * hardware: cuda
31
+ * });
39
32
  * cuda.dispose();
40
33
  * ```
34
+ *
35
+ * @see {@link Decoder} For hardware-accelerated decoding
36
+ * @see {@link Encoder} For hardware-accelerated encoding
37
+ * @see {@link HardwareFilterPresets} For hardware filter operations
41
38
  */
42
39
  export class HardwareContext {
40
+ /**
41
+ * Hardware-specific filter presets for this device.
42
+ * Provides convenient filter builders for hardware-accelerated operations.
43
+ */
44
+ filterPresets;
43
45
  _deviceContext;
44
- _framesContext;
45
46
  _deviceType;
46
- _deviceName;
47
+ _deviceTypeName;
47
48
  _devicePixelFormat;
48
49
  _isDisposed = false;
49
- waitingComponents = new Set();
50
50
  /**
51
- * Create a new HardwareContext instance.
52
- *
53
- * Private constructor - use HardwareContext.create() or HardwareContext.auto() to create instances.
54
- *
55
- * Stores the device context and type for later use.
56
- *
57
51
  * @param deviceContext - Initialized hardware device context
58
- * @param deviceType - Hardware device type
59
- * @param deviceName - Optional device name/identifier
52
+ * @param deviceType - Hardware device type enum
53
+ * @param deviceTypeName - Human-readable device type name
54
+ * @internal
60
55
  */
61
- constructor(deviceContext, deviceType, deviceName) {
56
+ constructor(deviceContext, deviceType, deviceTypeName) {
62
57
  this._deviceContext = deviceContext;
63
58
  this._deviceType = deviceType;
64
- this._deviceName = deviceName;
65
- this._devicePixelFormat = this.getHardwarePixelFormat();
59
+ this._deviceTypeName = deviceTypeName;
60
+ this._devicePixelFormat = this.getHardwareDecoderPixelFormat();
61
+ this.filterPresets = new HardwareFilterPresets(deviceType, deviceTypeName);
66
62
  }
67
63
  /**
68
64
  * Auto-detect and create the best available hardware context.
69
65
  *
70
66
  * Tries hardware types in order of preference based on platform.
71
67
  * Returns null if no hardware acceleration is available.
72
- *
73
- * Platform-specific preferences:
74
- * - macOS: VideoToolbox
75
- * - Windows: D3D12VA, D3D11VA, DXVA2, QSV, CUDA
76
- * - Linux: VAAPI, VDPAU, CUDA, Vulkan, DRM
68
+ * Platform-specific preference order ensures optimal performance.
77
69
  *
78
70
  * @param options - Optional hardware configuration
79
- *
80
- * @returns Promise resolving to HardwareContext or null
71
+ * @returns Hardware context or null if unavailable
81
72
  *
82
73
  * @example
83
74
  * ```typescript
84
- * const hw = await HardwareContext.auto();
75
+ * const hw = HardwareContext.auto();
85
76
  * if (hw) {
86
77
  * console.log(`Auto-detected: ${hw.deviceTypeName}`);
78
+ * // Use for decoder/encoder
87
79
  * }
88
80
  * ```
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * // With specific device
85
+ * const hw = HardwareContext.auto({
86
+ * deviceName: '/dev/dri/renderD128'
87
+ * });
88
+ * ```
89
+ *
90
+ * @see {@link create} For specific hardware type
91
+ * @see {@link listAvailable} To check available types
89
92
  */
90
- static async auto(options = {}) {
93
+ static auto(options = {}) {
91
94
  // Platform-specific preference order
92
95
  const preferenceOrder = this.getPreferenceOrder();
93
96
  for (const deviceType of preferenceOrder) {
94
97
  try {
95
- const hw = await this.createFromType(deviceType, options.deviceName, options.options);
98
+ const hw = this.createFromType(deviceType, options.device, options.options);
96
99
  if (hw) {
97
100
  return hw;
98
101
  }
102
+ else {
103
+ // Try next device type
104
+ continue;
105
+ }
99
106
  }
100
107
  catch {
101
108
  // Try next device type
@@ -107,41 +114,57 @@ export class HardwareContext {
107
114
  /**
108
115
  * Create a hardware context for a specific device type.
109
116
  *
110
- * Creates and initializes a hardware device context using FFmpeg's
111
- * av_hwdevice_ctx_create() internally.
117
+ * Creates and initializes a hardware device context.
118
+ * Throws if the device type is not supported or initialization fails.
119
+ *
120
+ * Direct mapping to av_hwdevice_ctx_create().
112
121
  *
113
- * @param device - Device type name (e.g., AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VIDEOTOOLBOX)
114
- * @param deviceName - Optional device name/index
122
+ * @param deviceType - Hardware device type from AVHWDeviceType
123
+ * @param device - Optional device specifier (e.g., GPU index, device path)
115
124
  * @param options - Optional device initialization options
125
+ * @returns Initialized hardware context
116
126
  *
117
- * @returns Promise resolving to HardwareContext
127
+ * @throws {Error} If device type unsupported or initialization fails
118
128
  *
119
- * @throws {Error} If device type is not supported or initialization fails
129
+ * @example
130
+ * ```typescript
131
+ * import { AV_HWDEVICE_TYPE_CUDA } from 'node-av/constants';
132
+ *
133
+ * // CUDA with specific GPU
134
+ * const cuda = HardwareContext.create(AV_HWDEVICE_TYPE_CUDA, '0');
135
+ * ```
120
136
  *
121
137
  * @example
122
138
  * ```typescript
123
- * // Create CUDA context
124
- * const cuda = await HardwareContext.create(AV_HWDEVICE_TYPE_CUDA, '0');
139
+ * import { AV_HWDEVICE_TYPE_VAAPI } from 'node-av/constants';
125
140
  *
126
- * // Create VAAPI context
127
- * const vaapi = await HardwareContext.create(AV_HWDEVICE_TYPE_VAAPI, '/dev/dri/renderD128');
141
+ * // VAAPI with render device
142
+ * const vaapi = HardwareContext.create(
143
+ * AV_HWDEVICE_TYPE_VAAPI,
144
+ * '/dev/dri/renderD128'
145
+ * );
128
146
  * ```
147
+ *
148
+ * @see {@link auto} For automatic detection
149
+ * @see {@link HardwareDeviceContext} For low-level API
129
150
  */
130
- static async create(device, deviceName, options) {
131
- if (device === AV_HWDEVICE_TYPE_NONE) {
132
- throw new Error(`Unknown hardware device type: ${device}`);
151
+ static create(deviceType, device, options) {
152
+ if (deviceType === AV_HWDEVICE_TYPE_NONE) {
153
+ throw new Error('Cannot create hardware context for unknown hardware device type');
133
154
  }
134
- const hw = await this.createFromType(device, deviceName, options);
155
+ const hw = this.createFromType(deviceType, device, options);
135
156
  if (!hw) {
136
- throw new Error(`Failed to create hardware context for ${device}`);
157
+ throw new Error(`Failed to create hardware context for ${HardwareDeviceContext.getTypeName(deviceType) ?? 'unknown'} hardware`);
137
158
  }
138
159
  return hw;
139
160
  }
140
161
  /**
141
162
  * List all available hardware device types.
142
163
  *
143
- * Uses av_hwdevice_iterate_types() internally to enumerate
144
- * all hardware types supported by the FFmpeg build.
164
+ * Enumerates all hardware types supported by the FFmpeg build.
165
+ * Useful for checking hardware capabilities at runtime.
166
+ *
167
+ * Direct mapping to av_hwdevice_iterate_types().
145
168
  *
146
169
  * @returns Array of available device type names
147
170
  *
@@ -149,7 +172,10 @@ export class HardwareContext {
149
172
  * ```typescript
150
173
  * const available = HardwareContext.listAvailable();
151
174
  * console.log('Available hardware:', available.join(', '));
175
+ * // Output: "cuda, vaapi, videotoolbox"
152
176
  * ```
177
+ *
178
+ * @see {@link auto} For automatic selection
153
179
  */
154
180
  static listAvailable() {
155
181
  const types = HardwareDeviceContext.iterateTypes();
@@ -165,47 +191,26 @@ export class HardwareContext {
165
191
  /**
166
192
  * Get the hardware device context.
167
193
  *
168
- * This can be assigned to CodecContext.hwDeviceCtx for hardware acceleration.
194
+ * Used internally by encoders and decoders for hardware acceleration.
195
+ * Can be assigned to CodecContext.hwDeviceCtx.
169
196
  *
170
- * @returns Hardware device context
197
+ * @example
198
+ * ```typescript
199
+ * codecContext.hwDeviceCtx = hw.deviceContext;
200
+ * ```
171
201
  */
172
202
  get deviceContext() {
173
203
  return this._deviceContext;
174
204
  }
175
- /**
176
- * Get the hardware frames context.
177
- *
178
- * Created on-demand when needed for frame allocation.
179
- *
180
- * @returns Hardware frames context or undefined
181
- */
182
- get framesContext() {
183
- return this._framesContext;
184
- }
185
- /**
186
- * Set the hardware frames context.
187
- *
188
- * First component to set it "wins" - subsequent sets are ignored.
189
- * This is typically called by the decoder after decoding the first frame,
190
- * allowing other components (encoder, filters) to share the same frames context.
191
- *
192
- * @param framesContext - The hardware frames context to set
193
- */
194
- set framesContext(framesContext) {
195
- // Only set if we don't have one yet (first wins)
196
- if (framesContext && !this._framesContext) {
197
- this._framesContext = framesContext;
198
- // Notify all waiting components
199
- for (const waiter of this.waitingComponents) {
200
- waiter.resolve(this._framesContext);
201
- }
202
- this.waitingComponents.clear();
203
- }
204
- }
205
205
  /**
206
206
  * Get the device type enum value.
207
207
  *
208
- * @returns AVHWDeviceType enum value
208
+ * @example
209
+ * ```typescript
210
+ * if (hw.deviceType === AV_HWDEVICE_TYPE_CUDA) {
211
+ * console.log('Using NVIDIA GPU');
212
+ * }
213
+ * ```
209
214
  */
210
215
  get deviceType() {
211
216
  return this._deviceType;
@@ -213,25 +218,26 @@ export class HardwareContext {
213
218
  /**
214
219
  * Get the hardware device type name.
215
220
  *
216
- * Uses FFmpeg's native av_hwdevice_get_type_name() function.
221
+ * Human-readable device type string.
217
222
  *
218
- * @returns Device type name as string (e.g., 'cuda', 'videotoolbox')
223
+ * @example
224
+ * ```typescript
225
+ * console.log(`Hardware type: ${hw.deviceTypeName}`);
226
+ * // Output: "cuda" or "videotoolbox" etc.
227
+ * ```
219
228
  */
220
229
  get deviceTypeName() {
221
- return HardwareDeviceContext.getTypeName(this._deviceType) ?? 'unknown';
222
- }
223
- /**
224
- * Get the device name/identifier.
225
- *
226
- * @returns Device name or undefined
227
- */
228
- get deviceName() {
229
- return this._deviceName;
230
+ return this._deviceTypeName;
230
231
  }
231
232
  /**
232
233
  * Get the device pixel format.
233
234
  *
234
- * @returns Device pixel format
235
+ * Hardware-specific pixel format for frame allocation.
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * frame.format = hw.devicePixelFormat;
240
+ * ```
235
241
  */
236
242
  get devicePixelFormat() {
237
243
  return this._devicePixelFormat;
@@ -239,191 +245,201 @@ export class HardwareContext {
239
245
  /**
240
246
  * Check if this hardware context has been disposed.
241
247
  *
242
- * @returns True if disposed
248
+ * @example
249
+ * ```typescript
250
+ * if (!hw.isDisposed) {
251
+ * hw.dispose();
252
+ * }
253
+ * ```
243
254
  */
244
255
  get isDisposed() {
245
256
  return this._isDisposed;
246
257
  }
247
258
  /**
248
- * Create or ensure a frames context exists for this hardware device.
249
- *
250
- * If a frames context already exists with different dimensions, throws an error.
251
- * This is used for raw/generated frames that need hardware processing.
259
+ * Check if this hardware type supports a specific codec.
252
260
  *
253
- * @param width - Frame width
254
- * @param height - Frame height
255
- * @param swFormat - Software pixel format (default: AV_PIX_FMT_NV12)
256
- * @param initialPoolSize - Initial frame pool size (default: 20)
261
+ * Queries FFmpeg's codec configurations to verify hardware support.
262
+ * Checks both decoder and encoder support based on parameters.
257
263
  *
258
- * @returns HardwareFramesContext - Either existing or newly created
264
+ * Direct mapping to avcodec_get_hw_config().
259
265
  *
260
- * @throws {Error} If frames context exists with incompatible dimensions
266
+ * @param codecId - Codec ID from AVCodecID enum
267
+ * @param isEncoder - Check for encoder support (default: decoder)
268
+ * @returns true if codec is supported
261
269
  *
262
270
  * @example
263
271
  * ```typescript
264
- * // For raw frames
265
- * hw.ensureFramesContext(1920, 1080, AV_PIX_FMT_YUV420P);
272
+ * import { AV_CODEC_ID_H264 } from 'node-av/constants';
273
+ *
274
+ * if (hw.supportsCodec(AV_CODEC_ID_H264, true)) {
275
+ * // Can use hardware H.264 encoder
276
+ * }
266
277
  * ```
278
+ *
279
+ * @see {@link findSupportedCodecs} For all supported codecs
267
280
  */
268
- ensureFramesContext(width, height, swFormat = AV_PIX_FMT_NV12, initialPoolSize = 20) {
269
- if (this._framesContext) {
270
- // Validate compatibility
271
- if (this._framesContext.width !== width || this._framesContext.height !== height) {
272
- // prettier-ignore
273
- throw new Error(`Incompatible frames context: existing ${this._framesContext.width}x${this._framesContext.height} ` +
274
- `vs requested ${width}x${height}. Use separate HardwareContext instances for different sizes.`);
275
- }
276
- return this._framesContext;
281
+ supportsCodec(codecId, isEncoder = false) {
282
+ // Try to find the codec
283
+ const codec = isEncoder ? Codec.findEncoder(codecId) : Codec.findDecoder(codecId);
284
+ if (!codec) {
285
+ return false;
286
+ }
287
+ if (isEncoder) {
288
+ return codec.isHardwareAcceleratedEncoder(this._deviceType);
277
289
  }
278
- // Create new frames context on our device
279
- const frames = new HardwareFramesContext();
280
- frames.alloc(this._deviceContext);
281
- frames.format = this.getHardwarePixelFormat();
282
- frames.swFormat = swFormat;
283
- frames.width = width;
284
- frames.height = height;
285
- frames.initialPoolSize = initialPoolSize;
286
- const ret = frames.init();
287
- FFmpegError.throwIfError(ret, 'Failed to initialize hardware frames context');
288
- this._framesContext = frames;
289
- // Notify waiting components
290
- for (const waiter of this.waitingComponents) {
291
- waiter.resolve(this._framesContext);
290
+ else {
291
+ return codec.isHardwareAcceleratedDecoder(this._deviceType);
292
292
  }
293
- this.waitingComponents.clear();
294
- return frames;
295
293
  }
296
294
  /**
297
- * Wait for frames context to become available.
298
- *
299
- * Used by components that need hw_frames_ctx but don't have it yet.
300
- * Resolves when another component (typically decoder) sets the frames context.
295
+ * Check if this hardware supports a specific pixel format for a codec.
301
296
  *
302
- * @param timeout - Maximum time to wait in milliseconds (default: 5000)
297
+ * Verifies pixel format compatibility with hardware codec.
298
+ * Important for ensuring format compatibility in pipelines.
303
299
  *
304
- * @returns Promise that resolves with the frames context
305
- *
306
- * @throws {Error} If timeout expires or HardwareContext is disposed
300
+ * @param codecId - Codec ID from AVCodecID enum
301
+ * @param pixelFormat - Pixel format to check
302
+ * @param isEncoder - Check for encoder (default: decoder)
303
+ * @returns true if pixel format is supported
307
304
  *
308
305
  * @example
309
306
  * ```typescript
310
- * // Wait up to 3 seconds for frames context
311
- * const framesCtx = await hw.waitForFramesContext(3000);
307
+ * import { AV_CODEC_ID_H264, AV_PIX_FMT_NV12 } from 'node-av/constants';
308
+ *
309
+ * if (hw.supportsPixelFormat(AV_CODEC_ID_H264, AV_PIX_FMT_NV12)) {
310
+ * // Can use NV12 format with H.264
311
+ * }
312
312
  * ```
313
+ *
314
+ * @see {@link supportsCodec} For basic codec support
313
315
  */
314
- async waitForFramesContext(timeout = 5000) {
315
- if (this._framesContext) {
316
- return Promise.resolve(this._framesContext);
316
+ supportsPixelFormat(codecId, pixelFormat, isEncoder = false) {
317
+ const codec = isEncoder ? Codec.findEncoder(codecId) : Codec.findDecoder(codecId);
318
+ if (!codec) {
319
+ return false;
320
+ }
321
+ const pixelFormats = codec.pixelFormats ?? [];
322
+ if (pixelFormats.length === 0) {
323
+ return false;
317
324
  }
318
- return Promise.race([
319
- new Promise((resolve, reject) => {
320
- this.waitingComponents.add({ resolve, reject });
321
- }),
322
- new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout waiting for frames context')), timeout)),
323
- ]);
325
+ return pixelFormats.some((fmt) => fmt === pixelFormat);
324
326
  }
325
327
  /**
326
- * Get the hardware pixel format for this device type.
328
+ * Get the appropriate encoder codec for a given base codec name.
327
329
  *
328
- * Maps device types to their corresponding pixel formats.
330
+ * Maps generic codec names to hardware-specific encoder implementations.
331
+ * Returns null if no hardware encoder is available for the codec.
332
+ * Automatically tests encoder viability before returning.
333
+ *
334
+ * @param codecName - Generic codec name (e.g., 'h264', 'hevc', 'av1')
335
+ * @returns Hardware encoder codec or null if unsupported
329
336
  *
330
- * Returns the appropriate AV_PIX_FMT_* constant for the hardware type.
337
+ * @example
338
+ * ```typescript
339
+ * const encoderCodec = await hw.getEncoderCodec('h264');
340
+ * if (encoderCodec) {
341
+ * console.log(`Using encoder: ${encoderCodec.name}`);
342
+ * // e.g., "h264_nvenc" for CUDA
343
+ * }
344
+ * ```
345
+ *
346
+ * @example
347
+ * ```typescript
348
+ * // Use with Encoder.create
349
+ * const codec = await hw.getEncoderCodec('hevc');
350
+ * if (codec) {
351
+ * const encoder = await Encoder.create(codec, streamInfo, {
352
+ * hardware: hw
353
+ * });
354
+ * }
355
+ * ```
331
356
  *
332
- * @returns Hardware pixel format
357
+ * @see {@link Encoder.create} For using the codec
333
358
  */
334
- getHardwarePixelFormat() {
359
+ async getEncoderCodec(codecName) {
360
+ // Build the encoder name
361
+ let encoderSuffix = '';
362
+ // We might only have hardware decode capabilities (d3d11va, d3d12va etc)
363
+ // So we need to check for other hardware encoders
364
+ const getAlternativeEncoder = () => {
365
+ const nvencCodecName = `${codecName}_nvenc`;
366
+ const qsvCodecName = `${codecName}_qsv`;
367
+ const amfCodecName = `${codecName}_amf`;
368
+ const codecNames = [nvencCodecName, qsvCodecName, amfCodecName];
369
+ let suffix = '';
370
+ for (const name of codecNames) {
371
+ const encoderCodec = Codec.findEncoderByName(name);
372
+ if (!encoderCodec) {
373
+ continue;
374
+ }
375
+ suffix = name.split('_')[1]; // Get suffix after underscore
376
+ }
377
+ if (!suffix) {
378
+ return null;
379
+ }
380
+ return suffix;
381
+ };
335
382
  switch (this._deviceType) {
336
- case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
337
- return AV_PIX_FMT_VIDEOTOOLBOX;
338
- case AV_HWDEVICE_TYPE_VAAPI:
339
- return AV_PIX_FMT_VAAPI;
340
383
  case AV_HWDEVICE_TYPE_CUDA:
341
- return AV_PIX_FMT_CUDA;
342
- case AV_HWDEVICE_TYPE_QSV:
343
- return AV_PIX_FMT_QSV;
384
+ // CUDA uses NVENC for encoding
385
+ encoderSuffix = 'nvenc';
386
+ break;
344
387
  case AV_HWDEVICE_TYPE_D3D11VA:
345
- return AV_PIX_FMT_D3D11;
346
388
  case AV_HWDEVICE_TYPE_DXVA2:
347
- return AV_PIX_FMT_DXVA2_VLD;
348
- case AV_HWDEVICE_TYPE_DRM:
349
- return AV_PIX_FMT_DRM_PRIME;
350
- case AV_HWDEVICE_TYPE_OPENCL:
351
- return AV_PIX_FMT_OPENCL;
352
- case AV_HWDEVICE_TYPE_MEDIACODEC:
353
- return AV_PIX_FMT_MEDIACODEC;
354
- case AV_HWDEVICE_TYPE_VULKAN:
355
- return AV_PIX_FMT_VULKAN;
389
+ encoderSuffix = getAlternativeEncoder() ?? '';
390
+ break;
356
391
  case AV_HWDEVICE_TYPE_D3D12VA:
357
- return AV_PIX_FMT_D3D12;
392
+ // D3D12VA currently only supports HEVC encoding
393
+ if (codecName === 'hevc') {
394
+ encoderSuffix = 'd3d12va';
395
+ }
396
+ else {
397
+ encoderSuffix = getAlternativeEncoder() ?? '';
398
+ }
399
+ break;
400
+ case AV_HWDEVICE_TYPE_OPENCL:
401
+ case AV_HWDEVICE_TYPE_VDPAU:
402
+ case AV_HWDEVICE_TYPE_DRM:
403
+ encoderSuffix = getAlternativeEncoder() ?? '';
404
+ break;
358
405
  default:
359
- return AV_PIX_FMT_NV12; // Common hardware format
360
- }
361
- }
362
- /**
363
- * Check if this hardware type supports a specific codec.
364
- *
365
- * Checks both decoder and encoder support by querying FFmpeg's codec configurations.
366
- *
367
- * Uses avcodec_get_hw_config() internally to check hardware support.
368
- *
369
- * @param codecId - Codec ID from AVCodecID enum
370
- * @param isEncoder - Check for encoder support (default: false for decoder)
371
- *
372
- * @returns True if codec is supported by this hardware
373
- */
374
- supportsCodec(codecId, isEncoder = false) {
375
- // Try to find the codec
376
- const codec = isEncoder ? Codec.findEncoder(codecId) : Codec.findDecoder(codecId);
377
- if (!codec) {
378
- return false;
379
- }
380
- // Check hardware configurations
381
- for (let i = 0;; i++) {
382
- const config = codec.getHwConfig(i);
383
- if (!config) {
384
- break; // No more configurations
385
- }
386
- // Check if this hardware device type is supported
387
- // Accept both HW_DEVICE_CTX and HW_FRAMES_CTX methods
388
- const supportsDeviceCtx = (config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) !== 0;
389
- const supportsFramesCtx = (config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) !== 0;
390
- if ((supportsDeviceCtx || supportsFramesCtx) && config.deviceType === this._deviceType) {
391
- return true;
392
- }
406
+ // Use the device type name as suffix
407
+ encoderSuffix = this._deviceTypeName;
393
408
  }
394
- return false;
395
- }
396
- /**
397
- * Check if this hardware device type supports a specific pixel format.
398
- *
399
- * @param codecId - Codec ID from AVCodecID enum
400
- * @param pixelFormat - Pixel format to check
401
- * @param isEncoder - Check for encoder support (default: false for decoder)
402
- *
403
- * @returns True if pixel format is supported by this hardware
404
- */
405
- supportsPixelFormat(codecId, pixelFormat, isEncoder = false) {
406
- const codec = isEncoder ? Codec.findEncoder(codecId) : Codec.findDecoder(codecId);
407
- if (!codec) {
408
- return false;
409
+ if (!encoderSuffix) {
410
+ return null;
409
411
  }
410
- const pixelFormats = codec.pixelFormats ?? [];
411
- if (pixelFormats.length === 0) {
412
- return false;
412
+ // Construct the encoder name
413
+ const encoderName = `${codecName}_${encoderSuffix}`;
414
+ const encoderCodec = Codec.findEncoderByName(encoderName);
415
+ if (!encoderCodec || !(await this.testHardwareEncoder(encoderName))) {
416
+ return null;
413
417
  }
414
- return pixelFormats.some((fmt) => fmt === pixelFormat);
418
+ return encoderCodec;
415
419
  }
416
420
  /**
417
421
  * Find all codecs that support this hardware device.
418
422
  *
419
- * Uses FFmpeg's native codec list to find compatible codecs.
423
+ * Iterates through all available codecs and checks hardware compatibility.
424
+ * Useful for discovering available hardware acceleration options.
420
425
  *
421
- * Iterates through all codecs using av_codec_iterate() and checks
422
- * their hardware configurations.
426
+ * Direct mapping to av_codec_iterate() with hardware config checks.
423
427
  *
424
428
  * @param isEncoder - Find encoders (true) or decoders (false)
425
- *
426
429
  * @returns Array of codec names that support this hardware
430
+ *
431
+ * @example
432
+ * ```typescript
433
+ * const decoders = hw.findSupportedCodecs(false);
434
+ * console.log('Hardware decoders:', decoders);
435
+ * // ["h264_cuvid", "hevc_cuvid", ...]
436
+ *
437
+ * const encoders = hw.findSupportedCodecs(true);
438
+ * console.log('Hardware encoders:', encoders);
439
+ * // ["h264_nvenc", "hevc_nvenc", ...]
440
+ * ```
441
+ *
442
+ * @see {@link supportsCodec} For checking specific codec
427
443
  */
428
444
  findSupportedCodecs(isEncoder = false) {
429
445
  const supportedCodecs = [];
@@ -455,101 +471,203 @@ export class HardwareContext {
455
471
  /**
456
472
  * Clean up and free hardware resources.
457
473
  *
458
- * Safe to call multiple times - subsequent calls are no-ops.
459
- * Called automatically by Decoder/Encoder on close.
474
+ * Releases the hardware device context.
475
+ * Safe to call multiple times.
476
+ * Automatically called by Symbol.dispose.
477
+ *
478
+ * @example
479
+ * ```typescript
480
+ * const hw = HardwareContext.auto();
481
+ * try {
482
+ * // Use hardware
483
+ * } finally {
484
+ * hw?.dispose();
485
+ * }
486
+ * ```
460
487
  *
461
- * Frees both frames context (if created) and device context.
462
- * Notifies any waiting components that disposal occurred.
488
+ * @see {@link Symbol.dispose} For automatic cleanup
463
489
  */
464
490
  dispose() {
465
491
  if (this._isDisposed) {
466
- return; // Already disposed, safe to return
467
- }
468
- // Notify waiting components that we're disposing
469
- for (const waiter of this.waitingComponents) {
470
- waiter.reject(new Error('HardwareContext disposed'));
471
- }
472
- this.waitingComponents.clear();
473
- if (this._framesContext) {
474
- this._framesContext.free();
475
- this._framesContext = undefined;
492
+ return;
476
493
  }
477
494
  this._deviceContext.free();
478
495
  this._isDisposed = true;
479
496
  }
497
+ /**
498
+ * Get the hardware decoder pixel format for this device type.
499
+ *
500
+ * Maps device types to their corresponding pixel formats.
501
+ * Used internally for frame format configuration.
502
+ *
503
+ * @returns Hardware-specific pixel format
504
+ */
505
+ getHardwareDecoderPixelFormat() {
506
+ switch (this._deviceType) {
507
+ case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
508
+ return AV_PIX_FMT_VIDEOTOOLBOX;
509
+ case AV_HWDEVICE_TYPE_VAAPI:
510
+ return AV_PIX_FMT_VAAPI;
511
+ case AV_HWDEVICE_TYPE_CUDA:
512
+ return AV_PIX_FMT_CUDA;
513
+ case AV_HWDEVICE_TYPE_QSV:
514
+ return AV_PIX_FMT_QSV;
515
+ case AV_HWDEVICE_TYPE_D3D11VA:
516
+ return AV_PIX_FMT_D3D11;
517
+ case AV_HWDEVICE_TYPE_DXVA2:
518
+ return AV_PIX_FMT_DXVA2_VLD;
519
+ case AV_HWDEVICE_TYPE_DRM:
520
+ return AV_PIX_FMT_DRM_PRIME;
521
+ case AV_HWDEVICE_TYPE_OPENCL:
522
+ return AV_PIX_FMT_OPENCL;
523
+ case AV_HWDEVICE_TYPE_MEDIACODEC:
524
+ return AV_PIX_FMT_MEDIACODEC;
525
+ case AV_HWDEVICE_TYPE_VULKAN:
526
+ return AV_PIX_FMT_VULKAN;
527
+ case AV_HWDEVICE_TYPE_D3D12VA:
528
+ return AV_PIX_FMT_D3D12;
529
+ case AV_HWDEVICE_TYPE_RKMPP:
530
+ return AV_PIX_FMT_DRM_PRIME; // RKMPP uses DRM Prime buffers
531
+ default:
532
+ return AV_PIX_FMT_NV12; // Common hardware format
533
+ }
534
+ }
535
+ /**
536
+ * Test if a hardware encoder can be created.
537
+ *
538
+ * Attempts to initialize the encoder to verify support.
539
+ * Used internally by getEncoderCodec.
540
+ *
541
+ * @param encoderCodec - Encoder to test
542
+ * @returns true if encoder can be initialized
543
+ */
544
+ async testHardwareEncoder(encoderCodec) {
545
+ let codec = null;
546
+ if (encoderCodec instanceof Codec) {
547
+ codec = encoderCodec;
548
+ }
549
+ else if (typeof encoderCodec === 'string') {
550
+ codec = Codec.findEncoderByName(encoderCodec);
551
+ }
552
+ else {
553
+ codec = Codec.findEncoder(encoderCodec);
554
+ }
555
+ if (!codec?.pixelFormats || !codec.isHardwareAcceleratedEncoder()) {
556
+ return false;
557
+ }
558
+ const codecContext = new CodecContext();
559
+ codecContext.allocContext3(codec);
560
+ codecContext.hwDeviceCtx = this._deviceContext;
561
+ codecContext.timeBase = new Rational(1, 30);
562
+ codecContext.pixelFormat = codec.pixelFormats[0];
563
+ codecContext.width = 100;
564
+ codecContext.height = 100;
565
+ const ret = await codecContext.open2(codec);
566
+ codecContext.freeContext();
567
+ return ret >= 0;
568
+ }
480
569
  /**
481
570
  * Create hardware context from device type.
482
571
  *
483
572
  * Internal factory method using av_hwdevice_ctx_create().
484
573
  *
485
574
  * @param deviceType - AVHWDeviceType enum value
486
- * @param deviceName - Optional device name/index
575
+ * @param device - Optional device specifier
487
576
  * @param options - Optional device options
488
- *
489
- * @returns HardwareContext or null if creation fails
577
+ * @returns Hardware context or null if creation fails
490
578
  */
491
- static async createFromType(deviceType, deviceName, options) {
492
- const device = new HardwareDeviceContext();
579
+ static createFromType(deviceType, device, options) {
580
+ const deviceCtx = new HardwareDeviceContext();
493
581
  // Convert options to Dictionary if provided
494
582
  let optionsDict = null;
495
583
  if (options && Object.keys(options).length > 0) {
496
584
  optionsDict = Dictionary.fromObject(options);
497
585
  }
498
- const ret = device.create(deviceType, deviceName ?? null, optionsDict);
586
+ const ret = deviceCtx.create(deviceType, device, optionsDict);
499
587
  // Clean up dictionary if used
500
588
  if (optionsDict) {
501
589
  optionsDict.free();
502
590
  }
503
- if (ret < 0) {
504
- device.free();
591
+ const deviceTypeName = HardwareDeviceContext.getTypeName(deviceType);
592
+ if (ret < 0 || !deviceTypeName) {
593
+ deviceCtx.free();
505
594
  return null;
506
595
  }
507
- return new HardwareContext(device, deviceType, deviceName);
596
+ return new HardwareContext(deviceCtx, deviceType, deviceTypeName);
508
597
  }
509
598
  /**
510
599
  * Get platform-specific preference order for hardware types.
511
600
  *
512
- * Returns the optimal hardware types for the current platform.
601
+ * Returns available hardware types sorted by platform preference.
602
+ * Ensures optimal hardware selection for each platform.
513
603
  *
514
604
  * @returns Array of AVHWDeviceType values in preference order
515
605
  */
516
606
  static getPreferenceOrder() {
607
+ // Get all available hardware types on this system
608
+ const available = HardwareDeviceContext.iterateTypes();
609
+ if (available.length === 0) {
610
+ return [];
611
+ }
517
612
  const platform = process.platform;
613
+ let preferenceOrder;
518
614
  if (platform === 'darwin') {
519
615
  // macOS: VideoToolbox is preferred
520
- return [AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_VULKAN, AV_HWDEVICE_TYPE_OPENCL];
616
+ preferenceOrder = [AV_HWDEVICE_TYPE_VIDEOTOOLBOX];
521
617
  }
522
618
  else if (platform === 'win32') {
523
- // Windows: D3D12VA (newest), D3D11VA, DXVA2, QSV, CUDA
524
- return [
525
- AV_HWDEVICE_TYPE_D3D12VA,
526
- AV_HWDEVICE_TYPE_D3D11VA,
619
+ // Windows: Match FFmpeg's hw_configs order
620
+ // DXVA2 → D3D11VA → D3D12VA → NVDEC (CUDA)
621
+ preferenceOrder = [
527
622
  AV_HWDEVICE_TYPE_DXVA2,
528
- AV_HWDEVICE_TYPE_QSV,
623
+ AV_HWDEVICE_TYPE_D3D11VA,
624
+ AV_HWDEVICE_TYPE_D3D12VA,
529
625
  AV_HWDEVICE_TYPE_CUDA,
626
+ AV_HWDEVICE_TYPE_QSV,
530
627
  AV_HWDEVICE_TYPE_VULKAN,
531
628
  AV_HWDEVICE_TYPE_OPENCL,
532
629
  ];
533
630
  }
534
631
  else {
535
- // Linux: VAAPI, VDPAU, CUDA, Vulkan, DRM
536
- return [AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VDPAU, AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_VULKAN, AV_HWDEVICE_TYPE_DRM, AV_HWDEVICE_TYPE_OPENCL];
632
+ // Linux: Match FFmpeg's hw_configs order
633
+ // NVDEC (CUDA) VAAPI VDPAU → Vulkan
634
+ // RKMPP is platform-specific for ARM/Rockchip
635
+ const isARM = process.arch === 'arm64' || process.arch === 'arm';
636
+ if (isARM) {
637
+ // ARM platforms: Prioritize RKMPP for Rockchip SoCs
638
+ preferenceOrder = [AV_HWDEVICE_TYPE_RKMPP, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VULKAN, AV_HWDEVICE_TYPE_DRM, AV_HWDEVICE_TYPE_OPENCL];
639
+ }
640
+ else {
641
+ // x86_64 Linux: CUDA → VAAPI → VDPAU → Vulkan
642
+ preferenceOrder = [AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VDPAU, AV_HWDEVICE_TYPE_VULKAN, AV_HWDEVICE_TYPE_DRM, AV_HWDEVICE_TYPE_OPENCL];
643
+ }
537
644
  }
645
+ // Filter preference order to only include available types
646
+ const availableSet = new Set(available);
647
+ const sortedAvailable = preferenceOrder.filter((type) => availableSet.has(type));
648
+ // Add any available types not in our preference list at the end
649
+ for (const type of available) {
650
+ if (!preferenceOrder.includes(type)) {
651
+ sortedAvailable.push(type);
652
+ }
653
+ }
654
+ return sortedAvailable;
538
655
  }
539
656
  /**
540
- * Automatic cleanup when using 'using' statement.
541
- *
542
- * Implements the Disposable interface for automatic cleanup.
657
+ * Dispose of hardware context.
543
658
  *
544
- * Calls dispose() to free hardware resources.
659
+ * Implements Disposable interface for automatic cleanup.
660
+ * Equivalent to calling dispose().
545
661
  *
546
662
  * @example
547
663
  * ```typescript
548
664
  * {
549
- * using hw = await HardwareContext.auto();
665
+ * using hw = HardwareContext.auto();
550
666
  * // Use hardware context...
551
667
  * } // Automatically disposed
552
668
  * ```
669
+ *
670
+ * @see {@link dispose} For manual cleanup
553
671
  */
554
672
  [Symbol.dispose]() {
555
673
  this.dispose();