Java调用FFmpeg
- 1、FFmepg基础知识
- 1.1 下载 FFmpeg
- 1.2 FFmpeg 工具使用
- 2、Java使用
- 2.1 FFmpeg源码编译
- 2.2 Java集成FFmpeg
- 2.2.1 JNI
- 2.2.2 Java调用执行 FFmpeg 工具 命令
1、FFmepg基础知识
About FFmpeg
ffmpeg(计算机程序) - 百度百科
FFmpeg/FFmpeg - GitHub
CSDN:FFmpeg 基础知识 @在奋斗的大道
关于FFmpeg
FFmpeg
是领先的多媒体框架,能够解码,编码, 转码,复用,解复用,流,过滤和播放几乎任何东西 人类和机器创造的。它支持最晦涩的 古老的格式直到最前沿。不管他们是不是 由一些标准委员会,社区或公司设计。是的 而且高度可移植:FFmpeg 编译、运行并通过我们的测试基础设施 FATE 跨 Linux、Mac OS X、 Microsoft Windows,BSD,Solaris等在各种各样的构建下 环境、计算机体系结构和配置。它包含
libavcodec
,libavutil
,libavformat
,libavfilter
,libavdevice
,libswscale
和libswresample
可供应用程序使用。 以及ffmpeg,ffplay和ffprobe
,可用于 最终用户进行转码和播放。
FFmpeg
项目试图提供最好的技术可能 适用于应用程序开发人员和最终用户的解决方案。要实现 我们结合了可用的最佳免费软件选项。我们稍微 支持我们自己的代码,以保持对其他库的依赖较低,并 最大化FFmpeg
各部分之间的代码共享。 凡是“最好”的问题无法回答的地方,我们都支持两者 选项,以便最终用户可以选择。
FFmpeg
欢迎所有人,也欢迎所有贡献。 我们很高兴收到补丁,拉取请求,错误报告,捐赠 或任何其他类型的贡献。安全性是重中之重,代码审查始终使用 牢记安全性。虽然由于大量的代码接触 不受信任的数据安全问题是不可避免的,因此我们提供 在以下情况下尽快更新到我们上一个稳定版本 发现新的安全问题。
FFmpeg 工具
- FFMPEG 用于转换多媒体文件的 命令行工具 格式之间
- ffplay 基于 SDL 和 FFmpeg 库的简单媒体播放器
- FF探针 一个简单的多媒体流分析仪
面向开发人员的 FFmpeg 库
- libavutil 是一个包含函数的库 简化编程,包括随机数生成器、数据 结构、数学例程、核心多媒体实用程序等等 更多。
- libavcodec是一个包含解码器和编码器的库 用于音频/视频编解码器。
- libavformat 是一个包含解复用器和 用于多媒体容器格式的复用器。
- libavdevice 是一个包含输入和输出的库 用于抓取和渲染许多常见多媒体的设备 输入/输出软件框架,包括Video4Linux,Video4Linux2, VfW和ALSA。
- libavfilter 是一个包含媒体过滤器的库。
- libswscale 是一个执行高度优化图像的库 缩放和色彩空间/像素格式转换操作。
- libswresample 是一个执行高度优化的库 音频重新采样、重新矩阵和样本格式转换操作。
1.1 下载 FFmpeg
Download FFmpeg
-
Windows EXE Files:Windows builds from gyan.dev、Windows builds by BtbN
-
FFmpeg Source Code:ffmpeg-6.0.tar.xz
1.2 FFmpeg 工具使用
ffmpeg\bin\ffmpeg.exe
命令 | 说明 |
---|---|
ffmpeg -i input.avi | 查询视频信息 |
ffmpeg -i input.avi -hide_banner | 查询只显示视频信息 |
ffmpeg -i input.avi output.mp4 | 通过重新编码媒体流,将输入媒体文件转换为其他格式 |
ffmpeg -i input.avi -b:v 64k -bufsize 64k output.mp4 | 将输出文件的视频比特率设置为 64 kbit/s |
ffmpeg -i input.avi -r 24 output.mp4 | 强制输出文件的帧速率为 24 fps |
ffmpeg -r 1 -i input.m2v -r 24 output.mp4 | 强制输入文件的帧速率(仅对原始格式有效)为 1 fps,并且 输出文件的帧速率为 24 fps |
ffmpeg\bin\ffplay.exe
命令 | 说明 |
---|---|
ffplay -i input.avi | 读取视频input.avi。不会自动退出,原比例播放 |
ffplay -autoexit input.avi | 视频播放完毕后退出。 |
ffplay -x 600 -y 800 input.avi | 以600x800 播放 |
ffmpeg\bin\ffprobe.exe
命令 | 说明 |
---|---|
ffprobe input.avi -hide_banner | 显示视频信息 |
ffprobe input.avi -hide_banner -show_format | 显示有关输入多媒体的容器格式的信息 |
ffprobe input.avi -hide_banner -show_format -print_format json | 以json数据显示有关输入多媒体的容器格式的信息 |
2、Java使用
2.1 FFmpeg源码编译
Windows下编译FFmpeg - 知乎
Windows编译和使用ffmpeg
2.2 Java集成FFmpeg
2.2.1 JNI
Java版流媒体编解码和图像处理(JavaCPP+FFmpeg)
Javacv使用ffmpeg实现音视频同步播放
Java通过JNI调用FFmpeg的c语言,Window上需要FFmpeg相应的
.dll
文件,Linux上需要FFmpeg相应的.so
文件
2.2.2 Java调用执行 FFmpeg 工具 命令
Java执行命令方法:
java/lang/Runtime.java
java/lang/ProcessBuilder.java
// 执行命令 Process process = Runtime.getRuntime().exec("cmd /c dir /b"); // 获取命令输出结果 BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { XLog.d(line); } // 等待命令执行完成 process.waitFor();
Java通过流获取命令输出结果可能会存在缓存的问题。当使用Java通过Runtime.getRuntime().exec
等方法执行指令时,命令本身的输出结果是通过标准输出流(stdout
)和标准错误流(stderr
)来输出的。而Java读取输出结果的方式是通过获取进程的标准输出流/标准错误流来进行读取的。但当命令输出比较多时,标准输出流和标准错误流会同时存在一定大小的缓存区,如果Java读取不及时,就可能无法获取到完整的输出结果。解决该问题可以采用多线程读取和行缓冲。即为程序开启一个线程去读取进程输出,每读取一行即将其写入缓冲中。这样就能解决输出结果获取不到的问题。
- 配置ffmpeg环境变量,命令找到ffmpeg程序
1、IOUtils
使用apache的commons-io库
2、XLog
使用Logger:Java原生日志工具
String osname = System.getProperty("os.name").toLowerCase();
XLog.d("osname = " + osname);
String cmd = osname.contains("windows") ? "where.exe ffmpeg" : "which ffmpeg";
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
String ffmpeg = IOUtils.toString(p.getInputStream(), Charset.defaultCharset()).trim();
XLog.d(ffmpeg);
- 调用
ffmpeg -i input.avi -hide_banner
:这里配置了环境变量,如ffmpeg\bin
Process process = Runtime.getRuntime().exec("ffmpeg -i C:\\Users\\Administrator\\Desktop\\input.avi -hide_banner");
process.waitFor();
String ffmpegGetInputStream = IOUtils.toString(process.getInputStream(), Charset.defaultCharset()).trim();
String ffmpegGetErrorStream = IOUtils.toString(process.getErrorStream(), Charset.defaultCharset()).trim();
XLog.d("ffmpegGetInputStream: "+ffmpegGetInputStream);
XLog.d("ffmpegGetErrorStream: "+ffmpegGetErrorStream);
String osname = System.getProperty("os.name").toLowerCase();
XLog.d("osname = " + osname);
String cmd = osname.contains("windows") ? "where.exe ffmpeg" : "which ffmpeg";
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
String ffmpeg = IOUtils.toString(p.getInputStream(), Charset.defaultCharset()).trim();
XLog.d(ffmpeg);
String[] cmdarray = new String[]{ffmpeg, "-i", "C:\\Users\\Administrator\\Desktop\\input.avi", "-hide_banner"};
Process process = Runtime.getRuntime().exec(cmdarray);
process.waitFor();
String ffmpegGetInputStream = IOUtils.toString(process.getInputStream(), Charset.defaultCharset()).trim();
String ffmpegGetErrorStream = IOUtils.toString(process.getErrorStream(), Charset.defaultCharset()).trim();
XLog.d("ffmpegGetInputStream: "+ffmpegGetInputStream);
XLog.d("ffmpegGetErrorStream: "+ffmpegGetErrorStream);
1> 这里比较奇怪,输出结果在
process.getErrorStream()
获取
2> 可以研究一下ProcessBuilder
:Java ProcessBuilder类源码分析(开发“Java命令执行器”前期准备)
3> 建议使用线程池ExecutorService、Executors