FFmpeg有两种方式控制IO退出:
- 设置超时时间timeout
- 传一个“AVIOInterruptCB”给AVFormatContext,在callback里返回1来让IO退出
两种方式并不是非此即彼,可以结合使用:
1. 超时时间用于读不到数据时的主动退出
2. callback方式用于响应用户的请求,比如用户停止播放时,终止拉流
RTMP是否支持配置timeout,可以看下帮助:
$ ffmpeg -hide_banner -h protocol=rtmp
...
-rtmp_tcurl <string> ED......... URL of the target stream. Defaults to proto://host[:port]/app.
-rtmp_listen <int> .D......... Listen for incoming rtmp connections (from INT_MIN to INT_MAX) (default 0)
-listen <int> .D......... Listen for incoming rtmp connections (from INT_MIN to INT_MAX) (default 0)
-timeout <int> .D......... Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1 (from INT_MIN to INT_MAX) (default -1)
...
可以看到,RTMP有个timeout配置,但是含义却是listen模式accept()等待的时间,即server模式等待client连接的时间。RTMP的timeout不是作为client的读写超时时间。
再看下TCP:
$ ffmpeg -hide_banner -h protocol=tcp
tcp AVOptions:
-listen <int> ED......... Listen for incoming connections (from 0 to 2) (default 0)
-timeout <int> ED......... set timeout (in microseconds) of socket I/O operations (from -1 to INT_MAX) (default -1)
-listen_timeout <int> ED......... Connection awaiting timeout (in milliseconds) (from -1 to INT_MAX) (default -1)
- TCP的timeout是read、write、connect的超时时间,不是listen accept的超时时间
- TCP的timeout时间单位是微秒
- TCP的listen_timeout含义和RTMP的timeout含义一样,单位不同
由此可见FFmpeg protocol timeout相关配置有多混乱。问题来了:
- 配置RTMP timeout,会传递到TCP的timeout吗?答案是不能。框架层不会自动传递参数给更底层的协议,每个协议负责向下层传递参数。
- 能改成RTMP timeout透传给TCP timeout吗?不能,两者含义不一样,单位不一样。如果直接改RTMP timeout配置的含义,会带来向下兼容的问题。
怎么解决RTMP读写无法配置timeout的问题呢?
一种思路是RTMP里加个新的参数配置作为读写timeout,再传给TCP。
实际上,大家往往忽略了,libavformat里的传输协议都有个公共的读写超时时间:
URLContext AVOptions:
-protocol_whitelist <string> .D......... List of protocols that are allowed to be used
-protocol_blacklist <string> .D......... List of protocols that are not allowed to be used
-rw_timeout <int64> ED......... Timeout for IO operations (in microseconds) (from 0 to I64_MAX) (default 0)
这个配置是否有效果,取决于具体的协议。对于RTMP来说,它收到了rw_timeout的配置,但没有进一步传递给更底层的协议。
所以,支持RTMP读写配置,最简单的做法是透传rw_timeout:
diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c
index 98718bc6da..a0c6195eb2 100644
--- a/libavformat/rtmpproto.c
+++ b/libavformat/rtmpproto.c
@@ -2635,6 +2635,9 @@ static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **o
if (rt->listen_timeout > 0)
rt->listen = 1;
+ /* Pass rw_timeout to underlying transport protocol */
+ if (s->rw_timeout > 0)
+ av_dict_set_int(opts, "rw_timeout", s->rw_timeout, 0);
rt->is_input = !(flags & AVIO_FLAG_WRITE);
细心的同学可能会发现,配置通用的rw_timeout参数,与TCP的timeout参数,还是有不同的地方:
- TCP的timeout同时用于open connect、read、write
- rw_timeout仅用于read write(如它的名字)
如果把RTMP的rw_time配置,传递给TCP的timeout,涵义上说不通。所以上面patch遗留的问题是RTMP over TCP connect没法配置超时(FFmpeg TCP connect默认5秒超时)。话说回来,connect和read write共用相同的timeout值得商榷。兴趣到此为止,我不打算往下深究了。
作者:quink
来源:Fun With FFmpeg
原文:https://mp.weixin.qq.com/s/IzPpnTh-hdGpQDtqYzxEsQ
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。