ffmpeg问题汇总及解决方案 <设置avformat_open_input 超时><转>

1:
如果数据是rtp/rtsp传输的话,ffmpeg会每隔30s(哪里设置该值?)发送一个keepalive包,如果ipc支持GET_PARAMETER命令,就发该命令等ipc回复以确认ipc还活着。
某些ipc(IPCamera)不支持GET_PARAMETER的rtsp命令。则会通过OPTIONS *来是keepalive,不过这会导致连接断掉
原代码,及修改部分如下。先这样处理,有时间再研究原代码为什么不这么处理。

//ffmpeg/libavformat/rtspdec.c rtsp_read_packet()
if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN)) {
        /* send dummy request to keep TCP connection alive */
        if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 ||
            rt->auth_state.stale) {
            if (rt->server_type == RTSP_SERVER_WMS ||
                (rt->server_type != RTSP_SERVER_REAL &&
                 rt->get_parameter_supported)) {
                ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
            } else {
                // ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL);                 //原代码
                ff_rtsp_send_cmd_async(s, "OPTIONS", rt->control_uri, NULL);        //修改后的代码,这样就算ipc不支持GET_PARAMETER的命令可以keepalive了
            }
            /* The stale flag should be reset when creating the auth response in
             * ff_rtsp_send_cmd_async, but reset it here just in case we never
             * called the auth code (if we didn't have any credentials set). */
            rt->auth_state.stale = 0;
        }
    }

2:
如果数据是rtp/rtsp/tcp传输,如果没有设置stimeout(socket timeout),那么server断线后av_read_frame会阻塞

AVFormatContext *pFormatCtx = NULL;
    AVPacket packet;
    AVDictionary *optionsDict = NULL;
    char *streamurl1 = "rtsp://test:test@192.168.11.111:554/test.stream";
    
    // Register all formats and codecs
    av_register_all();
    avformat_network_init();

    pFormatCtx = avformat_alloc_context();
    av_dict_set(&optionsDict, "rtsp_transport", "tcp", 0);                //采用tcp传输
    av_dict_set(&optionsDict, "stimeout", "2000000", 0);                  //如果没有设置stimeout,那么把ipc网线拔掉,av_read_frame会阻塞(时间单位是微妙)

    // Open video file
    if(avformat_open_input(&pFormatCtx, streamurl, NULL, &optionsDict)!=0){
        printf("linesize = %d\n", __LINE__);    
        return -1; // Couldn't open file
    }

    // Retrieve stream information
    if(avformat_find_stream_info(pFormatCtx, NULL)<0){
        printf("linesize = %d\n", __LINE__);    
        return -1; // Couldn't find stream information
    }

    // Find the first video stream
    int videoStream=-1;
    for(i=0; i<pFormatCtx->nb_streams; i++){
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
            videoStream=i;
            break;
        }
    }
    
    if(videoStream==-1){
        printf("linesize = %d\n", __LINE__);    
        return -1; // Didn't find a video stream
    }
    
    // Read frames and save first five frames to disk
    while(av_read_frame(pFormatCtx, &packet)>=0) {
        av_free_packet(&packet);
    }

如果是ffmpeg2.0.1版本的话,添加一句就ok了。可是旧版本ffmpeg1.2.*没有stimeout这个字段可以设置
那么只好自己添加了。
在ffmpeg/libavformat/rtsp.h  struct RTSPState添加一个stimeout字段

typedef struct RTSPState {
    /**
     * timeout of socket i/o operations.(this version do not have this segment. added by yqing, refer to ffmpeg-2.0.1)
     */
    int stimeout;
} RTSPState;

在ffmpeg/libavformat/rtsp.c  ff_rtsp_options添加一个stimeout字段

const AVOption ff_rtsp_options[] = {
    { "stimeout", "timeout (in micro seconds) of socket i/o operations.", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },    //添加这行代码
    RTSP_REORDERING_OPTS(),
    { NULL },
};

在ffmpeg/libavformat/rtsp.c  ff_rtsp_connect函数修改部分代码如下

//ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL);                            //原代码
  ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, "?timeout=%d", rt->stimeout);     //修改后的代码

原贴地址:http://blog.chinaunix.net/uid-27091949-id-4186640.html

1:
如果数据是rtp/rtsp传输的话,ffmpeg会每隔30s(哪里设置该值?)发送一个keepalive包,如果ipc支持GET_PARAMETER命令,就发该命令等ipc回复以确认ipc还活着。
某些ipc(IPCamera)不支持GET_PARAMETER的rtsp命令。则会通过OPTIONS *来是keepalive,不过这会导致连接断掉
原代码,及修改部分如下。先这样处理,有时间再研究原代码为什么不这么处理。

点击(此处)折叠或打开

  1. //ffmpeg/libavformat/rtspdec.c rtsp_read_packet()
  2. if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN)) {
  3.         /* send dummy request to keep TCP connection alive */
  4.         if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 ||
  5.             rt->auth_state.stale) {
  6.             if (rt->server_type == RTSP_SERVER_WMS ||
  7.                 (rt->server_type != RTSP_SERVER_REAL &&
  8.                  rt->get_parameter_supported)) {
  9.                 ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
  10.             } else {
  11.                 // ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL);                 //原代码
  12.                 ff_rtsp_send_cmd_async(s, "OPTIONS", rt->control_uri, NULL);        //修改后的代码,这样就算ipc不支持GET_PARAMETER的命令可以keepalive了
  13.             }
  14.             /* The stale flag should be reset when creating the auth response in
  15.              * ff_rtsp_send_cmd_async, but reset it here just in case we never
  16.              * called the auth code (if we didn't have any credentials set). */
  17.             rt->auth_state.stale = 0;
  18.         }
  19.     }


2:
如果数据是rtp/rtsp/tcp传输,如果没有设置stimeout(socket timeout),那么server断线后av_read_frame会阻塞

点击(此处)折叠或打开

  1. AVFormatContext *pFormatCtx = NULL;
  2.     AVPacket packet;
  3.     AVDictionary *optionsDict = NULL;
  4.     char *streamurl1 = "rtsp://test:test@192.168.11.111:554/test.stream";
  5.     
  6.     // Register all formats and codecs
  7.     av_register_all();
  8.     avformat_network_init();
  9.     pFormatCtx = avformat_alloc_context();
  10.     av_dict_set(&optionsDict, "rtsp_transport", "tcp", 0);                //采用tcp传输
  11.     av_dict_set(&optionsDict, "stimeout", "2000000", 0);                  //如果没有设置stimeout,那么把ipc网线拔掉,av_read_frame会阻塞(时间单位是微妙)
  12.     // Open video file
  13.     if(avformat_open_input(&pFormatCtx, streamurl, NULL, &optionsDict)!=0){
  14.         printf("linesize = %d\n", __LINE__);    
  15.         return -1; // Couldn't open file
  16.     }
  17.     // Retrieve stream information
  18.     if(avformat_find_stream_info(pFormatCtx, NULL)<0){
  19.         printf("linesize = %d\n", __LINE__);    
  20.         return -1; // Couldn't find stream information
  21.     }
  22.     // Find the first video stream
  23.     int videoStream=-1;
  24.     for(i=0; i<pFormatCtx->nb_streams; i++){
  25.         if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
  26.             videoStream=i;
  27.             break;
  28.         }
  29.     }
  30.     
  31.     if(videoStream==-1){
  32.         printf("linesize = %d\n", __LINE__);    
  33.         return -1; // Didn't find a video stream
  34.     }
  35.     
  36.     // Read frames and save first five frames to disk
  37.     while(av_read_frame(pFormatCtx, &packet)>=0) {
  38.         av_free_packet(&packet);
  39.     }

如果是ffmpeg2.0.1版本的话,添加一句就ok了。可是旧版本ffmpeg1.2.*没有stimeout这个字段可以设置
那么只好自己添加了。
在ffmpeg/libavformat/rtsp.h  struct RTSPState添加一个stimeout字段

点击(此处)折叠或打开

  1. typedef struct RTSPState {
  2.     /**
  3.      * timeout of socket i/o operations.(this version do not have this segment. added by yqing, refer to ffmpeg-2.0.1)
  4.      */
  5.     int stimeout;
  6. } RTSPState;

在ffmpeg/libavformat/rtsp.c  ff_rtsp_options添加一个stimeout字段

点击(此处)折叠或打开

  1. const AVOption ff_rtsp_options[] = {
  2.     { "stimeout", "timeout (in micro seconds) of socket i/o operations.", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },    //添加这行代码
  3.     RTSP_REORDERING_OPTS(),
  4.     { NULL },
  5. };

在ffmpeg/libavformat/rtsp.c  ff_rtsp_connect函数修改部分代码如下

点击(此处)折叠或打开

  1. //ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, NULL);                            //原代码
  2.   ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port, "?timeout=%d", rt->stimeout);     //修改后的代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值