Node.js下如何通过FFmpeg spawn实现两个子进程的MP4流拷贝
方案失效根因
此前的实现本质是两个逻辑硬伤:
- 把Node.js的stdout流对象直接转模板字符串,最终得到的是无意义的
[object Object]字符串,根本不是FFmpeg可识别的输入地址 - 没有在两个FFmpeg子进程之间建立实际的数据流连接,哪怕写了路径参数,FFmpeg也拿不到任何输入数据
正确实现逻辑
两个进程通过操作系统管道直连,完全不需要落地中间临时文件,核心逻辑全部围绕FFmpeg内置的管道输入/输出协议实现:
- 第一个FFmpeg录制进程:把原本写文件的输出位置改为写自身的标准输出(对应
pipe:1),保留原有x11grab采集、PulseAudio采集、libx264/AAC编码、分片MP4的全部原有配置,必须显式指定输出格式为mp4——因为输出到管道时没有文件后缀,FFmpeg无法自动探测格式,不指定会直接报错。 - 第二个FFmpeg转存进程:把输入源指定为读自身的标准输入(对应
pipe:0),保留无重编码流拷贝的配置,最终输出到目标MP4文件。 - 通过Node.js的流pipe方法,把第一个进程的标准输出直接绑定到第二个进程的标准输入,完成进程间的数据流打通。
关键参考代码
const { spawn } = require('child_process') // 1. 初始化屏幕录制的FFmpeg进程 const recorder = spawn('ffmpeg', [ // 原有屏幕采集配置 '-f', 'x11grab', '-i', ':0.0', // 替换为实际DISPLAY变量值 // 原有音频采集配置 '-f', 'pulse', '-i', 'default', // 原有编码配置 '-c:v', 'libx264', '-c:a', 'aac', // 原有分片MP4标记,保证边写边读的兼容性 '-movflags', 'frag_keyframe+empty_moov', // 显式指定输出格式,输出到自身标准输出 '-f', 'mp4', 'pipe:1' ]) // 2. 初始化流拷贝转存的FFmpeg进程 const remuxer = spawn('ffmpeg', [ '-i', 'pipe:0', // 从自身标准输入读取录制流 '-c', 'copy', // 无重编码流拷贝 './target_output.mp4' ]) // 3. 打通两个进程的数据流 recorder.stdout.pipe(remuxer.stdin) // 可选:将进程运行日志直接输出到当前控制台,方便问题排查 recorder.stderr.pipe(process.stderr) remuxer.stderr.pipe(process.stderr)
常见踩坑提示
- 不要在Node.js层把第一个进程的输出流全部读成Buffer存在内存里再传给第二个进程,长时录制场景会直接导致内存溢出,管道直连是操作系统层面的零拷贝数据传输,不会额外占用应用内存。
- 不要遗漏
-movflags frag_keyframe+empty_moov参数:普通MP4的moov元数据会在文件写完后才生成,如果不加这个分片标记,录制进程会等全部录制完成才往stdout写数据,下游的第二个进程根本拿不到实时流。 - 如果遇到管道断连的问题,检查两个进程的
stdin是否被过早关闭:只要pipe连接保持,两个进程的数据流就会持续传输,直到录制正常结束。
内容的提问来源于stack exchange,提问作者Abadi
相关产品推荐
相关产品推荐

