我一直在通过 MediaCodec 将视频直接渲染到从我的 UI 中的 SurfaceView 获取的 Surface。这很好用。
我现在正尝试使用 MediaCodec 作为编码器。作为测试,我想渲染到 Surface(如上所示)并通过配置为编码器的不同 MediaCodec 实例进行环回。
我看到了编码器的 createInputSurface() 方法。我想我希望编码器创建这个表面,然后让解码器 MediaCodec 使用它作为要绘制的表面。首先,这可能吗?
其次,我不确定如何从编码器创建的 Surface 创建 SurfaceView。我只从 SurfaceView 中提取了一个 Surface,但我没有从文档中看到如何反向执行此操作。
最佳答案
表面是生产者-消费者安排的“生产者”端。一般而言,API 以消费者为中心,消费者创建两端,然后将生产者接口(interface)(Surface)交还给您。
因此,对于 SurfaceView 或 MediaCodec 编码器,您创建对象并获取其 Surface。然后使用 Canvas、OpenGL ES 或 MediaCodec 解码器向它们发送图形数据缓冲区。
无法获取编码器的输入 Surface 并将其用作 SurfaceView 的显示 Surface——它们是两个不同的管道。 SurfaceView 的使用者位于系统合成器 (SurfaceFlinger) 中,这就是为什么您必须等待“表面创建”回调触发的原因。 MediaCodec 编码器的消费者在 mediaserver 进程中,尽管异步性被更好地隐藏了。
将 MediaCodec 解码器输出发送到 SurfaceView 非常简单,将输出发送到 MediaCodec 编码器也是如此。如您所料,只需将编码器的输入 Surface 传递给解码器即可。当您想同时做这两件事时,生活就会变得有趣。
Surface 的底层代码(称为 BufferQueue)应该能够(从 Lollipop 开始)多路复用,但我不知道 Lollipop 中的 API 向应用程序公开了该功能。这意味着您无法以艰难的方式做事。
困难的方法涉及创建 SurfaceTexture(a/k/a GLConsumer),它是管道的消费者端。从那里你可以创建一个表面,使用 sole constructor .你把它交给 MediaCodec 解码器。现在出来的每一帧都会被 SurfaceTexture 转换为 GLES 纹理。您可以将它们渲染到 SurfaceView 和编码器的输入 Surface。
您可以在 Grafika 中找到各种示例,以及在 graphics architecture doc 中对机制的更详细解释.
关于使用 MediaCodec 和 Surface 进行 Android 编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32439950/