ffmpeg avformat_open_input 返回 -1094995529 问题排查

使用场景:live555 mediaServer作为服务端, 客户端ffmpeg rtsp拉流

问题:开始拉流正常,但多次之后 avformat_open_input 总是返回 -1094995529,导致触发超时回调

原因:只调用 avformat_free_context() 释放了 AVFormatContext ,rtsp 连接未关闭,多次之后无法再建立连接

解决方法:调用 avformat_close_input() 关闭 avformat_open_input() 打开的流,两者必须成对使用

排查:

首先设置ffmpeg日志级别为debug,可以打印 ffmpeg 底层 api调用细节

av_log_set_level(AV_LOG_DEBUG);

发现正常执行流程日志如下:

[tcp @ 0x7f61e41d6c80] No default whitelist set
[tcp @ 0x7f61e41d6c80] Original list of addresses:
[tcp @ 0x7f61e41d6c80] Address 172.20.35.17 port 554
[tcp @ 0x7f61e41d6c80] Interleaved list of addresses:
[tcp @ 0x7f61e41d6c80] Address 172.20.35.17 port 554
[tcp @ 0x7f61e41d6c80] Starting connection attempt to 172.20.35.17 port 554
[tcp @ 0x7f61e41d6c80] Successfully connected to 172.20.35.17 port 554

[rtsp @ 0x7f61f0199b80] SDP:
v=0
o=- 1649730133151151 1 IN IP4 192.168.242.1
s=Matroska video+audio+(optional)subtitles, streamed by the LIVE555 Media Server
i=9-1920x1080-264.mkv
t=0 0
a=tool:LIVE555 Streaming Media v2021.02.11
a=type:broadcast
a=control:*
a=range:npt=0-
a=x-qt-text-nam:Matroska video+audio+(optional)subtitles, streamed by the LIVE555 Media Server
a=x-qt-text-inf:9-1920x1080-264.mkv
m=video 0 RTP/AVP 96
c=IN IP4 0.0.0.0
b=AS:500
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=640028;sprop-parameter-sets=Z2QAKKy0A8ARPywgAAADACAAAAUR4wZU,aO8Lyw==
a=control:track1

当tcp连接成功之后开始交换rtsp/sdp信令,但是多次之后开始失败,日志如下:

[tcp @ 0x7f61e41d6c80] No default whitelist set
[tcp @ 0x7f61e41d6c80] Original list of addresses:
[tcp @ 0x7f61e41d6c80] Address 172.20.35.17 port 554
[tcp @ 0x7f61e41d6c80] Interleaved list of addresses:
[tcp @ 0x7f61e41d6c80] Address 172.20.35.17 port 554
[tcp @ 0x7f61e41d6c80] Starting connection attempt to 172.20.35.17 port 554
[tcp @ 0x7f61e41d6c80] Successfully connected to 172.20.35.17 port 554

只有tcp连接成功,不再发送sdp信令。

rtsp协议建立连接阶段的sdp传输总是用的tcp协议,后续媒体流可以选择tcp/udp,所以为rtsp连接失败导致。而多次拉流后才会发生,说明可能是 tcp 连接没有关闭释放导致。

根据ffmpeg代码注释,发现:

avformat_alloc_context() 分配的 fmt 可以 调用 avformat_free_context() 释放.
avformat_open_input() 打开的 fmt 必须 调用 avformat_close_input() 关闭,关闭的同时会释放 fmt.

ffmpeg拉流:

av_log_set_level(AV_LOG_ERROR); // AV_LOG_DEBUG

// avformat_free_context() can be used to free the context
in_fmt = avformat_alloc_context();

// 设置av_read_frame 超时回调
in_fmt->interrupt_callback.callback = read_interrupt_callback;
in_fmt->interrupt_callback.opaque = this;
read_start_time = time(NULL); // 每次读流之前记录一下起始时间

// must be closed with avformat_close_input(),会释放掉in_fmt,不用再次调用 avformat_free_context()
int ret = avformat_open_input(&in_fmt, srcPath.c_str(), NULL, NULL);
if (ret < 0) {
    releaseSources();
    return ErrorCode::E_STREAM_OPEN_TIMEOUT; // 拉流超时
}

// releaseSources();
// avformat_close_input(&in_fmt)

posted @ 2022-04-12 11:19  jixhua  阅读(3472)  评论(4编辑  收藏  举报