-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgpuDetect.ts
More file actions
112 lines (100 loc) · 2.83 KB
/
Copy pathgpuDetect.ts
File metadata and controls
112 lines (100 loc) · 2.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import { spawn } from 'node:child_process';
import { existsSync } from 'node:fs';
import { access } from 'node:fs/promises';
export type GpuBackend = 'cpu' | 'vaapi' | 'nvenc';
export type GpuEncodeConfig = {
backend: GpuBackend;
/** Appended to Encore profile base name, e.g. vmp-720p-audio-gpu-vaapi */
profileSuffix: '' | '-gpu-vaapi' | '-gpu-nvenc';
vaapiDevice: string;
};
const VAAPI_DEVICE = (process.env.VAAPI_DEVICE || '/dev/dri/renderD128').trim();
const FORCE_GPU = (process.env.VMP_GPU_BACKEND || 'auto').trim().toLowerCase();
let cached: GpuEncodeConfig | null = null;
function runQuick(cmd: string, args: string[]): Promise<boolean> {
return new Promise((resolve) => {
const child = spawn(cmd, args, { stdio: 'ignore' });
const timeout = setTimeout(() => {
child.kill('SIGKILL');
resolve(false);
}, 10_000);
child.on('error', () => {
clearTimeout(timeout);
resolve(false);
});
child.on('close', (code) => {
clearTimeout(timeout);
resolve(code === 0);
});
});
}
async function canUseVaapi(): Promise<boolean> {
if (!existsSync(VAAPI_DEVICE)) return false;
try {
await access(VAAPI_DEVICE);
} catch {
return false;
}
return runQuick('ffmpeg', [
'-hide_banner',
'-init_hw_device',
`vaapi=va:${VAAPI_DEVICE}`,
'-f',
'lavfi',
'-i',
'testsrc2=size=64x64:rate=1',
'-t',
'0.1',
'-c:v',
'h264_vaapi',
'-f',
'null',
'-',
]);
}
async function canUseNvenc(): Promise<boolean> {
return runQuick('ffmpeg', [
'-hide_banner',
'-f',
'lavfi',
'-i',
'testsrc2=size=64x64:rate=1',
'-t',
'0.1',
'-c:v',
'h264_nvenc',
'-f',
'null',
'-',
]);
}
export async function detectGpuEncodeConfig(): Promise<GpuEncodeConfig> {
if (cached) return cached;
if (FORCE_GPU === 'cpu' || FORCE_GPU === 'none') {
cached = { backend: 'cpu', profileSuffix: '', vaapiDevice: VAAPI_DEVICE };
return cached;
}
if (FORCE_GPU === 'vaapi') {
cached = { backend: 'vaapi', profileSuffix: '-gpu-vaapi', vaapiDevice: VAAPI_DEVICE };
return cached;
}
if (FORCE_GPU === 'nvenc' || FORCE_GPU === 'nvidia') {
cached = { backend: 'nvenc', profileSuffix: '-gpu-nvenc', vaapiDevice: VAAPI_DEVICE };
return cached;
}
if (await canUseNvenc()) {
cached = { backend: 'nvenc', profileSuffix: '-gpu-nvenc', vaapiDevice: VAAPI_DEVICE };
return cached;
}
if (await canUseVaapi()) {
cached = { backend: 'vaapi', profileSuffix: '-gpu-vaapi', vaapiDevice: VAAPI_DEVICE };
return cached;
}
cached = { backend: 'cpu', profileSuffix: '', vaapiDevice: VAAPI_DEVICE };
return cached;
}
export function resolveEncoreProfileBase(base: string, profileSuffix: string): string {
if (!profileSuffix) return base;
const withGpu = `${base}${profileSuffix}`;
return withGpu;
}