ffmpeg的avformat_open_input()和av_read_frame默认是阻塞的
* 用户可以通过设置“ic->flags |= AVFMT_FLAG_NONBLOCK;”设置成非阻塞(通常是不推荐的);
* 或者是设置超时时间;
* 或者是设置interrupt_callback定义返回机制。
开流超时设计
主要注意点是要注意协议
timeout:(http:ms udp:s)
stimeout:(rtsp us)
1.设置rtsp超时
AVDictionary* opts = NULL;
av_dict_set(&opts, "rtsp_transport", m_bTcp ? "tcp" : "udp", 0); //设置tcp or udp,默认一般优先tcp再尝试udp
av_dict_set(&opts, "stimeout", "3000000", 0);//单位us 也就是这里设置的是3s
ret = avformat_open_input(&ctx, url, NULL, &opts);
2.设置udp,http超时
AVDictionary* opts = NULL;
av_dict_set(&opts, "timeout", "3000000", 0);//单位 如果是http:ms 如果是udp:s
int ret = avformat_open_input(&ctx, url, NULL, &opts);
读流超时设计
1.回调用的方式
//打开成功后 设置回调,监控read超时情况 通过这种方式可以动态修改
context->ifmt_ctx->interrupt_callback.opaque = (void*)context;
context->ifmt_ctx->interrupt_callback.callback = interruptCallback;//设置回调
//每次读流之前记录一下起始时间
context->read_start_time = time(NULL);
int ret = av_read_frame(context->ifmt_ctx, &pkt);
//回调监控
static int interruptCallback(void *context){
ACCHLSContext *ctx = (ACCHLSContext *)context;//ACCHLSContext是我自定义的结构体,这是回调opaque设置的
if (ctx == NULL) {
return 0;
}
ACCUInt64_t end = time(NULL);
if (end - ctx->read_start_time >= 3) {
return 1;
}
return 0;
}
2.参数设置
//不可动态设置,只能在开流之前设置好
AVDictionary* opts = NULL;
av_dict_set(&opts, "rw_timeout", "3000", 0);//单位:ms
int ret = avformat_open_input(&ctx, url, NULL, &opts);
备注:我在做HLS拉流直播和点播时,由于点播的m3u8文件是实时生成的,理论上是3s生成一个文件,但如果网络不好,这时间就会很长。
如果按照这种设计,就很容易出现超时。但如果设置时间太长,关闭时又容易卡住线程。所以我的处理方式是:除了这个超时设计外,另外增加一设计。连续读流失败25s,就通知外面超时断开。
不知道还有没有其他好的方法,欢迎一起交流