ffmpeg输出能否通过管道传输给ffprobe进行处理?
首先直接回应你的核心疑问:你可以将ffmpeg的输出管道到ffprobe,但你的命令报错是因为两者的行为不匹配——ffprobe的作用是分析媒体的元数据,它读取完足够识别媒体格式、时长等信息的数据流后就会立即退出;而你的ffmpeg命令会持续输出完整的视频流,当ffprobe关闭管道后,ffmpeg还在尝试往里面写数据,自然就会抛出Broken pipe错误。
修正ffmpeg→ffprobe的管道命令
如果你只是想通过管道让ffprobe分析ffmpeg输出流的元数据,可以让ffmpeg只输出元数据部分,不输出实际的帧数据。加上-vframes 0参数即可:
ffmpeg -i /path/to/in.mp4 -f mpegts -vframes 0 - | ffprobe -i - -print_format json
这个命令会让ffmpeg仅生成流的头部信息,ffprobe读完后正常退出,不会出现管道错误。
更适合你场景的进度跟踪方案
不过从你的NodeJS脚本场景来看,你需要的是实时跟踪视频处理的进度,用ffprobe管道的方式其实并不合适——它只能获取静态的元数据,无法实时监控ffmpeg的处理进度。这里有两个更靠谱的方案:
1. 解析ffmpeg的标准错误输出(stderr)
ffmpeg在处理视频时,会把实时进度信息输出到stderr,典型的输出行类似:
frame= 1560 fps= 30 q=22.0 size= 18432kB time=00:01:02.40 bitrate= 2400.0kbits/s speed=1.0x
你可以在NodeJS中监听ffmpeg子进程的stderr流,用正则表达式提取关键信息:
- 用
time=(\d+:\d+:\d+\.\d+)匹配当前处理到的时间点 - 提前用ffprobe获取视频的总时长(比如
ffprobe -i /path/to/in.mp4 -show_entries format=duration -v quiet -of csv="p=0") - 计算当前进度:
(当前时间秒数 / 总时长秒数) * 100%
这种方式不需要额外参数,兼容性好,但要注意不同ffmpeg版本的stderr输出格式可能略有差异。
2. 使用ffmpeg的-progress参数(推荐)
ffmpeg提供了-progress参数,可以将结构化的进度信息输出到指定的文件或管道,格式是键值对,非常容易解析。比如在你的ffmpeg命令中加上:
ffmpeg -i /path/to/in.mp4 -f mpegts - -progress pipe:1
此时ffmpeg会把进度信息输出到stdout,每条信息类似:
frame=1560 fps=30 out_time=00:01:02.40 out_time_ms=62400000 total_duration=00:02:04.80 total_duration_ms=124800000 speed=1.0x ...
在NodeJS中,你可以监听ffmpeg子进程的stdout流,按行读取并解析这些键值对,轻松获取当前处理时间、总时长、处理速度等数据,进而计算进度。这种方式格式稳定,解析成本低,是跟踪ffmpeg处理进度的最优方案。
内容的提问来源于stack exchange,提问作者slifty

