我在我的java代码中执行这个ffmpeg
命令有问题:
ffmpeg -i sample.mp4 -i ad.mp4 -filter_complex "[0:v]trim=0:15,setpts=PTS-STARTPTS[v0]; [1:v]trim=0:5,setpts=PTS-STARTPTS[v1]; [0:v]trim=20:30,setpts=PTS-STARTPTS[v2]; [v0][v1][v2]concat=n=3:v=1:a=0[out]" -map "[out]" output.mp4
我使用了下面的getRuntime()
方法,但是这对我不起作用。 即使我只是删除了"
,仍然不起作用,当我简单地复制粘贴等效的string在terminal,它的工作。
String c1=" -i "+dir+"sample.mp4 "+"-i "+dir+"ad.mp4 -filter_complex [0:v]trim=0:15,setpts=PTS-STARTPTS[v0]; [1:v]trim=0:5,setpts=PTS-STARTPTS[v1]; [0:v]trim=20:30,setpts=PTS-STARTPTS[v2]; [v0][v1][v2]concat=n=3:v=1:a=0[out] -map [out] "+dir+"output.mp4"; RunCommand("ffmpeg"+c1);
使用这种方法:
private static void RunCommand(String command) throws InterruptedException { try { // Execute command Process proc = Runtime.getRuntime().exec(command); System.out.println(proc.exitValue()); // Get output stream to write from it // Read the output BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream())); String line = ""; while((line = reader.readLine()) != null) { System.out.print(line + "\n"); // System.out.println(ads.get(0)); } proc.waitFor(); } catch (IOException e) { } }
这个也不起作用,而打印出口值显示这个:
Exception in thread "main" java.lang.IllegalThreadStateException: process hasn't exited at java.lang.UNIXProcess.exitValue(UNIXProcess.java:423) at parser.Parser.RunCommand(Parser.java:106) at parser.Parser.commandGenerator2(Parser.java:79) at parser.Parser.main(Parser.java:44)
如果我移动proc.waitFor();
在打印出口值之前,它是1
。
问题是什么? 为什么它不能在Java代码中运行?
你的代码有一些问题,首先,使用线程流入和内部进程的错误到控制台
创建一个管道流类如下所示:
class PipeStream extends Thread { InputStream is; OutputStream os; public PipeStream(InputStream is, OutputStream os) { this.is = is; this.os = os; } public void run() { byte[] buffer=new byte[1024]; int len; try { while ((len=is.read(buffer))>=0){ os.write(buffer,0,len); } } catch (IOException e) { e.printStackTrace(); } } }
然后调整运行时间部分:
System.out.println("Launching command: "+command); ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", command); Process proc=pb.start(); PipeStream out=new PipeStream(proc.getInputStream(), System.out); PipeStream err=new PipeStream(proc.getErrorStream(), System.err); out.start(); err.start(); proc.waitFor(); System.out.println("Exit value is: "+proc.exitValue());
它将显示将要运行的命令,日志和潜在的错误。
你将能够复制粘贴命令来检查终端上发生了什么,如果需要的话。
编辑:这很有趣。 你的代码是缺少一些转义字符,并没有在你的代码中可见的字符。 当我复制粘贴代码行时,我看到了它们。 复制代码中粘贴以下行,它将删除错误:
String command="ffmpeg -i "+dir+"sample.mp4 -i "+dir+"ad.mp4 -filter_complex '[0:v]trim=0:15,setpts=PTS-STARTPTS[v0]; [1:v]trim=0:5,setpts=PTS-STARTPTS[v1]; [0:v]trim=20:30,setpts=PTS-STARTPTS[v2]; [v0][v1][v2]concat=n=3:v=1:a=0[out]' -map '[out]' "+dir+"output.mp4";
有几个问题需要解决(大多数是通过其他答案单独解决的,并且有不同程度的解释,但是您需要解决所有问题):
ffmpeg
正如shell所要做的那样,这意味着你需要用单独的参数作为字符串数组来创建一个命令,或者为了使它更容易(和shell行为相同),引用你的参数: \"
围绕着大的过滤器参数,那么你应该能够将命令传递给runCommand
就像你在shell中写入一样。 ffmpeg
,但是/bin/sh
可以为你做:用/bin/sh -c ...
包装你的命令(为此我将使用ProcessBuilder
下面) ProcessBuilder
来拯救:将stderr
重定向到stdout
只获得一个单独的流消耗,然后将stdout
重定向到任何你想要的地方(下面我从父进程继承,所以它转到你的java
进程本身的输出。 waitFor()
,它会等待尽可能长的时间,但也有其他的选择) -fi......lter_complex
(十六进制中的点是e2 80 8c e2 80 8b
),但是在你的命令中有更多的分散。 从而:
String c1 = " -i " + dir + "sample.mp4 -i " + dir + "ad.mp4 -filter_complex \"[0:v]trim=0:15,setpts=PTS-STARTPTS[v0]; [1:v]trim=0:5,setpts=PTS-STARTPTS[v1]; [0:v]trim=20:30,setpts=PTS-STARTPTS[v2]; [v0][v1][v2]concat=n=3:v=1:a=0[out]\" -map \"[out]\" " + dir + "output.mp4"; // Notice additional quotes around filter & map above runCommand("ffmpeg" + c1); // ... static void runCommand(String command) throws IOException, InterruptedException { Process p = new ProcessBuilder("/bin/sh", "-c", command) .redirectErrorStream(true) .redirectOutput(ProcessBuilder.Redirect.INHERIT) .start(); p.waitFor(); System.out.println("Exit value: " + p.exitValue()); }
(*)在一个shell中,如果你想打印ab
你echo "ab"
,但在Java中这是行不通的:
Runtime.getRuntime().exec("echo \"ab\"");
它所做的是天真地分割空间,它会传递2个参数而不是1 echo
: "a
then b"
。 不是你想要的。
另类:单独传递参数。
runCommandAsVarargs( "ffmpeg", "-i", dir + "sample.mp4", "-i", dir + "ad.mp4", "-filter_complex", "[0:v]trim=0:15,setpts=PTS-STARTPTS[v0]; [1:v]trim=0:5,setpts=PTS-STARTPTS[v1]; [0:v]trim=20:30,setpts=PTS-STARTPTS[v2]; [v0][v1][v2]concat=n=3:v=1:a=0[out]", "-map", "[out]", dir + "output.mp4" ); // ... static void runCommandAsVarargs(String... command) throws IOException, InterruptedException { Process p = new ProcessBuilder(command) .redirectErrorStream(true) .redirectOutput(ProcessBuilder.Redirect.INHERIT) .start(); p.waitFor(); System.out.println("Exit value: " + p.exitValue()); }
似乎你错过了参数-filter_complex
参数的引号。 Java将运行如下所示:
ffmpeg -i ./sample.mp4 -i ./ad.mp4 -filter_complex [0:v]trim=0:15,setpts=PTS-STARTPTS[v0]; [1:v]trim=0:5,setpts=PTS-STARTPTS[v1]; [0:v]trim=20:30,setpts=PTS-STARTPTS[v2]; [v0][v1][v2]concat=n=3:v=1:a=0[out] -map [out] output.mp4
这从那以后就不起作用了;
意味着在bash中的命令结束。 把报价放回到java代码应该修复命令(确保正确地转义它们)。
String c1=" -i "+dir+"sample.mp4 "+"-i "+dir+"ad.mp4 -filter_complex \"[0:v]trim=0:15,setpts=PTS-STARTPTS[v0]; [1:v]trim=0:5,setpts=PTS-STARTPTS[v1]; [0:v]trim=20:30,setpts=PTS-STARTPTS[v2]; [v0][v1][v2]concat=n=3:v=1:a=0[out]\" -map [out] "+dir+"output.mp4"; RunCommand("ffmpeg"+c1);