【发布时间】:2017-03-10 17:36:56
【问题描述】:
对于在 CPU 上解码 4k (3840x2160@60hz) 视频以渲染为 OpenGL ES 纹理的软件进程,最好的方法是什么?
我目前的做法如下:
创建像素缓冲区对象:
glGenBuffers(1, &pbo_id);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_id);
将 3840x2160x4(宽 x 高 x bpp)分配给 PBO:
glBufferData(GL_PIXEL_UNPACK_BUFFER, size, NULL, GL_STREAM_DRAW);
将 PBO 映射到客户端的内存空间:
GLubyte *ptr = (GLubyte *)glMapBufferRange(
GL_PIXEL_UNPACK_BUFFER,
0,
size,
GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
直接解码到这个内存并手动刷新:
glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, size);
看来我可以以每秒约 300 帧的速度执行此操作。这看起来很漂亮 令人印象深刻,这是很多数据。
创建纹理:
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
将 PBO 复制到纹理中:
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
这个阶段速度很慢,将性能限制在 ~60 fps。
并渲染:
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
此阶段将性能进一步限制为 ~40 fps。
这是最好的方法吗?有没有更好的方法在 PBO 中让像素在屏幕上显示一次?每秒 40 帧不够快。
注释:
将内存映射到客户端的地址空间使得与视频解码的集成更简单,并且传输到 GPU 时不必等待整个帧被解码。
我可以使用两个或更多 PBO。将当前帧解码为一个 PBO,然后渲染/显示前一帧的 PBO,以利用写入 PBO 的异步特性?但是,这会增加额外的解码延迟帧,我非常希望避免这种延迟。
我的顶点和片段着色器现在是直通的。我没有锁定/隔离自动取款机,但显然以后会需要它。
我正在使用 Linux、Wayland 和 EGL。直接使用 DRM Dumb Buffers 我可以达到 ~200 fps。
【问题讨论】: