使用Android Media Projection API进行可靠的屏幕捕获

时间:2016-03-03 16:05:54

标签: android performance android-ndk screen-capture android-mediaprojection

我们使用Media Projection API的实施工作正常。但是我们经常在尝试将捕获的图像写入文件时丢失帧。即使所有的io代码都是在不同的线程中执行的。

我们想对捕获的帧进行一些在线图像分析,因此我们无法使用screenrecord或类似的工具。

有没有办法从本机代码调用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);

1 个答案:

答案 0 :(得分:2)

使用Bitmap执行任何后果的所有代码都是本机实现的,因此将现有代码转换为使用JNI并不会产生任何影响。我猜测你正在运行内存带宽或CPU限制(来自复制和扩展每帧的数据)或只是缺少实时截止日期,因为调度程序让其他线程运行。

最佳方法取决于您需要的质量级别以及应用程序正在执行的操作。如果您录制为视频流,而不是捕获一系列独立帧,您将使用更少的内存和非常少的CPU。当你以30fps的速度刻录几MB /秒时,将数据保存在RAM中更实用。如果您的应用经常更改屏幕上的每个像素,这可能无法正常工作。您的分析代码必须能够容忍宏块和矢量量化错误。

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