-------------别人解决的, rtmp中音频和视频数据不对称导致的卡顿的情况-----------------

本文主要是介绍-------------别人解决的, rtmp中音频和视频数据不对称导致的卡顿的情况-----------------,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:http://www.cnweblog.com/fly2700/archive/2011/12/06/318916.html



(原创) 
花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快。
 事情是这样的,前面跟外地一家公司,开发一个二路RTSP音视频合成一路RTMP音视频的设备。设备在公司内运行是好好的,可到了现场,出现直播流畅,录制后点播卡顿的问题。由于设备在外地,调试不方便。只能这边写日志打印代码,那边烧程序调试,于是远程调试的恶梦开始了。远程操作画面卡不说,关键是慢,本来一个几分钟的事情,远程要搞几十分钟。长达5天的远程调试,真是对人的耐性的一种考验。
 首先我怀疑的是时间戳不均匀。于是我将发送端的时间戳,接收端的时间戳分别日志成文件,统计,没有发现过大或过小的时间戳。也没有发现累计时间戳和累计到达时间偏差很大。这样能排除时间戳的问题。
 其次我怀疑是数据格式的问题。我们这边RTSP的数据源设备和现场的不一样。于是我又写代码,将RTSP下拉的数据保存文件,去掉RTP头,添加SPS、PPS,保存为裸H264文件。数据用VLC播放这个裸H.264文件,结果可以流畅播放,说明视频数据是完整的。再写代码将H264文件分帧并用RTMP协议打包发送直播,FP能流畅直播,录制依然是卡的。开始怀疑我的分帧发送代码是否有问题,于是将我以前录制好的H.264文件拿来,用同样的方法测试,结果直播流畅,录制流畅。同样的代码不同H264文件有不同效果,那么可能是H264文件格式的不同。于是分析h264文件的NAL。NAL等于5的就是关键帧。录制流畅的h264每个关键帧之间的间隔是固定的32,而录制卡顿的H264文件,十几个关键帧连在一起。根据以往经验,这是变码率的H264数据。我的RTMP协议栈并没用支持这种格式。于是开始分析这种变码率的h264格式,在我自己的电脑里面搭建环境调试改写协议栈,轻车熟路,没过多久,我的RTMP协议栈能支持发送这种变码率的H264数据直播了。直播流畅,录制流畅。好像问题攻克了。于是带着高兴的心情,将程序更新到我的远程设备,运行。一看效果,刚开始直播和录制流畅,没过多久就开始卡顿了。和之前卡顿不同的是,卡顿频率降低了,而且FP会反复打印日志NetStream.Buffer.Empty。刚才高兴的心情一下子仿佛回到了解放前。
 根据经验,这种情况一般是网络带宽不足,播放端缓存不足,或时间戳过小导致。于是我让在现场的工作的人员测试播放,结果他们在局域网看效果仍然卡顿,排除了带宽不足的问题。然后我增加播放器缓存到5秒,播放依然卡顿,又排除了缓存不足的问题。再然后我将发送端时间戳,接收端时间戳日志到文件,终于发现问题了。发送端时间戳正常,而接收端时间戳出现4000以上的大时间戳。按道理发送30帧每秒的视频,平滑处理后的时间戳应该是33-34。如果是FMS将我的时间戳修改增加了,那么会导致累计时间戳比累计时间大,但结果统计这二个值相差不大。我也没有发现有过小时间戳来中和这个大时间戳,那么累计时间戳是如何保持不变的呢,有一种可能性,丢包了。我将统计的帧数除以时间打印出来发现接收端只有20帧每秒。发送端打印的是30帧每秒。恩,可能是丢包了。我想看看是哪些数据丢了,于是将发送端的数据记录到文件,接收端接收的数据也保存到文件,对比,竟然发现数据总大小一模一样,说明没有丢包。于是我逐帧地对比发送端和接收端的数据,发现接收端有一包里面包含十多个帧的现象。而这种现象出现在接收到一个大关键帧的后面。FMS为什么会将大关键帧帧后面的小参考帧连起来做为一帧呢?这个问题我想了很久,也做了各种各样的实验。修改了多种打时间戳的方法和平滑时间戳的方法,也没有效果。最后,我猜测是否因为音频数据不足导致。因为我知道音频和视频播放不一样,它不会因为时间戳打得快就快放,它按照自己的频率计算时间匀速播放。如果音频数据不足或丢失,那么本来应该和它一起播放的视频帧会快进或跳过。于是我将发送音频部分的日志打印出来,果然发现存放问题,音频数据的环形缓存区满了,导致音频丢包。我为了防止重入,发送视频包的时候,音频不能发送。而且我们是1080P 的视频,视频关键帧有上百KB。我的音频环形缓存长度设置的10个。瞬间导致音频缓存满,然后就是音频数据丢失。于是我将音频环形缓冲长度改为30,日志显示环形缓冲最大不超过20个。小心地将最新的程序更新到设备,看效果,直播依然卡顿。我明明解决了一个BUG,竟然没有效果。神啊,救救我吧,我已经花了4天时间了,早已身心疲惫。
 当然,神是不会理我的,这BUG还是要我们程序员自己解决。FP还是打印日志NetStream.Buffer.Empty。于是又来分析时间戳,统计,没有发现过大或过小的时间戳。也没有发现累计时间戳和累计到达时间偏差很大。但是发现累计时间和累计到达时间相比戳抖动比较大。说明时间戳没问题,只是有些包来晚了,然后后来又补上了。这样子好像是远程直播带宽不稳定导致。于是让在现场的工作人员测试直播,效果流畅。再让他们测测录制,也是流畅的。反复测试没出现卡顿,问题终于解决了。心情愉悦。
 
总结,1,找BUG需要沉下心来,找不到问题不要灰心,一定要充满斗志,否则容易中途放弃不前。 2,判断问题需要准确定位,在一个错误方向上努力完全是浪费时间。3,多做实验,写日志,用数据说话,不要凭空猜测。4,写代码的时候,日志不要多,但处理严重错误的时候还是需要日志一下,方便日后排除错误。不要像我缓冲满了也不printf一下。



评论

re: 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快  回复  更多评论   

写的太好了,受益匪浅
2012-02-16 09:56 |  wxg0130

re: 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快  回复  更多评论   

发送端时间戳正常,而接收端时间戳出现4000以上的大时间戳。按道理发送30帧每秒的视频,平滑处理后的时间戳应该是33-34。如果是FMS将我的时间戳修改增加了,那么会导致累计时间戳比累计时间大,但结果统计这二个值相差不大 

这个时间戳是H264的IBP帧的时间戳还是RTMP包的时间戳呢?如果是264的时间戳不是连续增加的吗?33-34是rtmp包的相对时间戳吗?rtmp包的时间戳有什么作用呢,接触不多,请赐教
2012-02-16 10:19 |  wxg0130

回复:wxg0130   回复  更多评论   

1我指的是RTMP包的时间戳。 
2发送的rtmp包时间戳是相对时间戳。 
3rtmp时间戳是用来做音视频同步的。
2012-02-23 14:47 |  ZhangEF

re: 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快  回复  更多评论   

写的很好,给我们程序员很大的启发。有一个问题想请教一下博主。我做的也是获取到视频,经过X264编码,通过RTMP协议发送到RED5,可是发送的视频用flash播放器出现黑屏,但是时间正常走着。除了flash 播放器外,其他的播放器都可以播放,请赐教一下,这是怎么回事
2012-10-31 11:12 |  阿日月

re: 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快  回复  更多评论   

你好,我将dm368编码的h264视频裸流保存成文件,但是vlc打开后发现播放速度是原来的两倍,请问知道是为什么吗?
2013-01-09 10:35 |  AMAM

re: 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快[未登录]  回复  更多评论   

@AMAN
编码的时候,输入正确帧率就可以了。如果不输入帧率,编码后的裸H264 文件VLC会用默认帧率播放,默认好像是25还是30的。如果你实际压缩是15帧每秒,按照默认帧率播放就会快放了。
2013-02-11 17:39 |  ZhangEF

re: 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快  回复  更多评论   

请问大神,我写的实现流播放器。在开发工具下直接运行,画画是不卡的,但是当我打包出来,安装播放, 画画就变得一卡一卡的?这是为什么啊?
2013-08-13 11:04 |  黑熊

re: 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快  回复  更多评论   

请教一下,如何添加SPS、PPS,将数据保存为裸H264文件?如能告知,万分感谢!
2013-08-16 09:56 |  lxdlut




这篇关于-------------别人解决的, rtmp中音频和视频数据不对称导致的卡顿的情况-----------------的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/611307

相关文章

一文教你Python如何快速精准抓取网页数据

《一文教你Python如何快速精准抓取网页数据》这篇文章主要为大家详细介绍了如何利用Python实现快速精准抓取网页数据,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录1. 准备工作2. 基础爬虫实现3. 高级功能扩展3.1 抓取文章详情3.2 保存数据到文件4. 完整示例

解决IDEA报错:编码GBK的不可映射字符问题

《解决IDEA报错:编码GBK的不可映射字符问题》:本文主要介绍解决IDEA报错:编码GBK的不可映射字符问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录IDEA报错:编码GBK的不可映射字符终端软件问题描述原因分析解决方案方法1:将命令改为方法2:右下jav

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

MyBatis模糊查询报错:ParserException: not supported.pos 问题解决

《MyBatis模糊查询报错:ParserException:notsupported.pos问题解决》本文主要介绍了MyBatis模糊查询报错:ParserException:notsuppo... 目录问题描述问题根源错误SQL解析逻辑深层原因分析三种解决方案方案一:使用CONCAT函数(推荐)方案二:

python处理带有时区的日期和时间数据

《python处理带有时区的日期和时间数据》这篇文章主要为大家详细介绍了如何在Python中使用pytz库处理时区信息,包括获取当前UTC时间,转换为特定时区等,有需要的小伙伴可以参考一下... 目录时区基本信息python datetime使用timezonepandas处理时区数据知识延展时区基本信息

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

SpringMVC 通过ajax 前后端数据交互的实现方法

《SpringMVC通过ajax前后端数据交互的实现方法》:本文主要介绍SpringMVC通过ajax前后端数据交互的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价... 在前端的开发过程中,经常在html页面通过AJAX进行前后端数据的交互,SpringMVC的controll

IntelliJ IDEA 中配置 Spring MVC 环境的详细步骤及问题解决

《IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决》:本文主要介绍IntelliJIDEA中配置SpringMVC环境的详细步骤及问题解决,本文分步骤结合实例给大... 目录步骤 1:创建 Maven Web 项目步骤 2:添加 Spring MVC 依赖1、保存后执行2、将新的依赖

Spring 中的循环引用问题解决方法

《Spring中的循环引用问题解决方法》:本文主要介绍Spring中的循环引用问题解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录什么是循环引用?循环依赖三级缓存解决循环依赖二级缓存三级缓存本章来聊聊Spring 中的循环引用问题该如何解决。这里聊

Pandas统计每行数据中的空值的方法示例

《Pandas统计每行数据中的空值的方法示例》处理缺失数据(NaN值)是一个非常常见的问题,本文主要介绍了Pandas统计每行数据中的空值的方法示例,具有一定的参考价值,感兴趣的可以了解一下... 目录什么是空值?为什么要统计空值?准备工作创建示例数据统计每行空值数量进一步分析www.chinasem.cn处