我的问题:
我有一个视频(可以说是 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/