zoukankan      html  css  js  c++  java
  • 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。

  • 相关阅读:
    LeetCode题解 | [简单-数组] 485.最大连续1的个数
    PAT乙级真题 | 1032 挖掘机技术哪家强
    [leetcode]两个列表的最小索引总和
    【leetCode】两个数组的交集
    手写hashMap(非红黑树)
    Redis 删除数据后不能自动释放内存的问题
    Spring @Async/@Transactional 失效的原因及解决方案
    完全平方数问题
    用队列实现栈
    memcached安装踩坑
  • 原文地址:https://www.cnblogs.com/bbqzsl/p/6012127.html
Copyright © 2011-2022 走看看