ffmpeg 多个视频合成一个视频
/**
* 合成视频
*
* @param out_path 输出视频地址
* @param list 源视频地址列表
* @return
*/
public static String mergeVideo(String out_path, List<String> list) {
try {
String ffmpegPath = getPath();
List<String> txt = new ArrayList<>();
//将mp4转为ts
for (int i = 0; i < list.size(); i++) {
StringBuilder builder = new StringBuilder();
builder.append(ffmpegPath);
builder.append(" -i ");
builder.append(list.get(i) + " ");
builder.append("-vcodec copy ");
builder.append("-acodec copy ");
builder.append("-vbsf h264_mp4toannexb ");
int index = list.get(i).lastIndexOf(".");
String ts_path = list.get(i).substring(0, index) + ".ts";
txt.add(ts_path);
if (FileHandleUtil.isExists(ts_path)) {
FileHandleUtil.delete(ts_path);
}
builder.append(ts_path);
start(builder.toString());
}
//生成txt文件
int index = list.get(0).lastIndexOf(".");
String txtPath = list.get(0).substring(0, index) + ".txt";
FileOutputStream fos = new FileOutputStream(new File(txtPath));
for (String path : txt) {
fos.write(("file '" + path + "'\r\n").getBytes());
}
fos.close();
//合成视频
StringBuilder builder = new StringBuilder();
builder.append(ffmpegPath);
builder.append(" -f concat -safe 0 ");
builder.append("-i ");
builder.append(txtPath + " ");
builder.append("-acodec copy ");
builder.append("-vcodec copy ");
builder.append("-absf aac_adtstoasc ");
builder.append(out_path);
VideoUtil.start(builder.toString());
//删除txt文件
FileHandleUtil.delete(txtPath);
//删除ts文件
for (String path : txt) {
FileHandleUtil.delete(path);
}
return out_path;
} catch (Exception e) {
logger.error("合成视频异常 {}", e);
}
return "";
}
/**
* 执行ffmpeg命令
*
* @param command 命令
*/
public static void start(String command) {
try {
final Process process = Runtime.getRuntime().exec(command);
System.out.println(StrUtil.format("start run cmd {}", command));
//⚠️此处代码是因为如果合并大视频文件会产生大量的日志缓存导致线程阻塞,最终合并失败,所以加两个线程处理日志的缓存,之后再调用waitFor方法,等待执行结果。
new Thread() {
@Override
public void run() {
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
try {
while ((line = in.readLine()) != null) {
System.out.println(System.currentTimeMillis() + ":" + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread() {
@Override
public void run() {
BufferedReader err = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
try {
while ((line = err.readLine()) != null) {
System.out.println(System.currentTimeMillis() + ":" + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
err.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
// 等待命令子线程执行完成
process.waitFor();
process.destroy();
} catch (IOException e) {
logger.error("执行命令异常 {}", e);
} catch (InterruptedException e) {
logger.error("执行命令异常 {}", e);
}
}
经实践得经验!!!