Node.js中使用FFmpeg分片大音频文件时流未写入完整的问题
问题分析与解决方案
核心问题:过早终止FFmpeg进程
你的代码在读取流(fs.createReadStream)触发close事件时,立刻调用muxer.kill()杀死了FFmpeg子进程。但close事件仅代表本地文件的所有数据已经写入到FFmpeg的标准输入(stdin),FFmpeg还需要时间处理这些数据并生成所有分片文件。
对于小文件,数据量小,FFmpeg能在你杀死进程前快速处理完所有分片;但大文件数据量庞大,FFmpeg还在处理过程中就被强制终止,自然无法生成完整的分片。而命令行直接运行时,FFmpeg会处理完所有输入数据才会退出,所以能生成完整的328个分片。
修复代码
修改事件监听逻辑,等待FFmpeg子进程自行退出,而不是主动杀死它:
const muxer = child_process.spawn('ffmpeg', transformArgs, { cwd: `${cwd}/transforms`, }); console.log('creating stream (read)...'); // 读取文件并传入FFmpeg fs.createReadStream( `${cwd}/transforms/stream${path.extname(fileSrc.filename)}`, ) .pipe(muxer.stdin) .on('error', (e) => { console.error('读取流错误:', e); }); // 监听FFmpeg子进程的退出事件 muxer.on('exit', (code, signal) => { if (code === 0) { console.log('FFmpeg处理完成,所有分片已生成'); // 这里可以执行分片上传到S3的逻辑 } else { console.error(`FFmpeg异常退出,退出码: ${code}, 信号: ${signal}`); } }); // 监听FFmpeg的错误输出,方便排查问题 muxer.stderr.on('data', (data) => { console.error('FFmpeg错误输出:', data.toString()); });
关键修改点说明
- 移除了
readStream的close事件监听,不再主动调用muxer.stdin.end()和muxer.kill():当读取流结束时,pipe会自动关闭FFmpeg的stdin,FFmpeg会继续处理剩余数据直到完成。 - 添加
muxer.on('exit')监听:只有当FFmpeg正常退出(退出码为0)时,才表示所有分片生成完成,此时再执行后续的S3上传操作。 - 添加
muxer.stderr监听:可以捕获FFmpeg的错误输出,方便排查分片过程中可能出现的其他问题(比如参数错误、磁盘空间不足等)。
额外排查点
如果修复后仍有问题,可以检查:
- FFmpeg的
transformArgs参数是否正确:确认分片的时长/大小设置和命令行运行时一致。 - 服务器磁盘空间:大文件分片可能占用较多磁盘空间,确保目标目录有足够空间。
- Node.js的内存限制:虽然分片是FFmpeg处理,但如果读取流有异常,可以尝试调整读取流的
highWaterMark参数(比如fs.createReadStream(path, { highWaterMark: 64 * 1024 }))优化流处理。
内容的提问来源于stack exchange,提问作者Israel Edoghama
相关产品推荐
相关产品推荐

