Как конвертировать RGBA в NV12 с помощью OpenGL? - PullRequest
3 голосов
/ 25 марта 2019

Мне нужно преобразовать RGBA в NV12 с использованием шейдера OpenGL в качестве входа кодера.

Уже есть рендеринг двух разных фрагментных шейдеров, обе текстуры с одной камеры. Использование v4l2 для получения изображения с камеры (YUV). Затем конвертируйте YUV в RGB, чтобы OpenGL отображал. Следующим шагом мне нужно преобразовать RGB в NV12 в качестве входного сигнала кодера, потому что кодер принимает только формат NV12.

1 Ответ

1 голос
/ 25 марта 2019

Используйте вычислительный шейдер для преобразования RGB в планарное YUV, затем уменьшите семпл UV-плоскости в два раза.

Вот вычислительный шейдер:

#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.
  • Возможно, где-то отсутствует барьер памяти.
  • Это неСамый эффективный способ считывания данных из графического процессора - вам может понадобиться хотя бы прочитать один кадр позади, пока вычисляется следующий.
...