近日自己用下载的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。

ffmpeg-3.1.4居然也有这么坑的bug的更多相关文章

  1. 使用ffmpeg视频编码过程中踩的一个坑

           今天说说使用ffmpeg在写视频编码程序中踩的一个坑,这个坑让我花了好多时间,回头想想,非常多时候一旦思维定势真的挺难突破的.以下是不对的编码结果:                   ...

  2. FFMPEG系列一:Mac下FFMPEG编译安装配置及使用例子

    系统环境:10.13以前系统版本,没有升级到macOS High Sierra.正常情况是直接输入brew install ffmpeg即可安装ffmpeg,但是该过程还是有一些坑需要填. 一.mac ...

  3. 3D Lut 电影级调色算法 附完整C代码

    在前面的文章,我提到过VSCO Cam 的胶片滤镜算法实现是3d lut. 那么3d lut  到底是个什么东西呢? 或者说它是用来做什么的? 长话短说,3d lut(全称 : 3D Lookup t ...

  4. 120项改进:开源超级爬虫Hawk 2.0 重磅发布!

    沙漠君在历时半年,修改无数bug,更新一票新功能后,在今天隆重推出最新改进的超级爬虫Hawk 2.0! 啥?你不知道Hawk干吗用的? 这是采集数据的挖掘机,网络猎杀的重狙!半年多以前,沙漠君写了一篇 ...

  5. 搞了我一下午竟然是web.config少写了一个点

    Safari手机版居然有个这么愚蠢的bug,浪费了我整个下午,使尽浑身解数,国内国外网站搜索解决方案,每一行代码读了又想想了又读如此不知道多少遍,想破脑袋也想不通到底哪里出了问题,结果竟然是web.c ...

  6. HP ALM 使用经验

    使用HP ALM(Application Lifecycle Management)软件有一个多月的时间了,我是从安装,部署,建项,配置,使用,再到问题收集,这个过程过来的.发现ALM是一个功能确实强 ...

  7. bug检测报告---礼物挑选小工具--飞天小女警

    飞天小女警----礼物挑选小工具 测试产品链接:http://123.207.159.79:8088/giving_gifts/ 发布在作者的博客里面:http://www.cnblogs.com/s ...

  8. UVA 10816 + HDU 1839 Dijstra + 二分 (待研究)

    UVA 题意:两个绿洲之间是沙漠,沙漠的温度不同,告诉起点,终点,求使得从起点到终点的最高温度最小的路径,如果有多条,输出长度最短的路径: 思路:用最小费用(最短路径)最大流(最小温度)也能搞吧,但因 ...

  9. 3xian之所在(转)

    最后一天,漫天飘起了雪花,假装欢送我离去. 这次WF之战不太顺利,早期的C题大概花了1秒钟构思,然而由于输出格式多了一个空格直到两个半小时才逃脱Wrong Answer的纠缠.还好lynncui在期间 ...

随机推荐

  1. 基于canvas实现钟表

    原理说明 1.通过arc方法实现钟表外环: 2.通过line实现钟表时针,分针,秒针和刻度标志的绘制,基于save和restore方法旋转画布绘制不同角度的指针: 3.通过font方法实现在画布上绘制 ...

  2. 回头看 vue-router

    回头看 vue-router 复习 我的github iSAM2016 目录 响应路由参数的变化 嵌套路由 函数式导航 路由的命名 示例:切换路由的时候可以修改页面的标题 导航钩子 全局钩子 实例:检 ...

  3. Kafka 权威指南阅读笔记(第三章,第四章)

    Kafka 第三章,第四章阅读笔记 Kafka 发送消息有三种方式:不关心结果的,同步方式,异步方式. Kafka 的异常主要有两类:一种是可重试异常,一种是无需重试异常. 生产者的配置: acks ...

  4. Java自动化测试框架-06 - 来给你的测试报告化个妆整个形 - (下)(详细教程)

    简介 经过上一次的化妆和整形,有客户提出需求能不能将那个普通会员的套餐再升级一下,再漂亮一点.所以这次咱们就来看看从哪里下刀可以使它变得再漂亮一点点. 上一篇文章修改了一些基本的ReportNG信息, ...

  5. docker 概念简介、简单入门

    1.docker 简介 Docker 是一个开源项目,这个项目旨在通过把应用程序打包为可移植的.自给自足的容器(引用语) DocKer一次构建可放在任何地方就可以运行,不需要进行任何改变DocKer  ...

  6. Hibernate---快速入门

    Hibernate简介 Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可 ...

  7. Vue中Form表单验证无法消除验证问题

    iView的表单api给出了一个resetFields方法,用于重置整个表单输入的内容并清除验证提示. 但是有时候需要只消除部分的iview的resetFields方法源码是这样的resetField ...

  8. C语言1作业5

    问题 答案 这个作业属于那个课程 C语言程序设计1 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-2 我在这个课程的目的是 学习并掌握C ...

  9. [考试反思]1024csp-s模拟测试85:以为

    愈发垃圾. T1基本全场切(除了RP<-inf的zkt和把人擦) 然后T2想了半天逐渐趋近于正解,但是因为数据有问题锅了25分,没什么好说的.T3连题意转化都没有完成.括号匹配转为+1/-1做法 ...

  10. 大厂面试经:说一下你们线上JVM是如何优化的?

    JVM(Java虚拟机)简单来说就是运行Java代码的解释器,作为螺丝钉程序员JVM其实了解下就差不多啦,不懂JVM内部细节照样能写出优质的代码!但是一到造火箭.飞机的场景(面试)不懂JVM的你,会被 ...