From: Steinar H. Gunderson Date: Mon, 9 Jan 2017 22:33:26 +0000 (+0100) Subject: Add UYVY support to ChromaSubsampler. X-Git-Tag: 1.5.0~77 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=aad435ecc01e9e2fb3bc44274887213f9484cf10 Add UYVY support to ChromaSubsampler. --- diff --git a/chroma_subsampler.cpp b/chroma_subsampler.cpp index b75facd..a336005 100644 --- a/chroma_subsampler.cpp +++ b/chroma_subsampler.cpp @@ -12,6 +12,8 @@ using namespace std; ChromaSubsampler::ChromaSubsampler(ResourcePool *resource_pool) : resource_pool(resource_pool) { + vector frag_shader_outputs; + // Set up stuff for NV12 conversion. // // Note: Due to the horizontally co-sited chroma/luma samples in H.264 @@ -96,30 +98,86 @@ ChromaSubsampler::ChromaSubsampler(ResourcePool *resource_pool) "void main() { \n" " FragColor = 0.5 * (texture(cbcr_tex, tc0) + texture(cbcr_tex, tc1)); \n" "} \n"; - vector frag_shader_outputs; cbcr_program_num = resource_pool->compile_glsl_program(cbcr_vert_shader, cbcr_frag_shader, frag_shader_outputs); check_error(); - float vertices[] = { - 0.0f, 2.0f, - 0.0f, 0.0f, - 2.0f, 0.0f - }; - cbcr_vbo = generate_vbo(2, GL_FLOAT, sizeof(vertices), vertices); - check_error(); cbcr_texture_sampler_uniform = glGetUniformLocation(cbcr_program_num, "cbcr_tex"); check_error(); cbcr_position_attribute_index = glGetAttribLocation(cbcr_program_num, "position"); check_error(); cbcr_texcoord_attribute_index = glGetAttribLocation(cbcr_program_num, "texcoord"); check_error(); + + // Same, for UYVY conversion. + string uyvy_vert_shader = + "#version 130 \n" + " \n" + "in vec2 position; \n" + "in vec2 texcoord; \n" + "out vec2 y_tc0, y_tc1, cbcr_tc0, cbcr_tc1; \n" + "uniform vec2 foo_luma_offset_0; \n" + "uniform vec2 foo_luma_offset_1; \n" + "uniform vec2 foo_chroma_offset_0; \n" + "uniform vec2 foo_chroma_offset_1; \n" + " \n" + "void main() \n" + "{ \n" + " // The result of glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0) is: \n" + " // \n" + " // 2.000 0.000 0.000 -1.000 \n" + " // 0.000 2.000 0.000 -1.000 \n" + " // 0.000 0.000 -2.000 -1.000 \n" + " // 0.000 0.000 0.000 1.000 \n" + " gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, -1.0, 1.0); \n" + " vec2 flipped_tc = texcoord; \n" + " y_tc0 = flipped_tc + foo_luma_offset_0; \n" + " y_tc1 = flipped_tc + foo_luma_offset_1; \n" + " cbcr_tc0 = flipped_tc + foo_chroma_offset_0; \n" + " cbcr_tc1 = flipped_tc + foo_chroma_offset_1; \n" + "} \n"; + string uyvy_frag_shader = + "#version 130 \n" + "in vec2 y_tc0, y_tc1, cbcr_tc0, cbcr_tc1; \n" + "uniform sampler2D y_tex, cbcr_tex; \n" + "out vec4 FragColor; \n" + "void main() { \n" + " float y0 = texture(y_tex, y_tc0).r; \n" + " float y1 = texture(y_tex, y_tc1).r; \n" + " vec2 cbcr0 = texture(cbcr_tex, cbcr_tc0).rg; \n" + " vec2 cbcr1 = texture(cbcr_tex, cbcr_tc1).rg; \n" + " vec2 cbcr = 0.5 * (cbcr0 + cbcr1); \n" + " FragColor = vec4(cbcr.g, y0, cbcr.r, y1); \n" // FIXME: swap y0 and y1? + "} \n"; + + uyvy_program_num = resource_pool->compile_glsl_program(uyvy_vert_shader, uyvy_frag_shader, frag_shader_outputs); + check_error(); + + uyvy_y_texture_sampler_uniform = glGetUniformLocation(uyvy_program_num, "y_tex"); + check_error(); + uyvy_cbcr_texture_sampler_uniform = glGetUniformLocation(uyvy_program_num, "cbcr_tex"); + check_error(); + uyvy_position_attribute_index = glGetAttribLocation(uyvy_program_num, "position"); + check_error(); + uyvy_texcoord_attribute_index = glGetAttribLocation(uyvy_program_num, "texcoord"); + check_error(); + + // Shared between the two. + float vertices[] = { + 0.0f, 2.0f, + 0.0f, 0.0f, + 2.0f, 0.0f + }; + vbo = generate_vbo(2, GL_FLOAT, sizeof(vertices), vertices); + check_error(); } ChromaSubsampler::~ChromaSubsampler() { resource_pool->release_glsl_program(cbcr_program_num); check_error(); - glDeleteBuffers(1, &cbcr_vbo); + resource_pool->release_glsl_program(uyvy_program_num); + check_error(); + glDeleteBuffers(1, &vbo); check_error(); } @@ -159,7 +217,7 @@ void ChromaSubsampler::subsample_chroma(GLuint cbcr_tex, unsigned width, unsigne glUniform1i(cbcr_texture_sampler_uniform, 0); - glBindBuffer(GL_ARRAY_BUFFER, cbcr_vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); check_error(); for (GLint attr_index : { cbcr_position_attribute_index, cbcr_texcoord_attribute_index }) { @@ -186,3 +244,87 @@ void ChromaSubsampler::subsample_chroma(GLuint cbcr_tex, unsigned width, unsigne glDeleteVertexArrays(1, &vao); check_error(); } + +void ChromaSubsampler::create_uyvy(GLuint y_tex, GLuint cbcr_tex, unsigned width, unsigned height, GLuint dst_tex) +{ + GLuint vao; + glGenVertexArrays(1, &vao); + check_error(); + + glBindVertexArray(vao); + check_error(); + + GLuint fbo = resource_pool->create_fbo(dst_tex); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glViewport(0, 0, width/2, height); + check_error(); + + glUseProgram(uyvy_program_num); + check_error(); + + glUniform1i(uyvy_y_texture_sampler_uniform, 0); + check_error(); + glUniform1i(uyvy_cbcr_texture_sampler_uniform, 1); + check_error(); + + glActiveTexture(GL_TEXTURE0); + check_error(); + glBindTexture(GL_TEXTURE_2D, y_tex); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + check_error(); + + glActiveTexture(GL_TEXTURE1); + check_error(); + glBindTexture(GL_TEXTURE_2D, cbcr_tex); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + check_error(); + + float y_offset_0[] = { -0.5f / width, 0.0f }; + float y_offset_1[] = { 0.5f / width, 0.0f }; + float cbcr_offset0[] = { -1.0f / width, 0.0f }; + float cbcr_offset1[] = { -0.0f / width, 0.0f }; + set_uniform_vec2(uyvy_program_num, "foo", "luma_offset_0", y_offset_0); + set_uniform_vec2(uyvy_program_num, "foo", "luma_offset_1", y_offset_1); + set_uniform_vec2(uyvy_program_num, "foo", "chroma_offset_0", cbcr_offset0); + set_uniform_vec2(uyvy_program_num, "foo", "chroma_offset_1", cbcr_offset1); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + check_error(); + + for (GLint attr_index : { uyvy_position_attribute_index, uyvy_texcoord_attribute_index }) { + if (attr_index == -1) continue; + glEnableVertexAttribArray(attr_index); + check_error(); + glVertexAttribPointer(attr_index, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); + check_error(); + } + + glDrawArrays(GL_TRIANGLES, 0, 3); + check_error(); + + for (GLint attr_index : { uyvy_position_attribute_index, uyvy_texcoord_attribute_index }) { + if (attr_index == -1) continue; + glDisableVertexAttribArray(attr_index); + check_error(); + } + + glActiveTexture(GL_TEXTURE0); + check_error(); + glUseProgram(0); + check_error(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + check_error(); + + resource_pool->release_fbo(fbo); + glDeleteVertexArrays(1, &vao); +} diff --git a/chroma_subsampler.h b/chroma_subsampler.h index ea2b781..811f901 100644 --- a/chroma_subsampler.h +++ b/chroma_subsampler.h @@ -19,13 +19,23 @@ public: // width and height are the dimensions (in pixels) of the input texture. void subsample_chroma(GLuint cbcr_tex, unsigned width, unsigned height, GLuint dst_tex); + // Subsamples and interleaves luma and chroma to give 4:2:2 packed Y'CbCr (UYVY). + // Chroma positioning is left (H.264 convention). + // width and height are the dimensions (in pixels) of the input textures. + void create_uyvy(GLuint y_tex, GLuint cbcr_tex, unsigned width, unsigned height, GLuint dst_tex); + private: movit::ResourcePool *resource_pool; + GLuint vbo; // Holds position and texcoord data. + GLuint cbcr_program_num; // Owned by . GLuint cbcr_texture_sampler_uniform; - GLuint cbcr_vbo; // Holds position and texcoord data. GLuint cbcr_position_attribute_index, cbcr_texcoord_attribute_index; + + GLuint uyvy_program_num; // Owned by . + GLuint uyvy_y_texture_sampler_uniform, uyvy_cbcr_texture_sampler_uniform; + GLuint uyvy_position_attribute_index, uyvy_texcoord_attribute_index; }; #endif // !defined(_CHROMA_SUBSAMPLER_H)