OSDN Git Service

デバッグ出力を追加
[coroid/inqubus.git] / frontend / src / saccubus / converter / FfmpegCommand.java
1 /* $Id$ */
2 package saccubus.converter;
3
4 import java.io.BufferedReader;
5 import java.io.File;
6 import java.io.IOException;
7 import java.io.InputStreamReader;
8 import java.io.UnsupportedEncodingException;
9 import java.net.URLEncoder;
10 import java.util.ArrayList;
11 import java.util.List;
12 import java.util.logging.Level;
13 import java.util.logging.Logger;
14 import org.apache.commons.lang.StringUtils;
15 import saccubus.ConvertStopFlag;
16 import saccubus.conv.ConvertToVideoHook;
17 import saccubus.converter.profile.Ffmpeg;
18 import saccubus.converter.profile.FfmpegOption;
19 import saccubus.converter.profile.GeneralSetting;
20 import saccubus.converter.profile.NgSetting;
21 import saccubus.net.TextProgressListener;
22 import yukihane.mediainfowrapper.Info;
23 import yukihane.mediainfowrapper.MediaInfo;
24 import yukihane.mediainfowrapper.Size;
25 import yukihane.swf.Cws2Fws;
26
27 /**
28  *
29  * @author yuki
30  */
31 public class FfmpegCommand extends AbstractCommand {
32     private static final Logger logger = Logger.getLogger(FfmpegCommand.class.getName());
33     private final File commentMiddleFile;
34     private final File tcommMiddleFile;
35     private final File TMP_CWS;
36     private final File commentFile;
37     private final File tcommFile;
38     private final File videoFile;
39     private final File convertedVideoFile;
40     private final Ffmpeg ffmpeg;
41
42     FfmpegCommand(TextProgressListener listener, ConvertStopFlag flag, File commentFile, File tcommFile,
43             File videoFile, File convertedVideoFile, Ffmpeg ffmpeg, GeneralSetting general) throws IOException {
44         super(listener, flag);
45         this.commentFile = commentFile;
46         this.tcommFile = tcommFile;
47         this.videoFile = videoFile;
48         this.convertedVideoFile = convertedVideoFile;
49         this.ffmpeg = ffmpeg;
50
51         File tmpDir = general.getTempDir();
52         commentMiddleFile = File.createTempFile("vhk", ".tmp", tmpDir);
53         tcommMiddleFile = File.createTempFile("tcom", ".tmp", tmpDir);
54         TMP_CWS = File.createTempFile("cws", ".swf", tmpDir);
55     }
56
57     public boolean execute() throws InterruptedException, IOException {
58         try {
59             return exec();
60         } finally {
61             if (commentMiddleFile.exists()) {
62                 commentMiddleFile.delete();
63             }
64             if (tcommMiddleFile.exists()) {
65                 tcommMiddleFile.delete();
66             }
67             if (TMP_CWS.exists()) {
68                 TMP_CWS.delete();
69             }
70         }
71     }
72
73     private boolean exec() throws InterruptedException, IOException {
74         final NgSetting ngSetting = getFfmpeg().getNgSetting();
75         if (commentFile != null) {
76             sendText("コメントの中間ファイルへの変換中");
77             boolean conv = ConvertToVideoHook.convert(commentFile, commentMiddleFile, ngSetting.getId(), ngSetting.
78                     getWord());
79             if (!conv) {
80                 sendText("コメント変換に失敗。ファイル名に使用できない文字が含まれているか正規表現の間違い?");
81                 return false;
82             }
83         }
84         stopFlagReturn();
85         if (tcommFile != null) {
86             sendText("投稿者コメントの中間ファイルへの変換中");
87             boolean conv = ConvertToVideoHook.convert(tcommFile, tcommMiddleFile, ngSetting.getId(), ngSetting.getWord());
88             if (!conv) {
89                 sendText("コメント変換に失敗。ファイル名に使用できない文字が含まれているか正規表現の間違い?");
90                 return false;
91             }
92         }
93         stopFlagReturn();
94         sendText("動画の変換を開始");
95         int code;
96         if ((code = converting_video(videoFile, convertedVideoFile, (commentFile != null), commentMiddleFile.getPath(),
97                 (tcommFile
98                 != null), tcommMiddleFile.getPath(), getFfmpeg().getFfmpegOption())) == 0) {
99             sendText("変換が正常に終了しました。");
100             return true;
101         } else {
102             sendText("変換エラー:" + convertedVideoFile.getPath());
103         }
104         return false;
105     }
106
107     private int converting_video(File videoFile, File convertedVideoFile, boolean addComment, String commPath,
108             boolean addTcomment, String tcommPath, FfmpegOption ov) throws InterruptedException, IOException {
109         File fwsFile = Cws2Fws.createFws(videoFile, TMP_CWS);
110
111         List<String> cmdList = new ArrayList<String>();
112         cmdList.add(getFfmpeg().getFfmpeg().getPath());
113         cmdList.add("-y");
114         String[] mainOptions = ov.getMainOption().split(" +");
115         for (String opt : mainOptions) {
116             if (StringUtils.isNotBlank(opt)) {
117                 cmdList.add(opt);
118             }
119         }
120         String[] inOptions = ov.getInOption().split(" +");
121         for (String opt : inOptions) {
122             if (StringUtils.isNotBlank(opt)) {
123                 cmdList.add(opt);
124             }
125         }
126         cmdList.add("-i");
127
128         if (fwsFile == null) {
129             cmdList.add(videoFile.getPath());
130         } else {
131             cmdList.add(fwsFile.getPath());
132         }
133         String[] outOptions = ov.getOutOption().split(" +");
134         for (String opt : outOptions) {
135             if (StringUtils.isNotBlank(opt)) {
136                 cmdList.add(opt);
137             }
138         }
139
140         final Info info = MediaInfo.getInfo(new File("bin", "MediaInfo"), videoFile);
141         // 4:3 なら1.33, 16:9 なら1.76
142         boolean isHD = ((double)info.getWidth()/(double)info.getHeight() > 1.5);
143         if (ov.isResize()) {
144             final Size scaled = (ov.isAdjustRatio()) ? MediaInfo.adjustSize(info, ov.getResizeWidth(), ov.
145                     getResizeHeight()) : new Size(info.getWidth(), info.getHeight());
146             cmdList.add("-s");
147             cmdList.add(scaled.getWidth() + "x" + scaled.getHeight());
148         }
149
150         List<String> avfilterArgs = getAvfilterOptions(ov.getAvfilterOption());
151         if (!getFfmpeg().isVhookDisabled()) {
152             String vhookArg = getVhookArg(addComment, commPath, addTcomment, tcommPath, isHD);
153             if(StringUtils.isNotBlank(vhookArg)){
154                 avfilterArgs.add(vhookArg);
155             }
156         }
157
158         if (!avfilterArgs.isEmpty()) {
159             cmdList.add("-vfilters");
160             final String args = "\"" + StringUtils.join(avfilterArgs, ", ") + "\"";
161             cmdList.add(args);
162         }
163
164         cmdList.add(convertedVideoFile.getPath());
165
166         final StringBuilder argMsg = new StringBuilder();
167         argMsg.append("arg:");
168         for (String s : cmdList) {
169             argMsg.append(" ").append(s);
170         }
171         logger.log(Level.INFO, argMsg.toString());
172
173         try {
174             logger.log(Level.INFO, "\n\n----\nProcessing FFmpeg...\n----\n\n");
175             Process process = Runtime.getRuntime().exec(cmdList.toArray(new String[0]));
176             BufferedReader ebr = new BufferedReader(new InputStreamReader(
177                     process.getErrorStream()));
178             String e;
179             while ((e = ebr.readLine()) != null) {
180                 String state = e;
181                 if (state.startsWith("frame=")) {
182                     sendText(state, false);
183                 } else if (!state.endsWith("No accelerated colorspace conversion found")) {
184                     logger.log(Level.INFO, e);
185                 }
186
187                 try {
188                     stopFlagReturn();
189                 } catch (InterruptedException ex) {
190                     process.destroy();
191                     throw ex;
192                 }
193
194             }
195             process.waitFor();
196             return process.exitValue();
197         } finally {
198             if (fwsFile != null) {
199                 fwsFile.delete();
200             }
201         }
202     }
203
204     private List<String> getAvfilterOptions(String avfilterOption) {
205         final List<String> avfilterArgs = new ArrayList<String>();
206         if (StringUtils.isNotBlank(avfilterOption)) {
207             avfilterArgs.add(avfilterOption);
208         }
209         return avfilterArgs;
210     }
211
212     private String getVhookArg(boolean addComment, String commPath, boolean addTcomment,
213             String tcommPath, boolean isHD) throws UnsupportedEncodingException {
214         StringBuilder sb = new StringBuilder();
215         sb.append("vhext=");
216         sb.append(getFfmpeg().getVhook().getPath().replace("\\", "/"));
217         if (addComment) {
218             sb.append("|");
219             sb.append("--data-user:");
220             sb.append(URLEncoder.encode(commPath.replace("\\", "/"), "Shift_JIS"));
221         }
222         if (addTcomment) {
223             sb.append("|");
224             sb.append("--data-owner:");
225             sb.append(URLEncoder.encode(tcommPath.replace("\\", "/"), "Shift_JIS"));
226         }
227         sb.append("|");
228         sb.append("--font:");
229         sb.append(URLEncoder.encode(
230                 getFfmpeg().getFont().getPath().replace("\\", "/"), "Shift_JIS"));
231         sb.append("|");
232         sb.append("--font-index:");
233         sb.append(getFfmpeg().getFontIndex());
234         sb.append("|");
235         sb.append("--show-user:");
236         sb.append(getFfmpeg().getMaxNumOfComment());
237         sb.append("|");
238         sb.append("--shadow:");
239         sb.append(getFfmpeg().getShadowIndex());
240         sb.append("|");
241         if (getFfmpeg().isShowConverting()) {
242             sb.append("--enable-show-video");
243             sb.append("|");
244         }
245         if (getFfmpeg().isSelfAdjustFontSize()) {
246             sb.append("--enable-fix-font-size");
247             sb.append("|");
248         }
249         if (getFfmpeg().isCommentOpaque()) {
250             sb.append("--enable-opaque-comment");
251             sb.append("|");
252         }
253         if(isHD){
254             sb.append("--aspect-mode:1");
255             sb.append("|");
256         }
257         return sb.toString();
258     }
259
260     private Ffmpeg getFfmpeg() {
261         return ffmpeg;
262     }
263 }