Add support for Rec.709 encoding and inverse encoding. Reported-by: Tim Harvey <tharvey@xxxxxxxxxxxxx> Signed-off-by: Steve Longerbeam <slongerbeam@xxxxxxxxx> --- Changes in v5: - moved API changes to a previous patch. - moved CSC coeff calc to new function calc_csc_coeffs(). Changes in v4: - fix compile error. Chnges in v3: - none. Changes in v2: - only return "Unsupported YCbCr encoding" error if inf != outf, since if inf == outf, the identity matrix can be used. Reported by Tim Harvey. --- drivers/gpu/ipu-v3/ipu-ic.c | 63 ++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/ipu-v3/ipu-ic.c b/drivers/gpu/ipu-v3/ipu-ic.c index c4048c921801..1460901af9b5 100644 --- a/drivers/gpu/ipu-v3/ipu-ic.c +++ b/drivers/gpu/ipu-v3/ipu-ic.c @@ -214,6 +214,23 @@ static const struct ic_encode_coeff ic_encode_identity = { .scale = 2, }; +/* + * REC.709 encoding from RGB full range to YUV full range: + * + * Y = .2126 * R + .7152 * G + .0722 * B + * U = -.1146 * R - .3854 * G + .5000 * B + 128 + * V = .5000 * R - .4542 * G - .0458 * B + 128 + */ +static const struct ic_encode_coeff ic_encode_rgb2ycbcr_709 = { + .coeff = { + { 54, 183, 19 }, + { 483, 413, 128 }, + { 128, 396, 500 }, + }, + .offset = { 0, 512, 512 }, + .scale = 1, +}; + /* * Inverse BT.601 encoding from YUV full range to RGB full range: * @@ -237,11 +254,35 @@ static const struct ic_encode_coeff ic_encode_ycbcr2rgb_601 = { .scale = 2, }; +/* + * Inverse REC.709 encoding from YUV full range to RGB full range: + * + * R = 1. * Y + 0 * (Cb - 128) + 1.5748 * (Cr - 128) + * G = 1. * Y - .1873 * (Cb - 128) - .4681 * (Cr - 128) + * B = 1. * Y + 1.8556 * (Cb - 128) + 0 * (Cr - 128) + * + * equivalently (factoring out the offsets): + * + * R = 1. * Y + 0 * Cb + 1.5748 * Cr - 201.574 + * G = 1. * Y - .1873 * Cb - .4681 * Cr + 83.891 + * B = 1. * Y + 1.8556 * Cb + 0 * Cr - 237.517 + */ +static const struct ic_encode_coeff ic_encode_ycbcr2rgb_709 = { + .coeff = { + { 128, 0, 202 }, + { 128, 488, 452 }, + { 128, 238, 0 }, + }, + .offset = { -403, 168, -475 }, + .scale = 2, +}; + static int calc_csc_coeffs(struct ipu_ic_priv *priv, struct ic_encode_coeff *coeff_out, const struct ipu_ic_colorspace *in, const struct ipu_ic_colorspace *out) { + const struct ic_encode_coeff *encode_coeff; bool inverse_encode; if (in->colorspace != out->colorspace) { @@ -249,11 +290,6 @@ static int calc_csc_coeffs(struct ipu_ic_priv *priv, return -ENOTSUPP; } - if (out->enc != V4L2_YCBCR_ENC_601) { - dev_err(priv->ipu->dev, "Only BT.601 encoding supported\n"); - return -ENOTSUPP; - } - if ((in->cs == IPUV3_COLORSPACE_YUV && in->quant != V4L2_QUANTIZATION_FULL_RANGE) || (out->cs == IPUV3_COLORSPACE_YUV && @@ -278,8 +314,21 @@ static int calc_csc_coeffs(struct ipu_ic_priv *priv, inverse_encode = (in->cs == IPUV3_COLORSPACE_YUV); - *coeff_out = inverse_encode ? - ic_encode_ycbcr2rgb_601 : ic_encode_rgb2ycbcr_601; + switch (out->enc) { + case V4L2_YCBCR_ENC_601: + encode_coeff = inverse_encode ? + &ic_encode_ycbcr2rgb_601 : &ic_encode_rgb2ycbcr_601; + break; + case V4L2_YCBCR_ENC_709: + encode_coeff = inverse_encode ? + &ic_encode_ycbcr2rgb_709 : &ic_encode_rgb2ycbcr_709; + break; + default: + dev_err(priv->ipu->dev, "Unsupported YCbCr encoding\n"); + return -ENOTSUPP; + } + + *coeff_out = *encode_coeff; return 0; } -- 2.17.1