在Intel® Core™ i5-4460 CPU @ 3.20GHz 4核4线程中,视屏1080i50,12M,一路编码视频推流到服务器,一路Testpattern h264拉流解码,id为83,播放出来后音频偶尔卡顿,不明显,但缺乏长时间压力的测试。
两路的话,id为47,但Testpattern声音卡顿较一路明显。crtl+c有延时。
推流端改为在i7上推到本机i5-4460的sls服务器,本机四路Testpattern h264拉流解码喂给decklink。四路情况下声音无卡顿,0/1路用的是-m 3,2/3路用的是-m 17。id:22。四个核负载均衡。
之前出现卡顿可能的原因,绿屏的卡顿,推流端刚刚开始推流没有稳定,本机就开始拉流了。
编解码方式:
几路:
WxH帧率:
码率:
id:
cpu:
服务器和推拉流端部署在同一个计算机吗:
视频质量:
音频质量:
每个核是否负载均衡:
decklink使用:
testpattern 改变-m 后的的参数 视频调用间隔跟帧率相同,音频不跟帧率相同,都是20ms调用一次
改变这个函数StartScheduledPlayback(0, 100, 1.0)视频调用速度也会改变,目前测得大于1或是小数,视频调用速度都会增大,但音频调用速度依然不变是20ms
测得一个数据,在31ms内,调用7次音频喂给decklink,没有一次报错,说明音频是可以多次接收的,但视频根据测试如果喂频繁了会出现错误。
比如1080i50,视频调用的速度应该是40ms,但如果一次调用,函数本身就达到了50ms,decklink会在函数返回后7微妙(假如这个时间变量设置为x)左右的速度再次调用,并不是错过了一个调用点必须等到40ms后下一个调用点到来,考虑是用的信号量的方式通信调用。
测试得目前Testpattern时间都花在解码和av_read_frame这个函数上,解码一帧视频大概花费20ms左右,av_read_frame一般是1-2微妙,但有时会跳出20ms这样的大数字,但不会更大,跟读的是音频还是视频没有关系,考虑是等待流的阻塞。喂一帧音频在1微妙左右,喂一帧视频在300微妙左右。所以如果x的值不增大,理论上目前testpattern代码是最优的一种方式之一。另一种就是根据解码去调用喂的函数。
x测得一次7800微妙,但在它之前的几个x值依然正常只有20微妙。
四路梳头的时候有个卡顿。-m 3听得,p24。
排除问题在哪:一次卡顿时x并未超过5000微妙,也并未GetBufferedAudioSampleFrameCount执行错误,或剩余的缓冲小于2000个采样。推测可能是推流端问题或者实时流存在的网络丢包。
Actual_num还有实现,也有可能是这个导致断音。还有耳机的问题,但这个概率比较小。还有阿童木哈哈哈。
用耳机插在电脑上发现耳机没有问题,之前是阿童木3.5ms孔接触不良。
推流同样在i7上,虚拟机是四核四线程,后台部署在虚拟机上,然后ffplay -fflags nobuffer播放,推流端稳定在24帧后,依然有卡顿。此说明不能认为testpattern有问题。
用不含nobuffer的ffplay播放,观察是否有断音。目测两种ffplay延迟相差5s左右。西虹市首富上半部一个小时*两次播放,无断音。因此推断,不含缓存是断音的原因。
目前发现代码解码中,有无buffer延时相当,但有buffer后,音频有延时,考虑是有buffer后一次给decklink的过多,占大部分满缓冲区(占了40000个采样)。这样地方需要优化,然后观察是否还有断音。
代码改为无buffer后,1.2M情况下,一路拉流解码,西虹市首富半部无断音。连续运行一天再听半部的一半依然没问题。
无buffer后,12M,四路拉流,半部西红柿有断音,id20。
无buffer后,12M,一路拉流,半部西红柿无断音, id77。
因为推流端没问题,所以根本原因:目前的策略是认为断音是出现在发送七帧音频后,获取四帧视频花费的时间太久,放进去的音频已经被读完了,还没来得及放进去新的音频。因此可以通过增加音频的缓冲区,但会出现视频不同步的现象。需要改变视频的时间码来解决。
分析为什么会出现根本原因,是否是性能的问题,还是代码的问题。
Testpattern测试,周六晚上17:36,可执行程序即代码。
根本原因有两种,Decklink的缓冲区要么读完了,要不满了,送不进去了,debug发现执行久了这两种都会发生。
现在的策略是将缓冲区维持在25000个采样,一开始送进去一些音使其够25000,后面当超过这个音时,usleep(10000),保持维持。25000也给计算机性能是一个比较宽松的值了,如果这个值还不能满足,那就需要提升性能了。不过这也有个问题,就是音频相对视频有些滞后,需要将视频也滞后一些。拓展:了解av_read_frame在1080p24的推流下,运行一段时间后(约30分钟),为什么100ms没接受到音频和视频。观察首屏是否音频卡顿。
即使这样台式机也无法完成四路拉流,一夜四路跑崩一个,崩前连续四个视频帧解码耗时:53ms,46ms,54ms,67ms,再往前十几帧每帧解码都花费50-80ms,更有一个次达到90ms,致使Decklink音频缓冲区音频被消耗完。但这些帧的av_read_frame都在200微妙左右,最多2ms,x值每次60微妙左右。崩是因为解码耗时过长,这是性能问题。
再次测试四路一夜全崩,有一个崩是因为read_time,连续几个耗时50-90ms,解码耗时没问题。第二个也是read_time,连续几个耗时60-120ms,解码耗时正常水平。第三个是因为解码问题,连续十几帧解码花费50ms-70ms,read_time耗费时间200微妙左右。第四个是因为解码问题,连续十几帧花费50ms-70ms,read_time耗费可以忽略。
考虑到上面两次实验可能用的是-m 17,因此再次测试,用-m 3。4路测试,前一天下午3点钟开始,5点10分第三个断了,手工断第四个,留前两路跑。第二天上班:前两路也断了,第一路因为read_time太长,连续四帧里出现两帧read_time为140ms,89ms。第二路连续四帧里出现两帧read_time为63帧,116帧。第三个断是因为解码耗时太久,最后十个解码都在50ms以上,这个是因为四个一起跑,是性能问题。前两个不是性能问题,两路id为50,read_time不可能读100ms没收到一帧视频或者音频,推流端不会有问题,推测是跑久了台式机读写io发热导致读写卡顿了。
换成i7测试,4路解码,sls,一路ffmpeg推流。id为40,上午10:41开始,12:00断第二路,read_time和解码耗时都比较长,其他三路缓存也逐渐减少。13:33开始测试一路解码。
增加视频和音频的时间戳之后,上午11:00开始一路测试,id为70。半步西红柿无断音,跑5个小时后又听半步,无断音。下班前:依然在25000左右,并且7A睡六次,内存没有泄露为依然为50680测到第二天上班:buffer在17000左右。内存为45872,解码20ms左右,read_time是0-25ms左右。上午听半部西红柿音频没问题。连续一个小时稳定在14000左右,最后一个read_time花费148ms,上午11:00崩了,前一组音频读完还在14000左右,解码依然稳定在20ms左右,前几帧读都在10-20ms左右。是io读写性能的问题。再次启动几次没有睡眠了,执行一夜性能没缓过来?
换成i7 一路解码+推流, id70上午11:30测试,下午15:20崩,崩之前解码20ms左右,
但在最后一组视频中,一个read_time155ms,一个read_time86ms然后就崩了。现在可得出结论并不是性能问题,就是read函数阻塞问题。
在i7上每次用电视盒子,+A-B也靠概率,用电视盒子推会出现视屏抖动,推测是高温引起。
在台式机上推,电视盒子推,不出现抖动,上午11:30开始推,第二天9:00依然维持-A+B,但是电视盒子设置的只推12个小时自动关机。上午9:00重新开始推。
保留12M的问题,导致read阻塞。
后面可能要做其他工作这个要放一段落,总结一下:
有两个问题1,read函数有时阻塞太久,使得缓冲区出现问题,解决方法,超时设置或者睡眠。
在i7上Capture推,Testpattern拉,视频出现叠影卡顿。这个目前还不知道原因,但在台式机上就没问题,换成ffmpeg推也没问题。
台式机上,当缓存是0时也不立马exit,在每次调用av_read_frame之前主动睡5ms,10:49开始测试,发现read_time每次用的时间比较少,并且稳定,过程中发现弹性较大,有时候只有10000个采样,但能缓回来,测试到13:17,依然没什么问题。13:20再次测试,这次开始没有+A-B,read_time普遍在5ms左右,看到几分钟后只有10000后又缓会24000了,中间几次降到10000最后都缓回来了,待第二天9:00依然在24000左右。当缓存为0时立马exit,重新测试,9:01开始,下午出现buffer == 0,发现最后几帧read_time频繁出现20ms,30ms。编码器在30ms左右,启动初始编码器在20ms左右。说明这种情况下是有可能到0的即使它会自己缓回去。以上是decklink10ms+read_time5ms。
下面改为
deck3ms+read_time5ms:buffer==0崩了,最后read_time始终保持6ms,但解码器频繁在40-50ms。
deck20ms+read_time5ms:开始没有+A-B,30秒后缓到+A-B,17:00开始测试,设置了buffer为0直接exit(1),编码25ms左右,read_time最后几帧含120ms,57ms,37ms。
deck8ms+read_time5ms:十次开启均有+A-B,开始有+A-B,10:00开始测试,10:25看到只剩10000又缓过来了,11:10崩了,read_time普遍在7ms左右,但编码在30ms-40ms。
deck8ms+v+a10ms(也就是没次调用完视频睡10ms):开始三分钟内都没有+A-B,在22000左右,11:57开始,read_tijme最后几帧频繁在10ms-30ms,解码在27ms左右。
deck8ms+v+read_time5ms:解码线程改为4个,原来是1个,开始几分钟都不是+A-B,13:30开始,read_time最后几帧50ms,75ms,17ms,解码在20ms左右。
deck3ms+read_time5ms:解码线程改为4个,13:50开始测试,read_time最后几帧68ms,50ms,48ms。
deck3ms+read_time0ms+<30000:解码四线程,连续十次启动均有+A-B,14:00开始测试,15:25崩,最后几帧解码在20ms,但read_time在147ms,87ms,50ms等。
deck3ms+read_time0ms+<30000:15:30开始测试,解码1线程,16:36时解码器普遍在20ms左右,read_time在100微妙左右,依然+A-B,待记录稍后的结果,看到其中一个次10000多又缓回来了,17:18崩,明天再记录结果原因。
一下是第一个问题的解决尝试:
目前正在测试两个flags 13:19开始
AVFMT_FLAG_NONBLOCK
AVIO_FLAG_NONBLOCK
这两个一起添加read_time依然会阻塞,阻塞了114ms。
只测试AVFMT_FLAG_NONBLOCK 13:45开始 read_time一次54ms 再次测试不含AVDictionary 14:32开始 reat_time200ms
只测试AVIO_FLAG_NONBLOCK 15:04开始 read_time 51ms
只测rw_timeout 15:18开始29ms
设置回调函数也没有用,av_read_frame阻塞的地方有很多个,回调函数中断的地方有限。
发现ffmpeg命令推流的西红柿,7帧音频4帧视频,而用decklink采集电视盒子,1/2帧音频1帧视频,源都是同一份西红柿.mp4。
如果是音视频交叉的话,音频被读完的可能性非常小了。
偶尔短暂的吱声,是音频源的问题,可能是电视盒子或者是编码速度太快,或者计算机性能问题。
一次统计:
avcodec_decode_video2视频有30帧缓存。
avcodec_receive_frame有64帧缓存。
在台式机上测试:一路Capture,一路TestPattern,崩掉,从decklink音频缓冲区含24755个采样开始,经过3162秒,缓冲区消耗完,出现断音。1080i50。
这个时间段:音频解码获得113帧,视频68帧,但要想维持平衡,音频应该发来137帧,视频应该是79帧,音频缓冲区应该同样是24755左右。
(3162/23)x1115 == 24755 + 113x1115。
得到结论,台式机testpattern运行消耗正好,不快不慢。