使用場景: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)