Android 控制VirtualDisplay的帧速率

Android 控制VirtualDisplay的帧速率,android,android-mediacodec,Android,Android Mediacodec,我正在编写一个Android应用程序,其中有一个VirtualDisplay来镜像屏幕上的内容,然后将屏幕上的帧发送到MediaCodec的实例。它可以工作,但是,我想添加一种指定编码视频的FPS的方法,但是我不确定如何做 根据我阅读和实验的结果,删除编码帧(基于呈现时间)效果不好,因为它最终会产生块状/伪影视频,而不是低帧速率下的平滑视频。其他阅读建议,做我想要的事情(限制FPS)的唯一方法是将传入FPS限制到MediaCodec,但是VirtualDisplay只接收一个Surface,它是

我正在编写一个Android应用程序,其中有一个
VirtualDisplay
来镜像屏幕上的内容,然后将屏幕上的帧发送到
MediaCodec
的实例。它可以工作,但是,我想添加一种指定编码视频的FPS的方法,但是我不确定如何做

根据我阅读和实验的结果,删除编码帧(基于呈现时间)效果不好,因为它最终会产生块状/伪影视频,而不是低帧速率下的平滑视频。其他阅读建议,做我想要的事情(限制FPS)的唯一方法是将传入FPS限制到
MediaCodec
,但是
VirtualDisplay
只接收一个
Surface
,它是由
MediaCodec
构建的,如下所示

mSurface = <instance of MediaCodec>.createInputSurface();
mVirtualDisplay = mMediaProjection.createVirtualDisplay(
    "MyDisplay",
    screenWidth,
    screenHeight,
    screenDensity,
    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
    mSurface,
    null,
    null);
mSurface=.createInputSurface();
mVirtualDisplay=mmediprojection.createVirtualDisplay(
“我的显示器”,
屏幕宽度,
屏幕高度,
屏幕密度,
DisplayManager.VIRTUAL\u DISPLAY\u FLAG\u AUTO\u MIRROR,
M表面,
无效的
无效);
我还尝试了子类化
Surface
,并限制通过
unlockCanvasAndPost(Canvas Canvas)
馈送到
MediaCodec
的帧,但该函数似乎从未在我的实例上调用过,因此,我扩展
Surface
的方式可能有些奇怪,当
writeToParcel
函数在我的实例上被调用时,与
Parcel
的交互也可能有些奇怪,但这是在我的实例中唯一被调用的函数(我可以说)

其他阅读建议,我可以从编码器->解码器->编码器开始,限制第二个编码器接收帧的速率,但如果可以避免的话,我宁愿不做大量额外的计算


是否有人成功地限制了
VirtualDisplay
馈送其
表面的速率?任何帮助都将不胜感激

从你不能做的事情开始

无法从编码流中删除内容。编码流中的大多数帧基本上与其他帧“不同”。如果不知道帧是如何交互的,您就无法安全地删除内容,并最终导致宏块外观损坏

无法为MediaCodec编码器指定帧速率。它可能会在某个地方将这些内容塞进元数据中,但对编解码器来说,唯一真正重要的是要输入到其中的帧,以及与每个帧关联的表示时间戳。编码器不会丢弃帧

通过子类化Surface,您无法做任何有用的事情。画布操作仅用于软件渲染,这与从摄影机或虚拟显示器输入帧无关

您可以做的是将帧发送到中间曲面,然后选择是否将其转发到MediaCodec的输入曲面。一种方法是创建一个SurfaceTexture,从中构造一个曲面,然后将其传递给虚拟显示。当SurfaceTexture的“帧可用”回调触发时,您可以忽略它,或者使用GLES将纹理渲染到MediaCodec输入曲面上


在和中可以找到各种示例,其中没有一个是精确匹配的,但所有必需的EGL和GLES类都在那里。

您可以参考或中的代码示例,它们都使用虚拟显示器和媒体编码器之间的附加EGL纹理,第一个可以为输出视频保持至少15 fps。您可以从他们的代码库中搜索关键字createVirtualDisplay,以了解更多详细信息。

感谢您的输入!听起来不错(为什么我没想到呢?)。我是一名图形工程师,因此我应该非常熟悉OpenGL对纹理构造的调用,等等。我将对此进行拍摄并报告。因此,我注意到SurfaceTexture通过接收当前循环器或UI线程循环器上的消息来处理其帧上可用的回调,或者不接收任何消息。这很有趣。希望有办法指定处理程序或循环器。由于我是在一个HandlerThread中完成所有这些工作的,所以这需要一些工作。只需发送一条消息。典型的
onFrameAvailable()
实现如下所示:我还应该提到我的应用程序在后台(我正在试验)。如果我的应用程序在后台,我永远不会得到onFrameAvailable回调。我会继续四处寻找,看看能找到什么。