如何在Node.js中为FFmpeg实现视频编码队列?
解决方案:实现FFmpeg转码任务的串行执行
你的问题核心在于forEach是同步遍历逻辑,会一次性触发所有异步转码任务,导致FFmpeg同时占用过多系统资源引发报错。要实现任务串行执行(一个完成后再启动下一个),可以通过「将回调风格的转码函数改为Promise风格」,配合async/await和for...of循环来实现。
步骤1:将covertVideo改为Promise风格
把原来的回调写法替换为Promise,这样可以用await等待转码完成:
const Ffmpeg = require("fluent-ffmpeg"); function covertVideo(filename) { return new Promise((resolve, reject) => { const ffmpeg = new Ffmpeg(filename); ffmpeg.setFfmpegPath(pathToFfmpeg) .addOptions("-threads 1") .fps(23) .complexFilter([ "scale=w='if(gt(a,0.75),240,trunc(320*a/2)*2)':h='if(lt(a,0.75),320,trunc(240/a/2)*2)',pad=w=240:h=320:x='if(gt(a,0.75),0,(240-iw)/2)':y='if(lt(a,0.75),0,(320-ih)/2)':color=black[scaled]" ]) .on('error', function(err) { console.log(`转码出错:${filename} - ${err.message}`); reject(false); }) .on('end', function() { console.log(`转码完成:${filename}`); resolve(true); }) .save(`./tmp/${filename}`); }); }
步骤2:用async/await + for...of实现串行遍历
替换原来的forEach,用for...of循环逐个处理视频,确保上一个转码完成后再启动下一个:
async function processVideos(videos) { for (const video of videos) { // 注意:根据你的videos数组结构取文件名,比如video是字符串则直接用,是对象则取video.filename const filename = video; try { const result = await covertVideo(filename); // 这里添加转码完成后的逻辑,比如记录结果、更新状态等 if (result) { console.log(`处理成功:${filename}`); } } catch (err) { console.log(`处理失败:${filename}`); } } } // 启动批量处理 processVideos(videos);
补充:可选的并发控制
如果不想完全串行,而是想同时处理N个任务(比如2个),可以用分批处理的方式:
async function processVideosInBatches(videos, batchSize = 2) { for (let i = 0; i < videos.length; i += batchSize) { const batch = videos.slice(i, i + batchSize); await Promise.all( batch.map(video => covertVideo(video)) ); console.log(`完成一批转码,共${batch.length}个文件`); } } // 启动分批处理 processVideosInBatches(videos, 2);
关键说明
forEach不支持异步等待:它会同步遍历数组,立即执行所有回调,完全不管里面的异步操作何时完成,因此会一次性启动所有FFmpeg进程,导致资源耗尽。- Promise + async/await:通过Promise包装异步转码操作,用
await强制等待当前任务完成后再执行下一个,从根源上避免了并发过载问题。
内容的提问来源于stack exchange,提问作者Hall45
相关产品推荐
相关产品推荐

