【问题标题】:Feeding raw image bytes into ffmpeg rawvideo fails with Invalid buffer size on linux only仅在 Linux 上将原始图像字节馈送到 ffmpeg rawvideo 失败,缓冲区大小无效
【发布时间】:2021-05-09 14:33:05
【问题描述】:

我有一个 nodejs 程序,它生成原始 (rgb24) 图像,然后我将其通过管道传输到 ffmpeg,以便将其保存为 png 或 mp4。我的代码如下所示:

const fs = require("fs");
// ...
const outputBuffer = Buffer.alloc(outputPngWidth * 3 * outputPngHeight);
// ... write data into outputBuffer
fs.writeSync(process.stdout.fd, outputBuffer);

然后我在 CLI 中执行以下操作:

node generate | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 1000x1000 -i - test.png

或者,如果我从我的程序中生成大量图像,我会这样做来生成视频文件:

node generate | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 1000x1000 -r 60 -i - -codec:v libx265 test.mp4

在 Windows 上,这可以完美运行。在 linux 上(无论是在 Ubuntu 20 VM 上,还是直接安装在物理机上的 Ubuntu 20),它始终失败并显示:

pipe:: corrupt input packet in stream 0
[rawvideo @ 0x55f5256c8040] Invalid buffer size, packet size 65536 < expected frame_size 3000000
Error while decoding stream #0:0: Invalid argument

如果我像这样将它分成两个阶段,那么它也可以在 linux 上完美运行:

node generate > test.raw
cat test.raw | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 1000x1000 -i - test.png

通过查看错误“数据包大小 65536 fs.writeSync 一次只发送 65536 个字节,但 ffmpeg 期望 3000000 个字节(即 1000 宽度 * 1000 高度 * 3 个通道)。

如果我将图像尺寸缩小到较小的尺寸,例如 50x50 或 100x100,那么它可以工作。只要x * y * 3 超过 65536,它就会失败(例如,160x160 失败,“数据包大小 65536

到目前为止我为解决这个问题所做的尝试没有运气:

  • 强制节点一次吐出整个缓冲区:
fs.writeSync(process.stdout.fd, outputBuffer, 0, outputBuffer.length);

有没有办法克服这个问题?

【问题讨论】:

  • node generate | cat | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 1000x1000 -i - test.png 呢?
  • @DaBler:谢谢。它具有完全相同的行为:100x100 成功,160x160 失败并显示相同的消息。
  • node generate | pv --buffer-size 1G | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 1000x1000 -i - test.png 也可以工作。
  • @DaBler:同样的行为。我已经尝试过,以及stackoverflow.com/q/8554568/72478 中列出的所有其他解决方案
  • 最后一次尝试:stdbuf -o1G node generate | ffmpeg -f rawvideo -pixel_format rgb24 -video_size 1000x1000 -i - test.png.

标签: node.js linux ffmpeg


【解决方案1】:

这是在黑暗中的一次尝试,我知道以下内容可能听起来很古怪。

从测试中看到错误消息,似乎 ffmpeg 在等待足够的数据时超时,并且生成器同时没有足够快地填充管道。

我问自己,尽管 ffmpeg - 希望 - 会使用阻塞读取调用,但如何显然会超时收听 STDIN?好吧,也许它不会对 read 进行阻塞调用,而是在文件描述符上调用 select 并使用短暂的超时,然后在等待足够的数据时遇到该超时。

如果系统一直忙于生成数据或使用数据,即对方始终处于空闲状态,则可能发生这种情况的一个简洁解释。

既然你说它是一个运行所有这些的虚拟机,我可以想象虚拟机被配置为只有一个可用的 CPU。然后它可以在任何给定时间只执行两个进程中的一个,这些进程竞争 CPU。

我可以看到您运行的其他测试支持这一点:您首先创建了测试数据并将其存储在一个文件中。然后你让 ffmpeg 消费它。每个进程都可以全时使用可用的 CPU。没有竞争。

如果多 CPU 或多超线程系统对具有更高优先级的其他进程保持足够繁忙,它也可能会暴露此行为。

底线:我会确保我的虚拟机对两个进程都有足够的处理能力。

【讨论】:

  • 感谢您的回答。有趣的想法。不幸的是,我的配置是 vb.memory = "4096"vb.cpus = 4。此外,我一直在直接安装在 ryzen 5 上运行的金属上的 Ubuntu 20 上重现该问题。因此它与硬件限制无关。
猜你喜欢
  • 2016-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 2014-01-14
  • 1970-01-01
相关资源
最近更新 更多