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.
- package/README.md +56 -41
- package/dist/api/bitstream-filter.d.ts +180 -123
- package/dist/api/bitstream-filter.js +182 -126
- package/dist/api/bitstream-filter.js.map +1 -1
- package/dist/api/decoder.d.ts +286 -130
- package/dist/api/decoder.js +321 -159
- package/dist/api/decoder.js.map +1 -1
- package/dist/api/encoder.d.ts +254 -158
- package/dist/api/encoder.js +326 -298
- package/dist/api/encoder.js.map +1 -1
- package/dist/api/filter-presets.d.ts +912 -0
- package/dist/api/filter-presets.js +1407 -0
- package/dist/api/filter-presets.js.map +1 -0
- package/dist/api/filter.d.ts +280 -284
- package/dist/api/filter.js +435 -509
- package/dist/api/filter.js.map +1 -1
- package/dist/api/hardware.d.ts +226 -159
- package/dist/api/hardware.js +405 -287
- package/dist/api/hardware.js.map +1 -1
- package/dist/api/index.d.ts +3 -2
- package/dist/api/index.js +1 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/io-stream.d.ts +65 -61
- package/dist/api/io-stream.js +45 -47
- package/dist/api/io-stream.js.map +1 -1
- package/dist/api/media-input.d.ts +244 -141
- package/dist/api/media-input.js +207 -104
- package/dist/api/media-input.js.map +1 -1
- package/dist/api/media-output.d.ts +206 -128
- package/dist/api/media-output.js +212 -129
- package/dist/api/media-output.js.map +1 -1
- package/dist/api/pipeline.d.ts +168 -38
- package/dist/api/pipeline.js +238 -14
- package/dist/api/pipeline.js.map +1 -1
- package/dist/api/types.d.ts +22 -182
- package/dist/api/utilities/audio-sample.d.ts +1 -1
- package/dist/api/utilities/image.d.ts +1 -1
- package/dist/api/utilities/media-type.d.ts +1 -1
- package/dist/api/utilities/pixel-format.d.ts +1 -1
- package/dist/api/utilities/sample-format.d.ts +1 -1
- package/dist/api/utilities/timestamp.d.ts +1 -1
- package/dist/api/utils.d.ts +1 -2
- package/dist/api/utils.js +9 -0
- package/dist/api/utils.js.map +1 -1
- package/dist/{lib → constants}/channel-layouts.d.ts +1 -1
- package/dist/constants/channel-layouts.js.map +1 -0
- package/dist/{lib → constants}/constants.d.ts +19 -4
- package/dist/{lib → constants}/constants.js +15 -1
- package/dist/constants/constants.js.map +1 -0
- package/dist/constants/decoders.d.ts +609 -0
- package/dist/constants/decoders.js +617 -0
- package/dist/constants/decoders.js.map +1 -0
- package/dist/constants/encoders.d.ts +285 -0
- package/dist/constants/encoders.js +298 -0
- package/dist/constants/encoders.js.map +1 -0
- package/dist/constants/index.d.ts +4 -0
- package/dist/constants/index.js +5 -0
- package/dist/constants/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/audio-fifo.d.ts +128 -171
- package/dist/lib/audio-fifo.js +130 -173
- package/dist/lib/audio-fifo.js.map +1 -1
- package/dist/lib/binding.d.ts +7 -5
- package/dist/lib/binding.js +5 -0
- package/dist/lib/binding.js.map +1 -1
- package/dist/lib/bitstream-filter-context.d.ts +139 -184
- package/dist/lib/bitstream-filter-context.js +139 -188
- package/dist/lib/bitstream-filter-context.js.map +1 -1
- package/dist/lib/bitstream-filter.d.ts +69 -55
- package/dist/lib/bitstream-filter.js +68 -54
- package/dist/lib/bitstream-filter.js.map +1 -1
- package/dist/lib/codec-context.d.ts +317 -381
- package/dist/lib/codec-context.js +316 -381
- package/dist/lib/codec-context.js.map +1 -1
- package/dist/lib/codec-parameters.d.ts +161 -171
- package/dist/lib/codec-parameters.js +162 -172
- package/dist/lib/codec-parameters.js.map +1 -1
- package/dist/lib/codec-parser.d.ts +92 -105
- package/dist/lib/codec-parser.js +92 -103
- package/dist/lib/codec-parser.js.map +1 -1
- package/dist/lib/codec.d.ts +328 -217
- package/dist/lib/codec.js +392 -218
- package/dist/lib/codec.js.map +1 -1
- package/dist/lib/dictionary.d.ts +150 -204
- package/dist/lib/dictionary.js +159 -213
- package/dist/lib/dictionary.js.map +1 -1
- package/dist/lib/error.d.ts +97 -131
- package/dist/lib/error.js +98 -128
- package/dist/lib/error.js.map +1 -1
- package/dist/lib/filter-context.d.ts +317 -194
- package/dist/lib/filter-context.js +335 -200
- package/dist/lib/filter-context.js.map +1 -1
- package/dist/lib/filter-graph.d.ts +252 -293
- package/dist/lib/filter-graph.js +253 -294
- package/dist/lib/filter-graph.js.map +1 -1
- package/dist/lib/filter-inout.d.ts +87 -95
- package/dist/lib/filter-inout.js +87 -95
- package/dist/lib/filter-inout.js.map +1 -1
- package/dist/lib/filter.d.ts +93 -111
- package/dist/lib/filter.js +94 -112
- package/dist/lib/filter.js.map +1 -1
- package/dist/lib/format-context.d.ts +321 -429
- package/dist/lib/format-context.js +314 -386
- package/dist/lib/format-context.js.map +1 -1
- package/dist/lib/frame.d.ts +263 -406
- package/dist/lib/frame.js +263 -408
- package/dist/lib/frame.js.map +1 -1
- package/dist/lib/hardware-device-context.d.ts +150 -204
- package/dist/lib/hardware-device-context.js +149 -203
- package/dist/lib/hardware-device-context.js.map +1 -1
- package/dist/lib/hardware-frames-context.d.ts +171 -181
- package/dist/lib/hardware-frames-context.js +171 -181
- package/dist/lib/hardware-frames-context.js.map +1 -1
- package/dist/lib/index.d.ts +2 -3
- package/dist/lib/index.js +2 -5
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/input-format.d.ts +90 -118
- package/dist/lib/input-format.js +89 -117
- package/dist/lib/input-format.js.map +1 -1
- package/dist/lib/io-context.d.ts +210 -242
- package/dist/lib/io-context.js +221 -253
- package/dist/lib/io-context.js.map +1 -1
- package/dist/lib/log.d.ts +86 -120
- package/dist/lib/log.js +85 -122
- package/dist/lib/log.js.map +1 -1
- package/dist/lib/native-types.d.ts +127 -112
- package/dist/lib/native-types.js +9 -0
- package/dist/lib/native-types.js.map +1 -1
- package/dist/lib/option.d.ts +285 -242
- package/dist/lib/option.js +310 -250
- package/dist/lib/option.js.map +1 -1
- package/dist/lib/output-format.d.ts +78 -102
- package/dist/lib/output-format.js +77 -101
- package/dist/lib/output-format.js.map +1 -1
- package/dist/lib/packet.d.ts +173 -241
- package/dist/lib/packet.js +172 -241
- package/dist/lib/packet.js.map +1 -1
- package/dist/lib/rational.d.ts +0 -2
- package/dist/lib/rational.js +0 -2
- package/dist/lib/rational.js.map +1 -1
- package/dist/lib/software-resample-context.d.ts +242 -326
- package/dist/lib/software-resample-context.js +242 -326
- package/dist/lib/software-resample-context.js.map +1 -1
- package/dist/lib/software-scale-context.d.ts +130 -174
- package/dist/lib/software-scale-context.js +132 -176
- package/dist/lib/software-scale-context.js.map +1 -1
- package/dist/lib/stream.d.ts +88 -198
- package/dist/lib/stream.js +87 -197
- package/dist/lib/stream.js.map +1 -1
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/utilities.d.ts +372 -181
- package/dist/lib/utilities.js +373 -182
- package/dist/lib/utilities.js.map +1 -1
- package/install/check.js +0 -1
- package/package.json +32 -24
- package/release_notes.md +43 -13
- package/CHANGELOG.md +0 -8
- package/dist/lib/channel-layouts.js.map +0 -1
- package/dist/lib/constants.js.map +0 -1
- /package/dist/{lib → constants}/channel-layouts.js +0 -0
package/dist/api/hardware.js
CHANGED
|
@@ -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
|
-
*
|
|
5
|
+
* High-level hardware acceleration management.
|
|
3
6
|
*
|
|
4
|
-
* Provides
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
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 =
|
|
18
|
+
* const hw = HardwareContext.auto();
|
|
28
19
|
* if (hw) {
|
|
29
|
-
* console.log(`Using hardware: ${hw.
|
|
30
|
-
* decoder
|
|
20
|
+
* console.log(`Using hardware: ${hw.deviceTypeName}`);
|
|
21
|
+
* const decoder = await Decoder.create(stream, { hardware: hw });
|
|
31
22
|
* }
|
|
23
|
+
* ```
|
|
32
24
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
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
|
-
|
|
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
|
|
52
|
+
* @param deviceType - Hardware device type enum
|
|
53
|
+
* @param deviceTypeName - Human-readable device type name
|
|
54
|
+
* @internal
|
|
60
55
|
*/
|
|
61
|
-
constructor(deviceContext, deviceType,
|
|
56
|
+
constructor(deviceContext, deviceType, deviceTypeName) {
|
|
62
57
|
this._deviceContext = deviceContext;
|
|
63
58
|
this._deviceType = deviceType;
|
|
64
|
-
this.
|
|
65
|
-
this._devicePixelFormat = this.
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
111
|
-
*
|
|
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
|
|
114
|
-
* @param
|
|
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
|
-
* @
|
|
127
|
+
* @throws {Error} If device type unsupported or initialization fails
|
|
118
128
|
*
|
|
119
|
-
* @
|
|
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
|
-
*
|
|
124
|
-
* const cuda = await HardwareContext.create(AV_HWDEVICE_TYPE_CUDA, '0');
|
|
139
|
+
* import { AV_HWDEVICE_TYPE_VAAPI } from 'node-av/constants';
|
|
125
140
|
*
|
|
126
|
-
* //
|
|
127
|
-
* const vaapi =
|
|
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
|
|
131
|
-
if (
|
|
132
|
-
throw new Error(
|
|
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 =
|
|
155
|
+
const hw = this.createFromType(deviceType, device, options);
|
|
135
156
|
if (!hw) {
|
|
136
|
-
throw new Error(`Failed to create hardware context for ${
|
|
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
|
-
*
|
|
144
|
-
*
|
|
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
|
-
*
|
|
194
|
+
* Used internally by encoders and decoders for hardware acceleration.
|
|
195
|
+
* Can be assigned to CodecContext.hwDeviceCtx.
|
|
169
196
|
*
|
|
170
|
-
* @
|
|
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
|
-
* @
|
|
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
|
-
*
|
|
221
|
+
* Human-readable device type string.
|
|
217
222
|
*
|
|
218
|
-
* @
|
|
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
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
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
|
-
*
|
|
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
|
-
*
|
|
254
|
-
*
|
|
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
|
-
*
|
|
264
|
+
* Direct mapping to avcodec_get_hw_config().
|
|
259
265
|
*
|
|
260
|
-
* @
|
|
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
|
-
*
|
|
265
|
-
*
|
|
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
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
279
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
297
|
+
* Verifies pixel format compatibility with hardware codec.
|
|
298
|
+
* Important for ensuring format compatibility in pipelines.
|
|
303
299
|
*
|
|
304
|
-
* @
|
|
305
|
-
*
|
|
306
|
-
* @
|
|
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
|
-
*
|
|
311
|
-
*
|
|
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
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
|
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
|
|
328
|
+
* Get the appropriate encoder codec for a given base codec name.
|
|
327
329
|
*
|
|
328
|
-
* Maps
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
357
|
+
* @see {@link Encoder.create} For using the codec
|
|
333
358
|
*/
|
|
334
|
-
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
-
|
|
348
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
|
418
|
+
return encoderCodec;
|
|
415
419
|
}
|
|
416
420
|
/**
|
|
417
421
|
* Find all codecs that support this hardware device.
|
|
418
422
|
*
|
|
419
|
-
*
|
|
423
|
+
* Iterates through all available codecs and checks hardware compatibility.
|
|
424
|
+
* Useful for discovering available hardware acceleration options.
|
|
420
425
|
*
|
|
421
|
-
*
|
|
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
|
-
*
|
|
459
|
-
*
|
|
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
|
-
*
|
|
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;
|
|
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
|
|
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
|
|
492
|
-
const
|
|
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 =
|
|
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
|
-
|
|
504
|
-
|
|
591
|
+
const deviceTypeName = HardwareDeviceContext.getTypeName(deviceType);
|
|
592
|
+
if (ret < 0 || !deviceTypeName) {
|
|
593
|
+
deviceCtx.free();
|
|
505
594
|
return null;
|
|
506
595
|
}
|
|
507
|
-
return new HardwareContext(
|
|
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
|
|
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
|
-
|
|
616
|
+
preferenceOrder = [AV_HWDEVICE_TYPE_VIDEOTOOLBOX];
|
|
521
617
|
}
|
|
522
618
|
else if (platform === 'win32') {
|
|
523
|
-
// Windows:
|
|
524
|
-
|
|
525
|
-
|
|
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
|
-
|
|
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:
|
|
536
|
-
|
|
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
|
-
*
|
|
541
|
-
*
|
|
542
|
-
* Implements the Disposable interface for automatic cleanup.
|
|
657
|
+
* Dispose of hardware context.
|
|
543
658
|
*
|
|
544
|
-
*
|
|
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 =
|
|
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();
|