gpt4 book ai didi

ffmpeg - 使用 ffmpeg 将流转换为帧时进行缓冲

转载 作者:行者123 更新时间:2023-12-04 05:47:29 25 4
gpt4 key购买 nike

我正在尝试使用 ffmpeg 将 udp 流转换为帧。我运行以下命令:

ffmpeg -loglevel debug -strict 2 -re -i "udp://192.168.15.50:3200?fifo_size=1000000&overrun_nonfatal=1" -r 8 -vf scale=432:243 -f image2pipe -vcodec ppm pipe:1

它发生在不同的流类型、mpeg2video 和 h264 上。核心处理此特定流的 CPU 负载低于 30%,其分辨率为 640x576 的低质量 sd 流。

它在大多数情况下都运行良好,但有时,有时会出现延迟,并且帧会延迟到达。所以我想要8 fps,但有时我得到的更少,有时更多。

为什么会出现这种延迟,我该如何减少它?

更新:我尝试将其更改为:
ffmpeg -loglevel debug -i "udp://192.168.15.50:3200?fifo_size=1000000&overrun_nonfatal=1" -r 8 -preset ultrafast -fflags nobuffer -vf scale=432:243 -f image2pipe -vcodec ppm pipe:1

但我仍然得到这个问题。例如,在 ffmpeg 日志中,我得到:
[2016/02/11 13:32:30] frame= 7477 fps=8.0 q=-0.0 size= 2299638kB time=00:15:34.62 bitrate=20156.4kbits/s dup=7 drop=15867 ^M*** dropping frame 7477 from stream 0 at ts 7475
[2016/02/11 13:32:30] ***dropping frame 7477 from stream 0 at ts 7476
[2016/02/11 13:32:30] ***dropping frame 7478 from stream 0 at ts 7476
[2016/02/11 13:32:32] Last message repeated 1 times
[2016/02/11 13:32:32] frame= 7479 fps=8.0 q=-0.0 size= 2300253kB time=00:15:34.87 bitrate=20156.4kbits/s dup=7 drop=15871 ^M*** dropping frame 7479 from stream 0 at ts 7477

如您所见,在第 31 秒期间,没有输出任何帧......并且 ffmpeg 报告的两帧之间的时间为 0.25s

最佳答案

问题中发布的 ffmpeg 命令通常通过管道传输到另一个二进制文件中。该二进制文件保存 ffmpeg 提供的帧并对它们进行一些处理。

一开始我没有使用"fifo_size=1000000&overrun_nonfatal=1"选项,我从 ffmpeg 收到以下错误:

[udp @ 0x4ceb8a0] Circular buffer overrun. To avoid, increase fifo_size URL option. To survive in such case, use overrun_nonfatal option
udp://192.168.15.50:3200: Input/output error

然后ffmpeg会崩溃。为了避免它,我添加了: "fifo_size=1000000&overrun_nonfatal=1" ,正如 ffmpeg 所建议的那样。

但是,在使用这些参数之后,我会得到问题中描述的时移,有时它还会在帧中出现伪影。

如前所述,CPU 没有问题,所以最初,我们怀疑 udp 流,特别是 udp 缓冲区大小:

https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Administration_And_Configuration_Guide/jgroups-perf-udpbuffer.html

所以我们改变了 udp 缓冲区的大小:
sysctl -w net.core.rmem_max=26214400

并将 ffmpeg 命令更改为“udp://231.20.20.8:2005?buffer_size=26214400”

但是,这并没有解决问题。 ffmpeg 仍然会出现“循环缓冲区溢出”并崩溃。而且我无法重现这个循环缓冲区溢出,它只是随机发生的。

我的下一个想法是管道缓冲区大小,因为我发现了以下内容:

http://blog.dataart.com/linux-pipes-tips-tricks/

The size of the buffer since kernel version 2.6.11 is 65536 bytes (64K) and is equal to the page memory in older kernels. When attempting to read from an empty buffer, the read process is blocked until data appears.
Similarly, if you attempt to write to a full buffer, the recording process will be blocked until the necessary amount of space is available.



http://ffmpeg.gusari.org/viewtopic.php?f=12&t=624 [链接现已失效]

Poster1: What causes these circular buffer overruns? My assumption is that ffmpeg is reading the input stream into the aforementioned circular buffer, and the code then generates the output stream also reads from that same buffer. The overrun would happen when the code that generates the output doesn't keep up with the rate at which it's being written to the buffer, right?
Poster2: Looking at the source code it appears that the buffer gets overflowed either by too fast input or too slow output (slow cpu?). Your assumption is correct.



所以理论上是我们的二进制文件读取管道的速度不够快。结果管道被阻塞,ffmpeg 无法写入,这导致 udp fifo 缓冲区溢出(ffmpeg 不断读取 udp INTO FIFO,但无法将其从它写入我们的管道)。

我设法通过运行(在单独的终端中)证明了这个理论:

mkfifo mypipe
ffmpeg -loglevel debug -i "udp://192.168.15.50:3200?fifo_size=1000000&overrun_nonfatal=1" -r 8 -preset ultrafast -fflags nobuffer -vf scale=432:243 -f image2pipe -vcodec ppm pipe:1 > mypipe
cat < mypipe > /dev/null # run this for 10 seconds, allowing ffmpeg to start. then pause it with CTRL-Z and see ffmpeg crashing because it cannot read more udp stream

接下来是调查为什么我们的二进制文件在某些​​时候停止读取管道。似乎没有理由,因为通常它会在某些东西进入管道后立即读入内存。

但是,它也将帧保存到硬盘驱动器,并且在某些时候(有时 12 分钟,有时 15 小时),磁盘操作会由于读/写操作而变慢(它是 bcache(SSD 和 HDD 混合,使用 SSD 作为缓存) ))。当我从该驱动器中并行删除数百万个文件以进行调试时,我随机发现了这个事实。

因此,将文件写入繁忙的硬盘驱动器会暂时阻止我们的二进制文件读取输入管道。

udp 循环缓冲区溢出问题和最终时移的原因是 HDD,理论上的解决方案是 SSD。

这项调查花了大约 3 周时间,因此发布所有这些内容,希望它至少能在一定程度上帮助将来的某个人。

更新 :

后来我还检测到另一个导致同样问题的瓶颈(更换 HDD 还不够),这是由于后端的 postgres 插入导致的 tcp 套接字缓冲区溢出。

整个管道如下所示:
udp_videostream -> ffmpeg -> linux_pipe -> our_client_side_binary -> tcp -> our_server_side_binary -> postgres
Postgres 查询有时很慢,这导致我们的服务器读取 TCP 套接字的速度比 our_binary 向它推送的速度慢。结果,tcp 套接字将被阻塞(最大为 4Mb),因此,客户端将阻塞其输入管道,并且由于该 CBO 错误,ffmpeg 将崩溃。

关于ffmpeg - 使用 ffmpeg 将流转换为帧时进行缓冲,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35338478/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com