? ? ?我們知道喉镰,ffmpeg中的avformat有個(gè)"timeout"的opt參數(shù),可以設(shè)置播放tcp讀寫超時(shí)時(shí)間亚茬,當(dāng)我們使用ffmpeg的api來播放網(wǎng)絡(luò)點(diǎn)播或直播url的時(shí)候郁岩,這個(gè)參數(shù)可以指定網(wǎng)絡(luò)斷開后多長時(shí)間后能返回讀取失敗的錯(cuò)誤耘拇,比如設(shè)置超時(shí)時(shí)間為10s代碼如下:
av_dict_set(&ffp->format_opts, "timeout", "1000000", 0);
但當(dāng)我們使用rtmp協(xié)議時(shí)姐军,設(shè)置該參數(shù)將導(dǎo)致無法正常連接播放铁材,比如IJKPlayer為了規(guī)避這個(gè)問題尖淘,就做了如下處理:
if(av_stristart(is->filename,"rtmp",NULL) ||
av_stristart(is->filename,"rtsp",NULL)) {
// There is total different meaning for 'timeout' option in rtmp
av_log(ffp,AV_LOG_WARNING,"remove 'timeout' option for rtmp.\n");
av_dict_set(&ffp->format_opts, "timeout", NULL, 0);
}
這樣雖然能播放rtmp了,但帶來的一個(gè)問題就是無法設(shè)置timeout參數(shù)了著觉,只能承受默認(rèn)的兩分鐘的超時(shí)時(shí)間德澈,對(duì)于需要靈活處理網(wǎng)絡(luò)不穩(wěn)定時(shí)能及時(shí)返回并嘗試重連的播放器來說就會(huì)是一個(gè)坑。
那為什么播放rtmp時(shí)不能設(shè)置這個(gè)參數(shù)呢固惯?我們先來看看ffmpeg中l(wèi)ibavformat里面的tcp.c的參數(shù)列表中這一行:
{ "timeout",? ? "set timeout (in microseconds) of socket I/O operations", OFFSET(rw_timeout)...
這個(gè)timeout原來是設(shè)置給了TCPContext中的rw_timeout,完整結(jié)構(gòu)體如下:
typedef struct TCPContext {
const AVClass *class;
int fd;
int listen;
int open_timeout;
int rw_timeout;
int listen_timeout;
int recv_buffer_size;
int send_buffer_size;
int64_t app_ctx_intptr;
int addrinfo_one_by_one;
int addrinfo_timeout;
AVApplicationContext *app_ctx;
} TCPContext;
這個(gè)rw_timeout就是我們在tcp連接后讀寫超時(shí)的時(shí)間缴守,我們再來看rtmp中的設(shè)置葬毫,在rtmpproto.c中的rtmp_options里的最后一行,卻把timeout賦給了listen_timeout屡穗,而當(dāng)我們是作為客戶端去連接rtmp服務(wù)器的時(shí)候贴捡,給listen_timeout賦值會(huì)導(dǎo)致連接不上rtmp服務(wù)器,我想這就是ijkplayer的作者為什么要在read_thread里面判斷是rtmp協(xié)議時(shí)村砂,將"timeout"清空的原因了吧烂斋,要修復(fù)這個(gè)問題很簡單,只需要將rtmp_options里的"timeout"修改為"listen_time"即可础废,當(dāng)然你也可以改為其它參數(shù)名汛骂,這樣就避免了沖突,而且在你很確定需要設(shè)置listen的超時(shí)時(shí)間時(shí)评腺,在外部設(shè)置"listen_time"這個(gè)參數(shù)就可以了帘瞭。