X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=ycbcr.cpp;h=59b7eed4eff496d31a653b0814ece809a148b3f4;hp=50059125dc4a3c866dff4ef08e82916d94ff7a43;hb=c6a0f381cca8ec937ef046e0ef0d62156fb1d7be;hpb=f71dd67f6a2abca2bb95eb3e0902f9fdcf8e8ed9 diff --git a/ycbcr.cpp b/ycbcr.cpp index 5005912..59b7eed 100644 --- a/ycbcr.cpp +++ b/ycbcr.cpp @@ -59,7 +59,7 @@ float compute_chroma_offset(float pos, unsigned subsampling_factor, unsigned res // Given , compute the values needed to turn Y'CbCr into R'G'B'; // first subtract the returned offset, then left-multiply the returned matrix // (the scaling is already folded into it). -void compute_ycbcr_matrix(YCbCrFormat ycbcr_format, float* offset, Matrix3d* ycbcr_to_rgb) +void compute_ycbcr_matrix(YCbCrFormat ycbcr_format, float* offset, Matrix3d* ycbcr_to_rgb, GLenum type, double *scale_factor) { double coeff[3], scale[3]; @@ -89,25 +89,30 @@ void compute_ycbcr_matrix(YCbCrFormat ycbcr_format, float* offset, Matrix3d* ycb assert(false); } + int num_levels = ycbcr_format.num_levels; + if (num_levels == 0) { + // For the benefit of clients using old APIs, but still zeroing out the structure. + num_levels = 256; + } if (ycbcr_format.full_range) { - // TODO: Use num_levels. - offset[0] = 0.0 / 255.0; - offset[1] = 128.0 / 255.0; - offset[2] = 128.0 / 255.0; + offset[0] = 0.0 / (num_levels - 1); + offset[1] = double(num_levels / 2) / (num_levels - 1); // E.g. 128/255. + offset[2] = double(num_levels / 2) / (num_levels - 1); scale[0] = 1.0; scale[1] = 1.0; scale[2] = 1.0; } else { - // Rec. 601, page 4; Rec. 709, page 19; Rec. 2020, page 4. - // TODO: Use num_levels. - offset[0] = 16.0 / 255.0; - offset[1] = 128.0 / 255.0; - offset[2] = 128.0 / 255.0; - - scale[0] = 255.0 / 219.0; - scale[1] = 255.0 / 224.0; - scale[2] = 255.0 / 224.0; + // Rec. 601, page 4; Rec. 709, page 19; Rec. 2020, page 5. + // Rec. 2020 contains the most generic formulas, which we use here. + const double s = num_levels / 256.0; // 2^(n-8) in Rec. 2020 parlance. + offset[0] = (s * 16.0) / (num_levels - 1); + offset[1] = (s * 128.0) / (num_levels - 1); + offset[2] = (s * 128.0) / (num_levels - 1); + + scale[0] = double(num_levels - 1) / (s * 219.0); + scale[1] = double(num_levels - 1) / (s * 224.0); + scale[2] = double(num_levels - 1) / (s * 224.0); } // Matrix to convert RGB to YCbCr. See e.g. Rec. 601. @@ -131,6 +136,24 @@ void compute_ycbcr_matrix(YCbCrFormat ycbcr_format, float* offset, Matrix3d* ycb // Fold in the scaling. *ycbcr_to_rgb *= Map(scale).asDiagonal(); + + 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; + if (scale_factor != nullptr) { + *scale_factor = scale; + } + } else if (scale_factor != nullptr) { + *scale_factor = 1.0; + } } } // namespace movit