当我尝试生成一个子ffmpeg进程时,我使用附加标志-progress
,接下来我使用管道将此进度输出传递到stderr。所以整个命令看起来像:
ffmpeg -i ... -progress pipe:2 ...
在没有-progress
标志的情况下,ffmepg在stderr中输出以下行,可能每秒一次:
frame=46 46 fps=0.0 q=0.0 size= 0kB time=00:00:01.72 bitrate= 0.2kbits/s speed=2.69x
在stderr中使用-progress
标志ffmepg输出(多行(,可能每秒一次:
frame=1 1 fps=0.0 q=0.0 size= 0kB time=00:00:00.19 bitrate= 2.0kbits/s speed=2.94x
fps=0.00
stream_0_0_q=0.0
bitrate= 2.0kbits/s
total_size=48
out_time_us=192000
out_time_ms=192000
out_time=00:00:00.192000
dup_frames=0
drop_frames=0
speed=2.94x
progress=continue
使用-progress
标志的主要用途是通过解析out_time_ms
行并与整个持续时间进行比较来计算完成百分比。
在NodeJS中读取这个区块(部分行(非常简单:
const { spawn } = require('child_process');
const child = spawn('ffmpeg', [..., '-progress', 'pipe:2', ...]);
child.stderr.on('data', (data) => {
// data will contain multiple lines, exactly one chunk
});
在Deno中读取这个区块(部分行(也很简单:
const child = Deno.spawnChild("ffmpeg", {
args: [..., '-progress', 'pipe:2', ...],
});
const stderrReader = child.stderr.getReader();
let readResult = await stderrReader.read();
while (readResult.done !== true) {
readResult = await stderrReader.read();
// readResult will contain multiple lines, exactly one chunk
}
我在铁锈上无法做到这一点:
let mut command = Command::new("ffmpeg");
command.args(["...", "-progress", "pipe:2", "..."]);
let mut child = command
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap();
let child_stderr = child.stderr.as_mut().expect("Unable to pipe stderr");
let mut reader = BufReader::new(child_stderr);
let mut buff = String::new();
while reader.read_line(&mut buff).expect("Unable to read chunk") > 0 {
// buff will contain only on line
buff.clear();
}
我是Rust的新手。我无法检测出哪个字符表示块结束。
- Runnig
read_line()
-将只读取一行 - Runnig
read_to_end()
-将读取整个输出,直到进程结束(EOF(
如何在Rust中读取ffmpeg每秒可能输出一次的行的部分?Node/Deno如何检测到这一"问题";块的末尾";?铁锈也有这样的事件/信号吗?
您可以使用ChildStderr::read
来实现与其他语言相同的行为。
⚠警告⚠
在任何语言中,这种行为都是不可靠的。
Stderr是数据流。它不是基于数据包的。它意味着被一个字符一个字符地消耗。
您之所以得到块是出于性能原因。操作系统将多个字符组合在一起进行单个读/写操作。请注意,对哪些字符进行分组的决定是由操作系统任意选择的。
在你的情况下,看起来这些状态信息总是作为一个数据包来的,因为它产生得太快了,操作系统将其组合在一起是明智的。但是,请注意,不能保证总是这样,依赖它是危险的。
BufReader
将所有这些抽象掉,并公开了常见的功能,如阅读一行文本。
建议:
使用BufReader
逐行处理状态信息。没有可靠的方法来检测状态更新的结束,所以将每一行处理为一条自包含的消息。(除非ffmpeg打印某种消息结束标记,如双换行符(