使用MediaCodec和Surface的Android编码

使用MediaCodec和Surface的Android编码,android,surfaceview,android-mediacodec,encoder,decoder,Android,Surfaceview,Android Mediacodec,Encoder,Decoder,我一直在通过MediaCodec将视频直接渲染到从UI中的SurfaceView获取的曲面。这很有效 我现在尝试使用MediaCodec作为编码器。作为测试,我希望渲染到曲面(如上所述),并通过配置为编码器的MediaCodec的不同实例进行环回 我看到了编码器的createInputSurface()方法。我想我希望编码器创建这个曲面,然后让解码器MediaCodec使用它作为要绘制的曲面。首先,这可能吗 其次,我不确定如何从编码器创建的曲面创建SurfaceView。我只从SurfaceVi

我一直在通过MediaCodec将视频直接渲染到从UI中的SurfaceView获取的曲面。这很有效

我现在尝试使用MediaCodec作为编码器。作为测试,我希望渲染到曲面(如上所述),并通过配置为编码器的MediaCodec的不同实例进行环回

我看到了编码器的createInputSurface()方法。我想我希望编码器创建这个曲面,然后让解码器MediaCodec使用它作为要绘制的曲面。首先,这可能吗

其次,我不确定如何从编码器创建的曲面创建SurfaceView。我只从SurfaceView中提取了一个曲面,但从文档中看不到如何进行反向提取。

曲面是生产者-消费者协议的“生产者”端。一般来说,API以消费者为中心,消费者创建两端,然后将生产者界面(表面)交还给您

因此,对于SurfaceView或MediaCodec编码器,您可以创建对象并获取其曲面。然后,使用Canvas、OpenGL ES或MediaCodec解码器向它们发送图形数据缓冲区

无法将编码器的输入面用作SurfaceView的显示面——它们是两条不同的管道。SurfaceView的使用者位于系统合成器(SurfaceFlinger)中,这就是为什么您必须等待“surface created”回调触发的原因。MediaCodec编码器的使用者在mediaserver进程中,尽管异步性更好地隐藏起来

将MediaCodec解码器输出发送到SurfaceView非常简单,将输出发送到MediaCodec编码器也是如此。正如您所猜测的,只需将编码器的输入面传递给解码器。当你想同时做这两件事时,生活就会变得有趣

底层代码(称为BufferQueue)应该能够(像Lollipop一样)进行多路复用,但我不知道Lollipop中有一个API将此功能公开给应用程序。这就意味着你不得不用艰难的方式做事

困难的方法是创建一个SurfaceTexture(a/k/a GLConsumer),它是管道的使用者端。从中可以使用创建曲面。你把它交给MediaCodec解码器。现在,出来的每个帧都将通过SurfaceTexture转换为GLES纹理。可以将这些渲染到SurfaceView和编码器的输入曲面


您可以在中找到各种示例,并在中找到有关机制的详细解释。

我正在使用MediaCodec将流解码到SurfaceView。这很有效。使用MediaCodec作为编码器让我感到困惑的是,我需要向编解码器请求一个曲面(createSurface)。我是否使用编码器创建曲面,并将该曲面引用提供给解码器使用?或者我必须在解码表面像素和编码器创建的像素之间执行复制吗?是的。。。要将解码器的输出直接发送到编码器,请首先使用
createInputSurface()
创建编码器的曲面,然后在配置时将其交给解码器。不需要手动复制。如果我想在曲面上查看解码器实例的输出,这是否意味着我必须使用另一个SurfaceView/SurfaceTexture实例,因为编码器会为其功能创建不同的曲面?您可以将解码器的输出发送到单个曲面。这意味着您可以查看它或对其编码,但不能同时查看和编码,除非您做额外的工作(例如,使用回答中提到的SurfaceTexture)。嗯。如果我使用编码器创建的曲面,我的解码器实例将在dequeueOutputBuffer处抛出一个IllegalStateException。如果我调回从SurfaceView派生的曲面,我不会得到这个异常,它会按预期工作。所有的事情都和我以前的一样。在解码端工作的代码版本。