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

FFmpeg录屏命令在Windows CMD可用但Java类调用生成文件不可读问题

问题:Java调用FFmpeg录制屏幕生成的文件无法播放(错误码0xc10100be)

我有一个JUnit测试,通过ScreenRecordingWatcher类在测试失败时调用FFmpeg录制屏幕。CMD中直接执行命令能生成正常可播放的文件,但Java调用生成的文件无法被Windows播放器读取,报错错误码0xc10100be。

正常工作的CMD命令

C:\outils\ffmpeg-master-latest-win64-gpl\bin\ffmpeg.exe -f gdigrab -framerate 30 -i desktop -c:v h264_nvenc -qp 0 C:\outils\video\output.mkv

Java实现代码(原版本)

public class ScreenRecordingWatcher extends TestWatcher {

private static final String FFMPEG_PATH = "C:\\outils\\ffmpeg-master-latest-win64-gpl\\bin\\ffmpeg.exe";
private static final String OUTPUT_FILE = "C:\\outils\\video\\fichier.mkv";
private boolean testFailed = false;

@Override
protected void failed(Throwable e, Description description) {
    super.failed(e, description);
    testFailed = true;
}

@Override
protected void finished(Description description) {
    super.finished(description);
    if (testFailed) {
        startRecording();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        stopRecording();
    }
}

private void startRecording() {
    String[] command = { FFMPEG_PATH, "-f", "gdigrab", "-framerate", "30", "-i", "desktop", "-c:v", "h264_nvenc", "-qp", "0", OUTPUT_FILE };

    System.out.println(Arrays.toString(command));
    ProcessBuilder builder = new ProcessBuilder(command);
    try {
        builder.start();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void stopRecording() {
    String[] command = { "tskill", "ffmpeg" };
    ProcessBuilder builder = new ProcessBuilder(command);
    try {
        builder.start();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
}
原因与解决方法
  • 核心原因:强制终止FFmpeg进程导致文件结构损坏。原代码用tskill ffmpeg直接杀死进程,FFmpeg来不及完成视频文件的封装收尾(比如写入MKV索引、完善文件头),导致播放器无法识别。而CMD中是手动输入q让FFmpeg优雅退出,文件能正常完成写入。

  • 修复后的代码:

import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

public class ScreenRecordingWatcher extends TestWatcher {

private static final String FFMPEG_PATH = "C:\\outils\\ffmpeg-master-latest-win64-gpl\\bin\\ffmpeg.exe";
private static final String OUTPUT_FILE = "C:\\outils\\video\\fichier.mkv";
private boolean testFailed = false;
private Process ffmpegProcess; // 保存FFmpeg进程引用

@Override
protected void failed(Throwable e, Description description) {
    super.failed(e, description);
    testFailed = true;
}

@Override
protected void finished(Description description) {
    super.finished(description);
    if (testFailed) {
        startRecording();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        stopRecording();
    }
}

private void startRecording() {
    String[] command = { FFMPEG_PATH, "-f", "gdigrab", "-framerate", "30", "-i", "desktop", "-c:v", "h264_nvenc", "-qp", "0", OUTPUT_FILE };

    System.out.println(Arrays.toString(command));
    ProcessBuilder builder = new ProcessBuilder(command);
    // 重定向日志到文件,方便排查问题
    builder.redirectErrorStream(true);
    builder.redirectOutput(new File("C:\\outils\\video\\ffmpeg_recording.log"));
    try {
        ffmpegProcess = builder.start(); // 保存进程实例
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void stopRecording() {
    if (ffmpegProcess == null || !ffmpegProcess.isAlive()) {
        return;
    }

    try {
        // 向FFmpeg发送退出指令,触发优雅收尾
        ffmpegProcess.getOutputStream().write('q');
        ffmpegProcess.getOutputStream().flush();
        // 等待进程正常退出,最多等3秒
        if (!ffmpegProcess.waitFor(3, TimeUnit.SECONDS)) {
            // 超时未退出则强制终止
            ffmpegProcess.destroyForcibly();
        }
    } catch (IOException | InterruptedException e) {
        e.printStackTrace();
        ffmpegProcess.destroyForcibly();
    }
}
}
  • 关键优化点:
    1. 保存FFmpeg进程的直接引用,避免通过进程名杀死(可能误杀其他FFmpeg实例)。
    2. 发送q字符让FFmpeg优雅退出,确保文件完成封装。
    3. 添加日志重定向,便于排查FFmpeg执行中的隐藏错误。
    4. 设置超时等待,超时后再强制终止,兼顾可靠性和效率。

内容的提问来源于stack exchange,提问作者Youssef Hammouma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 15:16:29