从节点生成时 ffmpeg 缓冲标准输入
ffmpeg buffering stdin when spawned from node
我正在尝试使用 node.js 将 png 数据写入 ffmpeg 以创建视频。我已验证以下代码有效:
let ffmpeg = spawn(
"ffmpeg",
[
"-y",
"-loglevel", "info",
"-f", "image2pipe",
"-c:v", "png",
"-r", `${this.fps}`,
"-i", "-",
"-an",
"-vcodec", "libx264",
"-pix_fmt", "yuv420p",
"output.mp4",
],
);
ffmpeg.stdout.on('data', data => {
console.log(`ffmpeg stdout: ${data}`);
});
ffmpeg.stderr.on('data', data => {
console.log(`ffmpeg stderr: ${data}`);
});
let bufs = [];
let p = Promise.resolve();
for (let i = 0; i < this.frameData.length; i++) {
p = p.then(_ => new Promise(resolve => {
this.renderFrame(i);
this.renderer.domElement.toBlob(blob => {
blob.arrayBuffer().then(arr => {
console.log('writing...');
let uInt8Arr = new Uint8Array(arr);
// ffmpeg.stdin.write(uInt8Arr);
bufs.push(uInt8Arr);
resolve();
});
});
}));
}
p = p.then(_ => {
for (let buf of bufs) {
ffmpeg.stdin.write(buf);
}
ffmpeg.stdin.end();
});
抱歉,如果它看起来很复杂,promises 被用作 toBlob()
异步运行但必须按顺序编写帧这一事实的解决方法。
该代码按照编写的方式正常工作,但它不必要地低效,因为它将帧数据写入数组只是为了稍后将其写入 ffmpeg。但是,如果我取消注释 ffmpeg.stdin.write(uInt8Arr);
并注释将数组数据复制到 ffmpeg 的循环,ffmpeg 将简单地挂在最后而不会生成任何视频。如果我随后执行 "large enough" 操作,例如保存文件或生成新进程,ffmpeg 将正确生成视频。
我怀疑是某种缓冲问题导致了这种情况,但我不完全理解它或不知道如何解决它。我已经尝试使用 ffmpeg.kill()
向 ffmpeg 发送各种信号,并按照建议 here 通过 stdbuf
运行 发送各种信号,但无济于事。有什么解决方法吗?
对于偶然发现此问题的任何人,解决方案是将对 ffmpeg.stdin.close()
的调用替换为 ffmpeg.stdin.destroy()
。
我正在尝试使用 node.js 将 png 数据写入 ffmpeg 以创建视频。我已验证以下代码有效:
let ffmpeg = spawn(
"ffmpeg",
[
"-y",
"-loglevel", "info",
"-f", "image2pipe",
"-c:v", "png",
"-r", `${this.fps}`,
"-i", "-",
"-an",
"-vcodec", "libx264",
"-pix_fmt", "yuv420p",
"output.mp4",
],
);
ffmpeg.stdout.on('data', data => {
console.log(`ffmpeg stdout: ${data}`);
});
ffmpeg.stderr.on('data', data => {
console.log(`ffmpeg stderr: ${data}`);
});
let bufs = [];
let p = Promise.resolve();
for (let i = 0; i < this.frameData.length; i++) {
p = p.then(_ => new Promise(resolve => {
this.renderFrame(i);
this.renderer.domElement.toBlob(blob => {
blob.arrayBuffer().then(arr => {
console.log('writing...');
let uInt8Arr = new Uint8Array(arr);
// ffmpeg.stdin.write(uInt8Arr);
bufs.push(uInt8Arr);
resolve();
});
});
}));
}
p = p.then(_ => {
for (let buf of bufs) {
ffmpeg.stdin.write(buf);
}
ffmpeg.stdin.end();
});
抱歉,如果它看起来很复杂,promises 被用作 toBlob()
异步运行但必须按顺序编写帧这一事实的解决方法。
该代码按照编写的方式正常工作,但它不必要地低效,因为它将帧数据写入数组只是为了稍后将其写入 ffmpeg。但是,如果我取消注释 ffmpeg.stdin.write(uInt8Arr);
并注释将数组数据复制到 ffmpeg 的循环,ffmpeg 将简单地挂在最后而不会生成任何视频。如果我随后执行 "large enough" 操作,例如保存文件或生成新进程,ffmpeg 将正确生成视频。
我怀疑是某种缓冲问题导致了这种情况,但我不完全理解它或不知道如何解决它。我已经尝试使用 ffmpeg.kill()
向 ffmpeg 发送各种信号,并按照建议 here 通过 stdbuf
运行 发送各种信号,但无济于事。有什么解决方法吗?
对于偶然发现此问题的任何人,解决方案是将对 ffmpeg.stdin.close()
的调用替换为 ffmpeg.stdin.destroy()
。