BufferQueue低延迟优化,以及SurfaceView帧率上限问题解决

目录

了解BufferQueue

为什么会出现问题?

如何优化?


最近在做一个与音视频播放相关的项目,使用到了MediaCodec解码后送到SurfaceView播放场景。发现SurfaceView播放上限是60HZ,不符合项目需求,故而进行了研究并找到了解决办法。送给SurfaceView的帧如果过快会被阻塞。

虽然文档描述,在android14,默认应当丢弃多余的帧(如下):

当将输出渲染到 Surface 时,Surface 可以配置为丢弃过多的帧(没有及时被 Surface 处理掉的帧)。 或者可以将其配置为不丢弃过多的帧。 在后一种模式下,如果 Surface 无法足够快地处理输出帧,则它将最终阻塞解码器。 在 Build.VERSION_CODES.Q 之前,确切的行为是不确定的,除了 View Surface(SurfaceView 或 TextureView)始终丢弃过多的帧。 从 Build.VERSION_CODES.Q 开始,默认行为是丢弃过多的帧。 应用程序可以选择通过设置目标 SDK 为 Build.VERSION_CODES.Q 并在其配置格式中将键 "allow-frame-drop" 设置为 0,将非 View Surface(例如 ImageReader 或 SurfaceTexture)的这种行为取消。

但是不清楚为何,并没啥用。只能另想他法。

故而此方法需要修改aosp代码,并不合适普通的应用开发。

环境:AOSP14

了解BufferQueue

Android的显示框架使用了BufferQueue作为图形缓冲区的缓存队列,我们不需要深究BufferQueue的实现细节,只需要了解其大概工作原理即可。

Android图形系统使用BufferQueue实现了一个非常典型的生产者消费者模型。

生产者(如app的view或者视频解码器等)通过dequeueBuffer方法从BufferQueue中获取空闲图形缓冲区,填充数据后通过queueBuffer方法归还图形缓冲区,同时通知消费者可以消费。

消费者(一般为SurfaceFlinger,负责图像的显示)接收到生产者的通知后,通过acquirebuffer方法从BufferQueue获取一个可显示的图形缓冲区,等待垂直同步事件到来后显示(每秒60次)。显示完毕后通过releaseBuffer释放图形缓冲区。

为什么会出现问题?

假设生产和消费都是每秒60帧的速率时,理想的生产消费时序如下图所示:

生产和消费有序进行,生产一个图形缓冲区随后便消费一个。BufferQueue待消费的缓冲区始终不超过1个。

但是实际的情况,尤其是涉及到网络时,生产速率远没有如此理想,如下图所示:

生产端因为网络抖动的问题,有两帧没用及时到达,导致两次生产和消费被跳过。随后网络恢复后,极短的时间内达到了3帧数据(本次帧+延迟达到的2帧)。因为消费者只能按照固定的显示速度显示,生产也会继续以相同的速率生产,此时BufferQueue内会永远积压大于1帧的数据。直到下次网络抖动导致无生产输出,消费者才会消耗队列内的缓冲区。

这种模型有助于平滑抖动,轻微抖动时可以天然的被平滑过渡,不易被察觉卡顿。但是随之而来的是,队列积压导致的延迟增加。

更要致命的是,如果生产者是120帧的视频,但是显示是60帧,那视频就会被慢放至原来的二分之一。

典型的如SurfaceView,其播放速率为60HZ,如果播放大于此帧率的视频会被慢放。TextureView无此问题,但是TextureView需要GPU绘制,无论从延迟还是内存带宽占用上都是不小的开销,况且不需要后期处理的场景GPU绘制一次完全多此一举。

当前这种问题在播放30帧视频时问题不大,因为消费快于生产,积压很快会被消费。但是仍有短期的积压可能。

在延迟方面,SurfaceView整体占用小,延迟低,但是可能短期丢堆积帧,还有帧率上限;TextureView没有帧率上限,但是延迟高啊!如何既要又要?

如何优化?

如果是需要低延迟的场景,优化也很简单。

方案一:判断积压缓冲数量,积压较多时通知生产者丢帧处理或者降低生产速度。但是Android框架下无法得到积压数量,改动框架成本较大。放弃。

方案二:生产者向BufferQueue插入新的缓冲区时,如果BufferQueue存在未及时消费的缓冲区,直接丢弃。理所当然,Android也考虑到了这点,BufferQueue支持此操作,图形缓冲区有一个mIsDroppable属性,为True时若此帧在下一帧插入队列时未被消费,则丢弃。但是尚不清楚如何使之生效。故代码内直接写死,简单有效。

编辑frameworks/native/libs/gui/BufferQueueProducer.cpp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值