主程序 java.exe 啟動子進程 ffmpeg.exe 轉碼視頻,需:
List<String> cmd = Arrays.asList("ffmpeg", "-i", "input.mp4", "-c:v", "libx264", "output.mp4");
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true); // 合併 stderr 到 stdout,簡化讀取
Process process = pb.start();
// 異步讀取輸出流(生產環境建議用單獨線程或 CompletableFuture)
new Thread(() -> {
try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = br.readLine()) != null) {
parseProgress(line); // 解析 "frame=123 fps=25 time=00:00:05.00 bitrate=..."
pushToFrontend(progress); // WebSocket/HTTP 推送給前端
}
} catch (IOException e) { log.error("讀取 ffmpeg 輸出失敗", e); }
}).start();
// 等待結束(可設超時)
boolean finished = process.waitFor(30, TimeUnit.MINUTES);
int exitCode = process.exitValue();
if (exitCode == 0) { onSuccess(); } else { onFailure(exitCode); }
| 問題 | 解答 |
|---|---|
| 能否設置子進程優先級? | Java 無跨平台 API。Windows 可用 ProcessHandle (JDK 9+) 配合 JNA 調用 SetPriorityClass;Linux 用 nice 啟動腳本包裹。 |
| 如何獲取進程運行時間? | ProcessHandle.of(process.pid()).info().startInstant() (JDK 9+) 或解析 ps -o etime= -p <pid>。 |
| 為何 java 結束前 ffmpeg 不執行? | 可能未正確調用 pb.start()、或主線程提前 System.exit(0) 導致 JVM 關閉銷毀子進程。確保主線程 waitFor 或註冊 ShutdownHook 清理。 |
| Windows 默認調度算法? | 多級反饋隊列(優先級動態調整、時間片輪轉),非實時系統不建議依賴優先級控制。 |
process.waitFor(timeout, unit) + process.destroyForcibly()。Java 操作外部進程的標準範式是 ProcessBuilder → redirectErrorStream → 異步消費流 → waitFor。掌握此模式,配合 JDK 9+ ProcessHandle,即可覆蓋 95% 進程編排場景。