ffmpeg-3.14居然也有这么坑的bug

近日自己用下载的ffmpeg-3.14代码自己编译来用,没想到会碰到这么一下低级坑。
我用自己的编译出来的库总是会在用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.14版本加入了两行代码引入了BUG。

解决方法也就是脚痛医脚手痛医手,在3.14版本增加的两行代码前加oformat判断,一般地outputFormat为Muxer而inputFormat为Demuxer。

时间: 2024-10-13 20:04:36

ffmpeg-3.14居然也有这么坑的bug的相关文章

开始学习 ubuntu 14.04 各种安装各种坑

一把鼻涕一把泪啊   新手不会就拿电脑练手 可惜我的新电脑了 ----------------------------------------------------nvidia gtx660双显卡驱动--------------------------------------------------------------- sudo apt-get install nvidia-331 nvidia-settings nvidia-prime 然后安装切换小工具 sudo add-apt-r

RISC-V踩坑记----__builtin_clz((x)库函数的应用

RISC-V的确是个好东西,可是,免费的东西往往需要付出代价才能得到了,最近遇到了一个算法中的问题,追了好久,最终追到了这个库函数中,没想到,这个库函数居然还隐藏着一些猫腻.值得记下来啊. 首先上一个在X86平台下的例子:  1 #include <stdio.h> 2 /* Position of the most significant bit of x */ 3 #define gap8_fl1(x) (31 - __builtin_clz((x))) 4 5 static int ar

FFmpeg 维基百科

FFmpeg是一个自由软件,可以运行音频和视频多种格式的录影.转换.流功能[1],包含了libavcodec ─这是一个用于多个项目中音频和视频的解码器库,以及libavformat——一个音频与视频格式转换库. "FFmpeg"这个单词中的"FF"指的是"Fast Forward"[2].有些新手写信给"FFmpeg"的项目负责人,询问FF是不是代表“Fast Free”或者“Fast Fourier”等意思,"F

安卓转战React-Native之windows下android环境搭建爬坑血泪史

前言 最近又有新的项目立项,所以好久都没有写博客了,然后都是利用闲暇时间来学习React-native. 由于安卓和ios的就业环境给移动端开发带来前所未有的冲击,于是乎很多伙伴们不得不另谋他路,然后现在比较火爆的Hybird和react-native也是对我们移动端的影响比较大,比如去面试会问你会nodej或者react不,前端工程师(js)转移动端的门槛变得很低,angularjs和reactjs都很不错,并且6月底阿里开源weex,估计很多人对weex还是特别期待的,唉,只能拿知识武装自己

AndroidStudio3.0到3.1遇到的坑

原文:https://blog.csdn.net/qq_36676433/article/details/80361064 本以为3.0到3.1仅仅是界面的优化,万万没想到的是这个坑比起2.0到3.0居然一点也不差,坑太大了,差了好多资料,解决了. 第一个坑: 项目中所有的compile都替换为api或者implementation,这个错报错的时候是有提示的,可以根据报错的提示进行修改即可; 第二个坑: 项目中的有些依赖包升级到最高;比如烦人的butterknife 我平时不用这个的,但是老项

FFmpeg示例程序合集-Git批量获取脚本

此前做了一系列有关FFmpeg的示例程序,组成了<FFmpeg示例程序合集>,其中包含了如下项目:simplest ffmpeg player:                  最简单的基于FFmpeg的视频播放器simplest ffmpeg audio player:       最简单的基于FFmpeg的音频播放器simplest ffmpeg pic encoder:        最简单的基于FFmpeg的图像编码器simplest ffmpeg video encoder:  

坑死我啊,一个WPF Adorner使用注意事项

1.见鬼了? 项目中遇到这样的要求,一个Button用一个Adorner装饰,这个Adorner上又有一个Button,如下面这样 此时,我们在点击小Button的时候只希望处理小Button的事件,可是这时候,居然大Button的事件也触发了.按道理上讲,Adorner和Button不在可视化树的一个层次上,即使冒泡也不可能冒到另一个分支上呀?这不科学呀,于是乎见鬼了~~. 2.小心求证 于是乎自己做了一个简单的Demo,怕因为工程中干扰因素太多导致的bug,可是!居然还是发生了!这个bug卡

关于django中间件使用的踩坑经历

背景 ??这个之前本地写的那个django测试项目说起,那时候写了个练手的项目,目的是为了熟悉总结django2.0和django1.8的区别.不试不知道,一试就发现了许许多多的坑以及bug,把这些坑以及bug解决完了之后,打算写篇文章记录下我遇到的问题以及解决方法和思路. 起因 ??起因是当我在自强学堂的django课堂上,看到了有一个demo,这个demo具体实现的效果就是当网站在正式环境上运行的时候,为了安全起见,将DEBUG改为False(关闭调试模式),但是导致网站发生错误无法查看错误

写给那些常年战痘的痘友们~~~

转载:https://www.douban.com/group/topic/34900818/ 转机出现在八月份那时候虽然我的脸非常非常严重但是我在学车我们的教练人非常非常好我把我的事情告诉他教练像一个爸爸一样一直耐心的开导我我的心情终于豁然开朗不再想任何关于感情的事情了非常开心的度过了学车的时光~但是痘痘还是很大而且严重的是被我挤了虽然什么都挤不出来可我还是挤了挤过的地方就是一个大坑太悲剧了啊~~可是我太着急了因为以前额头上的痘痘一两天就冒白点了挤了第二天就平了一个星期就看不见痕迹了但是这些痘