节点。缓冲数据到Ffmpeg

时间:2022-01-02 21:26:00

I used Node.js and Ffmpeg to create animations. Because I was trying to avoid third-party avi/mp4 parsers, I decided to output the animation as raw rgb24 data file and then use some program to convert it to mp4 file.

我使用节点。js和Ffmpeg创建动画。因为我试图避免第三方avi/mp4解析器,所以我决定将动画输出为原始rgb24数据文件,然后使用一些程序将其转换为mp4文件。

I found that Ffmpeg is free and open source which can do exactly it. So, I made a Node.js application which allocates a Buffer of size 1920 x 1080 x 3 (width times height times number of bytes per pixel), then I created a rendering context library, and finally I animated frame by frame and saved each frame consecutivelly in a binary file (using fs module).

我发现Ffmpeg是免费的和开源的,它可以做到这一点。我做了一个节点。js应用程序分配了一个大小为1920 x 1080 x 3的缓冲区(宽度乘以高度乘以每个像素的字节数),然后我创建了一个呈现上下文库,最后我逐帧动画化并连续地将每个帧保存在一个二进制文件中(使用fs模块)。

Then I invoked Ffmpeg to convert it to mp4 file and it works very good. Animations are pretty easy to make and Ffmpeg does its job correctly.

然后我调用Ffmpeg将它转换为mp4文件,效果非常好。动画很容易制作,Ffmpeg正确地完成了它的工作。

However, the only problem is because it is very slow and eats space on hard disk. I want to create very long animations (more than a hour). The final mp4 file is relativelly small, but raw video file is extremelly big. About ninety percents of each frame are black pixels, so Ffmpeg comress it very good, but raw file cannot be compressed and it takes sometimes mor ethan 100 Gigabytes. Also, there is very unnecessary double processing same data. Firstly I process it in Node.js to save data to file, and then Ffmpeg reads it to convert it to mp4. There is a lot of unnecessary work.

然而,唯一的问题是它非常慢,占用硬盘空间。我想要创建非常长的动画(超过一个小时)。最终的mp4文件相对较小,但是原始的视频文件非常大。大约90%的帧都是黑色像素,所以Ffmpeg很好地压缩了它,但是原始文件不能被压缩,有时需要100 gb的内存。同样,也有非常不必要的重复处理相同的数据。首先我在Node进行处理。将数据保存到文件中,然后Ffmpeg读取数据并将其转换为mp4。有很多不必要的工作。

So, I'm looking for a way (and I'm pretty sure it is possible, but I didn't find a way to do it yet) to output raw video data (one frame at a time) to Ffmpeg process (without saving anything to the hard disk).

因此,我正在寻找一种方法(我很确定这是可能的,但我还没有找到一种方法)将原始视频数据(一次一帧)输出到Ffmpeg进程(没有保存到硬盘上)。

My goal is to do the following:

我的目标是:

  1. Open Ffmpeg process
  2. 公开的Ffmpeg过程
  3. Render a frame in Node.js
  4. 在Node.js中呈现一个框架
  5. Output raw byte stream to Ffmpeg
  6. 将原始字节流输出到Ffmpeg
  7. Wait for Ffmpeg to encode it and append to mp4 file
  8. 等待Ffmpeg对其进行编码并将其附加到mp4文件
  9. Let Ffmpeg wait for my Node.js process to render next frame
  10. 让Ffmpeg等待我的节点。js进程渲染下一帧

Is there a way to achieve it? I really don't see a reason to post code, because my current code has nothing to do with the question I'm asking here. I don't struggle with syntax errors or implementation problems. No, instead I just don't know which parameters to pass to Ffmpeg process in order to achieve what I've already explained.

有办法实现它吗?我真的没有理由写代码,因为我当前的代码与我在这里问的问题没有任何关系。我不会纠结于语法错误或实现问题。不,相反,我只是不知道要将哪些参数传递给Ffmpeg过程,以便实现我已经解释过的内容。

I've searched in documentation to find out which parameters I need to pass to Ffmpeg process in order to let it read raw data from stdin instead from file, and also to wait until my Node.js process render next frame (so to disable time limit) because rendering a frame may take more than 24 hours. Therefore, Ffmpeg process should wait without time limit. However, I didn't find anything about it in documentation.

我在文档中搜索了哪些参数需要传递给Ffmpeg进程,以便让它从stdin中读取原始数据,而不是从file中读取,还要等到我的节点。js进程渲染下一个帧(因此禁用时间限制),因为渲染一个帧可能需要超过24小时。因此,Ffmpeg过程应该没有时间限制。但是,我没有在文档中找到任何关于它的信息。

I know how to write to stdin from Node.js and similar technical stuff, so no need to explain it. The only question(s) here:

我知道如何从Node写到stdin。js和类似的技术,不需要解释。唯一的问题(s):

  1. Which parameters to pass to Ffmpeg?
  2. 要传递给Ffmpeg的哪些参数?
  3. Do I need to create Ffmpeg process (using child_process) with some special options?
  4. 我需要用一些特殊的选项创建Ffmpeg进程(使用child_process)吗?

Thank you in advance. Please, take it easy, this is my first question! :)

提前谢谢你。请放轻松,这是我的第一个问题!:)

1 个解决方案

#1


2  

As suggested by @Mulvya and @estus, the correct parameter is -i - (to enable input from stdin):

根据@Mulvya和@estus的建议,正确的参数是-i -(启用stdin的输入):

'use strict';

var cp = require('child_process');

var proc = cp.spawn('ffmpeg', [
  '-hide_banner',
  '-f', 'rawvideo',
  '-pix_fmt', 'rgb24',
  '-s', '2x2',
  '-i', '-',
  '1.png'
]);

proc.stdin.write(Buffer.from([
  255, 0, 0,
  0, 255, 0,
  0, 255, 255,
  255, 0, 255
]));

proc.stdin.end();

proc.stderr.pipe(process.stdout);

It produces this image:
节点。缓冲数据到Ffmpeg
It works for animations too.

它产生这个图像:它也适用于动画。

Thanks guys for helping!

感谢大家帮助!

#1


2  

As suggested by @Mulvya and @estus, the correct parameter is -i - (to enable input from stdin):

根据@Mulvya和@estus的建议,正确的参数是-i -(启用stdin的输入):

'use strict';

var cp = require('child_process');

var proc = cp.spawn('ffmpeg', [
  '-hide_banner',
  '-f', 'rawvideo',
  '-pix_fmt', 'rgb24',
  '-s', '2x2',
  '-i', '-',
  '1.png'
]);

proc.stdin.write(Buffer.from([
  255, 0, 0,
  0, 255, 0,
  0, 255, 255,
  255, 0, 255
]));

proc.stdin.end();

proc.stderr.pipe(process.stdout);

It produces this image:
节点。缓冲数据到Ffmpeg
It works for animations too.

它产生这个图像:它也适用于动画。

Thanks guys for helping!

感谢大家帮助!