Node.js child_process调用ffmpeg报错:TypeError: Cannot read property '_writableState' of undefined
我一眼就看出问题出在你处理ffmpeg.stdin.write的方式上,咱们一步步拆解:
错误根源
你写的frames.forEach(ffmpeg.stdin.write)这行代码有个典型的JavaScript上下文丢失问题:当你直接把ffmpeg.stdin.write作为forEach的回调函数时,这个方法的this指向不再是ffmpeg.stdin这个可写流对象了,而是变成了undefined(严格模式下)。而write方法内部需要依赖this来访问流的_writableState属性,所以才会抛出这个错误。
快速修复
有两种简单的方式解决这个上下文问题:
方式1:用箭头函数包裹(推荐)
箭头函数会自动继承外部的上下文,确保write方法的this正确指向ffmpeg.stdin:
frames.forEach(frame => ffmpeg.stdin.write(frame))
方式2:用bind绑定上下文
显式把write方法的this绑定到ffmpeg.stdin上:
frames.forEach(ffmpeg.stdin.write.bind(ffmpeg.stdin))
代码里的其他坑
除了这个错误,你的代码还有几个需要修正的地方,否则后续可能还会出问题:
stderr事件监听错误
你写的ffmpeg.stderr.on("data", reject(data))会立即调用reject,而不是等到stderr有数据时才触发。应该改成:ffmpeg.stderr.on("data", (data) => reject(new Error(data.toString())))(把Buffer转成字符串,方便查看错误信息)
没有关闭
stdin
发送完所有帧后,需要调用ffmpeg.stdin.end()告诉ffmpeg没有更多输入了,否则ffmpeg会一直等待输入,进程永远不会退出。ffmpeg输出逻辑矛盾
你当前的ffmpeg命令是把结果写入output.mkv文件,但同时又在监听stdout收集数据——这是冲突的。如果你的目标是获取编码后的视频数据(而不是写入文件),需要调整ffmpeg参数,把输出重定向到stdout:const ffmpeg = spawn("ffmpeg", [ "-f", "image2pipe", "-i", "-", "-f", "matroska", // 指定输出格式 "-" // 输出到stdout ])如果你的目标是生成
output.mkv文件,那stdout不会有数据,Buffer.concat(chunks)会是空的,需要调整Promise的resolve逻辑(比如resolve文件路径或者成功状态)。
修复后的完整代码
这里给出一个兼顾正确性和健壮性的版本:
import { spawn } from "child_process" export default frames => { // 调整ffmpeg参数,输出到stdout(如果要写文件,改回"output.mkv"即可) const ffmpeg = spawn("ffmpeg", [ "-f", "image2pipe", "-i", "-", "-f", "matroska", "-" ]) // 正确发送每帧数据 frames.forEach(frame => ffmpeg.stdin.write(frame)) // 关闭stdin,告知ffmpeg输入结束 ffmpeg.stdin.end() return new Promise((resolve, reject) => { const chunks = [] ffmpeg.stdout.on("data", chunk => chunks.push(chunk)) // 处理错误输出 ffmpeg.stderr.on("data", (data) => reject(new Error(`ffmpeg error: ${data.toString()}`))) // 处理进程退出 ffmpeg.on("close", code => { if (code !== 0) { return reject(new Error(`ffmpeg exited with code ${code}`)) } resolve(Buffer.concat(chunks)) }) // 处理进程启动失败的情况 ffmpeg.on("error", err => reject(new Error(`Failed to spawn ffmpeg: ${err.message}`))) }) }
内容的提问来源于stack exchange,提问作者functorial

