Java程序中向FFmpeg进程发送停止命令失败求助
解决Java中向FFmpeg发送'q'优雅停止屏幕录制的问题
你的代码存在三个核心问题,导致FFmpeg无法接收停止命令:
- 通过CMD中转启动FFmpeg:用
CMD /C启动时,Java进程的输出流是写给CMD而非FFmpeg本身,发送的'q'根本传不到FFmpeg那里。 - 未处理FFmpeg的输出缓冲区:FFmpeg运行时会输出大量日志,如果不及时读取标准输出和错误输出,缓冲区满了会直接阻塞进程,连命令都接收不到。
- 发送了错误的字符:
KeyEvent.VK_Q对应的是大写Q的ASCII码(81),但FFmpeg只识别小写字母q(ASCII码113)。
下面是修复后的完整代码:
import java.io.IOException; import java.io.OutputStream; import java.util.concurrent.TimeUnit; public class FFmpegScreenRecorder { public static void main(String[] args) throws IOException, InterruptedException { // 直接指定ffmpeg的完整路径 String ffmpegPath = "D:\\ffmpeg-5.1-essentials_build\\bin\\ffmpeg.exe"; String outputFile = "D:\\Users\\vabali\\Documents\\Workspace\\Captures\\output.mp4"; // 用ProcessBuilder拆分每个命令参数,避免CMD解析问题 ProcessBuilder processBuilder = new ProcessBuilder( ffmpegPath, "-f", "gdigrab", "-i", "desktop", "-c:v", "libx264", "-b:v", "6000K", "-minrate", "6000K", "-maxrate", "6000K", "-bufsize", "6000K", "-pix_fmt", "yuv420p", "-r", "60", "-profile:v", "main", "-crf", "12", "-x264-params", "scenecut=0:open_gop=0:min-keyint=72:keyint=72", "-y", outputFile ); Process process = processBuilder.start(); // 启动线程读取FFmpeg的标准输出,防止缓冲区阻塞 new Thread(() -> { try (var inputStream = process.getInputStream()) { byte[] buffer = new byte[1024]; while (inputStream.read(buffer) != -1) { // 可选:打印输出日志 // System.out.print(new String(buffer).trim()); } } catch (IOException e) { e.printStackTrace(); } }).start(); // 启动线程读取FFmpeg的错误输出 new Thread(() -> { try (var errorStream = process.getErrorStream()) { byte[] buffer = new byte[1024]; while (errorStream.read(buffer) != -1) { // 可选:打印错误日志 // System.err.print(new String(buffer).trim()); } } catch (IOException e) { e.printStackTrace(); } }).start(); // 模拟录制5秒 TimeUnit.SECONDS.sleep(5); // 发送小写q,触发FFmpeg优雅停止 OutputStream outputStream = process.getOutputStream(); outputStream.write('q'); outputStream.flush(); outputStream.close(); // 等待FFmpeg完成收尾工作,确保文件正常保存 int exitCode = process.waitFor(); System.out.println("FFmpeg退出码: " + exitCode); System.out.println("录制是否正常结束: " + (exitCode == 0)); } }
关键修改说明:
- 去掉CMD中转:直接启动FFmpeg.exe,让Java的输出流和FFmpeg的标准输入直接关联,确保命令能被接收。
- 拆分命令参数:每个FFmpeg的选项和参数单独传入ProcessBuilder,避免CMD解析字符串时出现的各种问题。
- 处理输出缓冲区:必须读取FFmpeg的输出,否则缓冲区满会导致进程卡死,无法响应任何命令。
- 发送正确的停止命令:用
output.write('q')发送小写q,符合FFmpeg的停止触发条件。 - 等待进程结束:调用
waitFor()让Java等待FFmpeg完成文件写入和收尾,避免MP4文件损坏。
内容的提问来源于stack exchange,提问作者Varun Bali
相关产品推荐
相关产品推荐

