我想将类似 ffmpeg -i “input.mkv” -i “input.chs&jpn.ass” -c copy "output/output1.mkv" 这样的命令由 Java 代码来执行
java
List<String> command = new ArrayList<>();
command.add(ffmpegPath);
command.add("-i");
//输入视频文件 File
command.add(file.getAbsolutePath());
command.add("-i");
//输入字幕文件 File
command.add(sub.getAbsolutePath());
command.add("-c");
command.add("copy");
//拼接输出路径
command.add((new File(out,fileName)).getAbsolutePath());
由于考虑多平台运行,所以路径获取和拼接都是通过 File ,没有自己加 Separate 。
Log 以后,提示是这样的:
INFO: "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv": No such file or directory
其实已经分好类了,也就是说 File 对象指向是符合我预期的,只是创建文件夹利用的是 Java File 类的 mkdirs ()。
那就是 ffmpeg 命令这里参数出了问题,我试过给参数再套一层双引号(""),同样是 win 编译执行 ok ,linux “No such file or directory”
java Process 在不同平台执行看了会源码没看太明白。
老哥们这是我的代码,写的有点粗糙,轻喷。 点击访问代码
额外需要的依赖这里下载 https://commons.apache.org/proper/commons-io/download_io.cgi
1
urnoob 2023-05-25 23:57:11 +08:00 via Android
文件名包含空格导致的吧
判断下平台,Linux 就给空格加转义 |
2
urnoob 2023-05-25 23:59:06 +08:00 via Android
或者把文件名用双引号包起来
|
3
CLMan 2023-05-26 00:01:45 +08:00
文件没找到就是特殊字符的原因,先一个个测试是否哪些字符导致的问题,在想办法从程序上,还是从修改文件名上解决问题。
|
4
DIO OP @urnoob 双引号包起来亲测不可行,命令行直接用是奏效的。如果不用双引号包起来,命令行直接执行时就是割裂的。平台判断也加了。转义之前没尝试,因为不知道空格转义成什么,也不知道有没有什么其他字符需要处理。
|
5
msg7086 2023-05-26 00:10:44 +08:00
很高兴见到你下载我组作品。
建议你先把 command 的内容打印出来看看是不是符合预期。 “/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv” 这个文件真实存在吗? 双引号应该是不需要套的。 |
6
DIO OP @msg7086 贵组字幕做的很好,其他有直接内嵌的但是翻译太差不想用于是想搞个工具 233 。command 在平台执行的具体内容可以打印出来吗,我在 ide 调试看不到转换后的内容。由于能力有限,查看源码也没搞清楚。
|
7
msg7086 2023-05-26 00:18:10 +08:00
@DIO 直接执行命令是不会被转义的,只有经过 shell 运行的时候才需要考虑转义(和双引号等 shell 会处理的符号)。
所以不存在转换后的内容一说,你填在 command 里的参数就是实际执行的参数。 |
8
DIO OP @msg7086 文件是真实存在的,我的代码都是自动从当前目录扫描得到 file 的,我其实不会去手动输入任何路径。双引号我在参数里套过,但是照样是 win 符合预期执行,linux 不符合。相同的命令形式在两个平台测试,却是都能达到预期效果
|
9
DIO OP @msg7086 如果说是按照数组形式,命令是否符合预期,是的,我在 LOG 以及 IDE 调试时都会查看 command 数组内容,参数均与预期一致
|
10
msg7086 2023-05-26 00:33:56 +08:00
你贴的错误日志应该是从 logger 输出的吧。logger.info()里的参数你填的是什么?以及有没有抓到任何 exception ?
|
11
ysc3839 2023-05-26 00:56:50 +08:00 via Android
@urnoob 你说 Windows 出错了这么做还有点道理。Windows 和 Unix 有个显著差异是,Windows 的进程命令行是一个字符串,而 Unix 的进程命令行是字符串数组。既然 Windows 只能传单个字符串,这其中就涉及空格转义问题了。理论上 Windows 程序可以用任意规则解析命令行,不过为了兼容 Unix ,是有提供一套标准的解析规则来解析成字符串数组的。而 Unix 进程拿到的就是字符串数组,解析工作是由 shell 进行的。如果是自己程序启动进程,那可以直接传递字符串数组,不需要转义。
至于楼主的问题,我比较怀疑是命令行写错了,建议给出一段最简单的可复现代码。 |
12
githmb 2023-05-26 01:39:04 +08:00
你是不是忽略了 & 在 Linux 下的作用?
|
13
ETiV 2023-05-26 01:51:17 +08:00 via iPhone
😂 恰恰是最关键的 [用什么去执行命令] 的代码没给出来
|
14
cslive 2023-05-26 08:44:38 +08:00
文件名有空格,在 linux 下识别不出来,将空格替换成下划线就可以了
|
15
DIO OP @msg7086
## 我是简单把 list 转成字符串了 `code` ``` BindingContextFactory.LOGGER.info("command is"+command.toString()); ``` 'res' ``` INFO: command is[ffmpeg, -i, "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv", -i, "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].jpn.ass", -c, copy, "/home/codeTest/ffmpegSubTest/output/jpn/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv"] ``` ## 另外就是简单的把 process 的流输出出来,能简单看到命令执行反馈 ``` try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String line = null; while ((line = bufferedReader.readLine()) != null) { BindingContextFactory.LOGGER.info(line); } } catch (IOException e) { } }).start(); ``` ## 然后 Exception 好像没有抓取到 |
18
DIO OP @githmb 我注意到 linux 目录下,带有&符号的目录会带单引号'',于是我尝试了判断系统类型,windows 加双引号或者不带,其他加单引号传参。还是 No such file or directory 。
接下来我会尝试转义&字符 感谢您,我在 append 中贴出代码链接,您什么时候有空希望能指教一二 |
19
yazinnnn 2023-05-26 09:36:02 +08:00
val command =
ProcessBuilder( "ffmpeg", "-i", "/home/yazi/Downloads/[20230402]ん ⧸ YuuRi Cas\uD83E\uDD40.mp4", "/home/yazi/Downloads/output.mp4" ).command() println(command) val process = Runtime.getRuntime().exec(command.toTypedArray()) 用这个命令试了一下, 可以正常执行, 是不是你路径写错了? |
20
msg7086 2023-05-26 09:40:24 +08:00
@DIO #15
[ffmpeg, -i, "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv", -i, "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].jpn.ass", -c, copy, "/home/codeTest/ffmpegSubTest/output/jpn/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv"] 双引号都删掉试试呢 [ffmpeg, -i, /home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv, -i, /home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].jpn.ass, -c, copy, /home/codeTest/ffmpegSubTest/output/jpn/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv] 变成这样应该就对了。 |
21
msg7086 2023-05-26 09:45:20 +08:00
Linux 下,Shell 才是负责转义的,包括空格,&,[],等等,都只有在经过 Shell 的时候(比如 bash -c ,或者在命令行提示符下运行时)。
直接从 Java 调用 syscall 运行的时候加双引号是错误的行为。 我想这也是为什么你一开始的提示里 "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv": No such file or directory 会有双引号的原因。因为你这样写的话就是要寻找 [.] / ["] / [home] 这个目录了。 |
23
loginv2 2023-05-26 10:46:57 +08:00
简化输入文件名 使用绝对目录定位。我记得 ffmpeg 以前我载入 ass 文件的时候 相对路径总出错 不知道是我用的不对 还是怎么样
|