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

如何将Python BytesIO功能转换为Node.js/TypeScript处理内存媒体文件?

在Node.js(Svelte-Kit)中内存调用FFmpeg解析媒体时长

问题背景

我正在使用带Node.js适配器的Svelte-Kit,需要整合Python后端逻辑与Svelte前端。现有一个媒体文件的Buffer,希望全程在内存中处理(类似Python的BytesIO)。需要将以下Python函数转换为TypeScript/Node.js:

def get_duration(input: BytesIO):
    command = "ffmpeg -i -".split(" ")
    output = subprocess.run(
        command,
        input=input.read(),
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    duration = None
    lines = output.stderr.decode().split("\n")
    print(lines)
    for line in lines:
        if "Duration:" in line:
            match = re.search(r"Duration: (\d+):(\d+):(\d+.\d+)", line)
            if match:
                hours = int(match.group(1))
                minutes = int(match.group(2))
                seconds = float(match.group(3))
                duration = hours * 3600 + minutes * 60 + seconds
            break
    input.seek(0)
    print(duration)
    return duration

该函数通过调用FFmpeg从stdin传入数据,捕获stderr解析媒体时长。此前尝试使用ffprobe时时长始终为0,因此改用ffmpeg。不清楚Node.js中如何实现内存内的stdin输入及stdout/stderr捕获,不确定使用流还是Buffer,也不确定createWriteStream是否适配Buffer。


实现方案

Node.js中可通过child_process.spawn实现类似Python的subprocess功能,支持直接向子进程stdin写入Buffer,同时捕获stderr输出进行解析,全程无需写入磁盘,完全在内存中处理。

TypeScript实现代码

import { spawn } from 'child_process';
import type { Buffer } from 'buffer';

async function getDuration(inputBuffer: Buffer): Promise<number | null> {
  return new Promise((resolve, reject) => {
    // 启动FFmpeg进程,从stdin读取输入,忽略stdout,捕获stderr
    const ffmpegProcess = spawn('ffmpeg', ['-i', '-'], {
      stdio: ['pipe', 'ignore', 'pipe']
    });

    let stderrLog = '';

    // 收集stderr输出
    ffmpegProcess.stderr.on('data', (chunk) => {
      stderrLog += chunk.toString();
    });

    // 处理进程退出事件
    ffmpegProcess.on('close', (exitCode) => {
      // FFmpeg未指定输出文件时会以1退出,属于正常情况
      if (exitCode !== 0 && exitCode !== 1) {
        return reject(new Error(`FFmpeg进程异常退出,代码: ${exitCode}`));
      }

      // 正则匹配时长信息
      const durationRegex = /Duration: (\d+):(\d+):(\d+\.\d+)/;
      const matchResult = stderrLog.match(durationRegex);

      if (!matchResult) {
        return resolve(null);
      }

      // 计算总秒数
      const hours = parseInt(matchResult[1], 10);
      const minutes = parseInt(matchResult[2], 10);
      const seconds = parseFloat(matchResult[3]);
      const totalSeconds = hours * 3600 + minutes * 60 + seconds;

      resolve(totalSeconds);
    });

    // 处理进程启动错误
    ffmpegProcess.on('error', (error) => {
      reject(new Error(`启动FFmpeg失败: ${error.message}`));
    });

    // 向stdin写入Buffer并关闭输入流
    ffmpegProcess.stdin.write(inputBuffer, (writeError) => {
      if (writeError) {
        reject(writeError);
      }
      ffmpegProcess.stdin.end();
    });
  });
}

核心细节说明

  • 进程选择:使用spawn而非exec/execFile,因为它支持流式IO,更适合内存中处理Buffer,避免数据量过大时的性能问题。
  • stdio配置:['pipe', 'ignore', 'pipe']分别对应stdin可写入、stdout忽略(无需FFmpeg输出文件)、stderr可捕获。
  • Buffer写入:直接向ffmpegProcess.stdin写入Buffer,写完后调用end()告知FFmpeg输入结束,触发后续处理。
  • 退出码处理:FFmpeg在无输出文件时会返回1,这是预期行为,无需判定为错误。
  • 时长解析:通过正则匹配stderr中的时长字符串,转换为总秒数,逻辑与Python版本完全一致。

使用示例

// 示例:从内存Buffer中获取媒体时长
async function getMediaDurationExample() {
  // 假设mediaBuffer是你的媒体文件Buffer(比如从请求、内存生成等)
  const mediaBuffer: Buffer = Buffer.from(...);
  
  try {
    const duration = await getDuration(mediaBuffer);
    console.log(`媒体总时长:${duration} 秒`);
  } catch (error) {
    console.error('解析时长失败:', error);
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:08:11