高频卡顿问题分析

从监控图中可以看到,3.76k的用户,两分钟内报卡顿次数达到100万次 ,很恐怖,这个是非正常的卡顿

由于没有日志,只能先看代码分析,出现高频卡顿的原因

问题描述

在播放过程,会频繁上报卡顿,2分钟能报几百次,从报卡顿开始到卡顿结束最短时间接近0ms

做的相关实验

模拟测试

1.只有视频、没有音频,不会快进,能正常播放,只是没有声音
2.音频数据播放完之后,再播放一段视频数据,再来音频数据,不会有快进,只是音画不同步,能持续播放音频和视频,会出现一次卡顿
3.在一段音视频数据中,丢弃一段音频数据,会快进丢弃一段视频,音画同步之后正常播放 

--------------------------------------------------------------------------------------------------------------------------

1.丢少量音频帧(未出现音频缓存为空):无卡顿,视频有快进,音画同步后音频和视频均正常
2.丢很多音频帧(出现音频缓存为空):有卡顿(送音频之后卡顿消失),且视频无快进,后续音画一直不同步的持续播放

--------------------------------------------------------------------------------------------------------------------------

1.灌入正常音视频数据至队列的1/2,正常播放
2.快速灌入只有视频的数据,至队列满
3.按正常播放速度灌入正常的音、视频数据
这个现象是:
播放过程没有一次buffer,不过这个过程会有画面快进的现象,整个过程声音保持有,另外从日志看到,播放到一定时间后,音视频数据会同步,播放回归正常

--------------------------------------------------------------------------------------------------------------------------

在视频解码的地方延时50ms

SDL_AMediaCodecJava_dequeueOutputBuffer

 就会出现高频卡顿

数据分析

最近30天的数据分析

出现概率比较高的6个频道如下:

出现概率比较高的用户如下:

Buffer次数

设备数

备注

大于100k

3

最大次数198860

50K~100K之间

9

30K~50K之间

26

20K~30K之间

41

10

代码分析

从播放到buffer

场景

备注

是否可能

开始播放时候,先buffer

播放过程只会出现一次

可能

package拿不到音频的data的时候

本地实验切换声道即可复现

可能

seek的时候

用户拖动进度条,会清除缓冲队列数据

不可能

ffp_toggle_buffering(ffp, 0)buffer状态切换到播放状态

从buffer到播放

场景

备注

是否可能

缓冲满(音频加视频)

本地实验切换声道即可复现

可能

播放结束,从新播放

播放过程只会出现一次

不可能

音频和视频缓冲区两个都达到播放大小

这个是500ms去判断一次

不可能

原因

从代码上分析上看,只有一种情况会导致频繁buffer,即:

解复用视频流的线程,缓冲区里读音频数据,当读不到音频package的时候,就会报buffer;而read线程判断到播放器缓冲区满15m的时候,就会把播放器状态从buffer状态改到播放状态。如此循环,就会导致频繁buffer

解决方案

如果出现频繁buffer原因是由于播放器缓冲达到最大限制,而音频的packat却为0导致的,这个时候播放已经音频不同步,可以通过清除播放器缓冲来解决。当前MFC点播用户也有反馈,播放过程会出现没有声音的情况。

后续

是什么样的情况会导致播放器缓冲已经满,但是音频的packat却为0呢?可能原因

  1. 视频流或者传输过程出现问题
  2. 系统已经出现问题,导致音视频同步出现问题。猜测依据是MFC点播系统,有相当一部分客户反馈播放过程会出现没声音的场景

BUFFER TIMEOUT: remove(4099) from active list on thread 0xa6e03440

D/AudioHardwareTiny: close device但是这个只会出现一次

低内存实验

出现视频队列里的帧数为0,音频满。。。

正常启动播放器

只会出现一次

来回切换HOME键

当低内存的时候,new_packet == 0时竟然会有q->is_buffer_indicator = 0的情况,导致new_packet == 0不报卡顿

为什么q->is_buffer_indicator = 0呢?

   if (is->audio_stream >= 0) {
        is->audioq.is_buffer_indicator = 1;//音频流队列有效
        is->buffer_indicator_queue = &is->audioq;
    } else if (is->video_stream >= 0) {
        is->videoq.is_buffer_indicator = 1;//视频流队列有效
        is->buffer_indicator_queue = &is->videoq;
    } else {
        assert("invalid streams");
    }

原来是以audio为先,所以音频的 is_buffer_indicator为1,视频的is_buffer_indicator为0,所以产生频繁卡顿的条件只有一个,就是audio为0

vd代表video.duration,vp代表video.packat,vb代表video.size

从图中可以看出,当video的缓冲数量为0时,duration并不为0.。。。

AudioTrack Underrun optimization · Issue #7808 · google/ExoPlayer · GitHub

android - AudioTrack restarting even after it is stopped - Stack Overflow

Ok, I think the problem is solved. The error is generated when the buffer is not completely filled with data on time (buffer underrun) . I have no idea what the timeout is but if you experience this make sure that:

1、You don't call the play method until you have some data in the buffer.

2、You can generate the data fast enough to beat the timeout.

3、After you are finished feeding the buffer with data, before you call stop() method, make sure that the "last" buffer was completely filled with data before timeout.

当我实例化名为 audioTrack.play() 的 Audiotrack 时,我收到了该警告,并且 play() 调用和 audioTrack.write() 之间存在轻微延迟。 如果我在 write() 之前调用 play() 警告消失了。

Keep in mind that you must always send the buffer in smaller chunks,
 even if you have the big chunk ready. It still bothers me a bit that
 I'm not 100% sure if that is the right way but the errors are gone so I guess I can live with that :)
您必须始终以较小的块发送缓冲区,即使您已准备好大块。 我仍然有点困扰,我不是 
100% 确定这是否是正确的方法,但错误已经消失,所以我想我可以接受:)
I've solved by this

        if (mAudioTrack.getPlayState()!=AudioTrack.PLAYSTATE_PLAYING)
            mAudioTrack.play();
        mAudioTrack.write(b, 0, sz * 2);
        mAudioTrack.stop();
        mAudioTrack.flush();

android 0.5.1使用硬解码出现ANR · Issue #1388 · bilibili/ijkplayer · GitHub

I find out that it is caused by AudioTrack.write blocked for 5 seconds in ijksdl_aout_android_audiotrack:aout_thread_n
I try force pauce in stream_component_close audio before SDL_AoutCloseAudio(ffp->aout)
 as a workaround Are there any better ways?
我发现它是由 AudioTrack.write 在 ijksdl_aout_android_audiotrack:aout_thread_n 中阻塞 5 秒引起的
我在 SDL_AoutCloseAudio(ffp->aout) 之前尝试在 stream_component_close 音频中强制暂停作为解决方法
有没有更好的方法?

 09-21 12:05:39.843: W/AudioTrack(3956): obtainBuffer() track 0x2bec20 disabled, restarting错误_weixin_34122604的博客-CSDN博客

一般都在一个进程里面使用AudioTrack对象,AudioTrack对象使用完而回收,就会出现以上错误。解决方法是调用AudioTrack对象的release方法。释放AudioTrack对象,解除资源占用。

重要发现,当播放MP4完成后,执行ijkMediaPlayer.reset(),就会百分百出现

点播出现画面卡住,然后没声音,字幕还在稍微的动。出现问题的影片,都是在指定的位置,即特定的block后,画面就卡住

每次都是第90个block开始卡住

这个时候v.size缓冲区已经满,但是audio为0这个即为高频卡顿?

我们自己测试到高频卡顿现象,首先看到的日志是内存溢出,还有出现很多

Binder:2923_7 expire 8 lines

Slow operation: 52ms so far, now at startProcess: returned from zygote!

 

 软解出现高频卡顿了。。。软解才导致?

  硬解也出现高频卡顿。。。。video.size也出现15m。。。。为啥????

1.解决AudioManager可能存在的内存泄漏问题 (639a3a34) · 提交 · andylao62 / DKVideoPlayer · GitCode

解决AudioManager可能存在的内存泄漏问题 

android-(AudioManager)getSystemService(Context.AUDIO_SERVICE)导致内存泄漏-icode9专业技术文章分享

(AudioManager)getSystemService(Context.AUDIO_SERVICE)导致内存泄漏

有盒子出现media.codec进程报错的情况,这个进程出错,会导致画面不动,视频数据满,音频数据为0的情况

从这里可以判断,如果media.codec进程报错,如果没有换台,会一直是硬解码,也会一直报卡顿

 

解码这里加延时后,会有Log

 

 同时出现高频卡顿

 最终解决方案:

1、查内存泄漏

2、ijk切换到软解的时候,通知前端,让前端提示需要重启设备

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值