目录
一、前言
二、JAVA代码调用ffmpeg
方式一:采用第三方封装了ffmpeg功能的jar包实现
方式二:采用ProcessBuilder类创建进程的方式调用ffmpeg实现
一、前言
FFmpeg是一款多媒体视频处理工具,有非常强大的功能包括:视频采集、视频推流、视频格式转换、视频抓图、给视频加水印等功能。FFmpeg本身是一个命令行程序,需要通过执行 ffmpeg命令来实现功能,如下:
ffmpeg -i 123.mp4 -c:a copy -c:v libx264 -f flv rtmp://127.0.0.1:1935/live/test
ffmpeg -i 123.mp4 -c copy -f hls -hls_list_size 5 -hls_flags 50 -hls_time 10 D:\hls\test.m3u8
在实际开发工作中,会需要通过JAVA代码去调用ffmpeg程序去完成功能,而不是手动去执行ffmpeg命令。本篇文章将介绍如何通过JAVA代码去调用执行ffmpeg程序。
二、JAVA代码调用ffmpeg
本篇文章将介绍两种方式实现 JAVA代码去调用ffmpeg程序。
方式一:采用第三方封装调用ffmpeg接口的jar包实现
1. 在Maven项目pom.xml文件中引入jar包依赖
<dependency>
<groupId>net.bramp.ffmpeg</groupId>
<artifactId>ffmpeg</artifactId>
<version>0.6.2</version>
</dependency>
2. 编写java代码
//创建FFmpeg对象
FFmpeg ffmpeg = new FFmpeg("D:\\ffmpeg\\bin\\ffmpeg.exe"); //参数是:ffmpeg命令工具的安装路径
//创建FFmpegBuilder对象,设置推流/转码参数
FFmpegBuilder builder = new FFmpegBuilder()
.setInput("D:\\111.mp4") //输入视频源地址
.overrideOutputFiles(true) //设置是否覆盖已存在的输出文件
.addOutput("D:\\hls\\test.m3u8") //输出流地址
.setFormat("hls") //输出流格式 -f hls
.setAudioCodec("copy") //设置音频转码 copy表示不转码
.setVideoCodec("libx264") //设置视频转码 copy表示不转码
.setVideoQuality(1) //设置视频质量,一般为1到5(1代表质量最高)
.setVideoFrameRate(25) //设置视频帧率
.addExtraArgs("-t", "30") //设置推流持续时间
.addExtraArgs("-hls_list_size", "5") //设置输出文件个数(hls输出流特有的参数)
.addExtraArgs("-hls_flags", "50") //设置输出文件替换(hls输出流特有的参数)
.addExtraArgs("-hls_time", "6") //设置输出文件每个时长多少秒(hls输出流特有的参数)
.done(); //最后调用done()完成参数配置
//创建FFmpegExecutor对象,用于执行ffpmeg转流任务
FFmpegExecutor executor=new FFmpegExecutor(ffmpeg);
//执行ffpmeg转流任务,并添加了监听器ProgressListener,可以监听ffpmeg运行状态情况
executor.createJob(builder, new ProgressListener() {
@Override
public void progress(Progress progress) {
System.out.println("-----------");
System.out.println(progress);
}
}).run();
3. 第三方jar包实现优缺点:
优点:封装好了ffmpeg调用功能,代码实现简单易用
缺点:没有提供停止ffmpeg程序的方法,无法实现手动终止任务。就算手动杀死JAVA程序也无法终止ffmpeg程序的执行,只有等ffmpeg转流任务完成了程序自行停止。
方式二:采用ProcessBuilder类创建进程的方式调用ffmpeg实现
ProcessBuilder 类是JDK中java.lang包下提供的用于创建操作系统进程的类, 可以通过JDK API 文档查看其用法。
1. 编写java代码
//创建一个命令List集合,用于存放ffmpeg执行的命令参数
List<String> command = new ArrayList<>();
command.add("D:\\ffmpeg\\bin\\ffmpeg.exe");
command.add("-i");
command.add("D:\\123.mp4"); //输入视频源或者流地址
command.add("-c");
command.add("copy");
command.add("-f");
command.add("hls");
command.add("-hls_time");
command.add("10");
command.add("-hls_list_size");
command.add("5");
command.add("-hls_flags");
command.add("50");
command.add("D:\\hls\\test.m3u8"); //输出流地址
//创建ProcessBuilder对象,传入集合
ProcessBuilder builder = new ProcessBuilder(command);
//start()方法创建一个系统进程,执行ffmpeg命令工具
Process process = builder.start();
//注意:使用ProcessBuilder执行任务,必须要手动接收正常输出信息和错误输出信息,不然ProcessBuilder任务会阻塞卡住
//多线程读取正常输出信息 process.getInputStream()
new Thread(() -> {
try {
InputStream is = process.getInputStream();
//将正常输出信息写入到normal.txt文件中
RandomAccessFile raf = new RandomAccessFile("D:\\normal.txt", "rw");
byte[] data = new byte[128];
int len = -1;
while((len = is.read(data)) != -1) {
raf.write(data, 0, len);
}
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}, "Thread-Normal").start();
//多线程读取错误输出信息 process.getErrorStream()
new Thread(() -> {
try {
InputStream is = process.getErrorStream();
//将错误输出信息写入到error.txt文件中
RandomAccessFile raf = new RandomAccessFile("D:\\error.txt", "rw");
byte[] data = new byte[128];
int len = -1;
while((len = is.read(data)) != -1) {
raf.write(data, 0, len);
}
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}, "Thread-Error").start();
//destroy()方法可以停止进程,从而终止ffmpeg程序
//process.destroy();
2. ProcessBuilder实现优缺点:
优点:可以手动调用destory()方法随时停止ffmpeg程序的执行
缺点:需要手动写代码去主动接收任务进程产生的正常输出信息和错误信息,不然进程会被卡住。