FFMPEG:'Nonmatching transport in server reply' 但 openRTSP 有效

FFMPEG: 'Nonmatching transport in server reply' But openRTSP works

我买了一个便宜的中国网络摄像机 (GWIPC-26xxx/Yoosee)。我想用ffmpeg录制它的流。

FFMPEG 上,我使用 RTSP/UDP[=54= 设法使其工作 ] 传输协议,如下所示。它在 VLC 上也能完美播放。

ffmpeg -rtsp_transport udp -i rtsp://admin:pass@192.168.0.103:554/onvif1 streamfile.mkv

pass 是 android 相机应用程序客户端上定义的密码。

但是我更喜欢RTSP/TCP传输因为使用UDP图像是经常损坏。出现污迹和撕裂的图像。所以我测试了几乎所有东西,甚至使用 latest repository 从源代码编译了 FFMPEG。但是没有什么能让 ffmpeg 工作,android 或 windows。如果使用 -rtsp_transport tcp 我总是最终收到:

[rtsp @ 0xxxxxxx] Nonmatching transport in server reply

终于发现 openRTSP 使用与 VLC 相同的库。有了它,我设法使用RTSP/TCP(从源编译后)连接。

openRTSP -n -D 1 -c -B 10000000 -b 10000000 -q -Q -F cam_file \ 
-d 60 -P 30 -t -u admin pass rtsp://192.168.0.103:554/onvif1

有关 openRTSP 参数的更多详细信息 here

最奇怪的部分是 RTSP 设置消息(FFMPEG 与 openRTSP)的比较。很明显,网络摄像机服务器支持 RTP/AVP/TCP。 RTP 交织到现有的 TCP 连接中。

并查看 ffmpeg/libavformat/rtsp.c 的源代码,发现 ffmpeg 在识别它时遇到了一些问题?

...
if (reply->transports[0].lower_transport != lower_transport) {
    av_log(s, AV_LOG_ERROR, "Nonmatching transport in server reply\n");
    err = AVERROR_INVALIDDATA;
    goto fail;
}
...

Quoting Wisdom

IP cameras are of varying quality, some behaving erratically in my experience. Dealing with their RTSP streams requires a dose of fault-tolerance.
This appears to be a byproduct of the low-end of the CCTV industry playing fast and loose with standards, RTSP and ONVIF being the two most frequently abused. Fortunately, you can usually work around these problems. Unless your IP cameras and controller are all designed to play nicely together, only use ONVIF for once-only discovery and settings management.

FFMPEG 在 RTSP 设置中不是很宽容

苦苦挣扎后,我开始比较 openRTSPffmpeg 之间的 RTSP/SETUP 消息。 openRTSP 默认情况下已经输出了很多详细的诊断信息。

openRTSP

openRTSP 发送命令 OPTIONSDESCRIBE 然后 SETUP。 SETUP 消息是:

Sending request: SETUP rtsp://192.168.0.103:554/onvif1/track2 RTSP/1.0
CSeq: 6
Authorization: Digest username="admin", realm="HIipCamera", nonce="ddd21dbd0620b6fb4b1f9bcbb06340a0", uri="rtsp://192.168.0.103:554/onvif1", response="91d9c611aa004eeb1390b3fbb9373648"
User-Agent: ./openRTSP (LIVE555 Streaming Media v2021.02.11)
Transport: RTP/AVP/TCP;unicast;interleaved=2-3
Session: 3a4d2e6d

摄像头响应:

Received a complete SETUP response:
RTSP/1.0 200 OK
CSeq: 6
Transport: RTP/AVP;unicast;destination=192.168.0.100;source=192.168.0.103;interleaved=2-3
Session: 3a4d2e6d;timeout=60

FFMPEG

对于 FFMPEG,您必须使用 -v 9 and -loglevel 99 参数才能查看 RTSP 消息。它只发送了一个DESCRIBE请求是:

DESCRIBE rtsp://192.168.0.103:554/onvif1 RTSP/1.0
Accept: application/sdp
CSeq: 2
User-Agent: Lavf58.67.100

摄像头响应:

Transport: RTP/AVP;unicast;destination=192.168.0.100;source=192.168.0.103;interleaved=0-1
Session: 37287775;timeout=60

RTSP 滥用和 FFMPEG 黑客攻击解决方案

比较消息很明显相机可以使用 RTSP/AVP/TCP 交错 TCP 进行连接。但是我们可以通过摄像头的回答看到,在'Transport:'行里面没有包含'TCP'之后的'RTP/AVP' 按照要求。喜欢:

Transport: RTP/AVP/('TCP' missing here);....

我分析了ffmpeg/libavformat/rtsp.c上的代码,发现直观的调用顺序如下:ff_rtsp_connectff_rtsp_make_setup_requestff_rtsp_send_cmdff_rtsp_read_replyff_rtsp_parse_line。在最后一个中,我找到了 rtsp_parse_transport 和以下代码:

if (!av_strcasecmp(lower_transport, "TCP"))
    th->lower_transport = RTSP_LOWER_TRANSPORT_TCP;
else
    th->lower_transport = RTSP_LOWER_TRANSPORT_UDP;

lower_transport 是在 'RTP/AVP;' 之后解析的文本,在我的例子中是 "" 空字符串,因为相机服务器不包含它。

我在代码中插入了|| !av_strcasecmp(lower_transport, "")。当省略 lower_transport 时,假定传输是 RTSP_LOWER_TRANSPORT_TCP。像下面这样:

if (!av_strcasecmp(lower_transport, "TCP") || !av_strcasecmp(lower_transport, ""))
    th->lower_transport = RTSP_LOWER_TRANSPORT_TCP;
else
    th->lower_transport = RTSP_LOWER_TRANSPORT_UDP;

ffmpeg 的这个小补丁 (git) 可用 here。在 ffmpeg git 仓库上使用 git am < RTSP_lower_transport_TCP.patch 申请。

重新编译后:FFMPEG 运行完美!

破解了 FFMPEG 使其容忍 RTSP 滥用 摄像头服务器正在做.由于我的 FFMPEG 版本只会 运行 在我未使用的 android 电视上(作为​​ cctv/nvr 相机服务器),这不会产生任何其他问题。

更好的解决方案是 FFMPEG (Ticket) 还要考虑 rtsp 服务器应答中 缺少下层传输 的情况。然后与客户端发送的请求进行比较,以确定是否省略了较低的传输。并尝试与之建立联系。

建议

如果您到达此处,您的网络摄像头可能可能遭受了一些 RTSP 滥用。我建议您先尝试使用 openRTSP 以查看它是否能够连接。如果是,则尝试调试其 RTSP/setup 消息。如果您修改(风险自负)ffmpeg/libavformat/rtsp.c 代码,则可能存在一些自定义或黑客解决方案。或者你 might/should 使用 live555 库、VLC 或 mplayer。