如何不按顺序显示解码的MediaCodec帧

时间:2014-01-27 09:49:47

标签: android mediacodec

我想按顺序显示MediaCodec的解码视频帧,或省略帧,或多次显示帧。

我考虑将MediaCodec配置为使用Surface,重复调用MediaCodec.dequeueOutputBuffer(),保存生成的缓冲区索引,然后再调用MediaCodec.releaseOutputBuffer(desired_index, true),但似乎没有为了增加输出缓冲区的数量,所以如果我要处理大量的帧要重新排列,我可能会用完输出缓冲区。

我正在考虑的一个想法是使用glReadPixels()将像素数据读入帧缓冲区,适当地转换颜色格式,然后在需要显示帧时将其复制到SurfaceView。但这似乎是很多复制(和颜色格式转换)的开销,特别是当我本身不需要修改像素数据时。

所以我想知道是否有更好,更高效的方式。也许有一种方法可以为每个解码帧配置不同的表面/纹理/缓冲区,然后告诉SurfaceView显示特定的表面/纹理/缓冲区(无需进行内存复制)。似乎必须有一种方法可以通过OpenGL实现这一目标,但我对OpenGL很新,可以使用有关区域的建议进行调查。如果必须,我甚至会去NDK。

到目前为止,我一直在审查Android文档,以及fadden的bigflake和Grafika。感谢。

1 个答案:

答案 0 :(得分:3)

在处理更高分辨率的视频和更高的帧数时,保存大量帧的副本可能会出现问题。保存在RGBA中的1280x720帧将为1280x720x4 = 3.5MB。如果你试图保存100帧,那就是1GB设备上1/3的内存。

如果你想采用这种方法,我认为你想要做的是将一系列纹理附加到FBO并渲染它们来存储像素。然后你可以在绘制时从纹理渲染。 FBO渲染的示例代码存在于Grafika中(这是屏幕录制活动中使用的方法之一)。

另一种方法是在解码流中寻找。您需要在感兴趣的帧之前寻找最近的同步帧(通过要求MediaExtractor执行此操作,或通过使用BufferInfo标志保存编码数据)并解码直到到达目标帧。这个速度有多快取决于您需要遍历的帧数,帧的分辨率以及设备上解码器的速度。 (正如您所料,向前迈进比向后退步更容易。您可能已经注意到您使用过的其他视频播放器中存在类似现象。)

不要打扰glReadPixels()。一般来说,如果可以从您的应用程序直接访问解码数据,那么您将会受到速度的打击(某些设备上的设备比其他设备更多)。此外,MediaCodec解码器使用的缓冲区数量在某种程度上取决于设备,因此我不会指望超过4或5。