我想问一下,是否可以通过覆盖视图提高录制屏幕的 FPS。
应用程序的伪结构:
1)AppCompatActivity中的全屏FrameLayout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:id="@+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
...
>
<RelativeLayout
android:id="@+id/controls"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<RelativeLayout
...
>
<ImageView
...
/>
<TextView
...
/>
</RelativeLayout>
</RelativeLayout>
</FrameLayout>
2) 使用 SurfaceView 进行相机预览:
class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
3)获取SurfaceView(CameraPreview),将CameraPreview添加到FrameLayout中,放到最前面
mPreview = new CameraPreview(this, mCamera); //surfaceView
frameLayout.addView(mPreview); //add surfaceView to root: FrameLayout
controls.bringToFront(); //bring controls to top Z-order
MediaProjection.createVirtualDisplay(...)
4) 创建输入表面 + 创建虚拟显示器并通过Next将虚拟显示器渲染到表面,MediaMuxer
用于音频/视频多路复用流。
第3点:问题
当我评论行时:controls.bringToFront();
视频有〜30FPS,但视频中没有覆盖视图。
当我取消注释行时:controls.bringToFront();
视频在视频中有叠加视图,但 FPS 仅为 ~20。
或者
当我禁用CameraPreview
视频有〜30FPS,但没有相机预览。
问题可能与覆盖视图有关。当我在设备的调试模式下启用过度绘制时:请参阅
相机预览过度绘制 1x(紫色)
ImageView 过度绘制 2x(绿色)
TextView 过度绘制 3x(粉红色)
当我在设备上以调试模式启用分析 GPU 渲染时:请参阅
我在绿线 (16ms) 下的所有条。
也许我有一些低效的东西。目标是用相同的 FPS 记录屏幕,有/没有覆盖视图。有可能的?
使用screenrecord
命令和 Hardware Composer 进行测试:
A)启用视图覆盖;启用相机预览:
$ ./adb shell screenrecord --time-limit 10 --bit-rate 6000000 /storage/sdcard1/demo3.mp4
结果是视频文件:1280 x 720;H.264 / AVC;20FPS;比特率:4585 kb/s。
硬件作曲家:
type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name
HWC | 557cf928d0 | 0000 | 0000 | 04 | 0100 | ? 00000011 | 0.0, 0.0, 1280.0, 720.0 | 0, 0, 720, 1280 | SurfaceView
HWC | 557cf40dd0 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 720.0, 1280.0 | 0, 0, 720, 1280 | com.example.test/com.example.test.RecordActivity
FB TARGET | 557cf3fd00 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 720.0, 1280.0 | 0, 0, 720, 1280 | HWC_FRAMEBUFFER_TARGET
B)禁用覆盖 ( //controls.bringToFront();
),因此仅启用相机预览:
$ ./adb shell screenrecord --time-limit 10 --bit-rate 6000000 /storage/sdcard1/demo4.mp4
结果是视频文件:1280 x 720;H.264 / AVC;30FPS;比特率:6684 kb/s。
硬件作曲家:
type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name
HWC | 557cf46610 | 0000 | 0000 | 04 | 0100 | ? 00000011 | 0.0, 0.0, 1280.0, 720.0 | 0, 0, 720, 1280 | SurfaceView
FB TARGET | 557cf3fd00 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 720.0, 1280.0 | 0, 0, 720, 1280 | HWC_FRAMEBUFFER_TARGET
C)仅android:id="@+id/frameLayout"
+android:id="@+id/controls"
启用布局;启用相机预览:
$ ./adb shell screenrecord --time-limit 10 --bit-rate 6000000 /storage/sdcard1/demo5.mp4
结果是视频文件:1280 x 720;H.264 / AVC;30FPS;比特率:4280 kbps。
硬件作曲家:
type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name
HWC | 557cf6e910 | 0000 | 0000 | 04 | 0100 | ? 00000011 | 0.0, 0.0, 1280.0, 720.0 | 0, 0, 720, 1280 | SurfaceView
FB TARGET | 557cf04f30 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 720.0, 1280.0 | 0, 0, 720, 1280 | HWC_FRAMEBUFFER_TARGET
D)仅启用android:id="@+id/frameLayout"
++布局;启用相机预览:结果是视频文件:1280 x 720;H.264 / AVC;20FPS;比特率:2879 kbps。android:id="@+id/controls"
<ImageView ...
$ ./adb shell screenrecord --time-limit 10 --bit-rate 6000000 /storage/sdcard1/demo3.mp4
硬件作曲家:
type | handle | hint | flag | tr | blnd | format | source crop (l,t,r,b) | frame | name
HWC | 557cfa2040 | 0000 | 0000 | 04 | 0100 | ? 00000011 | 0.0, 0.0, 1280.0, 720.0 | 0, 0, 720, 1280 | SurfaceView
HWC | 557cfb6be0 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 590.0, 880.0, 720.0, 1280.0 | 590, 880, 720, 1280 | com.example.test/com.example.test.RecordActivity
FB TARGET | 557cf04f30 | 0000 | 0000 | 00 | 0105 | RGBA_8888 | 0.0, 0.0, 720.0, 1280.0 | 0, 0, 720, 1280 | HWC_FRAMEBUFFER_TARGET
测试systrace
:(
图像从 1.5 图像组合到高度以获取更多信息。)
F)禁用叠加 ( //controls.bringToFront();
)、相机预览、运行记录:
G)启用覆盖,禁用所有视图上的Alpha,相机预览,运行记录:
警报是关于:
- 低效的视图 alpha 使用:
Setting an alpha between 0 and 1 has significant performance costs, if one of the fast alpha paths is not used.
=> 对于案例 G:我在所有视图上禁用了 alpha。警报已删除,但 FPS 仍为:20。 - 调度延迟:
Work to produce this frame was descheduled for several milliseconds, contributing to jank. Ensure that code on the UI thread doesn't block on work being done on other threads, and that background threads (doing e.g. network or bitmap loading) are running at android.os.Process#THREAD_PRIORITY_BACKGROUND or lower so they are less likely to interrupt the UI thread. These background threads should show up with a priority number of 130 or higher in the scheduling section under the Kernel process.
=> 仍未解决。
但这很有趣,因为当我评论时:(//controls.bringToFront();
案例 F),所以controls
布局在相机预览之后(如果我理解的话),所以位图处理的 alpha 仍然执行,但 FPS 是:30 => 好。
我从比较案例 E/F/G 中看到的差异(比例约为 5 秒):
- 案例 F/G:在 CPU 上工作的东西:4、5、6、7,案例 E 不是。
- in
surfaceFlinger
是应用程序的名称:com.*.pso(这是我的 RecordActivity):
案例 E:184 项,
案例 F:312 项,
案例 G:204 项。
图的项目数相似SurfaceView
。 - 在
/system/bin/surfaceflinger
:命令onDraw()
案例 E:切片:~7000 具有墙壁持续时间:~3300ms,
案例 F:切片:~11000 具有墙壁持续时间:~2300ms,
案例 G:切片:~7800 具有墙壁持续时间:~3400ms。 - 在
/system/bin/surfaceflinger
从Binder_1
到Binder_5
:命令dequeueBuffer
案例 E:切片:~1200 有墙持续时间~3500ms,
案例 F:切片:~2080 有墙持续时间~38ms,
案例 G:切片:~1509 有墙持续时间~3200ms, - in
/system/bin/mediaserver
中IppExecuterThre
的情况与 in 中的情况相似surfaceflinger
。dequeueBuffer
案例 E:切片:282 的墙持续时间约为 3600 毫秒,
案例 F:切片:462 的墙持续时间约为 117 毫秒,
案例 G:切片:304 的墙持续时间约为 3300 毫秒。
因此,从叠加视图中移除 alpha 会稍微提高性能,但不会增加 FPS。