控制VirtualDisplay的帧速率

时间:2015-07-20 22:04:21

标签: android mediacodec

我正在编写一个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);

我还尝试了子类化Surface并限制通过MediaCodec提供给unlockCanvasAndPost(Canvas canvas)的帧,但是我的实例上似乎永远不会调用该函数,所以,那里在我的实例中调用Surface以及ParcelwriteToParcel函数的交互可能有点奇怪,但这是唯一的函数在我的实例中调用(我可以告诉)。

其他阅读建议我可以从编码器 - &gt;解码器 - &gt;编码器并限制第二个编码器馈送帧的速率,但这是一个额外的计算,如果我可以避免它,我宁愿不做。

有没有人成功限制VirtualDisplay提供Surface的费率?任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:8)

从您无法做的事情开始......

您无法从编码流中删除内容。编码流中的大多数帧基本上是来自其他帧的“差异”。在不知道帧如何交互的情况下,您无法安全地丢弃内容,并最终导致宏块外观损坏。

您无法为MediaCodec编码器指定帧速率。它可能会在某个地方填充元数据,但对编解码器来说真正重要的唯一事情就是你要加入它的帧,以及与每个帧相关的表示时间戳。编码器不会丢帧。

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

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

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

答案 1 :(得分:1)

您可以从saki4510t's ScreenRecordingSampleRyanRQ's ScreenRecoder引用代码示例,它们都使用虚拟显示和媒体编码器之间的额外EGL纹理,第一个可以保留至少15 fps输出视频。您可以从代码库中搜索关键字 createVirtualDisplay 以获取更多详细信息。