如何使用OpenGL将RGBA转换为NV12?

4

我需要使用OpenGL着色器将RGBA转换为NV12作为编码器输入。

已经准备好了两个不同的片段着色器,在这两个着色器中,纹理都来自于同一台相机。使用v4l2获取相机图像(YUV)。然后将YUV转换为RGB再让OpenGL进行渲染。接下来,我需要将RGB转换为NV12作为编码器输入,因为编码器只接受NV12格式。

1个回答

3

使用计算着色器将RGB转换为平面YUV,然后将UV平面按照2的因子进行降采样。

以下是计算着色器:

#version 450 core
layout(local_size_x = 32, local_size_y = 32) in;
layout(binding = 0) uniform sampler2D src;
layout(binding = 0) uniform writeonly image2D dst_y;
layout(binding = 1) uniform writeonly image2D dst_uv;
void main() {
    ivec2 id = ivec2(gl_GlobalInvocationID.xy);
    vec3 yuv = rgb_to_yuv(texelFetch(src, id).rgb);
    imageStore(dst_y, id, vec4(yuv.x,0,0,0));
    imageStore(dst_uv, id, vec4(yuv.yz,0,0));
}

有许多不同的YUV标准,我不知道你的编码器期望哪个。因此,请将上面的rgb_to_yuv替换为您的YUV->RGB转换的反向操作。

然后按照以下步骤进行:

GLuint in_rgb = ...; // rgb(a) input texture
int width = ..., height = ...; // the size of in_rgb

GLuint tex[2]; // output textures (Y plane, UV plane)

glCreateTextures(GL_TEXTURE_2D, tex, 2);
glTextureStorage2D(tex[0], 1, GL_R8, width, height); // Y plane

// UV plane -- TWO mipmap levels
glTextureStorage2D(tex[1], 2, GL_RG8, width, height);

// use this instead if you need signed UV planes:
//glTextureStorage2D(tex[1], 2, GL_RG8_SNORM, width, height);

glBindTextures(0, 1, &in_rgb);
glBindImageTextures(0, 2, tex);
glUseProgram(compute); // the above compute shader

int wgs[3];
glGetProgramiv(compute, GL_COMPUTE_WORK_GROUP_SIZE, wgs);
glDispatchCompute(width/wgs[0], height/wgs[1], 1);

glUseProgram(0);
glGenerateTextureMipmap(tex[1]); // downsamples tex[1] 

// copy data to the CPU memory:
uint8_t *data = (uint8_t*)malloc(width*height*3/2);
glGetTextureImage(tex[0], 0, GL_RED, GL_UNSIGNED_BYTE, width*height, data);
glGetTextureImage(tex[1], 1, GL_RG, GL_UNSIGNED_BYTE, width*height/2,
    data + width*height);

免责声明:

  • 此代码未经测试。
  • 它假设宽度和高度可被32整除。
  • 可能会缺少某个内存屏障。
  • 这不是从GPU读取数据的最有效方式 - 您可能需要在计算下一帧时至少再读取一帧。

我想使用YUV约定作为NV12(YYYYYYYY UUVV)。因此,我需要使用计算着色器来扩展Y和UV。最终,我将获得两个纹理Y和UV。但是如何将这两个纹理合并成一个呢?就像我可以输出缓冲区或其他一些可以保存为NV12格式并且可以在yuv播放器中成功显示的东西。 - Julia Ding
@JuliaDing:你的NV12消费者接口是什么?它需要什么?GPU缓冲区?GPU纹理?CPU RAM内存? - Yakov Galka
这是CPU的RAM内存。 - Julia Ding
@JuliaDing:我已经相应地进行了编辑。请注意,它会给出YYYYYYYYUVUV,这通常是NV12的含义。如果您需要YYYYYYYYUUVV,那么您将需要三个纹理。 - Yakov Galka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接