ffmpeg-3.1.4居然也有這么坑的bug


近日自己用下載的ffmpeg-3.1.4代碼自己編譯來用,沒想到會碰到這么一下低級坑。
我用自己的編譯出來的庫總是會在用rtsp上傳視頻時崩掉,起初我還以為自己編譯的x264出問題,因為我是繞開使用pkg-config,手動修改了configure文件。但是不關事,我重新解壓代碼編譯不帶其它三方編碼庫的版本,也發生同樣的結果。
結果是我用這份代碼包編譯出來的庫,只能用rtsp作為輸入卻不能用作輸出。沒其它更加好的辦法,只好看代碼+gdb調試之。
過程不多說了,時間時間還是時間,需要很多時間。
程序在和流服務器完成了OPTION,ANNOUNCE,SETUP,SETUP,RECORD的rtsp常規五步后,在一個UDP包也未曾前發出崩掉,死在rtpenc.c里

rtp_write_packet
Program received signal SIGSEGV, Segmentation fault.
rtp_write_packet (s1=0x2ca28c0, pkt=0x22d548) at libavformat/rtpenc.c:524
524     rtcp_bytes = ((s->octet_count - s->last_octet_count) * RTCP_TX_RATIO_NUM) /

原因是rtpmuxer的context(AVFormatContext,category為MUXER,outputFormat的classname是"rtp output"),它的priv_data為0, 這個priv_data原本應該是一個RTPMuxContext,但卻是0。這就好辦啦,原以為只要在代碼中搜索到這個RTPMuxContext的構建之處就開展偵測。但這是純c項目,而且還是個priv_data,近似union多種解釋。
沒辦法只好由這個priv_data往上一點一點追索整個關系鏈。鎖定十幾個角色(對象)和幾十處操作。


過程省略。
原來以為是沒有對priv_data進行構建,最后偵測到priv_data在某處進行構建,卻在另一處被改成了0。原來如此,但不對,這項目的代碼被全世界的人使用過,可能會出現這么滑稽低級的問題嗎。
但真的出現了。

插入說明,一般InputFormat對應是demuxer,outputFormat對應是muxer。一個解碼為主,另一個編碼為主。


RTSPStream::transport_priv在muxer分支中是一個AVFormatContext,這個context的priv_data就是RTPMuxContext的指針。
RTSPStream::transport_priv在demuxer分支是一個RTPDEMUXContext,而這個context的ssrc位置正是上面行context的priv_data。
就這樣弄好的muxer context被作為demuxer而慘被亂寫。

 

找來較前的版本2.7.7進行比較。位置在libavformat/rtsp.c,函數int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st):

int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st)
{
    RTSPState *rt = s->priv_data;
    AVStream *st = NULL;
    int reordering_queue_size = rt->reordering_queue_size;
    if (reordering_queue_size < 0) {
        if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP || !s->max_delay)
            reordering_queue_size = 0;
        else
            reordering_queue_size = RTP_REORDER_QUEUE_DEFAULT_SIZE;
    }

    /* open the RTP context */
    if (rtsp_st->stream_index >= 0)
        st = s->streams[rtsp_st->stream_index];
    if (!st)
        s->ctx_flags |= AVFMTCTX_NOHEADER;

    if (CONFIG_RTSP_MUXER && s->oformat && st) {
        // !!!!!!!!!!
        // 注意這里rtsp_st->transport_priv是作為AVFormatContext,進行Mux操作
        // 伏筆 1
        //
        int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv,
                                        s, st, rtsp_st->rtp_handle,
                                        RTSP_TCP_MAX_PACKET_SIZE,
                                        rtsp_st->stream_index);
        /* Ownership of rtp_handle is passed to the rtp mux context */
        rtsp_st->rtp_handle = NULL;
        if (ret < 0)
            return ret;
        st->time_base = ((AVFormatContext*)rtsp_st->transport_priv)->streams[0]->time_base;
        // !!!!!!!!!!!!
        // 即使已經作為Mux打開,也不返回,依舊順流而下。
        // 伏筆 2
        //
    } else if (rt->transport == RTSP_TRANSPORT_RAW) {
        return 0; // Don't need to open any parser here
    } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT && st)
        rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index,
                                            rtsp_st->dynamic_protocol_context,
                                            rtsp_st->dynamic_handler);
    else if (CONFIG_RTPDEC)
        rtsp_st->transport_priv = ff_rtp_parse_open(s, st,
                                         rtsp_st->sdp_payload_type,
                                         reordering_queue_size);

    if (!rtsp_st->transport_priv) {
         return AVERROR(ENOMEM);
    } else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RTP) {
        // !!!!!!!!!!!!!!!
        // 舊版本被打開過的Mux隨控制流自然流入這里沒有問題,因為沒有作其它操作
        //
        // 但是 !!!!!!!!!
        // 3.14版本 !!!!
        // 加入下面兩句,BUG就來了
        //
        // RTPDemuxContext* rtpctx = rtsp_st->transport_priv;
        // rtpctx->ssrc = rtsp_st->ssrc;       
        // ^ !!!!!! 上面這句等於將AVFormatContext的priv_data賦值。            
        //

        if (rtsp_st->dynamic_handler) {
            ff_rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv,
                                              rtsp_st->dynamic_protocol_context,
                                              rtsp_st->dynamic_handler);
        }
        if (rtsp_st->crypto_suite[0])
            ff_rtp_parse_set_crypto(rtsp_st->transport_priv,
                                    rtsp_st->crypto_suite,
                                    rtsp_st->crypto_params);
    }

    return 0;
}
    

3.1.4版本加入了兩行代碼引入了BUG。

解決方法也就是腳痛醫腳手痛醫手,在3.1.4版本增加的兩行代碼前加oformat判斷,一般地outputFormat為Muxer而inputFormat為Demuxer。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM