【问题标题】:Buffering while converting stream to frames with ffmpeg使用ffmpeg将流转换为帧时进行缓冲
【发布时间】:2016-02-11 11:45:34
【问题描述】:

我正在尝试使用 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 video-streaming latency buffering


    【解决方案1】:

    问题中发布的 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/

    自内核版本 2.6.11 起,缓冲区的大小为 65536 字节 (64K),等于旧内核中的页面内存。尝试从空缓冲区读取时,读取过程会被阻止,直到数据出现。
    同样,如果您尝试写入一个完整的缓冲区,记录过程将被阻止,直到有足够的空间可用。

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

    Poster1:是什么导致这些循环缓冲区溢出?我的假设是 ffmpeg 正在将输入流读入上述循环缓冲区,然后代码生成的输出流也从同一个缓冲区读取。当生成输出的代码跟不上它写入缓冲区的速度时,就会发生溢出,对吧?
    Poster2:查看源代码似乎缓冲区因输入太快或输出太慢(cpu 慢?)而溢出。你的假设是正确的。

    所以理论上是我们的二进制文件读取管道的速度不够快。结果管道被阻塞,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 将崩溃。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-02
      • 2013-11-07
      • 1970-01-01
      • 2012-07-30
      • 1970-01-01
      • 2011-10-02
      • 1970-01-01
      相关资源
      最近更新 更多