(encoder: ConcreteGpuEncoder)
| 147 | } |
| 148 | |
| 149 | async function canUseGpuEncoder(encoder: ConcreteGpuEncoder): Promise<boolean> { |
| 150 | return new Promise((resolve) => { |
| 151 | let settled = false; |
| 152 | let timedOut = false; |
| 153 | let killTimer: ReturnType<typeof setTimeout> | undefined; |
| 154 | let stderr = ""; |
| 155 | const finish = (usable: boolean) => { |
| 156 | if (settled) return; |
| 157 | settled = true; |
| 158 | clearTimeout(timer); |
| 159 | if (killTimer) clearTimeout(killTimer); |
| 160 | resolve(usable); |
| 161 | }; |
| 162 | const ffmpeg = spawn(getFfmpegBinary(), getProbeArgs(encoder), { |
| 163 | stdio: ["ignore", "ignore", "pipe"], |
| 164 | }); |
| 165 | |
| 166 | ffmpeg.stderr?.on("data", (data) => { |
| 167 | stderr += data.toString(); |
| 168 | }); |
| 169 | |
| 170 | const timer = setTimeout(() => { |
| 171 | timedOut = true; |
| 172 | ffmpeg.kill("SIGTERM"); |
| 173 | killTimer = setTimeout(() => { |
| 174 | ffmpeg.kill("SIGKILL"); |
| 175 | finish(false); |
| 176 | }, GPU_PROBE_KILL_GRACE_MS); |
| 177 | }, GPU_PROBE_TIMEOUT_MS); |
| 178 | |
| 179 | ffmpeg.on("close", (code, signal) => { |
| 180 | const usable = code === 0; |
| 181 | logGpuProbeFailure(encoder, { code, signal, stderr, timedOut }); |
| 182 | finish(usable); |
| 183 | }); |
| 184 | |
| 185 | ffmpeg.on("error", (error) => { |
| 186 | logGpuProbeFailure(encoder, { error, timedOut }); |
| 187 | finish(false); |
| 188 | }); |
| 189 | }); |
| 190 | } |
| 191 | |
| 192 | function logGpuProbeFailure( |
| 193 | encoder: ConcreteGpuEncoder, |
nothing calls this directly
no test coverage detected