import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.List;
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import saccubus.conv.ConvertToVideoHook;
+import saccubus.conv.NicoXMLReader.ProcessType;
+import saccubus.util.FfmpegUtil;
import saccubus.worker.Worker;
import saccubus.worker.WorkerListener;
import saccubus.worker.profile.ConvertProfile;
*/
public class Convert extends Worker<ConvertResult, ConvertProgress> {
- private static final Logger logger = Logger.getLogger(Convert.class.getName());
+ private static final Logger logger = LoggerFactory.getLogger(Convert.class);
private final ConvertProfile profile;
private final File videoFile;
private final File commentFile;
this.profile = profile;
this.videoFile = video;
this.commentFile = comment;
+ logger.info("convert video:{}, comment:{}", videoFile, commentFile);
}
@Override
final GeneralProfile gene = profile.getGeneralProfile();
final OutputProfile outprof = profile.getOutputProfile();
- final OutputNamePattern pattern = new OutputNamePattern(outprof.getFileName());
+ final OutputNamePattern outputPattern = new OutputNamePattern(outprof.getFileName());
final String id = outprof.getVideoId();
- pattern.setId(isNotEmpty(id) ? id : "");
+ outputPattern.setId(isNotEmpty(id) ? id : "");
final String title = outprof.getTitile();
- pattern.setTitle(isNotEmpty(title) ? title : "");
+ outputPattern.setTitle(isNotEmpty(title) ? title : "");
final String fileName = getBaseName(videoFile.getPath());
- pattern.setFileName(fileName);
- pattern.setReplaceFrom(gene.getReplaceFrom());
- pattern.setReplaceFrom(gene.getReplaceTo());
- final File outputFile = new File(outprof.getDir(), pattern.createFileName());
+ outputPattern.setFileName(fileName);
+ outputPattern.setReplaceFrom(gene.getReplaceFrom());
+ outputPattern.setReplaceFrom(gene.getReplaceTo());
+ final File outputFile = new File(outprof.getDir(),
+ outputPattern.createFileName() + profile.getFfmpegOption().getExtOption());
File transformedComment = null;
+ File transformedOwner = null;
try {
if (profile.isCommentOverlay()) {
transformedComment = File.createTempFile("vhk", ".tmp", profile.getTempDir());
+ transformedOwner = File.createTempFile("vown", ".tmp", profile.getTempDir());
final HideCondition hide = profile.getNgSetting();
- publish(new ConvertProgress(PROCESS, 0.0, "コメントの中間ファイルへの変換中"));
- ConvertToVideoHook.convert(commentFile, transformedComment, hide.getId(), hide.getWord());
+
+ publish(new ConvertProgress(PROCESS, -1.0, "コメントの中間ファイルへの変換中"));
+ ConvertToVideoHook.convert(EnumSet.of(ProcessType.NORMAL), commentFile, transformedComment, hide.getId(),
+ hide.getWord());
+
+ publish(new ConvertProgress(PROCESS, -1.0, "投稿者コメントの中間ファイルへの変換中"));
+ ConvertToVideoHook.convert(EnumSet.of(ProcessType.OWNER), commentFile, transformedOwner, hide.getId(),
+ hide.getWord());
}
checkStop();
- publish(new ConvertProgress(PROCESS, 0.0, "動画の変換を開始"));
+ publish(new ConvertProgress(PROCESS, -1.0, "動画の変換を開始"));
- final int code = convert(transformedComment, outputFile);
+ final int code = convert(outputFile, transformedComment, transformedOwner);
if (code != 0) {
throw new IOException("ffmpeg実行失敗: " + outputFile.getPath());
}
if (transformedComment != null && transformedComment.exists()) {
transformedComment.delete();
}
+ if (transformedOwner != null && transformedOwner.exists()) {
+ transformedOwner.delete();
+ }
}
}
- private int convert(File transformedComment, File outputFile) throws InterruptedException, IOException {
+ private int convert(File outputFile, File commentNormal, File commentOwner) throws InterruptedException, IOException {
File fwsFile = null;
try {
final File tmpCws = File.createTempFile("cws", ".swf", profile.getTempDir());
tmpCws.delete();
final File target = (fwsFile != null) ? fwsFile : videoFile;
- final List<String> arguments = createArguments(target, transformedComment, outputFile);
- return executeFfmpeg(arguments);
+ final List<String> arguments = createArguments(target, outputFile, commentNormal, commentOwner);
+ final FfmpegUtil util = new FfmpegUtil(profile.getFfmpeg(), target);
+ int duration;
+ try {
+ duration = util.getDuration();
+ } catch (IOException ex) {
+ logger.info("動画再生時間を取得できませんでした: {}", target);
+ duration = Integer.MAX_VALUE;
+ }
+ return executeFfmpeg(arguments, duration);
} finally {
if (fwsFile != null && fwsFile.exists()) {
fwsFile.delete();
}
}
- private List<String> createArguments(final File targetVideoFile, File transformedComment, File output)
+ private List<String> createArguments(final File targetVideoFile, File output, File comment, File commentOwner)
throws IOException, UnsupportedEncodingException {
final ConvertProfile prof = profile;
final FfmpegProfile ffop = prof.getFfmpegOption();
- final List<String> cmdList = new ArrayList<String>();
+ final List<String> cmdList = new ArrayList<>();
cmdList.add(prof.getFfmpeg().getPath());
cmdList.add("-y");
final String[] mainOptions = ffop.getMainOption().split(" +");
}
final List<String> avfilterArgs = createAvfilterOptions(ffop.getAvfilterOption());
if (!prof.isVhookDisabled()) {
- // TODO 引数冗長
- final String vhookArg = getVhookArg(prof, prof.isCommentOverlay(), transformedComment.getPath(), isHD);
+ final String vhookArg = getVhookArg(prof, comment.getPath(), commentOwner.getPath(), isHD);
if (isNotBlank(vhookArg)) {
avfilterArgs.add(vhookArg);
}
}
if (!avfilterArgs.isEmpty()) {
cmdList.add("-vfilters");
- final String args = "\"" + join(avfilterArgs, ", ") + "\"";
+ final String args = join(avfilterArgs, ", ");
cmdList.add(args);
}
cmdList.add(output.getPath());
- final StringBuilder argMsg = new StringBuilder();
- argMsg.append("arg:");
- for (String s : cmdList) {
- argMsg.append(" ").append(s);
- }
- logger.log(Level.INFO, argMsg.toString());
+
+ logger.info("arg: {}", cmdList);
return cmdList;
}
+ private static final Pattern PATTERN_TIME = Pattern.compile("time=(\\d+):(\\d+):(\\d+)");
- private int executeFfmpeg(final List<String> cmdList) throws InterruptedException, IOException {
+ private int executeFfmpeg(final List<String> cmdList, int duration) throws InterruptedException, IOException {
Process process = null;
try {
- logger.log(Level.INFO, "Processing FFmpeg...");
+ logger.info("Processing FFmpeg...");
process = Runtime.getRuntime().exec(cmdList.toArray(new String[0]));
BufferedReader ebr = new BufferedReader(new InputStreamReader(
process.getErrorStream()));
String msg;
while ((msg = ebr.readLine()) != null) {
if (msg.startsWith("frame=")) {
- // TODO パーセンテージ計算、出力
- publish(new ConvertProgress(PROCESS, 0.0, msg));
+ final Matcher m = PATTERN_TIME.matcher(msg);
+ double per = -1.0;
+ if (m.find()) {
+ final double hour = Integer.parseInt(m.group(1));
+ final double min = Integer.parseInt(m.group(2));
+ final double sec = Integer.parseInt(m.group(3));
+ final double time = ((hour * 60) + min) * 60 + sec;
+ per = 100.0 * time / duration;
+ if (logger.isTraceEnabled()) {
+ logger.trace("time:{}, duration:{}", time, duration);
+ }
+ }
+ publish(new ConvertProgress(PROCESS, per, msg));
} else if (!msg.endsWith("No accelerated colorspace conversion found")) {
- logger.log(Level.INFO, msg);
+ logger.warn(msg);
}
checkStop();
process.waitFor();
return process.exitValue();
} finally {
- // TODO 正常終了した場合もdestroyしていいのか?
if (process != null) {
process.destroy();
}
}
private static List<String> createAvfilterOptions(String avfilterOption) {
- final List<String> avfilterArgs = new ArrayList<String>();
+ final List<String> avfilterArgs = new ArrayList<>();
if (isNotBlank(avfilterOption)) {
avfilterArgs.add(avfilterOption);
}
return avfilterArgs;
}
- private static String getVhookArg(ConvertProfile prof, boolean addComment, String commPath, boolean isHD) throws
+ private static String getVhookArg(ConvertProfile prof, String commPath, String commOwnerPath, boolean isHD) throws
UnsupportedEncodingException {
StringBuilder sb = new StringBuilder();
sb.append("vhext=");
sb.append(prof.getVhook().getPath().replace("\\", "/"));
- if (addComment) {
+ if (prof.isCommentOverlay()) {
sb.append("|");
sb.append("--data-user:");
sb.append(URLEncoder.encode(commPath.replace("\\", "/"), "Shift_JIS"));
+ sb.append("|");
+ sb.append("--data-owner:");
+ sb.append(URLEncoder.encode(commOwnerPath.replace("\\", "/"), "Shift_JIS"));
}
sb.append("|");
sb.append("--font:");
sb.append(prof.getFontIndex());
sb.append("|");
sb.append("--show-user:");
- sb.append(prof.getMaxNumOfComment());
+ final int dispNum = (prof.getMaxNumOfComment() < 0) ? 30 : prof.getMaxNumOfComment();
+ sb.append(dispNum);
sb.append("|");
sb.append("--shadow:");
sb.append(prof.getShadowIndex());