Android 虚拟显示的帧监听器(NDK 内部构建)

Frame Listener for Android Virtual Display (NDK internal build)

我正在为 Android 平台构建一个内部共享库。我有设备制造商的签名密钥库。

我的图书馆正在使用来自 Android 源的 ScreenRecord.cpp 内部文件。使用 MediaCodec 编码器录制效果很好;但是我想访问每一帧,以便在将图像传递给编码器之前,我可以在每一帧上应用一些图像叠加徽标。 Android 源代码中也有一个覆盖示例,但这仅适用于 Android (5.0 / API 21+) 的较新版本。我想要 Android Kitkat (4.4 / API 19)

的覆盖解决方案

这是我从 minicap 获得的代码示例。

mVirtualDisplay = android::SurfaceComposerClient::createDisplay(
android::String8("minicap"),
true);

LOGI("Creating buffer queue");
mScreenshotClient.getCpuConsumer();
mBufferQueue = mScreenshotClient.mBufferQueue;

LOGI("Creating CPU consumer");
mConsumer = new android::CpuConsumer(mBufferQueue, 3, false);
mConsumer->setName(android::String8("minicap"));
mConsumer->setDefaultBufferSize(targetWidth, targetHeight);
mConsumer->setDefaultBufferFormat(android::PIXEL_FORMAT_RGBA_8888);

mConsumer->setFrameAvailableListener(mFrameProxy); 
//mFrameProxy is from:
//class FrameProxy: public android::ConsumerBase::FrameAvailableListener

LOGI("Publishing virtual display");
android::SurfaceComposerClient::openGlobalTransaction();
android::SurfaceComposerClient::setDisplaySurface(mVirtualDisplay, mBufferQueue);
android::SurfaceComposerClient::setDisplayProjection(mVirtualDisplay,
android::DISPLAY_ORIENTATION_0, layerStackRect, visibleRect);
android::SurfaceComposerClient::setDisplayLayerStack(mVirtualDisplay, 0);// default stack

android::SurfaceComposerClient::closeGlobalTransaction();

我设置了上面的代码,但是 FrameAvailableListener 的 onFrameAvailable() 方法只被调用了一次。即使我在屏幕上做事,它也不会再被调用。我在这里错过了什么? 在传递给编码器之前,是否有更简单的方法来访问帧?

screenrecord sources for Lollipop. As far as I can recall it doesn't rely on any features added in Lollipop, so you should be able to build and run it on 4.4. As noted on bigflake 中内置了一个添加叠加层的示例,--bugreport 模式在 4.4 时间框架中添加到 AOSP,但直到 [=] 才真正与系统一起发布28=]。 (稍微调整一下,它甚至应该在 4.3 上 运行,但我还没有试过。)

关键源文件是Overlay.{cpp,h}。它做的事情与您在 Java 中编写的代码所做的事情相同:创建一个 GLConsumer (SurfaceTexture),使用它来将传入的帧转换为 GLES 纹理,然后将纹理 + 叠加层渲染到视频编码器。

示例视频是 here。请注意,它在开头添加了一个文本块,并在左上角添加了一个 运行ning 时间戳/帧计数器。

阅读本文的其他人请注意:此代码使用内部私有 APIs,这些 APIs 在最近的版本中发生了变化,因此必须为特定版本的 Android 构建任何二进制文件,并且可能不能移植到不同制造商制造的设备,即使它们 运行 相同版本的 Android(有时 OEM 喜欢搞砸)。

更新: 我之前关于在 KitKat 上工作的陈述并不准确——在 Lollipop 版本推出之前发生了重大的 API 转变。诀窍是在 this change went in, as that was when the BufferQueue API rewrite reached screenrecord. You can see from the change list 之前获取资源,--bugreport 选项在此之前大约五个月出现。