使用 Android 媒体投影 API 进行可靠的屏幕捕获

Reliable screen capturing using Android Media Projection API

我们使用媒体投影 API 的实现工作正常。但是我们在尝试将捕获的图像写入文件时经常丢失帧。即使所有的 io 代码都在单独的线程中执行。

我们想对捕获的帧进行一些在线图像分析,因此我们不能使用屏幕记录或类似工具。

有没有办法从本机代码调用 Android Media Projection 方法?为了获得更好的性能?

我们甚至尝试在捕获过程中不调用任何 io 操作。我们将所有内容保存在内存中,直到最后。但是我们在 30fps 时仍然存在丢失帧的问题。我们怎样才能避免这种情况?

        try {
            image = mImageReader.acquireLatestImage();
            if (image != null) {
                Image.Plane[] planes = image.getPlanes();
                ByteBuffer buffer = planes[0].getBuffer();
                int pixelStride = planes[0].getPixelStride();
                int rowStride = planes[0].getRowStride();
                int rowPadding = rowStride - pixelStride * mWidth;
                String.valueOf(pixelStride) + " -- rowStride: " + String.valueOf(rowStride) + " rowPadding: " + String.valueOf(rowPadding));
                // create bitmap
                if(mBitmap==null || rowPadding != mRowPadding || pixelStride != mPixelStride) {
                    mRowPadding = rowPadding; mPixelStride = pixelStride;
                    mBitmap = Bitmap.createBitmap(mWidth + rowPadding / pixelStride, mHeight, Bitmap.Config.ARGB_8888);
                }
                mBitmap.copyPixelsFromBuffer(buffer);
                Bitmap myBitmap = Bitmap.createScaledBitmap(mBitmap, (mWidth + rowPadding / pixelStride) / 16, mHeight / 16, false);

                ramStorage.add(myBitmap);

所有与 Bitmap 相关的代码都是本机实现的,因此将现有代码转换为使用 JNI 不会有什么不同。我猜你正在 运行 对抗内存带宽或 CPU 限制(从复制和缩放每个帧的数据)或者只是错过实时截止日期因为调度程序让其他线程 运行.

最佳方法取决于您需要的质量水平以及应用程序的功能。如果您录制为视频流,而不是捕获一系列独立的帧,您将使用更少的内存和很少的 CPU。当您仅以 30fps 的速度刻录一些 MB/sec 时,将数据保存在 RAM 中更为实用。如果您的应用程序频繁更改屏幕上的每个像素,这可能效果不佳。您的分析代码必须能够容忍宏块和矢量量化错误。

您可以通过在保存前不缩放位图来权衡 CPU RAM。您也可以完全避免 Bitmap,并执行您自己的复制 + 缩放操作以将 ImageReader 内容传输到 RAM 存储,一次完成这两个操作(您希望在本机代码中编写复制缩放功能)。