You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java程序中向FFmpeg进程发送停止命令失败求助

解决Java中向FFmpeg发送'q'优雅停止屏幕录制的问题

你的代码存在三个核心问题,导致FFmpeg无法接收停止命令:

  1. 通过CMD中转启动FFmpeg:用CMD /C启动时,Java进程的输出流是写给CMD而非FFmpeg本身,发送的'q'根本传不到FFmpeg那里。
  2. 未处理FFmpeg的输出缓冲区:FFmpeg运行时会输出大量日志,如果不及时读取标准输出和错误输出,缓冲区满了会直接阻塞进程,连命令都接收不到。
  3. 发送了错误的字符: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 08:18:35