X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=ycbcr_input.cpp;h=3e7cad9a0c858313e9c7b15c18efb4046b60fd78;hb=af438a8d5331bb1435494eaf377256deac74f408;hp=4a0ec0ea12b904e2a41f73b774a2c8da00fe43e6;hpb=cdbed3b89528ee2f640613219fa3c77a0ad8fef5;p=movit diff --git a/ycbcr_input.cpp b/ycbcr_input.cpp index 4a0ec0e..3e7cad9 100644 --- a/ycbcr_input.cpp +++ b/ycbcr_input.cpp @@ -19,10 +19,13 @@ namespace movit { YCbCrInput::YCbCrInput(const ImageFormat &image_format, const YCbCrFormat &ycbcr_format, unsigned width, unsigned height, - YCbCrInputSplitting ycbcr_input_splitting) + YCbCrInputSplitting ycbcr_input_splitting, + GLenum type) : image_format(image_format), ycbcr_format(ycbcr_format), ycbcr_input_splitting(ycbcr_input_splitting), + needs_mipmaps(false), + type(type), width(width), height(height), resource_pool(NULL) @@ -51,6 +54,8 @@ YCbCrInput::YCbCrInput(const ImageFormat &image_format, register_uniform_sampler2d("tex_cb", &uniform_tex_cb); register_uniform_sampler2d("tex_cr", &uniform_tex_cr); } + + register_int("needs_mipmaps", &needs_mipmaps); } YCbCrInput::~YCbCrInput() @@ -69,21 +74,40 @@ void YCbCrInput::set_gl_state(GLuint glsl_program_num, const string& prefix, uns if (texture_num[channel] == 0 && (pbos[channel] != 0 || pixel_data[channel] != NULL)) { GLenum format, internal_format; if (channel == 0 && ycbcr_input_splitting == YCBCR_INPUT_INTERLEAVED) { - format = GL_RGB; - internal_format = GL_RGB8; + if (type == GL_UNSIGNED_INT_2_10_10_10_REV) { + format = GL_RGBA; + internal_format = GL_RGB10_A2; + } else if (type == GL_UNSIGNED_SHORT) { + format = GL_RGB; + internal_format = GL_RGB16; + } else { + assert(type == GL_UNSIGNED_BYTE); + format = GL_RGB; + internal_format = GL_RGB8; + } } else if (channel == 1 && ycbcr_input_splitting == YCBCR_INPUT_SPLIT_Y_AND_CBCR) { format = GL_RG; - internal_format = GL_RG8; + if (type == GL_UNSIGNED_SHORT) { + internal_format = GL_RG16; + } else { + assert(type == GL_UNSIGNED_BYTE); + internal_format = GL_RG8; + } } else { format = GL_RED; - internal_format = GL_R8; + if (type == GL_UNSIGNED_SHORT) { + internal_format = GL_R16; + } else { + assert(type == GL_UNSIGNED_BYTE); + internal_format = GL_R8; + } } // (Re-)upload the texture. texture_num[channel] = resource_pool->create_2d_texture(internal_format, widths[channel], heights[channel]); glBindTexture(GL_TEXTURE_2D, texture_num[channel]); check_error(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, needs_mipmaps ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR); check_error(); glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbos[channel]); check_error(); @@ -91,10 +115,14 @@ void YCbCrInput::set_gl_state(GLuint glsl_program_num, const string& prefix, uns check_error(); glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch[channel]); check_error(); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, widths[channel], heights[channel], format, GL_UNSIGNED_BYTE, pixel_data[channel]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, widths[channel], heights[channel], format, type, pixel_data[channel]); check_error(); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); check_error(); + if (needs_mipmaps) { + glGenerateMipmap(GL_TEXTURE_2D); + 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); @@ -111,7 +139,9 @@ void YCbCrInput::set_gl_state(GLuint glsl_program_num, const string& prefix, uns // Bind samplers. uniform_tex_y = *sampler_num + 0; - uniform_tex_cb = *sampler_num + 1; + if (ycbcr_input_splitting != YCBCR_INPUT_INTERLEAVED) { + uniform_tex_cb = *sampler_num + 1; + } if (ycbcr_input_splitting == YCBCR_INPUT_PLANAR) { uniform_tex_cr = *sampler_num + 2; } @@ -125,6 +155,19 @@ string YCbCrInput::output_fragment_shader() Matrix3d ycbcr_to_rgb; compute_ycbcr_matrix(ycbcr_format, offset, &ycbcr_to_rgb); + if (type == GL_UNSIGNED_SHORT) { + // For 10-bit or 12-bit packed into 16-bit, we need to scale the values + // so that the max value goes from 1023 (or 4095) to 65535. We do this + // by folding the scaling into the conversion matrix, so it comes essentially + // for free. However, the offset is before the scaling (and thus assumes + // correctly scaled values), so we need to adjust that the other way. + double scale = 65535.0 / (ycbcr_format.num_levels - 1); + offset[0] /= scale; + offset[1] /= scale; + offset[2] /= scale; + ycbcr_to_rgb *= scale; + } + string frag_shader; frag_shader = output_glsl_mat3("PREFIX(inv_ycbcr_matrix)", ycbcr_to_rgb); @@ -167,8 +210,10 @@ void YCbCrInput::invalidate_pixel_data() bool YCbCrInput::set_int(const std::string& key, int value) { if (key == "needs_mipmaps") { - // We currently do not support this. - return (value == 0); + if (ycbcr_input_splitting != YCBCR_INPUT_INTERLEAVED && value != 0) { + // We do not currently support this. + return false; + } } return Effect::set_int(key, value); }