Java 程序调用 FFmpeg 教程

在 Java 应用中集成视频处理功能时,FFmpeg 是一个强大而灵活的选择。虽然 Java 本身没有内置音视频编解码能力,但我们可以通过调用系统命令的方式,借助 FFmpeg 实现转码、压缩、裁剪等操作。

核心原理 :Java 通过 ProcessBuilder 启动外部进程(如 ffmpeg.exe),并传递命令行参数来执行具体任务。这本质上是一种"命令行调用",但通过 Java 封装后,可以无缝集成到应用程序中。


一、为什么使用 ProcessBuilder

ProcessBuilder 是 Java 标准库(java.lang 包)提供的用于创建和管理操作系统进程的工具类。相比旧的 Runtime.exec(),它具有以下优势:

  • 更清晰的 API 设计
  • 支持设置工作目录、环境变量
  • 更安全地处理输入/输出流
  • 避免常见的死锁问题(需正确读取 stdout/stderr)

二、示例:用 Java 压缩视频

下面是一个完整的示例,展示如何使用 Java 调用 FFmpeg 对视频进行压缩:

java 复制代码
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

public class FfmpegCompressor {

    /**
     * 使用 FFmpeg 压缩视频
     *
     * @param inputPath     输入视频路径(相对或绝对)
     * @param outputPath    输出视频路径
     * @param videoBitrate  视频目标码率(如 "3M" 表示 3 Mbps)
     * @throws IOException          启动进程或读取流失败
     * @throws InterruptedException 进程被中断
     */
    public static void compressVideo(String inputPath, String outputPath, String videoBitrate)
            throws IOException, InterruptedException {

        // 务必指定 ffmpeg 可执行文件的完整路径(不是安装目录!)
        String ffmpegPath = "D:\\Develop\\ffmpeg-8.0.1-essentials_build\\bin\\ffmpeg.exe";

        ProcessBuilder pb = new ProcessBuilder(
                ffmpegPath,
                "-i", inputPath,
                "-b:v", videoBitrate,
                "-bufsize", videoBitrate,
                "-c:a", "aac",   // 音频编码为 AAC
                "-y",            // 覆盖输出文件(不提示)
                outputPath
        );

        // 设置工作目录(建议设为视频所在目录,避免路径问题)
        pb.directory(new File("C:\\Users\\x\\Videos\\原画"));

        System.out.println("正在启动 FFmpeg...");
        Process process = pb.start();

        // 异步读取 stdout 和 stderr,防止缓冲区阻塞导致死锁
        Thread outThread = new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()))) {
                reader.lines().forEach(line -> System.out.println("[FFmpeg OUT] " + line));
            } catch (IOException e) {
                System.err.println("读取 FFmpeg 标准输出失败: " + e.getMessage());
            }
        });

        Thread errThread = new Thread(() -> {
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getErrorStream()))) {
                reader.lines().forEach(line -> System.err.println("[FFmpeg LOG] " + line));
            } catch (IOException e) {
                System.err.println("读取 FFmpeg 错误流失败: " + e.getMessage());
            }
        });

        outThread.start();
        errThread.start();

        // 等待进程结束
        int exitCode = process.waitFor();
        outThread.join();
        errThread.join();

        if (exitCode == 0) {
            System.out.println("视频压缩成功: " + outputPath);
        } else {
            System.err.println("FFmpeg 执行失败,退出码: " + exitCode);
            throw new RuntimeException("视频压缩失败,请检查输入路径或 FFmpeg 配置");
        }
    }

    public static void main(String[] args) {
        try {
            compressVideo("1.mp4", "1-compressed.mp4", "3M");
        } catch (Exception e) {
            System.err.println("程序异常: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

三、关键注意事项

1. ffmpegPath 必须指向 ffmpeg.exe 文件

  • 错误:D:\Develop\ffmpeg-8.0.1-essentials_build
  • 正确:D:\Develop\ffmpeg-8.0.1-essentials_build\bin\ffmpeg.exe

2. 工作目录(Working Directory)建议设置

  • 若输入/输出路径为相对路径,pb.directory(...) 决定了这些路径的基准。
  • 推荐设为视频所在目录,避免路径解析错误。

3. FFmpeg 的日志输出在 stderr

⚠️ 注意:[FFmpeg ERR] 并不表示"错误"!

FFmpeg 遵循 Unix 哲学:

  • stdout :仅用于真正的数据输出(如 -f image2pipe 输出图像流)
  • stderr:输出所有日志、进度、警告、统计信息(包括成功信息)

因此,你看到的 [FFmpeg ERR]是正常运行日志。


四、进阶建议

方向 建议
路径配置 ffmpegPath 提取为配置项(如 properties 文件或环境变量),避免硬编码
异常处理 捕获更细粒度的异常,记录日志(如使用 SLF4J)
跨平台支持 检测操作系统,自动选择 ffmpegffmpeg.exe
资源清理 确保 BufferedReader 正确关闭(当前代码已用 try-with-resources)
异步执行 若在 Web 应用中使用,建议将压缩任务提交到线程池,避免阻塞主线程

五、总结

通过 ProcessBuilder 调用 FFmpeg 是 Java 中实现音视频处理的常用方案。虽然它依赖外部程序,但只要注意路径、流处理和错误判断,就能稳定高效地完成任务。

📌 记住:FFmpeg 强大,但"黑盒"调用需谨慎。建议先在命令行测试命令,再集成到 Java 代码中。

相关推荐
夕除3 分钟前
javaweb--02
java·tomcat
AI_Claude_code4 分钟前
ZLibrary访问困境方案三:Web代理与轻量级转发服务的搭建与优化
爬虫·python·web安全·搜索引擎·网络安全·web3·httpx
小陈工7 分钟前
2026年4月7日技术资讯洞察:下一代数据库融合、AI基础设施竞赛与异步编程实战
开发语言·前端·数据库·人工智能·python
ailvyuanj8 分钟前
2026年Java AI开发实战:Spring AI完全指南
java
时空无限13 分钟前
ansible 由于不同主机 python 版本不同执行报错
python·ansible
ZhengEnCi17 分钟前
P2E-Python字典操作完全指南-从增删改查到遍历嵌套的Python编程利器
python
alanesnape18 分钟前
使用AVL平衡树和列表实现 map容器 -- 附加测试/python代码
python·map·avl 平衡树·bst树·二叉树旋转
张np21 分钟前
java进阶-Dubbo
java·dubbo
汽车仪器仪表相关领域22 分钟前
NHFID-1000型非甲烷总烃分析仪:技术破局,重构固定污染源监测新体验
java·大数据·网络·人工智能·单元测试·可用性测试·安全性测试
一叶飘零_sweeeet24 分钟前
深入理解 AQS:从架构到实现,解锁 Java 并发编程的核心密钥
java·aqs