Node.js调用FFmpeg子进程报Error: Write EOF的原因及修复
问题原因
- 处理大视频时,FFmpeg仅需读取视频开头少量数据就能生成缩略图,会提前关闭
stdin管道。但你的代码中Readable流仍在持续向已关闭的stdin写入数据,触发write EOF错误。 - 代码未监听
ffmpeg.stdin和ffmpeg进程的error事件,导致错误未被捕获,最终引发程序崩溃。
修复方案
1. 捕获未处理的错误事件
给ffmpeg.stdin和ffmpeg进程添加错误监听,避免未捕获错误导致程序崩溃:
// 监听stdin写入错误 ffmpeg.stdin.on('error', (err) => { callback(err); }); // 监听FFmpeg进程错误 ffmpeg.on('error', (err) => { callback(err); });
2. 停止向已关闭的管道写入数据
当FFmpeg进程退出时,销毁可读流,防止继续向已关闭的stdin写入:
ffmpeg.on('exit', () => { readable.destroy(); // 终止可读流,停止写入操作 });
3. 优化为Promise风格(推荐)
原代码标记了async但未利用Promise特性,改成Promise风格更易维护和调用:
const { Readable } = require('stream'); const child_process = require('node:child_process'); function generate_thumbnail(videoFile) { return new Promise((resolve, reject) => { const readable = new Readable(); readable._read = () => {}; readable.push(videoFile.data); readable.push(null); const ffmpeg = child_process.spawn('C:\\FFmpeg\\bin\\ffmpeg', [ '-i', 'pipe:0', '-vframes', '1', '-vf', 'scale=iw*.5:ih*0.5', '-f', 'mjpeg', 'pipe:1' ], { stdio: ['pipe', 'pipe', 'ignore'] }); // 处理各类错误 ffmpeg.stdin.on('error', (err) => { reject(err); readable.destroy(); }); ffmpeg.on('error', (err) => { reject(err); readable.destroy(); }); ffmpeg.on('exit', (code) => { if (code !== 0) { reject(new Error(`FFmpeg执行失败,退出码:${code}`)); } readable.destroy(); }); const buffer = []; ffmpeg.stdout.on('data', (data) => { buffer.push(data); }); ffmpeg.stdout.on('end', () => { const buf = Buffer.concat(buffer); resolve(buf); }); readable.pipe(ffmpeg.stdin); }); } module.exports = { generate_thumbnail };
额外优化
添加-ss参数让FFmpeg快速定位到目标帧,减少读取的数据量,提升处理效率:
const ffmpeg = child_process.spawn('C:\\FFmpeg\\bin\\ffmpeg', [ '-ss', '00:00:01', // 从视频第1秒处取帧 '-i', 'pipe:0', '-vframes', '1', '-vf', 'scale=iw*.5:ih*0.5', '-f', 'mjpeg', 'pipe:1' ], { stdio: ['pipe', 'pipe', 'ignore'] });
内容的提问来源于stack exchange,提问作者Prithivin Lakshminarayanan
相关产品推荐
相关产品推荐

