使用Java+FFmpeg實現(xiàn)視頻分片合并(生成list.txt自動合并)
在很多視頻處理場景中,我們會將一個錄制任務(wù)拆成多個小片段(如 seg1.mp4、 seg2.mp4、 seg3.mp4 等)。多個分片合并成一個完整視頻是一個常見需求。
Java 調(diào)用 FFmpeg 生成用于合并的視頻列表文件 list.txt,并執(zhí)行合并命令生成最終視頻。
一、FFmpeg 的 concat 合并機(jī)制
FFmpeg 支持一種簡潔的合并方式 — concat demuxer,它要求:
? 所有分片編碼格式一致
? 生成的合并列表文件每行格式:
file 'path/to/seg1.mp4' file 'path/to/seg2.mp4' file 'path/to/seg3.mp4'
然后調(diào)用:
ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4
即可將多個文件無損合并成一個文件。([簡書][1])
實現(xiàn)思路
實現(xiàn)分為三步:
- 生成合并列表文件(list.txt)
- 調(diào)用 FFmpeg 進(jìn)行合并
- 輸出合并結(jié)果
二、核心 Java 代碼示例
下面是一個完整的 Java 類示例,通過 ProcessBuilder 調(diào)用 FFmpeg 完成合并。
package com.donglin.skyzlm.event;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
public class MergeVideos {
// ffmpeg 可執(zhí)行命令(系統(tǒng) PATH 中必須能執(zhí)行 ffmpeg)
private static final String FFMPEG = "ffmpeg";
public static void main(String[] args) {
// 1)分片視頻列表
List<String> clips = List.of(
"seg1.mp4",
"seg2.mp4",
"seg3.mp4"
);
// 2)生成合并列表文件
String listFilePath = "videos/list.txt";
try {
createConcatListFile(clips, listFilePath);
} catch (IOException e) {
System.err.println("生成 list.txt 失敗: " + e.getMessage());
return;
}
// 3)合并輸出
String output = "videos/merged.mp4";
boolean success = mergeWithFFmpeg(listFilePath, output);
System.out.println("合并 " + (success ? "成功" : "失敗") + ", 輸出:" + output);
}
/**
* 生成 concat 的 list.txt
*/
private static void createConcatListFile(List<String> clips, String listFilePath) throws IOException {
File file = new File(listFilePath);
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
for (String clip : clips) {
// FFmpeg concat list.txt 格式:file '路徑'
writer.write("file '" + clip.replace("\\", "/") + "'");
writer.newLine();
}
}
System.out.println("生成 list.txt: " + file.getAbsolutePath());
}
/**
* 調(diào)用 FFmpeg concat 合并
*/
private static boolean mergeWithFFmpeg(String listFilePath, String outputPath) {
try {
ProcessBuilder pb = new ProcessBuilder(
FFMPEG,
"-f", "concat",
"-safe", "0",
"-i", listFilePath,
"-fflags", "+genpts",
"-c:v", "libx264", // 可根據(jù)需要調(diào)整 codec
"-preset", "veryfast",
"-crf", "20",
"-c:a", "aac",
"-b:a", "128k",
"-movflags", "+faststart",
outputPath
);
// 合并 stdout 和 stderr 輸出
pb.redirectErrorStream(true);
Process process = pb.start();
// 打印 FFmpeg 輸出(可選)
new Thread(() -> {
try (var is = process.getInputStream()) {
is.transferTo(System.out);
} catch (IOException ignored) {}
}).start();
int exit = process.waitFor();
return exit == 0;
} catch (IOException | InterruptedException e) {
e.printStackTrace();
return false;
}
}
}

三、代碼詳解
1. 生成合并列表文件
writer.write("file '" + clip.replace("\\", "/") + "'");
- FFmpeg 要求每行以
file '...'開頭 - 用單引號包裹路徑
- 替換反斜杠為正斜杠,適配不同 OS 路徑規(guī)則
這樣生成的文件示例可能是:
file 'seg1.mp4' file 'seg2.mp4' file 'seg3.mp4'
2. 調(diào)用 FFmpeg 合并
ffmpeg -f concat -safe 0 -i list.txt -c:v libx264 -c:a aac ...
這里:
? -f concat:指定使用 concat demuxer
? -safe 0:允許使用任意路徑
? -c copy:如果不轉(zhuǎn)碼可以直接復(fù)制,他們保持原始編碼(若需要可自己調(diào)整)
? -movflags +faststart:讓視頻可以在網(wǎng)絡(luò)上邊下邊播
注意:如果分片編碼、分辨率、幀率一致,使用 -c copy 是更快/無損的方法。
四、大小寫混合或排序問題
如果你的分片文件名不是按順序排列,F(xiàn)Fmpeg 會按照文本列表順序合并。因此 list.txt 必須:
?? 按你想合并的順序?qū)懭朊總€路徑
?? 不要漏掉任何分片項
五、何時該用這個合并方案?
適合場景:
? 多個 MP4 分片按時間順序拼接
? 文件編碼一致(H.264 + AAC)
? 希望無損合并
? 使用 Java 批量處理視頻任務(wù)
六、總結(jié)
?? FFmpeg 程序必須已安裝且可在系統(tǒng) PATH 中找到
?? 分片視頻參數(shù)必須一致(否則會導(dǎo)致合并失敗或輸出異常)
?? 如果分片太多,建議動態(tài)生成 list.txt 并逐步合并
以上就是使用Java+FFmpeg實現(xiàn)視頻分片合并(生成list.txt自動合并)的詳細(xì)內(nèi)容,更多關(guān)于Java FFmpeg視頻分片合并的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Springboot集成spring data elasticsearch過程詳解
這篇文章主要介紹了springboot集成spring data elasticsearch過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-04-04
JavaWeb如何實現(xiàn)統(tǒng)一查詢接口(jfinal)
這篇文章主要介紹了JavaWeb如何實現(xiàn)統(tǒng)一查詢接口(jfinal),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06
記一次用IDEA打開java項目后不能運(yùn)行的解決方法
這篇文章主要介紹了記一次用IDEA打開java項目后不能運(yùn)行的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

