ffmpeg下载地址:http://www.ffmpeg.org/download.html
这里下载Windows版本的:ffmpeg-4.2.2-win64-static.zip
解压后bin目录下的内容(假设在D盘的bin路径下):
public class App {
// ffmpeg.exe全路径
private static final String FFMPEG_PATH = "D:/bin/ffmpeg.exe";
public static void main(String[] args) throws Exception {
File rootDir = new File("C:"+File.separator+"哔哩哔哩"+File.separator+"xx视频");
String outputDir = rootDir.getAbsolutePath() + File.separator + "out";
// 开始处理文件
renameAndCopyFile(rootDir, outputDir);
}
/**
* 具体合成视频函数
*
* @param videoInputPath 原视频的全路径
*
* @param audioInputPath 音频的全路径
*
* @param videoOutPath 视频与音频结合之后的视频的路径
*/
public static void convetor(String videoInputPath, String audioInputPath, String videoOutPath) throws Exception {
Process process = null;
InputStream errorStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader br = null;
try {
// ffmpeg命令
String command = FFMPEG_PATH + " -i " + videoInputPath + " -i " + audioInputPath
+ " -c:v copy -c:a aac -strict experimental " + " -map 0:v:0 -map 1:a:0 " + " -y " + videoOutPath;
process = Runtime.getRuntime().exec(command);
errorStream = process.getErrorStream();
inputStreamReader = new InputStreamReader(errorStream);
br = new BufferedReader(inputStreamReader);
// 用来收集错误信息的
String str = "";
while ((str = br.readLine()) != null) {
System.out.println(str);
}
process.waitFor();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
br.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (errorStream != null) {
errorStream.close();
}
}
}
// 遍历每个路径,找到entry.json文件所在路径
public static void renameAndCopyFile(File rootDir, String outputDir) throws Exception {
File dir = rootDir;
if (dir == null) {
return;
}
File[] files = dir.listFiles();
if (files == null || files.length == 0) {
return;
}
String fileName = null;
for (File f : files) {
if (f.isFile()) {
fileName = f.getName();
if ("entry.json".equalsIgnoreCase(fileName)) {
String jsonStr = FileUtils.readFileToString(f, "UTF-8");
if (jsonStr == null || jsonStr.isEmpty()) {
return;
}
Entry entry = getEntry(jsonStr);
// 文件名
String realFileName = entry.page_data.part;
realFileName = realFileName.replaceAll("\\s+", "-");
// 开始迭代查找视频和音频文件,并将数据拷贝到其他地方
List<FileInfo> fileList = findVideoAudioFile(dir);
// 对文件进行合并
String videoInputPath = null;
String audioInputPath = null;
String videoOutPath = outputDir + File.separator + realFileName + ".mp4";
System.out.println(videoOutPath);
for (FileInfo info : fileList) {
if ("audio.m4s".equalsIgnoreCase(info.fileName)) {
audioInputPath = info.file.getAbsolutePath();
}
if ("video.m4s".equalsIgnoreCase(info.fileName)) {
videoInputPath = info.file.getAbsolutePath();
}
}
convetor(videoInputPath, audioInputPath, videoOutPath);
}
} else if (f.isDirectory()) {
renameAndCopyFile(f, outputDir);
}
}
}
private static List<FileInfo> findVideoAudioFile(File dir) {
if (dir == null) {
return new ArrayList<FileInfo>();
}
File[] files = dir.listFiles();
if (files == null || files.length == 0) {
return new ArrayList<FileInfo>();
}
List<FileInfo> result = new ArrayList<FileInfo>();
String fileName = null;
for (File f : files) {
if (f.isFile()) {
fileName = f.getName();
if (fileName.endsWith("m4s")) {
result.add(new FileInfo(f));
}
} else if (f.isDirectory()) {
result.addAll(findVideoAudioFile(f));
}
}
return result;
}
public static class FileInfo {
public File file;
public String fileName;
public FileInfo(File file) {
this.file = file;
if (file != null) {
fileName = file.getName();
}
}
}
// 解析bilibili下的entry.json文件
public static Entry getEntry(String jsonText) {
return JSON.parseObject(jsonText, Entry.class);
}
public static class PageData {
// 文件名
public String part;
}
public static class Entry {
// 是否已经下载完成
public boolean is_completed;
// 课程名/专辑名
public String title;
// 文件信息
public PageData page_data;
}
}
ffmpeg相关指令:http://ffmpeg.org/ffmpeg.html
来源:oschina
链接:https://my.oschina.net/u/4362740/blog/3217166