通过Node.js运行FFmpeg时出现错误

11

我正在尝试在Node中运行ffmpeg,但是遇到了错误。这是代码:

var exec = require('child_process').exec;

var cmd = '/home/ubuntu/bin/ffmpeg -i /home/ubuntu/input.flv -s 640x480 -y -codec:a aac -b:a 44.1k -r 15 -b:v 1000k -codec:v h264 -f mp4 /home/ubuntu/output.mp4';

exec(cmd, function(err, stdout, stderr) {
    if (err) console.log('err:\n' + err);
    if (stderr) console.log('stderr:\n' + stderr);
    console.log('stdout:\n' + stdout);
});
当我运行这个节点脚本时,我会得到以下错误:
err:
Error: Command failed: /home/ubuntu/bin/ffmpeg -i /home/ubuntu/input.flv -s 640x480 -y -codec:a aac -b:a 44.1k -r 15 -b:v 1000k -codec:v h264 -f mp4 /home/ubuntu/output.mp4
ffmpeg version N-83323-g126e965 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
  configuration: --prefix=/home/ubuntu/ffmpeg_build --pkg-config-flags=--static --extra-cflags=-I/home/ubuntu/ffmpeg_build/include --extra-ldflags=-L/home/ubuntu/ffmpeg_build/lib --bindir=/home/ubuntu/bin --enable-gpl --enable-libopus --enable-libvpx --enable-libvorbis --enable-libmp3lame --enable-libfdk-aac --enable-libx264 --enable-nonfree
  libavutil      55. 45.100 / 55. 45.100
  libavcodec     57. 75.100 / 57. 75.100
  libavformat    57. 66.101 / 57. 66.101
  libavdevice    57.  2.100 / 57.  2.100
  libavfilter     6. 72.100 /  6. 72.100
  libswscale      4.  3.101 /  4.  3.101
  libswresample   2.  4.100 /  2.  4.100
  libpostproc    54.  2.100 / 54.  2.100
/home/ubuntu/input.flv: Invalid data found when processing input

stderr:
ffmpeg version N-83323-g126e965 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
  configuration: --prefix=/home/ubuntu/ffmpeg_build --pkg-config-flags=--static --extra-cflags=-I/home/ubuntu/ffmpeg_build/include --extra-ldflags=-L/home/ubuntu/ffmpeg_build/lib --bindir=/home/ubuntu/bin --enable-gpl --enable-libopus --enable-libvpx --enable-libvorbis --enable-libmp3lame --enable-libfdk-aac --enable-libx264 --enable-nonfree
  libavutil      55. 45.100 / 55. 45.100
  libavcodec     57. 75.100 / 57. 75.100
  libavformat    57. 66.101 / 57. 66.101
  libavdevice    57.  2.100 / 57.  2.100
  libavfilter     6. 72.100 /  6. 72.100
  libswscale      4.  3.101 /  4.  3.101
  libswresample   2.  4.100 /  2.  4.100
  libpostproc    54.  2.100 / 54.  2.100
/home/ubuntu/input.flv: Invalid data found when processing input

stdout:

但是当我运行时

/home/ubuntu/bin/ffmpeg -i /home/ubuntu/input.flv -s 640x480 -y -codec:a aac -b:a 44.1k -r 15 -b:v 1000k -codec:v h264 -f mp4 /home/ubuntu/output.mp4

在终端中直接运行,它完美地工作。我认为这与node运行命令的方式有关,但我的所有谷歌搜索都没有返回任何有用的结果。非常感谢任何帮助。


尝试使用spawn代替exec,因为exec的输出缓冲区有限。或者运行ffmpeg -loglevel error -i ...来抑制信息消息。 - Aikon Mogwai
我添加了“-loglevel error”,但仍然出现相同的错误。 - Greyhammer
下一步尝试:
  1. 确保节点应用程序具有读写文件的权限,例如您可以将此放在100%受保护的文件夹中并比较结果;
  2. 尝试将{cwd: __dirname}作为第二个参数传递给exec
  3. 尝试使用“spawn”获取相同结果或检测问题所在。
- Aikon Mogwai
我认为这与Node的异步特性有关,以及Node不等待ffmpeg完成其任务。因此,我将尝试使用child_process.execSync - Greyhammer
2个回答

32

这与Node的异步性质无关。Node进程总是等待生成的子进程(使用spawn和exec都可以创建子进程)。

我建议您在使用ffmpeg时使用spawn,原因如下:

  • spawn以不同于exec的方式处理参数。它自己启动进程,并将参数数组传递给该进程。但exec将整个命令作为字符串传递给shell进程。这可能导致一些转义错误。

  • ffmpeg大多数时间都是“长时间运行”的进程。最好在它仍在运行时解析其输出。exec不会在进程完成之前提供输出。

  • ffmpeg可能会产生大量的输出数据。这会对exec产生问题,因为它会使用有限缓冲区启动进程(如Aikon上面提到的)。spawn使用流实时以块的方式传递数据。

以下是包含您的cmd/args的示例:

var spawn = require('child_process').spawn;

var cmd = '/home/ubuntu/bin/ffmpeg';

var args = [
    '-y', 
    '-i', '/home/ubuntu/input.flv',
    '-s', '640x480', 
    '-codec:a', 'aac', 
    '-b:a', '44.1k', 
    '-r', '15', 
    '-b:v', '1000k', 
    '-c:v','h264', 
    '-f', 'mp4', '/home/ubuntu/output.mp4'
];

var proc = spawn(cmd, args);

proc.stdout.on('data', function(data) {
    console.log(data);
});

proc.stderr.setEncoding("utf8")
proc.stderr.on('data', function(data) {
    console.log(data);
});

proc.on('close', function() {
    console.log('finished');
});

1
你的 var cmd = '"/home/ubuntu/bin/ffmpeg"'; 上的双引号导致了错误。我把它们移除了,现在它可以正常工作了。谢谢。 - Greyhammer
2
几乎。确保设置编码以读取输出proc.stderr.setEncoding("utf8") - God Himself
“data”事件可能会在stdout和stderr上被多次调用,因此您需要将这些块缓冲到最终字符串中,在“close”事件中处理。 - danneu

9

基于另一个答案:

runCommand.js

var spawn = require('child_process').spawn;
module.exports = (cmd, args, onData, onFinish) => {
    var proc = spawn(cmd, args.split(' '));
    proc.stdout.on('data', onData);
    proc.stderr.setEncoding("utf8")
    proc.stderr.on('data', err => console.log(err) );
    proc.on('close', onFinish);
}

main.js:

runCommand('ffmpeg', '-y -f concat -i list.txt -c copy output-final.mp4', 
        data => console.log(data), () => console.log('finished'))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接