Android 7.1之SurfaceFlinger实时显示帧率FPS/LCD帧数/Camera帧数

浅笑安然 2024-08-26 ⋅ 26 阅读

简介

Android 7.1引入了一项新功能,允许开发者实时监测设备的帧率(FPS),LCD帧数和相机帧数。这对于开发高性能应用和游戏非常重要。在本文中,我将详细解释如何利用SurfaceFlinger实现这些功能,并提供相关的代码示例。

SurfaceFlinger

SurfaceFlinger是Android系统中的一个关键组件,负责管理和显示所有2D和3D图形层,以及将它们合成到设备的显示器上。它负责处理应用程序的绘制请求,并确保它们以适当的顺序和速度呈现。SurfaceFlinger是一个位于系统级别的服务,运行在系统进程中,并具有独立于应用程序进程的特权。因此,它能够获取更多底层信息,如帧率、LCD帧数和相机帧数。

实时显示帧率FPS

要实时显示帧率,我们需要在应用程序中通过SurfaceFlinger获取每秒钟的帧数,并将其显示在屏幕上。这样一来,开发者可以随时监测应用程序的性能,并及时进行调整。

下面是一段示例代码,展示了如何使用Choreographer类获取帧率数据:

public class FrameRateMonitor {

    private Choreographer.FrameCallback frameCallback;
    private long frameCount;

    public void startMonitoring() {
        frameCallback = new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {
                frameCount++;
                Choreographer.getInstance().postFrameCallback(this);
            }
        };

        Choreographer.getInstance().postFrameCallback(frameCallback);
    }

    public void stopMonitoring() {
        if (frameCallback != null) {
            Choreographer.getInstance().removeFrameCallback(frameCallback);
            frameCallback = null;
        }
    }

    public float getFramesPerSecond() {
        float frameRate = frameCount / ((float) getElapsedTimeMillis() / 1000);
        frameCount = 0;
        return frameRate;
    }
}

在启动监测时,我们使用postFrameCallback()方法注册一个FrameCallback回调函数。每次帧渲染完成后,该回调函数会被调用,我们可以在其中更新帧数,并使用postFrameCallback()方法注册下一帧。停止监测时,我们调用removeFrameCallback()方法移除回调函数。

实时显示LCD帧数

要实时显示LCD帧数,我们需要通过SurfaceFlinger获取显示器每秒钟的帧数,并将其显示在屏幕上。这样一来,开发者可以了解设备显示的性能。

下面是一段示例代码,展示了如何使用SurfaceFlinger类获取LCD帧数:

public class LcdFrameRateMonitor {

    private final static String SERVICE_NAME = "SurfaceFlinger";
    private IBinder service;
    private long frameCount;
    private long lastFrameTime;

    public void startMonitoring() {
        service = ServiceManager.getService(SERVICE_NAME);
        final ISurfaceComposer serviceInterface = ISurfaceComposer.Stub.asInterface(service);

        final SurfaceComposerClient.TransactionCallback transactionCallback =
                new SurfaceComposerClient.TransactionCallback() {
                    @Override
                    public void onTransactionReady(int transaction) {
                        try {
                            frameCount++;
                            serviceInterface.setTransactionNestCount(transaction, 0);
                            serviceInterface.setDisplayProjection(transaction,
                                    Display.DEFAULT_DISPLAY,
                                    SurfaceComposerClient.getDisplayRect(Display.DEFAULT_DISPLAY),
                                    SurfaceComposerClient.getDisplayRect(Display.DEFAULT_DISPLAY));
                            serviceInterface.setTransactionName(transaction, null);
                            serviceInterface.applyTransaction(transaction);
                            lastFrameTime = System.nanoTime();
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onTransactionCancelled(int transaction) {
                        // Ignored
                    }
                };

        SurfaceComposerClient.openTransaction();
        SurfaceComposerClient.closeTransaction(transactionCallback);
    }

    public void stopMonitoring() {
        if (service != null) {
            service = null;
            frameCount = 0;
            lastFrameTime = 0;
        }
    }

    public float getFramesPerSecond() {
        long elapsedTime = System.nanoTime() - lastFrameTime;
        float frameRate = frameCount / ((float) elapsedTime / 1000000000);
        frameCount = 0;
        lastFrameTime = System.nanoTime();
        return frameRate;
    }
}

在启动监测时,我们先获取SurfaceFlinger服务对象,并根据其接口进行操作。我们的目标是在每次事务执行完成后计算帧数,并使用setTransactionNestCount()方法将事务设置为0。如果不这样做,事务嵌套将会导致错误的帧数统计。

实时显示Camera帧数

要实时显示Camera帧数,我们需要通过Camera API获取相机每秒钟的帧数,并将其显示在屏幕上。这样一来,开发者可以查看相机的性能。

下面是一段示例代码,展示了如何使用Camera类获取相机帧数:

public class CameraFrameRateMonitor {

    private final static int CAMERA_ID = 0;
    private Camera camera;
    private long frameCount;
    private long lastFrameTime;

    public void startMonitoring() {
        camera = Camera.open(CAMERA_ID);
        camera.setPreviewCallback(new Camera.PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                frameCount++;
                lastFrameTime = System.nanoTime();
            }
        });
    }

    public void stopMonitoring() {
        if (camera != null) {
            camera.setPreviewCallback(null);
            camera.release();
            camera = null;
            frameCount = 0;
            lastFrameTime = 0;
        }
    }

    public float getFramesPerSecond() {
        long elapsedTime = System.nanoTime() - lastFrameTime;
        float frameRate = frameCount / ((float) elapsedTime / 1000000000);
        frameCount = 0;
        lastFrameTime = System.nanoTime();
        return frameRate;
    }
}

在启动监测时,我们使用open()方法打开相机,并利用setPreviewCallback()方法注册一个预览回调函数。每当相机预览帧可用时,该回调函数将被调用,我们可以在其中更新帧数。

结论

通过使用SurfaceFlinger,我们可以实时监测设备的帧率FPS、LCD帧数和Camera帧数。这对于开发高性能应用和游戏非常重要。在本文中,我们介绍了如何使用SurfaceFlinger获取帧率和帧数,并提供了相关的代码示例。希望这篇文章对你有所帮助!

参考链接:

  • https://developer.android.com/reference/android/view/Choreographer
  • https://android.googlesource.com/platform/frameworks/native/+/master/libs/surfaceflinger/README.md

全部评论: 0

    我有话说: