node-av 1.1.0 → 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 (134) hide show
  1. package/README.md +51 -38
  2. package/dist/api/bitstream-filter.d.ts +180 -123
  3. package/dist/api/bitstream-filter.js +180 -125
  4. package/dist/api/bitstream-filter.js.map +1 -1
  5. package/dist/api/decoder.d.ts +279 -132
  6. package/dist/api/decoder.js +285 -142
  7. package/dist/api/decoder.js.map +1 -1
  8. package/dist/api/encoder.d.ts +246 -162
  9. package/dist/api/encoder.js +272 -208
  10. package/dist/api/encoder.js.map +1 -1
  11. package/dist/api/filter-presets.d.ts +690 -94
  12. package/dist/api/filter-presets.js +686 -102
  13. package/dist/api/filter-presets.js.map +1 -1
  14. package/dist/api/filter.d.ts +249 -213
  15. package/dist/api/filter.js +252 -242
  16. package/dist/api/filter.js.map +1 -1
  17. package/dist/api/hardware.d.ts +224 -117
  18. package/dist/api/hardware.js +380 -214
  19. package/dist/api/hardware.js.map +1 -1
  20. package/dist/api/index.d.ts +3 -3
  21. package/dist/api/index.js +1 -1
  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 +43 -46
  25. package/dist/api/io-stream.js.map +1 -1
  26. package/dist/api/media-input.d.ts +242 -140
  27. package/dist/api/media-input.js +205 -103
  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 +210 -128
  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 +21 -187
  36. package/dist/api/utils.d.ts +1 -2
  37. package/dist/api/utils.js +9 -0
  38. package/dist/api/utils.js.map +1 -1
  39. package/dist/lib/audio-fifo.d.ts +127 -170
  40. package/dist/lib/audio-fifo.js +130 -173
  41. package/dist/lib/audio-fifo.js.map +1 -1
  42. package/dist/lib/binding.js +5 -0
  43. package/dist/lib/binding.js.map +1 -1
  44. package/dist/lib/bitstream-filter-context.d.ts +139 -184
  45. package/dist/lib/bitstream-filter-context.js +139 -188
  46. package/dist/lib/bitstream-filter-context.js.map +1 -1
  47. package/dist/lib/bitstream-filter.d.ts +68 -54
  48. package/dist/lib/bitstream-filter.js +68 -54
  49. package/dist/lib/bitstream-filter.js.map +1 -1
  50. package/dist/lib/codec-context.d.ts +316 -380
  51. package/dist/lib/codec-context.js +316 -381
  52. package/dist/lib/codec-context.js.map +1 -1
  53. package/dist/lib/codec-parameters.d.ts +160 -170
  54. package/dist/lib/codec-parameters.js +162 -172
  55. package/dist/lib/codec-parameters.js.map +1 -1
  56. package/dist/lib/codec-parser.d.ts +91 -104
  57. package/dist/lib/codec-parser.js +92 -103
  58. package/dist/lib/codec-parser.js.map +1 -1
  59. package/dist/lib/codec.d.ts +264 -281
  60. package/dist/lib/codec.js +268 -285
  61. package/dist/lib/codec.js.map +1 -1
  62. package/dist/lib/dictionary.d.ts +149 -203
  63. package/dist/lib/dictionary.js +158 -212
  64. package/dist/lib/dictionary.js.map +1 -1
  65. package/dist/lib/error.d.ts +96 -130
  66. package/dist/lib/error.js +98 -128
  67. package/dist/lib/error.js.map +1 -1
  68. package/dist/lib/filter-context.d.ts +284 -218
  69. package/dist/lib/filter-context.js +290 -227
  70. package/dist/lib/filter-context.js.map +1 -1
  71. package/dist/lib/filter-graph.d.ts +251 -292
  72. package/dist/lib/filter-graph.js +253 -294
  73. package/dist/lib/filter-graph.js.map +1 -1
  74. package/dist/lib/filter-inout.d.ts +87 -95
  75. package/dist/lib/filter-inout.js +87 -95
  76. package/dist/lib/filter-inout.js.map +1 -1
  77. package/dist/lib/filter.d.ts +93 -111
  78. package/dist/lib/filter.js +93 -111
  79. package/dist/lib/filter.js.map +1 -1
  80. package/dist/lib/format-context.d.ts +320 -428
  81. package/dist/lib/format-context.js +313 -385
  82. package/dist/lib/format-context.js.map +1 -1
  83. package/dist/lib/frame.d.ts +262 -405
  84. package/dist/lib/frame.js +263 -408
  85. package/dist/lib/frame.js.map +1 -1
  86. package/dist/lib/hardware-device-context.d.ts +149 -203
  87. package/dist/lib/hardware-device-context.js +149 -203
  88. package/dist/lib/hardware-device-context.js.map +1 -1
  89. package/dist/lib/hardware-frames-context.d.ts +170 -180
  90. package/dist/lib/hardware-frames-context.js +171 -181
  91. package/dist/lib/hardware-frames-context.js.map +1 -1
  92. package/dist/lib/index.d.ts +2 -1
  93. package/dist/lib/index.js +2 -2
  94. package/dist/lib/index.js.map +1 -1
  95. package/dist/lib/input-format.d.ts +89 -117
  96. package/dist/lib/input-format.js +89 -117
  97. package/dist/lib/input-format.js.map +1 -1
  98. package/dist/lib/io-context.d.ts +209 -241
  99. package/dist/lib/io-context.js +220 -252
  100. package/dist/lib/io-context.js.map +1 -1
  101. package/dist/lib/log.d.ts +85 -119
  102. package/dist/lib/log.js +85 -122
  103. package/dist/lib/log.js.map +1 -1
  104. package/dist/lib/native-types.d.ts +117 -106
  105. package/dist/lib/native-types.js +0 -7
  106. package/dist/lib/native-types.js.map +1 -1
  107. package/dist/lib/option.d.ts +284 -241
  108. package/dist/lib/option.js +309 -249
  109. package/dist/lib/option.js.map +1 -1
  110. package/dist/lib/output-format.d.ts +77 -101
  111. package/dist/lib/output-format.js +77 -101
  112. package/dist/lib/output-format.js.map +1 -1
  113. package/dist/lib/packet.d.ts +172 -240
  114. package/dist/lib/packet.js +172 -241
  115. package/dist/lib/packet.js.map +1 -1
  116. package/dist/lib/rational.d.ts +0 -2
  117. package/dist/lib/rational.js +0 -2
  118. package/dist/lib/rational.js.map +1 -1
  119. package/dist/lib/software-resample-context.d.ts +241 -325
  120. package/dist/lib/software-resample-context.js +242 -326
  121. package/dist/lib/software-resample-context.js.map +1 -1
  122. package/dist/lib/software-scale-context.d.ts +129 -173
  123. package/dist/lib/software-scale-context.js +131 -175
  124. package/dist/lib/software-scale-context.js.map +1 -1
  125. package/dist/lib/stream.d.ts +87 -197
  126. package/dist/lib/stream.js +87 -197
  127. package/dist/lib/stream.js.map +1 -1
  128. package/dist/lib/utilities.d.ts +372 -181
  129. package/dist/lib/utilities.js +373 -182
  130. package/dist/lib/utilities.js.map +1 -1
  131. package/install/check.js +0 -1
  132. package/package.json +21 -12
  133. package/release_notes.md +43 -59
  134. package/CHANGELOG.md +0 -8
@@ -1,107 +1,108 @@
1
- /**
2
- * HardwareContext - High-level Hardware Acceleration API
3
- *
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.
8
- * Manages lifecycle of hardware resources with automatic cleanup.
9
- *
10
- * @module api/hardware
11
- */
12
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';
13
- import { Codec, Dictionary, HardwareDeviceContext } from '../lib/index.js';
2
+ import { Codec, CodecContext, Dictionary, HardwareDeviceContext, Rational } from '../lib/index.js';
14
3
  import { HardwareFilterPresets } from './filter-presets.js';
15
4
  /**
16
- * HardwareContext - Simplified hardware acceleration management.
17
- *
18
- * Provides automatic detection and configuration of hardware acceleration.
19
- * Manages device contexts and frame contexts for hardware encoding/decoding.
5
+ * High-level hardware acceleration management.
20
6
  *
21
- * Supports various hardware types including VideoToolbox (macOS), CUDA,
22
- * 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.
23
11
  *
24
12
  * @example
25
13
  * ```typescript
26
14
  * import { HardwareContext } from 'node-av/api';
15
+ * import { AV_HWDEVICE_TYPE_CUDA } from 'node-av/constants';
27
16
  *
28
17
  * // Auto-detect best available hardware
29
- * const hw = await HardwareContext.auto();
18
+ * const hw = HardwareContext.auto();
30
19
  * if (hw) {
31
- * console.log(`Using hardware: ${hw.deviceType}`);
32
- * decoder.hwDeviceCtx = hw.deviceContext;
20
+ * console.log(`Using hardware: ${hw.deviceTypeName}`);
21
+ * const decoder = await Decoder.create(stream, { hardware: hw });
33
22
  * }
23
+ * ```
34
24
  *
35
- * // Use specific hardware
36
- * const cuda = await HardwareContext.create(AV_HWDEVICE_TYPE_CUDA);
37
- * encoder.hwDeviceCtx = cuda.deviceContext;
38
- *
39
- * // Clean up when done
40
- * 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
+ * });
41
32
  * cuda.dispose();
42
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
43
38
  */
44
39
  export class HardwareContext {
45
- _deviceContext;
46
- _deviceType;
47
- _deviceTypeName;
48
- _devicePixelFormat;
49
- _isDisposed = false;
50
40
  /**
51
41
  * Hardware-specific filter presets for this device.
52
42
  * Provides convenient filter builders for hardware-accelerated operations.
53
43
  */
54
44
  filterPresets;
45
+ _deviceContext;
46
+ _deviceType;
47
+ _deviceTypeName;
48
+ _devicePixelFormat;
49
+ _isDisposed = false;
55
50
  /**
56
- * Create a new HardwareContext instance.
57
- *
58
- * Private constructor - use HardwareContext.create() or HardwareContext.auto() to create instances.
59
- *
60
- * Stores the device context and type for later use.
61
- *
62
51
  * @param deviceContext - Initialized hardware device context
63
- * @param deviceType - Hardware device type
64
- * @param deviceName - Optional device name/identifier
52
+ * @param deviceType - Hardware device type enum
53
+ * @param deviceTypeName - Human-readable device type name
54
+ * @internal
65
55
  */
66
- constructor(deviceContext, deviceType, deviceName) {
56
+ constructor(deviceContext, deviceType, deviceTypeName) {
67
57
  this._deviceContext = deviceContext;
68
58
  this._deviceType = deviceType;
69
- this._deviceTypeName = deviceName ?? HardwareDeviceContext.getTypeName(this._deviceType);
70
- this._devicePixelFormat = this.getHardwarePixelFormat();
71
- this.filterPresets = new HardwareFilterPresets(deviceType, deviceName);
59
+ this._deviceTypeName = deviceTypeName;
60
+ this._devicePixelFormat = this.getHardwareDecoderPixelFormat();
61
+ this.filterPresets = new HardwareFilterPresets(deviceType, deviceTypeName);
72
62
  }
73
63
  /**
74
64
  * Auto-detect and create the best available hardware context.
75
65
  *
76
66
  * Tries hardware types in order of preference based on platform.
77
67
  * Returns null if no hardware acceleration is available.
78
- *
79
- * Platform-specific preferences:
80
- * - macOS: VideoToolbox
81
- * - Windows: D3D12VA, D3D11VA, DXVA2, QSV, CUDA
82
- * - Linux: VAAPI, VDPAU, CUDA, Vulkan, DRM
68
+ * Platform-specific preference order ensures optimal performance.
83
69
  *
84
70
  * @param options - Optional hardware configuration
85
- *
86
- * @returns Promise resolving to HardwareContext or null
71
+ * @returns Hardware context or null if unavailable
87
72
  *
88
73
  * @example
89
74
  * ```typescript
90
- * const hw = await HardwareContext.auto();
75
+ * const hw = HardwareContext.auto();
91
76
  * if (hw) {
92
77
  * console.log(`Auto-detected: ${hw.deviceTypeName}`);
78
+ * // Use for decoder/encoder
93
79
  * }
94
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
95
92
  */
96
- static async auto(options = {}) {
93
+ static auto(options = {}) {
97
94
  // Platform-specific preference order
98
95
  const preferenceOrder = this.getPreferenceOrder();
99
96
  for (const deviceType of preferenceOrder) {
100
97
  try {
101
- const hw = await this.createFromType(deviceType, options.deviceName, options.options);
98
+ const hw = this.createFromType(deviceType, options.device, options.options);
102
99
  if (hw) {
103
100
  return hw;
104
101
  }
102
+ else {
103
+ // Try next device type
104
+ continue;
105
+ }
105
106
  }
106
107
  catch {
107
108
  // Try next device type
@@ -113,41 +114,57 @@ export class HardwareContext {
113
114
  /**
114
115
  * Create a hardware context for a specific device type.
115
116
  *
116
- * Creates and initializes a hardware device context using FFmpeg's
117
- * 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().
118
121
  *
119
- * @param device - Device type name (e.g., AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_VIDEOTOOLBOX)
120
- * @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)
121
124
  * @param options - Optional device initialization options
125
+ * @returns Initialized hardware context
126
+ *
127
+ * @throws {Error} If device type unsupported or initialization fails
122
128
  *
123
- * @returns Promise resolving to HardwareContext
129
+ * @example
130
+ * ```typescript
131
+ * import { AV_HWDEVICE_TYPE_CUDA } from 'node-av/constants';
124
132
  *
125
- * @throws {Error} If device type is not supported or initialization fails
133
+ * // CUDA with specific GPU
134
+ * const cuda = HardwareContext.create(AV_HWDEVICE_TYPE_CUDA, '0');
135
+ * ```
126
136
  *
127
137
  * @example
128
138
  * ```typescript
129
- * // Create CUDA context
130
- * const cuda = await HardwareContext.create(AV_HWDEVICE_TYPE_CUDA, '0');
139
+ * import { AV_HWDEVICE_TYPE_VAAPI } from 'node-av/constants';
131
140
  *
132
- * // Create VAAPI context
133
- * 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
+ * );
134
146
  * ```
147
+ *
148
+ * @see {@link auto} For automatic detection
149
+ * @see {@link HardwareDeviceContext} For low-level API
135
150
  */
136
- static async create(device, deviceName, options) {
137
- if (device === AV_HWDEVICE_TYPE_NONE) {
138
- 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');
139
154
  }
140
- const hw = await this.createFromType(device, deviceName, options);
155
+ const hw = this.createFromType(deviceType, device, options);
141
156
  if (!hw) {
142
- 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`);
143
158
  }
144
159
  return hw;
145
160
  }
146
161
  /**
147
162
  * List all available hardware device types.
148
163
  *
149
- * Uses av_hwdevice_iterate_types() internally to enumerate
150
- * 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().
151
168
  *
152
169
  * @returns Array of available device type names
153
170
  *
@@ -155,7 +172,10 @@ export class HardwareContext {
155
172
  * ```typescript
156
173
  * const available = HardwareContext.listAvailable();
157
174
  * console.log('Available hardware:', available.join(', '));
175
+ * // Output: "cuda, vaapi, videotoolbox"
158
176
  * ```
177
+ *
178
+ * @see {@link auto} For automatic selection
159
179
  */
160
180
  static listAvailable() {
161
181
  const types = HardwareDeviceContext.iterateTypes();
@@ -171,9 +191,13 @@ export class HardwareContext {
171
191
  /**
172
192
  * Get the hardware device context.
173
193
  *
174
- * 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.
175
196
  *
176
- * @returns Hardware device context
197
+ * @example
198
+ * ```typescript
199
+ * codecContext.hwDeviceCtx = hw.deviceContext;
200
+ * ```
177
201
  */
178
202
  get deviceContext() {
179
203
  return this._deviceContext;
@@ -181,7 +205,12 @@ export class HardwareContext {
181
205
  /**
182
206
  * Get the device type enum value.
183
207
  *
184
- * @returns AVHWDeviceType enum value
208
+ * @example
209
+ * ```typescript
210
+ * if (hw.deviceType === AV_HWDEVICE_TYPE_CUDA) {
211
+ * console.log('Using NVIDIA GPU');
212
+ * }
213
+ * ```
185
214
  */
186
215
  get deviceType() {
187
216
  return this._deviceType;
@@ -189,9 +218,13 @@ export class HardwareContext {
189
218
  /**
190
219
  * Get the hardware device type name.
191
220
  *
192
- * Uses FFmpeg's native av_hwdevice_get_type_name() function.
221
+ * Human-readable device type string.
193
222
  *
194
- * @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
+ * ```
195
228
  */
196
229
  get deviceTypeName() {
197
230
  return this._deviceTypeName;
@@ -199,7 +232,12 @@ export class HardwareContext {
199
232
  /**
200
233
  * Get the device pixel format.
201
234
  *
202
- * @returns Device pixel format
235
+ * Hardware-specific pixel format for frame allocation.
236
+ *
237
+ * @example
238
+ * ```typescript
239
+ * frame.format = hw.devicePixelFormat;
240
+ * ```
203
241
  */
204
242
  get devicePixelFormat() {
205
243
  return this._devicePixelFormat;
@@ -207,61 +245,38 @@ export class HardwareContext {
207
245
  /**
208
246
  * Check if this hardware context has been disposed.
209
247
  *
210
- * @returns True if disposed
248
+ * @example
249
+ * ```typescript
250
+ * if (!hw.isDisposed) {
251
+ * hw.dispose();
252
+ * }
253
+ * ```
211
254
  */
212
255
  get isDisposed() {
213
256
  return this._isDisposed;
214
257
  }
215
- /**
216
- * Get the hardware pixel format for this device type.
217
- *
218
- * Maps device types to their corresponding pixel formats.
219
- *
220
- * Returns the appropriate AV_PIX_FMT_* constant for the hardware type.
221
- *
222
- * @returns Hardware pixel format
223
- */
224
- getHardwarePixelFormat() {
225
- switch (this._deviceType) {
226
- case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
227
- return AV_PIX_FMT_VIDEOTOOLBOX;
228
- case AV_HWDEVICE_TYPE_VAAPI:
229
- return AV_PIX_FMT_VAAPI;
230
- case AV_HWDEVICE_TYPE_CUDA:
231
- return AV_PIX_FMT_CUDA;
232
- case AV_HWDEVICE_TYPE_QSV:
233
- return AV_PIX_FMT_QSV;
234
- case AV_HWDEVICE_TYPE_D3D11VA:
235
- return AV_PIX_FMT_D3D11;
236
- case AV_HWDEVICE_TYPE_DXVA2:
237
- return AV_PIX_FMT_DXVA2_VLD;
238
- case AV_HWDEVICE_TYPE_DRM:
239
- return AV_PIX_FMT_DRM_PRIME;
240
- case AV_HWDEVICE_TYPE_OPENCL:
241
- return AV_PIX_FMT_OPENCL;
242
- case AV_HWDEVICE_TYPE_MEDIACODEC:
243
- return AV_PIX_FMT_MEDIACODEC;
244
- case AV_HWDEVICE_TYPE_VULKAN:
245
- return AV_PIX_FMT_VULKAN;
246
- case AV_HWDEVICE_TYPE_D3D12VA:
247
- return AV_PIX_FMT_D3D12;
248
- case AV_HWDEVICE_TYPE_RKMPP:
249
- return AV_PIX_FMT_DRM_PRIME; // RKMPP uses DRM Prime buffers
250
- default:
251
- return AV_PIX_FMT_NV12; // Common hardware format
252
- }
253
- }
254
258
  /**
255
259
  * Check if this hardware type supports a specific codec.
256
260
  *
257
- * Checks both decoder and encoder support by querying FFmpeg's codec configurations.
261
+ * Queries FFmpeg's codec configurations to verify hardware support.
262
+ * Checks both decoder and encoder support based on parameters.
258
263
  *
259
- * Uses avcodec_get_hw_config() internally to check hardware support.
264
+ * Direct mapping to avcodec_get_hw_config().
260
265
  *
261
266
  * @param codecId - Codec ID from AVCodecID enum
262
- * @param isEncoder - Check for encoder support (default: false for decoder)
267
+ * @param isEncoder - Check for encoder support (default: decoder)
268
+ * @returns true if codec is supported
263
269
  *
264
- * @returns True if codec is supported by this hardware
270
+ * @example
271
+ * ```typescript
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
+ * }
277
+ * ```
278
+ *
279
+ * @see {@link findSupportedCodecs} For all supported codecs
265
280
  */
266
281
  supportsCodec(codecId, isEncoder = false) {
267
282
  // Try to find the codec
@@ -269,30 +284,34 @@ export class HardwareContext {
269
284
  if (!codec) {
270
285
  return false;
271
286
  }
272
- // Check hardware configurations
273
- for (let i = 0;; i++) {
274
- const config = codec.getHwConfig(i);
275
- if (!config) {
276
- break; // No more configurations
277
- }
278
- // Check if this hardware device type is supported
279
- // Accept both HW_DEVICE_CTX and HW_FRAMES_CTX methods
280
- const supportsDeviceCtx = (config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) !== 0;
281
- const supportsFramesCtx = (config.methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) !== 0;
282
- if ((supportsDeviceCtx || supportsFramesCtx) && config.deviceType === this._deviceType) {
283
- return true;
284
- }
287
+ if (isEncoder) {
288
+ return codec.isHardwareAcceleratedEncoder(this._deviceType);
289
+ }
290
+ else {
291
+ return codec.isHardwareAcceleratedDecoder(this._deviceType);
285
292
  }
286
- return false;
287
293
  }
288
294
  /**
289
- * Check if this hardware device type supports a specific pixel format.
295
+ * Check if this hardware supports a specific pixel format for a codec.
296
+ *
297
+ * Verifies pixel format compatibility with hardware codec.
298
+ * Important for ensuring format compatibility in pipelines.
290
299
  *
291
300
  * @param codecId - Codec ID from AVCodecID enum
292
301
  * @param pixelFormat - Pixel format to check
293
- * @param isEncoder - Check for encoder support (default: false for decoder)
302
+ * @param isEncoder - Check for encoder (default: decoder)
303
+ * @returns true if pixel format is supported
304
+ *
305
+ * @example
306
+ * ```typescript
307
+ * import { AV_CODEC_ID_H264, AV_PIX_FMT_NV12 } from 'node-av/constants';
294
308
  *
295
- * @returns True if pixel format is supported by this hardware
309
+ * if (hw.supportsPixelFormat(AV_CODEC_ID_H264, AV_PIX_FMT_NV12)) {
310
+ * // Can use NV12 format with H.264
311
+ * }
312
+ * ```
313
+ *
314
+ * @see {@link supportsCodec} For basic codec support
296
315
  */
297
316
  supportsPixelFormat(codecId, pixelFormat, isEncoder = false) {
298
317
  const codec = isEncoder ? Codec.findEncoder(codecId) : Codec.findDecoder(codecId);
@@ -306,77 +325,121 @@ export class HardwareContext {
306
325
  return pixelFormats.some((fmt) => fmt === pixelFormat);
307
326
  }
308
327
  /**
309
- * Get the appropriate hardware encoder name for a given codec.
328
+ * Get the appropriate encoder codec for a given base codec name.
310
329
  *
311
- * Maps generic codec names and hardware types to their specific encoder implementations.
312
- * For example, 'h264' with VideoToolbox returns 'h264_videotoolbox'.
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.
313
333
  *
314
334
  * @param codecName - Generic codec name (e.g., 'h264', 'hevc', 'av1')
315
- *
316
- * @returns Hardware encoder name or null if not supported
335
+ * @returns Hardware encoder codec or null if unsupported
317
336
  *
318
337
  * @example
319
338
  * ```typescript
320
- * const hw = await HardwareContext.auto();
321
- * const encoderName = hw.getEncoderName('h264');
322
- * // Returns 'h264_videotoolbox' on macOS, 'h264_nvenc' with CUDA, etc.
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
+ * ```
323
345
  *
324
- * // Use the encoder
325
- * const encoder = Codec.findEncoderByName(encoderName);
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
+ * }
326
355
  * ```
356
+ *
357
+ * @see {@link Encoder.create} For using the codec
327
358
  */
328
- getEncoderCodec(codecName) {
329
- // Get the hardware device type name from FFmpeg
330
- const deviceTypeName = HardwareDeviceContext.getTypeName(this._deviceType);
331
- if (!deviceTypeName)
332
- return null;
359
+ async getEncoderCodec(codecName) {
333
360
  // Build the encoder name
334
- let encoderSuffix;
335
- switch (deviceTypeName) {
336
- case 'cuda':
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
+ };
382
+ switch (this._deviceType) {
383
+ case AV_HWDEVICE_TYPE_CUDA:
337
384
  // CUDA uses NVENC for encoding
338
385
  encoderSuffix = 'nvenc';
339
386
  break;
340
- case 'd3d11va':
341
- case 'dxva2':
342
- // D3D11VA and DXVA2 are decode-only APIs
343
- // Cannot encode with these hardware contexts
344
- // Need nvenc, qsv or amf for encoding
345
- return null;
346
- case 'd3d12va':
387
+ case AV_HWDEVICE_TYPE_D3D11VA:
388
+ case AV_HWDEVICE_TYPE_DXVA2:
389
+ encoderSuffix = getAlternativeEncoder() ?? '';
390
+ break;
391
+ case AV_HWDEVICE_TYPE_D3D12VA:
347
392
  // D3D12VA currently only supports HEVC encoding
348
393
  if (codecName === 'hevc') {
349
394
  encoderSuffix = 'd3d12va';
350
395
  }
351
- return null;
352
- case 'opencl':
353
- case 'vdpau':
354
- case 'drm':
355
- // These don't have dedicated encoders
356
- return null;
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;
357
405
  default:
358
406
  // Use the device type name as suffix
359
- encoderSuffix = deviceTypeName;
407
+ encoderSuffix = this._deviceTypeName;
408
+ }
409
+ if (!encoderSuffix) {
410
+ return null;
360
411
  }
361
412
  // Construct the encoder name
362
413
  const encoderName = `${codecName}_${encoderSuffix}`;
363
- const codec = Codec.findEncoderByName(encoderName);
364
- if (codec?.name) {
365
- return codec.name;
414
+ const encoderCodec = Codec.findEncoderByName(encoderName);
415
+ if (!encoderCodec || !(await this.testHardwareEncoder(encoderName))) {
416
+ return null;
366
417
  }
367
- return null;
418
+ return encoderCodec;
368
419
  }
369
420
  /**
370
421
  * Find all codecs that support this hardware device.
371
422
  *
372
- * 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.
373
425
  *
374
- * Iterates through all codecs using av_codec_iterate() and checks
375
- * their hardware configurations.
426
+ * Direct mapping to av_codec_iterate() with hardware config checks.
376
427
  *
377
428
  * @param isEncoder - Find encoders (true) or decoders (false)
378
- *
379
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
380
443
  */
381
444
  findSupportedCodecs(isEncoder = false) {
382
445
  const supportedCodecs = [];
@@ -408,100 +471,203 @@ export class HardwareContext {
408
471
  /**
409
472
  * Clean up and free hardware resources.
410
473
  *
411
- * Safe to call multiple times - subsequent calls are no-ops.
412
- * 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.
413
477
  *
414
- * Frees both frames context (if created) and device context.
415
- * Notifies any waiting components that disposal occurred.
478
+ * @example
479
+ * ```typescript
480
+ * const hw = HardwareContext.auto();
481
+ * try {
482
+ * // Use hardware
483
+ * } finally {
484
+ * hw?.dispose();
485
+ * }
486
+ * ```
487
+ *
488
+ * @see {@link Symbol.dispose} For automatic cleanup
416
489
  */
417
490
  dispose() {
418
491
  if (this._isDisposed) {
419
- return; // Already disposed, safe to return
492
+ return;
420
493
  }
421
494
  this._deviceContext.free();
422
495
  this._isDisposed = true;
423
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
+ }
424
569
  /**
425
570
  * Create hardware context from device type.
426
571
  *
427
572
  * Internal factory method using av_hwdevice_ctx_create().
428
573
  *
429
574
  * @param deviceType - AVHWDeviceType enum value
430
- * @param deviceName - Optional device name/index
575
+ * @param device - Optional device specifier
431
576
  * @param options - Optional device options
432
- *
433
- * @returns HardwareContext or null if creation fails
577
+ * @returns Hardware context or null if creation fails
434
578
  */
435
- static async createFromType(deviceType, deviceName, options) {
436
- const device = new HardwareDeviceContext();
579
+ static createFromType(deviceType, device, options) {
580
+ const deviceCtx = new HardwareDeviceContext();
437
581
  // Convert options to Dictionary if provided
438
582
  let optionsDict = null;
439
583
  if (options && Object.keys(options).length > 0) {
440
584
  optionsDict = Dictionary.fromObject(options);
441
585
  }
442
- const ret = device.create(deviceType, deviceName ?? null, optionsDict);
586
+ const ret = deviceCtx.create(deviceType, device, optionsDict);
443
587
  // Clean up dictionary if used
444
588
  if (optionsDict) {
445
589
  optionsDict.free();
446
590
  }
447
- if (ret < 0) {
448
- device.free();
591
+ const deviceTypeName = HardwareDeviceContext.getTypeName(deviceType);
592
+ if (ret < 0 || !deviceTypeName) {
593
+ deviceCtx.free();
449
594
  return null;
450
595
  }
451
- return new HardwareContext(device, deviceType, deviceName);
596
+ return new HardwareContext(deviceCtx, deviceType, deviceTypeName);
452
597
  }
453
598
  /**
454
599
  * Get platform-specific preference order for hardware types.
455
600
  *
456
- * 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.
457
603
  *
458
604
  * @returns Array of AVHWDeviceType values in preference order
459
605
  */
460
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
+ }
461
612
  const platform = process.platform;
613
+ let preferenceOrder;
462
614
  if (platform === 'darwin') {
463
615
  // macOS: VideoToolbox is preferred
464
- return [AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_VULKAN, AV_HWDEVICE_TYPE_OPENCL];
616
+ preferenceOrder = [AV_HWDEVICE_TYPE_VIDEOTOOLBOX];
465
617
  }
466
618
  else if (platform === 'win32') {
467
- // Windows: D3D12VA (newest), D3D11VA, DXVA2, QSV, CUDA
468
- return [
469
- AV_HWDEVICE_TYPE_D3D12VA,
470
- AV_HWDEVICE_TYPE_D3D11VA,
619
+ // Windows: Match FFmpeg's hw_configs order
620
+ // DXVA2 → D3D11VA → D3D12VA → NVDEC (CUDA)
621
+ preferenceOrder = [
471
622
  AV_HWDEVICE_TYPE_DXVA2,
472
- AV_HWDEVICE_TYPE_QSV,
623
+ AV_HWDEVICE_TYPE_D3D11VA,
624
+ AV_HWDEVICE_TYPE_D3D12VA,
473
625
  AV_HWDEVICE_TYPE_CUDA,
626
+ AV_HWDEVICE_TYPE_QSV,
474
627
  AV_HWDEVICE_TYPE_VULKAN,
475
628
  AV_HWDEVICE_TYPE_OPENCL,
476
629
  ];
477
630
  }
478
631
  else {
479
- // Linux: RKMPP (for ARM/Rockchip), VAAPI, VDPAU, CUDA, Vulkan, DRM
480
- return [
481
- AV_HWDEVICE_TYPE_RKMPP,
482
- AV_HWDEVICE_TYPE_VAAPI,
483
- AV_HWDEVICE_TYPE_VDPAU,
484
- AV_HWDEVICE_TYPE_CUDA,
485
- AV_HWDEVICE_TYPE_VULKAN,
486
- AV_HWDEVICE_TYPE_DRM,
487
- AV_HWDEVICE_TYPE_OPENCL,
488
- ];
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
+ }
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
+ }
489
653
  }
654
+ return sortedAvailable;
490
655
  }
491
656
  /**
492
- * Automatic cleanup when using 'using' statement.
493
- *
494
- * Implements the Disposable interface for automatic cleanup.
657
+ * Dispose of hardware context.
495
658
  *
496
- * Calls dispose() to free hardware resources.
659
+ * Implements Disposable interface for automatic cleanup.
660
+ * Equivalent to calling dispose().
497
661
  *
498
662
  * @example
499
663
  * ```typescript
500
664
  * {
501
- * using hw = await HardwareContext.auto();
665
+ * using hw = HardwareContext.auto();
502
666
  * // Use hardware context...
503
667
  * } // Automatically disposed
504
668
  * ```
669
+ *
670
+ * @see {@link dispose} For manual cleanup
505
671
  */
506
672
  [Symbol.dispose]() {
507
673
  this.dispose();