使用 MediaCodec 和 Surface 进行 Android 编码

标签 android surfaceview android-mediacodec encoder decoder

我一直在通过 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/

相关文章:

java - 如何通过Java运行 “echo”命令?

java - 创建接下来 4 个星期日(周的开始)的日期数组

android - 如何从 SurfaceView 绘制到 Canvas?

android - 调用 Drawable.draw() 时防止 "flickering"

android - 在 Android 中绘图使用什么 - View 或 SurfaceView?

android - 编码 mp4 视频以支持查找

android - 为 PinterestLikeAdapterView 调用 notifyDataSetChanged() 时如何避免刷新单元格?

android - 如何禁用主页键

android - AudioTrack 的内存泄漏

android - MediaCodec.dequeueOutputBuffer 在 Android 上编码 h264 时花费很长时间