在OpenGLES 2.0中缓存Outputimages

时间:2014-01-08 13:32:01

标签: android opengl-es-2.0 egl

我的问题:

我有一个视频(假设为25FPS),必须在屏幕上使用opengles 2.0进行渲染。 为了阅读视频,我使用解码器将该视频解码为opengl es纹理。使用renderpass,我在屏幕上绘制这个纹理。

我要做的是从解码器获取图像将其上传到gpu,调用着色器程序并在屏幕上渲染图像。如果视频有25FPS,我必须以40ms步长(1000ms / 25FPS)更新屏幕。

在每一步中我都有以下内容:

  • 从解码器中获取图像
  • 将其推送到gpu内存
  • 渲染屏幕
  • 交换缓冲区

到目前为止它正在发挥作用。 现在它发生,解码器花费超过40ms来解码帧。这不会一直发生,但有时会发生。

解决方案是构建缓存。意思是,在显示第一个之前,我会渲染5个图像。这带来了一个问题,它必须发生异步,因此可以构建缓存并同时呈现屏幕。如果发生这种情况,您可以在视频中看到它,因为它不再是“流畅的”。

我的问题:

  • 有解决方法吗?
  • 是否可以创建一个?-buffer,可以在rendersurface的后备缓冲区上复制(?!),这样我就可以用这种缓冲区创建一个缓存,并将其复制到后台缓冲区而不会阻塞正在创建此缓冲区的其他线程?

OR

  • 如何用另一个缓冲区填充后备缓冲区?

我已经尝试过了:

  • 将Framebuffer(纹理)渲染为缓存。除了必须渲染纹理外,这几乎是完美的。这意味着(因为它是异步的)如果构建了一个缓存帧并且构建了屏幕的图像,则必须互斥(/同步)rendermethods,否则程序崩溃。但是,同步化实现了异步的整个过程。所以这不是一个好的解决方案。

1 个答案:

答案 0 :(得分:1)

请记住,在OpenGL中,如果您不清除并重绘屏幕,则前一个图像将保持不变。如果新框架没有及时准备就绪,那就什么都不做。

听起来你有两个线程:一个解码帧,一个渲染它们。这很好。

如果调用render()并且未及时准备好新帧,则应立即返回render方法。不要清除或交换缓冲区。屏幕将被保留。

现在,当帧重复两次时,用户/可能/偶尔会发出打嗝声。 25 fps是一种不自然的帧速率(OpenGL仅支持60/30/15 /等),因此它不会完全符合屏幕刷新率。

你可以忍受这个(用户可能不会注意到)。或者你可以通过缓冲帧强制播放到30 fps。

一个好主意是在解码器和渲染器之间放置一个消息队列。它可能是一帧或几帧深。它可以是数组,链表或环形缓冲区。这允许解码器在渲染绘制不同纹理时上传到许多缓存纹理中。

解码器在进入队列时将帧添加到队列中。渲染器以固定速率(30 fps)运行。您可以暂停渲染,直到N帧被缓冲。