1

我的问题:

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

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

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

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

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

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

我的问题:

  • 有解决方案吗?
  • 是否可以创建一个?缓冲区,可以在渲染表面的后台缓冲区上复制(?!),这样我就可以使用这种缓冲区创建一个缓存,并将其复制到后台缓冲区而不阻塞另一个线程正在创建这个缓冲区?

或者

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

我已经试过了:

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

1 回答 1

1

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

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

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

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

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

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

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

于 2014-01-08T20:51:56.117 回答