一、背景
最近项目中遇到需要将.webm视频进行剪辑并合并的需求,系统为ubuntu。开始尝试使用ffmpeg,在java中调用指令剪辑已存在的问题没有问题,但将剪辑后的文件拼接起来的时候ffmpeg会报文件不存在的错误,暂时无法解,所以后来换成了mencoder。
二、指令调用
首先,定义执行命令方法。
/**
* 系统执行指定控制台命令
*/
public static boolean commandExecution(String command) throws Exception {
logger.info("执行指令 " + command);
boolean flg = true;
try {
Process proc = Runtime.getRuntime().exec(command);
DriverThreadPool.clearStream(proc.getInputStream());
DriverThreadPool.clearStream(proc.getErrorStream());
if (proc.waitFor() != 0) {
if (proc.exitValue() != 0) {
logger.info("指令执行失败" + command);
flg = false;
}
}
} catch (Exception e) {
flg = false;
throw e;
}
return flg;
}
其中 Runtime.getRuntime().exec()方法如果要等待系统执行完指令再继续运行需要调用proc.waitFor()方法。
而waitFor()方法中需要注意一个坑,在exec()执行后,java会为这个系统指令创建三个流:标准输入流、标准输出流和标准错误流,执行指令的过程中系统会不断向输入流和错误流写数据,如果不及时处理这两个流,可能会使得流的缓存区暂满而主线程阻塞。
尝试过在主线程内直接循环读取流,发现执行mencoder命令后依然会造成阻塞,所以后来使用两个线程单独读取输入流和错误流解决了问题,但这里注意在程序结束的时候需要吧线程池关闭掉,否则这两个线程依然会不断读取。
/**
* 流处理
*/
public static void clearStream(InputStream stream) {
// 处理buffer的线程
executor.execute(() -> {
String line = null;
try (BufferedReader in = new BufferedReader(new InputStreamReader(stream));) {
while ((line = in.readLine()) != null) {
logger.info(line);
}
} catch (Exception e) {
logger.error(line);
}
});
}
三、安装mencoder与webm格式的相关编码库
在ubuntu执行指令如下:
sudo apt-get update
sudo apt-get install mencoder
sudo apt-get install libavformat-dev // mencoder中lavf的支持库
sudo apt install libvpx-dev // webm格式编码VP80的支出库
随后java中调用指令如下:
mencoder -ovc copy -oac copy source.webm -o target.webm -of lavf -lavfopts format=webm -lavcopts acodec=vorbis:vcodec=libvpx -ffourcc VP80 -ss 00:10 -endpos 00:20
-ovc copy -oac COPY表示音频源和视屏源使用源视频格式,-o表示复制目标,-of lavf表示使用lavf库,format=webm -lavcopts acodec=vorbis:vcodec=libvpx表示指定web格式,-ffourcc VP80表示使用VP80编码,-ss 00:10 -endpos 00:20表示截取source.webm的10秒到20秒,然后输出到target.webm。
进行了几个视频的剪辑后,需要将多个视频进行合并。
mencoder -ovc copy -oac copy source1.webm source2.webm source3.webm -o target.webm -of lavf -lavfopts format=webm -lavcopts acodec=vorbis:vcodec=libvpx -ffourcc VP80
将多个原视频用空格隔开即可。