ffmpeg問題の要約と解決策

14546 ワード

1:rtp/rtsp転送であれば、ffmpegは30 sおきに(どこで設定しますか?)ipcがGET_をサポートしている場合、keepaliveパッケージを送信します.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転送でstimout(socket timeout)が設定されていない場合、server断線後av_read_フレームが詰まる
AVFormatContext *pFormatCtx = NULL;
    AVPacket packet;
    AVDictionary *optionsDict = NULL;
    char *streamurl1 = "rtsp://test:[email protected]: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
", __LINE__); return -1; // Couldn't open file } // Retrieve stream information if(avformat_find_stream_info(pFormatCtx, NULL)<0){ printf("linesize = %d
", __LINE__); return -1; // Couldn't find stream information } // Find the first video stream int videoStream=-1; for(i=0; inb_streams; i++){ if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) { videoStream=i; break; } } if(videoStream==-1){ printf("linesize = %d
", __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); }

ffmpeg 2なら.0.1バージョンなら、一言追加すればOKです.しかし旧バージョンffmpeg 1.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は30 sおきに(どこで設定しますか?)ipcがGET_をサポートしている場合、keepaliveパッケージを送信します.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転送でstimout(socket timeout)が設定されていない場合、server断線後av_read_フレームが詰まる
折りたたむか開くかクリック
AVFormatContext *pFormatCtx = NULL;
    AVPacket packet;
    AVDictionary *optionsDict = NULL;
    char *streamurl1 = "rtsp://test:[email protected]: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", __LINE__);    
        return -1; // Couldn't open file
    }

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

    // Find the first video stream
    int videoStream=-1;
    for(i=0; inb_streams; i++){
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
            videoStream=i;
            break;
        }
    }
    
    if(videoStream==-1){
        printf("linesize = %d", __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);
    }
ffmpeg 2なら.0.1バージョンなら、一言追加すればOKです.しかし旧バージョンffmpeg 1.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);//修正後のコード