我想按顺序显示MediaCodec
的解码视频帧,或省略帧,或多次显示帧。
我考虑将MediaCodec
配置为使用Surface
,重复调用MediaCodec.dequeueOutputBuffer()
,保存生成的缓冲区索引,然后再调用MediaCodec.releaseOutputBuffer(desired_index, true)
,但似乎没有为了增加输出缓冲区的数量,所以如果我要处理大量的帧要重新排列,我可能会用完输出缓冲区。
我正在考虑的一个想法是使用glReadPixels()
将像素数据读入帧缓冲区,适当地转换颜色格式,然后在需要显示帧时将其复制到SurfaceView
。但这似乎是很多复制(和颜色格式转换)的开销,特别是当我本身不需要修改像素数据时。
所以我想知道是否有更好,更高效的方式。也许有一种方法可以为每个解码帧配置不同的表面/纹理/缓冲区,然后告诉SurfaceView
显示特定的表面/纹理/缓冲区(无需进行内存复制)。似乎必须有一种方法可以通过OpenGL实现这一目标,但我对OpenGL很新,可以使用有关区域的建议进行调查。如果必须,我甚至会去NDK。
到目前为止,我一直在审查Android文档,以及fadden的bigflake和Grafika。感谢。
答案 0 :(得分:3)
在处理更高分辨率的视频和更高的帧数时,保存大量帧的副本可能会出现问题。保存在RGBA中的1280x720帧将为1280x720x4 = 3.5MB。如果你试图保存100帧,那就是1GB设备上1/3的内存。
如果你想采用这种方法,我认为你想要做的是将一系列纹理附加到FBO并渲染它们来存储像素。然后你可以在绘制时从纹理渲染。 FBO渲染的示例代码存在于Grafika中(这是屏幕录制活动中使用的方法之一)。
另一种方法是在解码流中寻找。您需要在感兴趣的帧之前寻找最近的同步帧(通过要求MediaExtractor
执行此操作,或通过使用BufferInfo
标志保存编码数据)并解码直到到达目标帧。这个速度有多快取决于您需要遍历的帧数,帧的分辨率以及设备上解码器的速度。 (正如您所料,向前迈进比向后退步更容易。您可能已经注意到您使用过的其他视频播放器中存在类似现象。)
不要打扰glReadPixels()
。一般来说,如果可以从您的应用程序直接访问解码数据,那么您将会受到速度的打击(某些设备上的设备比其他设备更多)。此外,MediaCodec
解码器使用的缓冲区数量在某种程度上取决于设备,因此我不会指望超过4或5。