Node.js中FFmpeg用-vf添加字幕时报输出路径错误求助
Node.js中FFmpeg添加字幕触发"无法打开输出路径"问题的解决
问题描述
在Node.js环境下使用fluent-ffmpeg拼接视频并添加字幕,未添加字幕时可正常编译输出;添加-vf subtitles滤镜后,出现**"无法打开输出路径"**错误,但所有文件路径已确认正确。
添加字幕前的正常代码
shuffleArrayVedios : (array) => { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } return array; }, compile:()=>{ return new Promise(async (resolve, reject) => { try { const videosDir = path.join(__dirname, '../public/images'); const outputVideoPath = path.join(__dirname, '../public/videos', 'output.mp4'); const audioFilePath = path.join(__dirname, '../voiceOver', 'voiceover.wav'); const subtitlesFilePath = path.join(__dirname, '../voiceOver', 'subtitles.srt'); console.log("Download started"); console.log("Audio file path:", audioFilePath); console.log("Subtitles file path:", subtitlesFilePath); let videoFiles = fs.readdirSync(videosDir).filter(file => file.match(/^vid\d+\.mp4$/)); videoFiles = module.exports.shuffleArrayVedios(videoFiles); const command = ffmpeg(); videoFiles.forEach(video => { command.input(path.join(videosDir, video)); }); command.input(audioFilePath); const filterComplex = [ `concat=n=${videoFiles.length}:v=1:a=0[outv]`, `[${videoFiles.length}:a]atempo=1.25[a]` ]; command .complexFilter(filterComplex) .outputOptions(['-map [outv]', '-map [a]', '-shortest']) .output(outputVideoPath) .on('start', (commandLine) => { console.log('Spawned FFmpeg with command: ' + commandLine); }) .on('progress', (progress) => { console.log('Processing: ' + JSON.stringify(progress) + '% done'); }) .on('end', () => { console.log('Video compilation finished!'); resolve(); }) .on('error', (err) => { console.error('Error during video compilation:', err); reject(err); }) .run(); } catch (err) { console.error('Error during processing:', err); reject(err); } }); },
添加字幕后的报错代码
compile: () => { return new Promise(async (resolve, reject) => { try { const videosDir = path.join(__dirname, '../public/images'); const outputVideoPath = path.join(__dirname, '../public/videos', 'output.mp4'); const audioFilePath = path.join(__dirname, '../voiceOver', 'voiceover.wav'); const subtitlesFilePath = path.join(__dirname, '../voiceOver', 'subtitles.srt'); console.log("Download started"); console.log("Audio file path:", audioFilePath); console.log("Subtitles file path:", subtitlesFilePath); let videoFiles = fs.readdirSync(videosDir).filter(file => file.match(/^vid\d+\.mp4$/)); videoFiles = module.exports.shuffleArrayVedios(videoFiles); const command = ffmpeg(); videoFiles.forEach(video => { command.input(path.join(videosDir, video)); }); command.input(audioFilePath); const filterComplex = [ `concat=n=${videoFiles.length}:v=1:a=0[outv]`, `[${videoFiles.length}:a]atempo=1.25[a]` ]; command .complexFilter(filterComplex) .outputOptions(['-map [outv]', '-map [a]', '-shortest']) // 新增的字幕滤镜,导致报错 .outputOptions(`-vf subtitles=${subtitlesFilePath}`) .output(outputVideoPath) .on('start', (commandLine) => { console.log('Spawned FFmpeg with command: ' + commandLine); }) .on('progress', (progress) => { console.log('Processing: ' + JSON.stringify(progress) + '% done'); }) .on('end', () => { console.log('Video compilation finished!'); resolve(); }) .on('error', (err) => { console.error('Error during video compilation:', err); reject(err); }) .run(); } catch (err) { console.error('Error during processing:', err); reject(err); } }); },
报错信息
Download started Audio file path: D:\programming\ai\voiceOver\voiceover.wav Subtitles file path: D:\programming\ai\voiceOver\subtitles.srt GET / 304 73.273 ms - - GET /stylesheets/style.css 304 3.741 ms - - Spawned FFmpeg with command: ffmpeg -i D:\programming\ai\public\images\vid5.mp4 -i D:\programming\ai\public\images\vid2.mp4 -i D:\programming\ai\public\images\vid6.mp4 -i D:\programming\ai\public\images\vid9.mp4 -i D:\programming\ai\public\images\vid7.mp4 -i D:\programming\ai\public\images\vid8.mp4 -i D:\programming\ai\public\images\vid4.mp4 -i D:\programming\ai\public\images\vid3.mp4 -i D:\programming\ai\public\images\vid13.mp4 -i D:\programming\ai\public\images\vid1.mp4 -i D:\programming\ai\public\images\vid10.mp4 -i D:\programming\ai\public\images\vid11.mp4 -i D:\programming\ai\public\images\vid12.mp4 -i D:\programming\ai\voiceOver\voiceover.wav -y -filter_complex concat=n=13:v=1:a=0[outv];[13:a]atempo=1.25[a] -map [outv] -map [a] -shortest -vf subtitles=D:\programming\ai\voiceOver\subtitles.srt D:\programming\ai\public\videos\output.mp4 Error during video compilation: Error: ffmpeg exited with code 4294967274: Error opening output file D:\programming\ai\public\videos\output.mp4. Error opening output files: Invalid argument at ChildProcess.<anonymous> (D:\programming\ai\node_modules\fluent-ffmpeg\lib\processor.js:180:22) at ChildProcess.emit (node:events:519:28) at ChildProcess._handle.onexit (node:internal/child_process:294:12) Error: Error: ffmpeg exited with code 4294967274: Error opening output file D:\programming\ai\public\videos\output.mp4. Error opening output files: Invalid argument at ChildProcess.<anonymous> (D:\programming\ai\node_modules\fluent-ffmpeg\lib\processor.js:180:22) at ChildProcess.emit (node:events:519:28) at ChildProcess._handle.onexit (node:internal/child_process:294:12) Error [ERR_HTTP_HEADERS_SENT]: D:\programming\ai\views\layout.hbs: Cannot set headers after they are sent to the client at ServerResponse.setHeader (node:_http_outgoing:659:11) at ServerResponse.header (D:\programming\ai\node_modules\express\lib\response.js:767:10) at ServerResponse.contentType (D:\programming\ai\node_modules\express\lib\response.js:595:15) at ServerResponse.send (D:\programming\ai\node_modules\express\lib\response.js:145:14) at done (D:\programming\ai\node_modules\express\lib\response.js:1004:10) at D:\programming\ai\node_modules\hbs\lib\hbs.js:106:11 at Object.done (D:\programming\ai\node_modules\hbs\lib\async.js:74:20) at D:\programming\ai\node_modules\hbs\lib\hbs.js:101:20 at D:\programming\ai\node_modules\hbs\lib\hbs.js:82:11 at Object.done (D:\programming\ai\node_modules\hbs\lib\async.js:74:20)
问题原因及解决方法
原因
FFmpeg中不能同时使用-filter_complex(对应代码中的complexFilter)和-vf参数,两者会造成滤镜链冲突,FFmpeg无法正确解析参数,从而抛出误导性的"无法打开输出路径"错误,实际并非路径问题。
解决步骤
- 将字幕滤镜整合到
filterComplex数组:把字幕处理逻辑加到拼接后的视频流上,生成新的输出流标记。 - 修改输出映射:将原来的
[outv]映射改为新生成的字幕处理后的流。 - 删除单独的
-vf参数:去掉.outputOptions('-vf subtitles=...')这一行。
修改后的核心代码片段
// 修改后的filterComplex,添加字幕滤镜 const filterComplex = [ `concat=n=${videoFiles.length}:v=1:a=0[outv]`, // 拼接视频 `[${videoFiles.length}:a]atempo=1.25[a]`, // 处理音频速度 `[outv]subtitles=${subtitlesFilePath}[finalv]` // 给拼接后的视频加字幕,生成finalv流 ]; command .complexFilter(filterComplex) // 修改映射为处理字幕后的finalv流 .outputOptions(['-map [finalv]', '-map [a]', '-shortest']) // 去掉单独的-vf参数 .output(outputVideoPath) // 后续的事件监听保持不变 ...
完整修改后的compile函数
compile: () => { return new Promise(async (resolve, reject) => { try { const videosDir = path.join(__dirname, '../public/images'); const outputVideoPath = path.join(__dirname, '../public/videos', 'output.mp4'); const audioFilePath = path.join(__dirname, '../voiceOver', 'voiceover.wav'); const subtitlesFilePath = path.join(__dirname, '../voiceOver', 'subtitles.srt'); console.log("Download started"); console.log("Audio file path:", audioFilePath); console.log("Subtitles file path:", subtitlesFilePath); let videoFiles = fs.readdirSync(videosDir).filter(file => file.match(/^vid\d+\.mp4$/)); videoFiles = module.exports.shuffleArrayVedios(videoFiles); const command = ffmpeg(); videoFiles.forEach(video => { command.input(path.join(videosDir, video)); }); command.input(audioFilePath); const filterComplex = [ `concat=n=${videoFiles.length}:v=1:a=0[outv]`, `[${videoFiles.length}:a]atempo=1.25[a]`, `[outv]subtitles=${subtitlesFilePath}[finalv]` ]; command .complexFilter(filterComplex) .outputOptions(['-map [finalv]', '-map [a]', '-shortest']) .output(outputVideoPath) .on('start', (commandLine) => { console.log('Spawned FFmpeg with command: ' + commandLine); }) .on('progress', (progress) => { console.log('Processing: ' + JSON.stringify(progress) + '% done'); }) .on('end', () => { console.log('Video compilation finished!'); resolve(); }) .on('error', (err) => { console.error('Error during video compilation:', err); reject(err); }) .run(); } catch (err) { console.error('Error during processing:', err); reject(err); } }); },
内容的提问来源于stack exchange,提问作者yahiya
相关产品推荐
相关产品推荐

