You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NodeJS中用ReadStream/Buffer调用ffprobe时进程挂起问题求助

解决ffprobe进程挂起问题

问题根源

  1. 无效参数导致命令异常:-ar是ffmpeg用于设置输出采样率的参数,ffprobe仅负责媒体探测,不支持该参数,会导致命令解析错误,进程无法正常执行。
  2. 未处理stderr缓冲区阻塞:子进程的stderr流如果不监听,当输出内容填满系统缓冲区时,进程会被阻塞挂起。
  3. ReadStream处理方式低效且易出问题:将ReadStream先转为Buffer再写入stdin,既浪费内存,又可能因手动调用stdin.end()的时机不当导致ffprobe未完成读取。

修复方案

  1. 移除-ar参数,ffprobe不需要设置输出采样率。
  2. 添加stderr流监听,避免缓冲区阻塞。
  3. 对于ReadStream,直接通过pipe方式写入ffprobe的stdin,自动处理流的传输和结束事件,无需手动转Buffer和调用stdin.end()。
  4. 修正close事件的参数,ffprobe的close事件回调参数为退出码和信号,而非输出内容。

修改后的probeStream代码

let probeStream = function (streamOrBuffer, params) {
  var self = this;
  return new Promise(async (resolve, reject) => {
    var loglevel = self.logger.isDebug() ? 'debug' : 'error';
    var args = [];
    args = args.concat([
      '-v', 'quiet',
      '-loglevel', loglevel,
      '-print_format', 'json',
      '-show_chapters',
      '-show_format',
      '-show_streams',
      '-i', 'pipe:'
    ]);
    // 移除无效的-ar参数

    const opts = self._options.child_process;
    self.logger.debug("probeStream probe options: %s", args.join(" "));
    var result = '';
    const ffprobe = cp.spawn('ffprobe', args, opts)
      .on('message', msg => self.logger.info(msg))
      .on('error', reject)
      .on('exit', (code, signal) => {
        self.logger.debug("probeStream [exit] code:%s signal:%s", code, signal);
        // 非0退出码直接抛出错误
        if (code !== 0) {
          reject(new Error(`ffprobe exited with code ${code}`));
        }
      })
      .on('close', (code, signal) => {
        self.logger.debug("probeStream [close] code:%s signal:%s", code, signal);
        if (code === 0) {
          try {
            // 解析JSON格式的探测结果
            resolve(JSON.parse(result));
          } catch (err) {
            reject(new Error(`Failed to parse ffprobe output: ${err.message}`));
          }
        } else {
          reject(new Error(`ffprobe closed with code ${code}`));
        }
      });

    // 收集stdout输出的探测结果
    ffprobe.stdout.on('data', function (data) {
      result += data.toString();
    });

    // 处理stderr,避免缓冲区阻塞导致进程挂起
    ffprobe.stderr.on('data', function (data) {
      self.logger.debug("ffprobe stderr: %s", data.toString());
    });

    ffprobe.stdin.on("error", (err) => {
      if (err.code !== "EPIPE") {
        self.logger.warn("probeStream ffprobe stdin error", err);
        reject(err);
      }
    });

    if (streamOrBuffer instanceof Buffer) { // 处理Buffer输入
      ffprobe.stdin.write(streamOrBuffer, (err) => {
        if (err) reject(err);
        ffprobe.stdin.end();
      });
    } else { // 处理ReadStream输入
      // 直接pipe,自动处理流的传输和结束事件
      streamOrBuffer.pipe(ffprobe.stdin);
      streamOrBuffer.on('error', reject);
    }
  });
}//probeStream

额外优化

  • 移除了无用的sample_rate参数,因为ffprobe不需要该参数。
  • 添加了JSON解析的错误处理,避免无效输出导致程序崩溃。
  • 对非0退出码进行了明确的错误处理,便于排查问题。

内容的提问来源于stack exchange,提问作者loretoparisi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:45:16