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

时间:2015-09-17 14:27:31

标签: android opengl-es android-ndk surfaceflinger screen-recording

我正在为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()方法只被调用一次。即使我在屏幕上做东西,它也永远不会被再次调用。我在这里错过了什么? 在传递给编码器之前,是否有任何较为棘手的方法来访问帧?

1 个答案:

答案 0 :(得分:2)

添加叠加层的示例内置于Lollipop的screenrecord sources。据我所知,它并不依赖于Lollipop中添加的任何功能,因此您应该能够在4.4上构建和运行它。正如bigflake所述,--bugreport模式已在4.4时间框架内添加到AOSP,但实际上并未随5.x一起提供给系统。 (稍微调整一下,它甚至应该在4.3上运行,但我还没试过。)

关键源文件为Overlay.{cpp,h}。它与使用Java编写的代码完全相同:创建GLConsumer(SurfaceTexture),使用它将传入的帧转换为GLES纹理,然后将纹理+覆盖渲染到视频编码器。

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

请注意其他人阅读此内容:此代码使用的内部私有API在最近的版本中已发生变化,因此必须为特定版本的Android构建任何二进制文件,并且可能无法移植到由不同制造商构建的设备,即使他们运行相同版本的Android(有时OEM会喜欢乱七八糟的东西)。

更新:我之前关于使用KitKat的陈述并不准确 - 在Lollipop版本发布之前,有一个重大的API转变。诀窍是在this change进入之前获取源,就像BufferQueue API重写到达screenrecord那样。您可以在change list之前看到--bugreport选项在此之前大约五个月内进入。