0

我想问一下,是否可以通过覆盖视图提高录制屏幕的 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 图像组合到高度以获取更多信息。)

E)启用叠加、相机预览、运行记录: 在此处输入图像描述

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 不是。
  • insurfaceFlinger是应用程序的名称: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/surfaceflingerBinder_1Binder_5:命令dequeueBuffer
    案例 E:切片:~1200 有墙持续时间~3500ms,
    案例 F:切片:~2080 有墙持续时间~38ms,
    案例 G:切片:~1509 有墙持续时间~3200ms,
  • in/system/bin/mediaserverIppExecuterThre的情况与 in 中的情况相似surfaceflingerdequeueBuffer
    案例 E:切片:282 的墙持续时间约为 3600 毫秒,
    案例 F:切片:462 的墙持续时间约为 117 毫秒,
    案例 G:切片:304 的墙持续时间约为 3300 毫秒。

因此,从叠加视图中移除 alpha 会稍微提高性能,但不会增加 FPS。

4

1 回答 1

1

有两个独立的事情发生:

  1. 视图的渲染和组合。这发生在单层上,由应用程序本身执行。
  2. 图层的渲染和合成。这发生在系统图形合成器 SurfaceFlinger 中。

通常#2可以通过硬件覆盖来完成——每一层都被传递到显示硬件,当像素被发送到显示器时,它会进行合成。对于虚拟显示器,不涉及显示硬件,合成由 SurfaceFlinger 在 GPU 上执行。

很难说是什么导致了你所看到的效果。可能是应用程序速度变慢且更新频率降低,可能是虚拟显示开销使 GPU 负担过重,以至于无法再跟上。如果您只有两层(View 和 SurfaceView),那么层组合开销应该不会那么糟糕。

唯一确定的方法是使用systrace在“快”和“慢”模式下捕获系统跟踪,并找出它们不同的原因。

补充:快速浏览一下 Hardware Composer 中的层堆栈可能会很有趣,只是想看看不同配置下的情况。如果你adb shell dumpsys SurfaceFlinger会得到一大堆输出;靠近底部将是这样的东西。这会告诉你层是什么,它们有多大,以及它们是如何排序的。

于 2016-05-30T16:02:07.277 回答