【问题标题】:ENOENT Error in Node When Calling Ffmpeg binary from Fluent-Ffmpeg Api从 Fluent-Ffmpeg Api 调用 Ffmpeg 二进制文件时节点出现 ENOENT 错误
【发布时间】:2018-01-22 19:00:26
【问题描述】:

背景

我正在 node.js 中连接一个 firebase 函数。目的是将入站音频剪辑解析为设定的长度。使用 ffmpeg 和 fluent-ffmpeg。

问题

当在 firebase 中触发该函数时,当 Fluent-Ffmpeg 尝试访问 Ffmpeg 二进制文件时出现 ENOENT 错误

Firebase 调试输出

错误:{ 错误:spawn ./Cloud/functions/node_modules/ffmpeg-binaries/bin/ffmpeg ENOENT 在exports._errnoException (util.js:1018:11) 在 Process.ChildProcess._handle.onexit (internal/child_process.js:193:32) 在 onErrorNT (internal/child_process.js:367:16) 在 _combinedTickCallback (内部/进程/next_tick.js:80:11) 在 process._tickDomainCallback (internal/process/next_tick.js:128:9) 代码:'ENOENT',errno: 'ENOENT',系统调用:'spawn ./Cloud/functions/node_modules/ffmpeg-binaries/bin/ffmpeg',路径: './Cloud/functions/node_modules/ffmpeg-binaries/bin/ffmpeg',
spawnargs: ['-formats'] }

预期结果

入站文件被下载到临时目录,被裁剪,然后作为裁剪文件重新上传到 Firebase 存储。

环境

  • mac 客户端/firebase 存储
  • 节点v8.1.0
  • ffmpeg v3.2.2
  • fluent-ffmpeg v2.1.2

代码 [更新以反映 Svenskunganka 的变化。现在工作]

const ffmpeg = require('fluent-ffmpeg');
const PREVIEW_PREFIX = 'preview_';

exports.generatePreviewClip = functions.storage.object('audioFiles').onChange(event => {

      //console.log('Times this function has run: ', run++);

      const object = event.data; // The Storage object.
      const fileBucket = object.bucket; // The Storage bucket that contains the file.
      const filePath = object.name; // File path in the bucket.
      const contentType = object.contentType; // File content type.
      const resourceState = object.resourceState; // The resourceState is 'exists' or 'not_exists' (for file/folder deletions).
      const metageneration = object.metageneration; // Number of times metadata has been generated. New objects have a value of 1.

      // Exit if this is triggered on a file that is not an audio file.
      if (!contentType.startsWith('audio/')) {
        console.log('This is not an audio file.');
        console.log('This is the file:', filePath);
        return;
      }

      // Get the file name.
      const fileName = path.basename(filePath);
      console.log('Working with filename', fileName);
      // Exit if the file is already an audio clip.
      if (fileName.startsWith(PREVIEW_PREFIX)) {
        console.log('Already a preview clip.');
        return;
      }

      // Exit if this is a move or deletion event.
      if (event.data.resourceState === 'not_exists') {
        console.log('This is a deletion event.');
        return;
      }

      // Exit if file exists but is not new and is only being triggered
      // because of a metadata change.
      if (resourceState === 'exists' && metageneration > 1) {
        console.log('This is a metadata change event.');
        return;
      }

      // Download file from bucket.

      const bucket = gcs.bucket(fileBucket);
      const tempFilePath = path.join(os.tmpdir(), fileName);
      return bucket.file(filePath).download({
        destination: tempFilePath
      }).then(() => {

        console.log('Audio file downloaded locally to temp directory', tempFilePath);

    var ffmpegPath = require("ffmpeg-binaries").ffmpegPath();
    var ffprobePath = require("ffmpeg-binaries").ffprobePath();

    // Generate a croped file using ffmpeg.
    var command = new ffmpeg(tempFilePath);
        command.setFfmpegPath(ffmpegPath);
        command.setFfprobePath(ffprobePath);

        command
              .setStartTime('00:00:03')
              .setDuration('10')
              .output(tempFilePath)
              .on('end', function() {
                    console.log('Audio Crop Done Successfully');
               })
               .on('error', function(err)
               {
                  console.log('Error:', err);
               }).run();

              }).then(() => {
        console.log('Preview file created at', tempFilePath);
        // We add a 'preview_' prefix to the audio file name. that's how it will appear in firebase.
        const previewFileName = PREVIEW_PREFIX + fileName;
        console.log('previewFileName is', previewFileName)
        const previewFilePath = path.join(path.dirname(filePath), previewFileName);
        console.log('previewFilePath is', previewFilePath);
        // Uploading the preview file.
        return bucket.upload(tempFilePath, {destination: previewFilePath});
      // Once the file has been uploaded delete the local file to free up disk space.
      }).then(() => fs.unlinkSync(tempFilePath));

      // [END audio file generation]

    });

我的 ffmpeg-binaries/bin 目录的内容和结构

-rwxrwxrwx  1 sherpa  staff    24M Dec 10  2016 ffmpeg
-rwxr--r--  1 sherpa  staff    35M Jan 12  2017 ffmpeg.exe
-rwxr--r--  1 sherpa  staff    35M Jan 12  2017 ffplay.exe
-rwxrwxrwx  1 sherpa  staff    24M Dec 10  2016 ffprobe
-rwxr--r--  1 sherpa  staff    35M Jan 12  2017 ffprobe.exe
-rwxrwxrwx  1 sherpa  staff    22M Dec 10  2016 ffserver

我尝试过的事情

  • 我可以从命令行执行ffmpeg
  • sudo chmod -R u+x ffmpeg-binaries/
  • ffmpeg 设置在全局路径中
  • 在 setFfmpegPath 中使用 ffmpeg.exe 二进制文件,得到相同的结果
    • 错误:{ 错误:spawn ./Cloud/functions/node_modules/ffmpeg-binaries/bin/ffmpeg.exe ENOENT
  • 使用了许多不同的 setFfmpegPath 路径结构,例如:
    • ./Cloud/functions/node_modules/ffmpeg-binaries/bin/ffmpeg
    • node_modules/ffmpeg-binaries/bin/ffmpeg
    • ./Cloud/functions/node_modules/ffmpeg-binaries/bin/

感谢您的任何建议。

【问题讨论】:

  • 如果你是ls node_modules/ffmpeg-binaries/bin/,二进制文件在吗? ENOENT 错误是 Error NO ENTry 的缩写,这意味着它要查找的内容不存在。你在安装 npm/yarn 的过程中是否遇到任何错误?
  • npm 期间没有错误。是的,二进制文件在那里并且具有完全的访问权限。
  • 谢谢,问题可能与您提供setFfmpegPath 方法的路径有关。如果您将其更改为:setFfmpegPath(path.join(path.dirname(require.resolve("ffmpeg-binaries")), "bin/ffmpeg"))。它未经测试,但可以使用 require.resolvepath 模块。
  • 非常感谢。获取 - 找不到模块 'ffmpeg‌​-binaries' - 现在但至少这是一个新错误。也许模块需要正确注册?我会尽力追捕这个...
  • 哎呀,错过了那部分。你是对的,你必须调用返回的函数:var ffmpegPath = require("ffmpeg-binaries").ffmpegPath();

标签: node.js firebase ffmpeg firebase-storage fluent-ffmpeg


【解决方案1】:

我们在 cmets 中解决了该问题的问题,但我会为可能遇到相同问题的任何未来用户发布答案。问题是提供给setFfmpegPath() 方法的路径是相对的,而应该是绝对的。 ffmpeg-binaries 模块导出了几个帮助函数,您可以调用它们来获取其二进制文件的路径:

var ffmpeg = require("fluent-ffmpeg")
var ffmpegPath = require("ffmpeg-binaries")

ffmpeg
  .setFfmpegPath(ffmpegPath)
  ...

确保您已安装 ffmpeg-binariesnpm i -S ffmpeg-binaries

2018 年 11 月 7 日更新:

ffmpeg-binaries 包在4.0.0 版本中发布了一项新的重大更改,该更改删除了它导出的所有函数,而只是导出了一个指向ffmpeg 所在目录的字符串。这在提交 009e4d5 中已更改。
我已经更新了答案以反映这些变化。

【讨论】:

  • ffmpegBinaries.ffmpegPath() 不是函数 - 我收到这样的错误
  • @Vishnu 那是因为自从我写这个答案以来,ffmpeg-binaries 发布了一个新的主要版本,其中包含一个改变其 API 的重大更改。它们不再导出函数,而只是导出一个指向 ffmpeg 所在目录的字符串。请参阅我的更新答案。
  • 感谢您的回复。我没有bin目录怎么办
  • 正在生成缩略图,但生成时间较长
猜你喜欢
  • 1970-01-01
  • 2013-11-14
  • 1970-01-01
  • 2016-10-07
  • 1970-01-01
  • 1970-01-01
  • 2017-12-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多