如何将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
相关产品推荐
相关产品推荐

