diff --git a/video.cpp b/video.cpp index 8024cf6..b66608e 100644 --- a/video.cpp +++ b/video.cpp @@ -1066,12 +1066,6 @@ static void hdmi_config_set_csc() // default color conversion matrices // for the original hexadecimal versions please refer // to the ADV7513 programming guide section 4.3.7 - float ypbpr_coeffs[] = { - 0.42944335937f, 1.64038085938f, 1.93017578125f, 0.49389648437f, - 0.25683593750f, 0.50415039062f, 0.09790039062f, 0.06250f, - 1.85498046875f, 1.71557617188f, 0.42944335937f, 0.49389648437f, - 0.0f, 0.0f, 0.0f, 1.0f - }; // no transformation, so use identity matrix float hdmi_full_coeffs[] = { @@ -1104,193 +1098,188 @@ static void hdmi_config_set_csc() const float pi = float(M_PI); - // select the base CSC int ypbpr = cfg.ypbpr && cfg.direct_video; + + // out-of-scope defines, not used with ypbpr + int16_t csc_int16[12]; int hdmi_limited_1 = cfg.hdmi_limited & 1; int hdmi_limited_2 = cfg.hdmi_limited & 2; - int hdr = cfg.hdr; - mat4x4 coeffs = hdmi_full_coeffs; - - if (hdr == 1) - coeffs = hdmi_full_coeffs; - else if (hdr == 2) - coeffs = hdr_dcip3_coeffs; - else + if (!ypbpr) { - if (ypbpr) - coeffs = ypbpr_coeffs; - else if (hdmi_limited_1) - coeffs = hdmi_limited_1_coeffs; - else if (hdmi_limited_2) - coeffs = hdmi_limited_2_coeffs; - else + + // select the base CSC + int hdr = cfg.hdr; + + mat4x4 coeffs = hdmi_full_coeffs; + + if (hdr == 1) coeffs = hdmi_full_coeffs; + else if (hdr == 2) + coeffs = hdr_dcip3_coeffs; + else + { + if (hdmi_limited_1) + coeffs = hdmi_limited_1_coeffs; + else if (hdmi_limited_2) + coeffs = hdmi_limited_2_coeffs; + else + coeffs = hdmi_full_coeffs; + } + mat4x4 csc(coeffs); + + // apply color controls + float brightness = (((cfg.video_brightness/100.0f) - 0.5f)); // [-0.5 .. 0.5] + float contrast = ((cfg.video_contrast/100.0f) - 0.5f) * 2.0f + 1.0f; // [0 .. 2] + float saturation = ((cfg.video_saturation/100.0f)); // [0 .. 1] + float hue = (cfg.video_hue * pi / 180.0f); + + char* gain_offset = cfg.video_gain_offset; + + // we have to parse these + float gain_red = 1; + float gain_green = 1; + float gain_blue = 1; + float off_red = 0; + float off_green = 0; + float off_blue = 0; + + size_t target = 0; + float* targets[6] = { &gain_red, &off_red, &gain_green, &off_green, &gain_blue, &off_blue }; + + for (size_t i = 0; i < strlen(gain_offset) && target < 6; i++) + { + // skip whitespace + if (gain_offset[i] == ' ' || gain_offset[i] == ',') + continue; + + int numRead = 0; + int match = sscanf(gain_offset + i, "%f%n", targets[target], &numRead); + + i += numRead > 0 ? numRead - 1 : 0; + + if (match == 1) + target++; + } + + // first apply hue matrix, because it does not touch luminance + float cos_hue = cos(hue); + float sin_hue = sin(hue); + float lr = 0.213f; + float lg = 0.715f; + float lb = 0.072f; + float ca = 0.143f; + float cb = 0.140f; + float cc = 0.283f; + + mat4x4 mat_hue; + mat_hue.setIdentity(); + + mat_hue.m11 = lr+cos_hue*(1-lr)+sin_hue*(-lr); + mat_hue.m12 = lg+cos_hue*(-lg) +sin_hue*(-lg); + mat_hue.m13 = lb+cos_hue*(-lb) +sin_hue*(1-lb); + + mat_hue.m21 = lr+cos_hue*(-lr) +sin_hue*(ca); + mat_hue.m22 = lg+cos_hue*(1-lg)+sin_hue*(cb); + mat_hue.m23 = lb+cos_hue*(-lb) +sin_hue*(cc); + + mat_hue.m31 = lr+cos_hue*(-lr) +sin_hue*(-(1-lr)); + mat_hue.m32 = lg+cos_hue*(-lg) +sin_hue*(lg); + mat_hue.m33 = lb+cos_hue*(1-lb)+sin_hue*(lb); + + csc = csc * mat_hue; + + // now saturation + float s = saturation; + float sr = ( 1.0f - s ) * .3086f; + float sg = ( 1.0f - s ) * .6094f; + float sb = ( 1.0f - s ) * .0920f; + + float mat_saturation[] = { + sr + s, sg, sb, 0, + sr, sg + s, sb, 0, + sr, sg, sb + s, 0, + 0, 0, 0, 1.0f + }; + + csc = csc * mat4x4(mat_saturation); + + // now brightness and contrast + float b = brightness; + float c = contrast; + float t = (1.0f - c) / 2.0f; + + float mat_brightness_contrast[] = { + c, 0, 0, (t+b), + 0, c, 0, (t+b), + 0, 0, c, (t+b), + 0, 0, 0, 1.0f + }; + + csc = csc * mat4x4(mat_brightness_contrast); + + // gain and offset + float rg = gain_red; + float ro = off_red; + float gg = gain_green; + float go = off_green; + float bg = gain_blue; + float bo = off_blue; + + float mat_gain_off[] = { + rg, 0, 0, ro, + 0, gg, 0, go, + 0, 0, bg, bo, + 0, 0, 0, 1.0f + }; + + csc = csc * mat4x4(mat_gain_off); + + // final compression + csc.compress(2.0f); + + // finally, apply a fixed multiplier to get it in + // correct range for ADV7513 chip + for (size_t i = 0; i < 12; i++) + { + csc_int16[i] = int16_t(csc.comp[i] * 2048.0f); + } } - mat4x4 csc(coeffs); - - // apply color controls - float brightness = (((cfg.video_brightness/100.0f) - 0.5f)); // [-0.5 .. 0.5] - float contrast = ((cfg.video_contrast/100.0f) - 0.5f) * 2.0f + 1.0f; // [0 .. 2] - float saturation = ((cfg.video_saturation/100.0f)); // [0 .. 1] - float hue = (cfg.video_hue * pi / 180.0f); - - char* gain_offset = cfg.video_gain_offset; - - // we have to parse these - float gain_red = 1; - float gain_green = 1; - float gain_blue = 1; - float off_red = 0; - float off_green = 0; - float off_blue = 0; - - size_t target = 0; - float* targets[6] = { &gain_red, &off_red, &gain_green, &off_green, &gain_blue, &off_blue }; - - for (size_t i = 0; i < strlen(gain_offset) && target < 6; i++) - { - // skip whitespace - if (gain_offset[i] == ' ' || gain_offset[i] == ',') - continue; - - int numRead = 0; - int match = sscanf(gain_offset + i, "%f%n", targets[target], &numRead); - - i += numRead > 0 ? numRead - 1 : 0; - - if (match == 1) - target++; - } - - // first apply hue matrix, because it does not touch luminance - float cos_hue = cos(hue); - float sin_hue = sin(hue); - float lr = 0.213f; - float lg = 0.715f; - float lb = 0.072f; - float ca = 0.143f; - float cb = 0.140f; - float cc = 0.283f; - - mat4x4 mat_hue; - mat_hue.setIdentity(); - - mat_hue.m11 = lr+cos_hue*(1-lr)+sin_hue*(-lr); - mat_hue.m12 = lg+cos_hue*(-lg) +sin_hue*(-lg); - mat_hue.m13 = lb+cos_hue*(-lb) +sin_hue*(1-lb); - - mat_hue.m21 = lr+cos_hue*(-lr) +sin_hue*(ca); - mat_hue.m22 = lg+cos_hue*(1-lg)+sin_hue*(cb); - mat_hue.m23 = lb+cos_hue*(-lb) +sin_hue*(cc); - - mat_hue.m31 = lr+cos_hue*(-lr) +sin_hue*(-(1-lr)); - mat_hue.m32 = lg+cos_hue*(-lg) +sin_hue*(lg); - mat_hue.m33 = lb+cos_hue*(1-lb)+sin_hue*(lb); - - csc = csc * mat_hue; - - // now saturation - float s = saturation; - float sr = ( 1.0f - s ) * .3086f; - float sg = ( 1.0f - s ) * .6094f; - float sb = ( 1.0f - s ) * .0920f; - - float mat_saturation[] = { - sr + s, sg, sb, 0, - sr, sg + s, sb, 0, - sr, sg, sb + s, 0, - 0, 0, 0, 1.0f - }; - - csc = csc * mat4x4(mat_saturation); - - // now brightness and contrast - float b = brightness; - float c = contrast; - float t = (1.0f - c) / 2.0f; - - float mat_brightness_contrast[] = { - c, 0, 0, (t+b), - 0, c, 0, (t+b), - 0, 0, c, (t+b), - 0, 0, 0, 1.0f - }; - - csc = csc * mat4x4(mat_brightness_contrast); - - // gain and offset - float rg = gain_red; - float ro = off_red; - float gg = gain_green; - float go = off_green; - float bg = gain_blue; - float bo = off_blue; - - float mat_gain_off[] = { - rg, 0, 0, ro, - 0, gg, 0, go, - 0, 0, bg, bo, - 0, 0, 0, 1.0f - }; - - csc = csc * mat4x4(mat_gain_off); - - // final compression - csc.compress(2.0f); - - // finally, apply a fixed multiplier to get it in - // correct range for ADV7513 chip - const int16_t csc_int16[12] = { - int16_t(csc.comp[0] * 2048.0f), - int16_t(csc.comp[1] * 2048.0f), - int16_t(csc.comp[2] * 2048.0f), - int16_t(csc.comp[3] * 2048.0f), - int16_t(csc.comp[4] * 2048.0f), - int16_t(csc.comp[5] * 2048.0f), - int16_t(csc.comp[6] * 2048.0f), - int16_t(csc.comp[7] * 2048.0f), - int16_t(csc.comp[8] * 2048.0f), - int16_t(csc.comp[9] * 2048.0f), - int16_t(csc.comp[10] * 2048.0f), - int16_t(csc.comp[11] * 2048.0f), - }; - // Clamps to reinforce limited if necessary // 0x100 = 16/256 * 4096 (12-bit mul) // 0xEB0 = 235/256 * 4096 // 0xFFF = 4095 (12-bit max) - uint16_t clipMin = (hdmi_limited_1 || hdmi_limited_2) ? 0x100 : 0x000; - uint16_t clipMax = hdmi_limited_1 ? 0xEB0 : 0xFFF; + uint16_t clipMin = (!ypbpr && (hdmi_limited_1 || hdmi_limited_2)) ? 0x100 : 0x000; + uint16_t clipMax = (!ypbpr && hdmi_limited_1) ? 0xEB0 : 0xFFF; // pass to HDMI, use 0xA0 to set a mode of [-2 .. 2] per ADV7513 programming guide uint8_t csc_data[] = { - 0x18, (uint8_t)(0b10100000 | (( csc_int16[0] >> 8) & 0b00011111)), // csc Coefficients, Channel A - 0x19, (uint8_t)(csc_int16[0] & 0xff), - 0x1A, (uint8_t)(csc_int16[1] >> 8), - 0x1B, (uint8_t)(csc_int16[1] & 0xff), - 0x1C, (uint8_t)(csc_int16[2] >> 8), - 0x1D, (uint8_t)(csc_int16[2] & 0xff), - 0x1E, (uint8_t)(csc_int16[3] >> 8), - 0x1F, (uint8_t)(csc_int16[3] & 0xff), + 0x18, (uint8_t)(ypbpr ? 0x86 : (0b10100000 | (( (csc_int16[0] >> 8) & 0b00011111)))), // csc Coefficients, Channel A + 0x19, (uint8_t)(ypbpr ? 0xDF : (csc_int16[0] & 0xff)), + 0x1A, (uint8_t)(ypbpr ? 0x1A : (csc_int16[1] >> 8)), + 0x1B, (uint8_t)(ypbpr ? 0x3F : (csc_int16[1] & 0xff)), + 0x1C, (uint8_t)(ypbpr ? 0x1E : (csc_int16[2] >> 8)), + 0x1D, (uint8_t)(ypbpr ? 0xE2 : (csc_int16[2] & 0xff)), + 0x1E, (uint8_t)(ypbpr ? 0x07 : (csc_int16[3] >> 8)), + 0x1F, (uint8_t)(ypbpr ? 0xE7 : (csc_int16[3] & 0xff)), - 0x20, (uint8_t)(csc_int16[4] >> 8), // csc Coefficients, Channel B - 0x21, (uint8_t)(csc_int16[4] & 0xff), - 0x22, (uint8_t)(csc_int16[5] >> 8), - 0x23, (uint8_t)(csc_int16[5] & 0xff), - 0x24, (uint8_t)(csc_int16[6] >> 8), - 0x25, (uint8_t)(csc_int16[6] & 0xff), - 0x26, (uint8_t)(csc_int16[7] >> 8), - 0x27, (uint8_t)(csc_int16[7] & 0xff), + 0x20, (uint8_t)(ypbpr ? 0x04 : (csc_int16[4] >> 8)), // csc Coefficients, Channel B + 0x21, (uint8_t)(ypbpr ? 0x1C : (csc_int16[4] & 0xff)), + 0x22, (uint8_t)(ypbpr ? 0x08 : (csc_int16[5] >> 8)), + 0x23, (uint8_t)(ypbpr ? 0x11 : (csc_int16[5] & 0xff)), + 0x24, (uint8_t)(ypbpr ? 0x01 : (csc_int16[6] >> 8)), + 0x25, (uint8_t)(ypbpr ? 0x91 : (csc_int16[6] & 0xff)), + 0x26, (uint8_t)(ypbpr ? 0x01 : (csc_int16[7] >> 8)), + 0x27, (uint8_t)(ypbpr ? 0x00 : (csc_int16[7] & 0xff)), - 0x28, (uint8_t)(csc_int16[8] >> 8), // csc Coefficients, Channel C - 0x29, (uint8_t)(csc_int16[8] & 0xff), - 0x2A, (uint8_t)(csc_int16[9] >> 8), - 0x2B, (uint8_t)(csc_int16[9] & 0xff), - 0x2C, (uint8_t)(csc_int16[10] >> 8), - 0x2D, (uint8_t)(csc_int16[10] & 0xff), - 0x2E, (uint8_t)(csc_int16[11] >> 8), - 0x2F, (uint8_t)(csc_int16[11] & 0xff), + 0x28, (uint8_t)(ypbpr ? 0x1D : (csc_int16[8] >> 8)), // csc Coefficients, Channel C + 0x29, (uint8_t)(ypbpr ? 0xAE : (csc_int16[8] & 0xff)), + 0x2A, (uint8_t)(ypbpr ? 0x1B : (csc_int16[9] >> 8)), + 0x2B, (uint8_t)(ypbpr ? 0x73 : (csc_int16[9] & 0xff)), + 0x2C, (uint8_t)(ypbpr ? 0x06 : (csc_int16[10] >> 8)), + 0x2D, (uint8_t)(ypbpr ? 0xDF : (csc_int16[10] & 0xff)), + 0x2E, (uint8_t)(ypbpr ? 0x07 : (csc_int16[11] >> 8)), + 0x2F, (uint8_t)(ypbpr ? 0xE7 : (csc_int16[11] & 0xff)), 0xC0, (uint8_t)(clipMin >> 8), // HDMI limited clamps 0xC1, (uint8_t)(clipMin & 0xff),