android - 在 OpenGLES 2.0 中缓存输出图像

标签 android opengl-es-2.0 egl

我的问题:

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

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

在每个步骤中,我必须执行以下操作:

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

到目前为止它正在工作。 现在它发生了,解码器需要超过 40ms 来解码一个帧。这种情况不会一直发生,但有时会发生。

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

我的问题:

  • 有解决方案吗?
  • 是否可以创建一个 ?-buffer,它可以被复制(?!)到渲染表面的后备缓冲区,这样我就可以创建一个带有这种缓冲区的缓存,然后将它复制到后备缓冲区而不阻塞其他正在创建此缓冲区的线程?

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

我已经试过了:

  • 将帧缓冲区(纹理)渲染为缓存。这几乎是完美的,除了还必须渲染纹理。这意味着(因为它是异步的)如果构建缓存帧并构建屏幕图像,则必须互斥(/同步)渲染方法,否则程序会崩溃。但是同步化处理了异步处理的全部要点。所以这不是一个好的解决方案。

最佳答案

请记住,在 OpenGL 中,如果您不清除并重新绘制屏幕,​​则之前的图像将保留。如果新框架没有及时准备好,什么也不做。

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

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

现在,当一个帧重复两次时,用户/可能/会注意到偶尔会出现问题。 25 fps 是不自然的帧率(OpenGL 仅支持 60/30/15 等),因此它不会与屏幕刷新率完美对齐。

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

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

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

关于android - 在 OpenGLES 2.0 中缓存输出图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20997163/

相关文章:

android - 解压aab resources.pb

android - 如何更改 ListView 中的分隔线颜色?

opengl-es-2.0 - OpenGL ES 2.0:是否支持GL_COMPRESSED_RGBA_S3TC_DXT5_EXT?

android - GLSL 2D 旋转不起作用

python - 如何在 Moderngl EGL 后端启用抗锯齿?

android - 尝试在 Android 上使用 OpenGL 上下文设置 SDL。获取错误消息 "Failed loading eglChooseConfig"

android - 将下载的 native 库放在 Android 中的最佳位置是什么?

android - 如何禁用 ListAdapter 的动画

iphone - opengl es 2.0 纹理的正确方式

android - GLSurfaceView.Renderer 可以在 onDrawFrame() 中多次交换缓冲区吗?