FFmpeg在解码MB时出现RTSP错误。

11

我正在使用FFmpeg读取来自Cisco 3050 IP相机的h264 RTSP流,并将其重新编码为磁盘上的h264(我之所以不仅使用-codec:copy,是因为有原因)。

FFmpeg版本如下:

ffmpeg version 3.2.6 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 6.3.0 (Alpine 6.3.0)

我还尝试过使用ffmpeg 2.8.14-0ubuntu0.16.04.1以及最新从源代码构建的ffmpeg(我使用了提交)并看到与下面相同的行为。

我运行的命令是:

ffmpeg -rtsp_transport udp -i 'rtsp://<user>:<pw>@<ip>:554/StreamingSetting?version=1.0&action=getRTSPStream&ChannelID=1&ChannelName=Channel1' -r 10 -c:v h264 -crf 23 -x264-params keyint=60:min-keyint=60 -an -f ssegment -segment_time 60 -strftime 1 /output/%Y%m%d_%H%M%S.ts -abort_on empty_output

我以相当稳定的速度每秒至少收到一种错误,以下是一个样例:

[rtsp @ 0x7f268c5e9220] max delay reached. need to consume packet
[rtsp @ 0x7f268c5e9220] RTP: missed 40 packets
[h264 @ 0x55b1e115d400] left block unavailable for requested intra mode
[h264 @ 0x55b1e115d400] error while decoding MB 0 12, bytestream 114567
[h264 @ 0x55b1e115d400] concealing 3889 DC, 3889 AC, 3889 MV errors in I frame
最常见的错误是“解码MB x x时出错,字节流x”。当视频回放时,这表示视频文件存在严重的损坏。
我在stackoverflow和其他地方看到了许多与该错误消息相关的参考资料,但我尚未找到令人满意的解释或解决方法。这来自于这一行,似乎对应于流末端缺失数据。'left block unavailable' 来自 这里,也看起来像是数据缺失。
其他人建议改用-rtsp_transport tcp123),但在我的情况下,这只会出现稍微不同的错误组合,仍会导致视频损坏。
[h264 @ 0x557923191b00] left block unavailable for requested intra4x4 mode -1
[h264 @ 0x557923191b00] error while decoding MB 0 28, bytestream 31068
[h264 @ 0x557923191b00] concealing 2609 DC, 2609 AC, 2609 MV errors in I frame
[rtsp @ 0x7f88e817b220] CSeq 5 expected, 0 received.
使用Wireshark,我确认在UDP和TCP模式下,所有的数据包都从摄像头传输到了电脑(有序RTP序列号没有丢失),这使我认为数据在到达ffmpeg后被丢失了。
当我对Panasonic WV-SFV110摄像机运行相同的命令时,我也看到了类似的行为,但总体错误较少。将Panasonic摄像机从UDP切换到TCP可以减少但不能完全消除错误/损坏。
我还尝试了一个相似的命令使用VLC并得到了类似的错误(cvlc rtsp://<user>:<pw>@<ip>/MediaInput/h264:sout='#transcode{vcodec=h264}:std{access=file,mux=ts,dst="output.ts"} )——假设代码与自从libav从ffmpeg分叉以来并没有太大的分歧。
摄像头直接插入PC上的PoE端口,因此网络拥塞不可能成为问题。鉴于PC具有足够的CPU来保持编码实时流,我认为它仍然会从TCP流中删除数据是ffmpeg的问题。
在定性上,有几个因素似乎会加剧问题:
- 更高的视频分辨率 - 在运行ffmpeg的机器上增加系统负载(例如,将转码为低分辨率.avi文件会产生比转码为h264 VBR更少的错误;使用-codec:copy可以消除所有错误,除了ffmpeg启动时的几个错误) - 摄像机视野内的运动更大
这个错误是什么意思?我该怎么办?

1
你能否使用VLC客户端播放流媒体,而且没有任何问题呢? - Micka
1
我在VLC中基本上得到了相同的结果 - 我已经将其编辑到问题中。 - Hugh W
2个回答

9

看一下最初的错误信息:

[rtsp @ 0x7f268c5e9220] max delay reached. need to consume packet
[rtsp @ 0x7f268c5e9220] RTP: missed 40 packets

我猜你的UDP数据包丢失了。其他H.264错误消息是因为接收到不完整的比特流造成的。 现在重要的是要分离问题。你的网络是否丢包?还是你的服务器接收UDP(RTP)太慢或超载了。
首先,我会检查你的操作系统的UDP缓冲区大小。https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Web_Platform/5/html/Administration_And_Configuration_Guide/jgroups-perf-udpbuffer.html 如果增加UDP缓冲区大小没有帮助-使用ffmpeg和-codec:copy来降低CPU负载。你还有错误吗? 由于你想重新编码,请考虑使用英特尔快速同步-vcodec h264_qsv或其他硬件编码器降低CPU负载。
问题并不在于PC是否有足够的CPU。而是更多地识别处理管道中的瓶颈。你的H.264编码器(x264)可能会超额订阅你的CPU,以至于你会得到瞬间的峰值负载,导致数据包丢失。尝试限制x264的线程数和/或将质量降低为“快速”或“更快”。

1
是的,我认为你是对的,“-rtsp_transport udp”会导致丢失UDP数据包,这就是为什么我转而使用“-rtsp_transport tcp”的原因。我已经在问题中添加了更多信息。使用“-codec: copy”可以消除错误,但如今所述的问题是,PC具有足够的CPU来保持编码速度,为什么ffmpeg会失败呢? - Hugh W
我在我的回答中添加了一个段落 - 请参见上文。 - Markus Schumann

6
看起来数据包丢失是一个问题。更高的视频分辨率和更多的动作会增加编码视频流的比特率,从而增加数据包丢失的可能性。根据所丢失的数据包,你在解码过程中会看到不同的错误,正如你在帖子中指出的那样。
运行ffmpeg时系统负载更高也表明你的网络卡可能会丢失数据包,例如当ffmpeg在转码视频时需要花费太长时间读取数据包时。
第一个问题是你的网络拓扑结构是什么?通过公共互联网进行流媒体传输比通过局域网进行传输要困难得多。网络中有哪些交换机/路由器?
接下来的问题是,你的摄像头正在以什么比特率进行流媒体传输?尝试减少这个比特率并检查结果。请按照系统性的方法进行操作,即:
- 首先不要进行转码。 - 只接收视频。 - 将其写入文件。 - 检查数据包丢失/视频伪影。 - 从较低的比特率(例如100kbps)开始,并在没有明显数据包丢失的情况下逐渐增加比特率。
接下来我要尝试的是增加接收缓冲区的大小。虽然我对ffmpeg不是很熟悉,但看起来你可以通过recv_buffer_size设置它,如此处所示。然后,你需要根据摄像头配置计算出一个足够大的大小,以存储几秒钟的视频数据(例如5秒)。当你增加接收缓冲区的大小或延长没有伪影的时间段时,请检查是否有更少的伪影。
当然,如果你的处理器无法实时转码视频,则迟早会用完空间,在这种情况下,你可能需要将视频转码为较低的分辨率/比特率或使用较少的编码器设置等方法,或在更快的机器上运行转码。
另外,请注意,调整接收缓冲区大小不能弥补公共互联网上发生的数据包丢失,因此以上方法只适用于你正在流媒体传输支持摄像头比特率的本地网络。如果你超过了网络带宽,就可能会发生数据包丢失。在这种情况下,使用TCP进行流媒体传输可能会有所帮助(至少直到接收缓冲区最终溢出)。
如果以上方法没有帮助或无法完全解决问题,你还可以尝试以下方法:
- 使用Wireshark或Tcpdump嗅探传入的流量。 - 查看跟踪记录。使用“RTSP”过滤跟踪记录。 - 你应该能够看到RTP流量,其中连续的RTP数据包具有递增的序列号(例如20、21、22、23等)。如果你看到缺失的序列号,则表示发生了数据包丢失,请尝试使用TCP进行流媒体传输。在使用TCP进行流媒体传输时也记得增加接收缓冲区的大小。
总之,你需要确定在管道架构中数据丢失发生的位置。

摄像头 -> 网络 -> 接收缓冲区(操作系统) -> 应用程序(ffmpeg)


关于缓冲区,我认为这里添加的(未记录的)buffer_size(https://git.libav.org/?p=libav.git;a=commit;h=e3ec6fe7bb2a622a863e3912181717a659eb1bad)是相关的,因为我正在使用rtsp而不是tcp FFmpeg协议。更改此设置没有任何影响。我已经编辑了我的帖子并提供了更多信息。总之,我越来越确信问题是ffmpeg中的一个错误 - 它应该能够跟上,当它无法跟上时的故障模式是不合理的。 - Hugh W
1
@HughW 你在更新的问题中描述的行为仍然表明接收缓冲区大小存在问题:这表明网络上没有丢失任何数据包(wireshark可以看到它们),但它们在应用程序消费之前被操作系统丢弃。我不知道你如何通过ffmpeg设置大小(如果我发布的链接无效),但你需要在Linux上使用SO_RCVBUF选项调用setsockopt。在Windows上有一个类似的命令。你可以使用相同的选项调用getsockopt来确保已实际设置接收缓冲区大小。 - Ralf
1
根据我的经验,在使用默认的操作系统缓冲区大小时,数据包很快就会被丢弃。我不确定ffmpeg默认设置了什么大小。 - Ralf
我理解了,我认为你是对的,缓冲区大小应该设置为这里所描述的那样,但在我的情况下,代码路径没有被运行,我仍在调查中。 - Hugh W

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接