Created
May 26, 2023 01:24
-
-
Save tianjiaoshanzai/3cc25da5d11c64973e3c2c324341f490 to your computer and use it in GitHub Desktop.
最终执行的主类是ListFilesUtil
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.*; | |
import java.net.URISyntaxException; | |
import java.nio.charset.StandardCharsets; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.Objects; | |
import java.util.logging.Logger; | |
// 在目录 JAVA_HOME\jre\lib\rt.jar 中,编译不一定能加载,需要单设path | |
import com.sun.xml.internal.ws.spi.db.BindingContextFactory; | |
/* | |
目的是批量将字幕插入视频 | |
*/ | |
public class InsertSubtitle { | |
File f = null;//获取当前执行文件的所在路径 | |
public InsertSubtitle(){ | |
try{ | |
//注意IDEA默认编译的.class文件在out目录中 | |
f = new File(Objects.requireNonNull(this.getClass().getResource("")).toURI().getPath()); | |
}catch (URISyntaxException e){ | |
e.printStackTrace(); | |
} | |
} | |
public static void main(String[] args) { | |
//TODO 获取所有视频和字幕文件,合成输出。“中间后缀”可以指定,默认全部输出,不同中间后缀对应的目录不同 | |
InsertSubtitle insertSubtitle=new InsertSubtitle(); | |
String fileName="[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv"; | |
String subName="[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].chs&jpn.ass"; | |
File file=new File(insertSubtitle.f,fileName); | |
File sub=new File(insertSubtitle.f,subName); | |
try{ | |
insertSubtitle.insertSoftSub(null, file, sub, null); | |
}catch (IOException | InterruptedException e){ | |
e.printStackTrace(); | |
} | |
String fileName2="[Kamigami&VCB-Studio] Boku dake ga Inai Machi [02][Ma10p_1080p][x265_flac_ac3].mkv"; | |
String subName2="[Kamigami&VCB-Studio] Boku dake ga Inai Machi [02][Ma10p_1080p][x265_flac_ac3].chs&jpn.ass"; | |
File file2=new File(insertSubtitle.f,fileName2); | |
File sub2=new File(insertSubtitle.f,subName2); | |
try{ | |
insertSubtitle.insertSoftSub(null,file2,sub2,null); | |
}catch (IOException | InterruptedException e){ | |
e.printStackTrace(); | |
} | |
System.out.println("完成"); | |
} | |
String getParameterForm(String row){ | |
String os = System.getProperty("os.name"); | |
//Windows操作系统 | |
if (os != null && os.toLowerCase().startsWith("windows")) { | |
// System.out.println(String.format("当前系统版本是:%s", os)); | |
return "\""+row+"\""; | |
} else if (os != null && os.toLowerCase().startsWith("linux")) {//Linux操作系统 | |
// System.out.println(String.format("当前系统版本是:%s", os)); | |
return "‘"+row+"’"; | |
} else { //其它操作系统 | |
// System.out.println(String.format("当前系统版本是:%s", os)); | |
return "‘"+row+"’"; | |
} | |
} | |
/* | |
为视频添加软字幕,仅支持mkv封装 | |
添加字幕非常快,几乎不消耗性能 | |
示例命令:ffmpeg -i test_1280x720_3.mp4 -i test_1280x720_3.srt -c copy output.mkv | |
*/ | |
public void insertSoftSub(String ffmpegPath,File file,File sub,File out) throws IOException, InterruptedException { | |
//Todo 将分隔符改为根据系统切换 | |
//TODO error log 想想办法 | |
String fileName,subName,outPutPath; | |
if(file!=null){ | |
fileName=file.getName(); | |
}else { | |
System.out.println("无转换对象"); | |
return; | |
} | |
if(sub!=null){ | |
subName=sub.getName(); | |
}else { | |
System.out.println("无转换对象"); | |
return; | |
} | |
if(out!=null){ | |
outPutPath=out.getAbsolutePath(); | |
}else { | |
outPutPath="output"; | |
// File output=new File() | |
out=new File(f,outPutPath); | |
} | |
if(ffmpegPath==null){ | |
ffmpegPath="ffmpeg"; | |
} | |
List<String> command = new ArrayList<>(); | |
command.add(ffmpegPath); | |
command.add("-i"); | |
// command.add(getParameterForm(file.getAbsolutePath())); | |
command.add(file.getAbsolutePath()); | |
command.add("-i"); | |
// command.add(getParameterForm(sub.getAbsolutePath())); | |
command.add(sub.getAbsolutePath()); | |
command.add("-c"); | |
command.add("copy"); | |
// command.add(getParameterForm((new File(out,fileName)).getAbsolutePath())); | |
command.add((new File(out,fileName)).getAbsolutePath()); | |
// 执行操作 | |
// System.out.println("command is:"+command); | |
BindingContextFactory.LOGGER.info("command is"+command.toString()); | |
ProcessBuilder builder = new ProcessBuilder(command); | |
builder.directory(f); | |
Process process = builder.start(); | |
mointor(process); | |
Thread.sleep(15000); | |
} | |
/** | |
* 检测进程 | |
* | |
* @param process | |
*/ | |
public static void mointor(Process process) { | |
// 读取进程标准输出 | |
new Thread(() -> { | |
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { | |
String line = null; | |
while ((line = bufferedReader.readLine()) != null) { | |
BindingContextFactory.LOGGER.info(line); | |
} | |
} catch (IOException e) { | |
} | |
}).start(); | |
// 读取进程异常输出 | |
new Thread(() -> { | |
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { | |
String line = null; | |
while ((line = bufferedReader.readLine()) != null) { | |
BindingContextFactory.LOGGER.info(line); | |
} | |
} catch (IOException e) { | |
} | |
}).start(); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.File; | |
import java.io.IOException; | |
import java.net.URISyntaxException; | |
import java.util.*; | |
//外部依赖 从 https://commons.apache.org/proper/commons-io/download_io.cgi 下载的binary code,最终要生成可执行文件需要注意 | |
import org.apache.commons.io.FilenameUtils; | |
public class ListFilesUtil { | |
File f = null;//获取当前执行文件的所在路径 | |
static List<String> videoFormat=new ArrayList<>(Arrays.asList(".mp4",".avi",".mov",".mkv")); | |
static List<String> subFormat=new ArrayList<>(Arrays.asList(".ass",".srt","sub")); | |
private List<File> videoList=new ArrayList<>(); | |
//获取字幕名称和“字幕注释” 例子:Home Alone.spanish.srt-->spanish;Home Alone.spa.forced.srt-->spa.forced | |
//List object[] index0是String,注释名 index1是File 字幕文件。 | |
private Map<String,List<Object[]>> subMap=new HashMap<>(); | |
public static void main(String[] args) { | |
ListFilesUtil listFilesUtil=new ListFilesUtil(); | |
File dir =listFilesUtil.f; | |
File outDir=new File(dir,"output"); | |
//遍历目标目录,将所有视频和字幕和字幕归档 | |
listFilesUtil.scanDir(dir); | |
List<File> videoList=listFilesUtil.getVideoList(); | |
Map<String,List<Object[]>> subMap=listFilesUtil.getSubMap(); | |
for(File video:videoList){ | |
if(subMap.containsKey(FilenameUtils.removeExtension(video.getName()))){ | |
List<Object[]> subObjList=subMap.get(FilenameUtils.removeExtension(video.getName())); | |
for(Object[] objArr:subObjList){ | |
//TODO if符合筛选标准(比如简体中文,双字等等),进行压制工作 | |
File outAnnotationDir=new File(outDir,(String) objArr[0]); | |
if(!outAnnotationDir.exists()){ | |
//TODO 判断创建失败与否 | |
outAnnotationDir.mkdirs(); | |
} | |
InsertSubtitle insertSubtitle=new InsertSubtitle(); | |
try { | |
insertSubtitle.insertSoftSub(null,video,(File)objArr[1],outAnnotationDir); | |
} catch (IOException | InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
} | |
} | |
public void scanDir(File dir) { | |
File[] files = dir.listFiles(); | |
if (files != null) { | |
for (File file : files) { | |
if (file.isFile() && isVideoFile(file)) { | |
videoList.add(file); | |
}else if(file.isFile() && isSubFile(file)){ | |
String subAnnotation=getSubAnnotation(file.getName()); | |
String originName=getSubOriginName(file.getName()); | |
List<Object[]> annotationList=subMap.getOrDefault(originName,new ArrayList<>()); | |
Object[] objArr=new Object[2]; | |
objArr[0]=subAnnotation; | |
objArr[1]=file; | |
annotationList.add(objArr); | |
subMap.put(originName,annotationList); | |
}else if (file.isDirectory()) { | |
//listFilesAndDirectories(file); | |
scanDir(file); | |
} | |
} | |
} | |
} | |
public List<File> getVideoList(){ | |
return videoList; | |
} | |
public Map<String,List<Object[]>> getSubMap(){ | |
return subMap; | |
} | |
private static String getSubOriginName(String fileName){ | |
String fileNameWithoutEx= FilenameUtils.removeExtension(fileName); | |
return fileNameWithoutEx.substring(0,fileNameWithoutEx.indexOf(".")); | |
} | |
private static String getSubAnnotation(String fileName){ | |
String fileNameWithoutEx= FilenameUtils.removeExtension(fileName); | |
return fileNameWithoutEx.substring(fileNameWithoutEx.indexOf(".")+1); | |
} | |
private static boolean isVideoFile(File file) { | |
String name = file.getName().toLowerCase(); | |
for(String vf:videoFormat){ | |
if(name.endsWith(vf)) | |
return true; | |
} | |
return false; | |
} | |
private static boolean isSubFile(File file) { | |
String name = file.getName().toLowerCase(); | |
for(String sf:subFormat){ | |
if(name.endsWith(sf)) | |
return true; | |
} | |
return false; | |
} | |
public ListFilesUtil(){ | |
try{ | |
//注意IDEA默认编译的.class文件在out目录中 | |
f = new File(Objects.requireNonNull(this.getClass().getResource("")).toURI().getPath()); | |
}catch (URISyntaxException e){ | |
e.printStackTrace(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment