使用Java修改字幕文件

今天在下了一部电影,准备看时却发现网上的字幕都和电影不同步,整整差了一分钟。本来暴风倒是可以调节字幕的延迟,但最大只能延迟三十几秒,无奈之下只好手动改字幕……

字幕文件是.srt格式的,但考虑到其它文件格式的读取,先建立一个抽象的父类,以后不同类型文件的操作类都继承这个父类。


package movie;

public abstract class SubtitleDesigner {
protected String src,des;
public SubtitleDesigner(String src,String des){
this.src = src;
this.des = des;
}

public abstract boolean forward(long msecond);
public abstract boolean delay(long msecond);
}


SubtitleDesigner实现了两个接口,forward和delay分别用来提前和延迟字幕。

下面就开始针对srt文件实现字幕的修改


子类除了实现父类的抽象方法外,还有几个私有方法:
[b]
private boolean editSubtitle(int ctl, long msecond)
[/b]
主要的一个函数,实现字幕的延迟和提前操作。


[b]
private String[] getStartAndEndTime(String line)
[/b]
从字幕文件中表示时间开始和结束的行中提取开始和结束时间,srt文件中像这样的行
00:00:00,229 --> 00:00:03,756
处理后会返回一个2维String,0和1的位置分别存储开始和结束的时间(在这里是00:00:00,229和00:00:03,756)


[b]
private int[] getTimes(String inTime)
[/b]
从上面函数得到的字符串中获得时、分、秒、毫秒的整数值,存储在返回的int数组中


[b]
private long timesToMs(int times[])
private int[] msToTimes(long ms)
[/b]
从上面函数得到的数组计算出毫秒数/从毫秒数得到时分秒毫秒的数组


[b]
private int[] reduceMs(int[] times, long ms)
private int[] addMs(int[] times, long ms)
[/b]
提前/延迟一定时间,返回时分秒毫秒的整形数组。


整个类的具体实现是这样的:


package movie;

import java.io.*;
import java.util.regex.*;

public class SrtDesigner extends SubtitleDesigner {

public static final int DELAY = 0;
public static final int FORWARD = 1;

public SrtDesigner(String src, String des) {
super(src, des);
}

private long timesToMs(int times[]) {
long ms;
ms = (times[0] * 3600 + times[1] * 60 + times[2]) * 1000 + times[3];
return ms;
}

private int[] msToTimes(long ms) {
int[] times = new int[4];
long tmp = ms;
times[3] = (int) (tmp % 1000);
tmp = tmp / 1000;
times[2] = (int) (tmp % 60);
tmp = tmp / 60;
times[1] = (int) (tmp % 60);
tmp = tmp / 60;
times[0] = (int) (tmp);
return times;
}

private int[] addMs(int[] times, long ms) {
long tmp;
int ret[];
tmp = timesToMs(times);
tmp += ms;
ret = msToTimes(tmp);
return ret;
}

private int[] reduceMs(int[] times, long ms) {
long tmp;
int ret[];
tmp = timesToMs(times);
tmp -= ms;
if(tmp<0)
return null;
ret = msToTimes(tmp);
return ret;
}

private String formatTime(int[] times){
String ret;
ret = String.format("%02d:%02d:%02d,%03d",times[0],times[1],times[2],times[3]);
return ret;
}

private int[] getTimes(String inTime) {
int[] times = new int[4];
String tmp[] = inTime.split(",");
times[3] = Integer.parseInt(tmp[1]);
String time[] = tmp[0].split(":");
times[0] = Integer.parseInt(time[0]);
times[1] = Integer.parseInt(time[1]);
times[2] = Integer.parseInt(time[2]);
return times;
}

private String[] getStartAndEndTime(String line) {
Pattern p = Pattern.compile("(\\d\\d:\\d\\d:\\d\\d,\\d\\d\\d)");
Matcher m = p.matcher(line);
String times[] = new String[2];
times[0] = m.find() ? m.group() : null;
times[1] = m.find() ? m.group() : null;
//System.out.println("Start:" + times[0] + "End:" + times[1]);
if (times[0] == null || times[1] == null)
return null;
return times;
}

private boolean editSubtitle(int ctl, long msecond) {
File srcFile = new File(src);
File desFile = new File(des);
BufferedReader reader = null;
BufferedWriter writer = null;
boolean visibleFlag = true;//是否显示
String line;
try {
reader = new BufferedReader(new FileReader(srcFile));
writer = new BufferedWriter(new FileWriter(desFile));
String regex = "\\d\\d:\\d\\d:\\d\\d,\\d\\d\\d --> \\d\\d:\\d\\d:\\d\\d,\\d\\d\\d";
while ((line = reader.readLine()) != null) {
if (Pattern.matches(regex, line)) {
visibleFlag = true;
String startAndEndTimes[];
int startTimes[], endTimes[];
if ((startAndEndTimes = getStartAndEndTime(line)) == null)
return false;
startTimes = getTimes(startAndEndTimes[0]);
endTimes = getTimes(startAndEndTimes[1]);
if(ctl == FORWARD){
startTimes = reduceMs(startTimes, msecond);
endTimes = reduceMs(endTimes, msecond);
if(startTimes==null||endTimes==null){
visibleFlag = false;
continue;
}
}else{
startTimes = addMs(startTimes, msecond);
endTimes = addMs(endTimes, msecond);
}
line = formatTime(startTimes) + " --> " + formatTime(endTimes);
// System.out.println(formatTime(startTimes));
// System.out.println(formatTime(endTimes));
}
if(visibleFlag){
writer.write(line + "\n");
//System.out.println(line);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
reader.close();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return true;
}

@Override
public boolean delay(long msecond) {
editSubtitle(DELAY, msecond);
return false;
}

@Override
public boolean forward(long msecond) {
editSubtitle(FORWARD, msecond);
return false;
}

}



好了,在main函数中测试一下编好的类……



public static void main(String args[]) {
System.out.println("Dealing with file");
SubtitleDesigner designer = new SrtDesigner("./src.srt", "./des.srt");
designer.delay(59000);
System.out.println("Done!!");
}


源文件中有一段是这样的:
[quote]
1
00:00:00,229 --> 00:00:03,756
贝蒂,能到外面聊几句吗?

2
00:00:18,447 --> 00:00:21,780
- 什么事?可可
- 你姨妈打电话给我
[/quote]

生成的新文件里变为:
[quote]
1
00:00:59,229 --> 00:01:02,756
贝蒂,能到外面聊几句吗?

2
00:01:17,447 --> 00:01:20,780
- 什么事?可可
- 你姨妈打电话给我
[/quote]

正好延迟了59秒。
OK!终于可以看电影了(为了看这玩意花了我快一小时,容易么……)

以后有时间的话为这个程序再加一个图形界面吧,先把现有代码传上来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值