OSDN Git Service

出力動画に拡張子がつかない問題に対処
[coroid/inqubus.git] / frontend / src / saccubus / worker / impl / convert / Convert.java
index d0a964d..1d472d9 100644 (file)
@@ -12,10 +12,15 @@ import java.io.InputStreamReader;
 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 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;
@@ -69,31 +74,40 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
 
         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());
             }
@@ -103,10 +117,13 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
             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());
@@ -114,8 +131,16 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
             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.log(Level.FINE, "動画再生時間を取得できませんでした: {0}", target);
+                duration = Integer.MAX_VALUE;
+            }
+            return executeFfmpeg(arguments, duration);
         } finally {
             if (fwsFile != null && fwsFile.exists()) {
                 fwsFile.delete();
@@ -123,12 +148,12 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
         }
     }
 
-    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(" +");
@@ -162,8 +187,7 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
         }
         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);
             }
@@ -182,8 +206,9 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
         logger.log(Level.INFO, argMsg.toString());
         return cmdList;
     }
+    private static final Pattern PATTERN_TIME = Pattern.compile("time=(\\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...");
@@ -193,8 +218,15 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
             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 String strTime = m.group(1);
+                        final double time = Double.parseDouble(strTime);
+                        per = 100.0 * time / duration;
+                        logger.log(Level.FINEST, "time:{0}, duration:{1}", new Object[]{time, duration});
+                    }
+                    publish(new ConvertProgress(PROCESS, per, msg));
                 } else if (!msg.endsWith("No accelerated colorspace conversion found")) {
                     logger.log(Level.INFO, msg);
                 }
@@ -205,7 +237,6 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
             process.waitFor();
             return process.exitValue();
         } finally {
-            // TODO 正常終了した場合もdestroyしていいのか?
             if (process != null) {
                 process.destroy();
             }
@@ -213,22 +244,25 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
     }
 
     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:");
@@ -239,7 +273,8 @@ public class Convert extends Worker<ConvertResult, ConvertProgress> {
         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());