aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2015-09-13 14:31:28 +0200
committerHans Verkuil <hans.verkuil@cisco.com>2015-09-13 14:31:28 +0200
commitc0a0c703d6dfd80314e4292c4fec1ed02aff164e (patch)
tree03833260b6811998a494892f217848d3e574b68f
parent41a3ae067c6a07d909c59de5eed4e430ec6ffb8e (diff)
qv4l2: add ycbcr.ccolorspace3
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
-rw-r--r--utils/qv4l2/ycbcr.c611
1 files changed, 611 insertions, 0 deletions
diff --git a/utils/qv4l2/ycbcr.c b/utils/qv4l2/ycbcr.c
new file mode 100644
index 00000000..c037e0e8
--- /dev/null
+++ b/utils/qv4l2/ycbcr.c
@@ -0,0 +1,611 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <math.h>
+#include <linux/videodev2.h>
+
+struct matrix {
+ double m[3][3];
+};
+
+struct vector {
+ double v[3];
+};
+
+struct luma {
+ double y[3];
+ double cb_div;
+ double cr_div;
+};
+
+#define UNITY { { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } } }
+
+struct colorspace {
+ /* (x, y) chromaticities for red, green and blue */
+ double chr[3][2];
+ /* (X, Y, Z) tristimulus values for the white point */
+ struct vector white_pnt;
+ /* R'G'B' to Y'CbCr luma coefficients */
+ struct luma coeffs;
+ /* Reference White Bradford transform */
+ struct matrix bradford;
+};
+
+static const struct colorspace srgb = {
+ /* Rec 709 chromaticity */
+ { { 0.64, 0.33 },
+ { 0.3, 0.6 },
+ { 0.15, 0.06 } },
+ /* D65 */
+ { { 0.95047, 1, 1.08883 } },
+ /* BT.601 R'G'B' to Y'CbCr coefficients */
+ { { 0.299, 0.587, 0.114 },
+ 1.772, 1.402 },
+ UNITY
+};
+
+static const struct colorspace ntsc_1953 = {
+ /* NTSC (1953) chromaticity */
+ { { 0.6700, 0.3300 },
+ { 0.2100, 0.7100 },
+ { 0.1400, 0.0800 } },
+ /* C */
+ { { 0.98074, 1, 1.18232 } },
+ /* BT.601 R'G'B' to Y'CbCr coefficients */
+ { { 0.299, 0.587, 0.114 },
+ 1.772, 1.402 },
+ /* C to D65 Bradford transform */
+ { { { 0.9904476, -0.0071683, -0.0116156 },
+ { -0.0123712, 1.0155950, -0.0029282 },
+ { -0.0035635, 0.0067697, 0.9181569 } } }
+};
+
+static const struct colorspace pal = {
+ /* PAL chromaticity */
+ { { 0.6400, 0.3300 },
+ { 0.2900, 0.6000 },
+ { 0.1500, 0.0600 } },
+ /* D65 */
+ { { 0.95047, 1, 1.08883 } },
+ /* BT.601 R'G'B' to Y'CbCr coefficients */
+ { { 0.299, 0.587, 0.114 },
+ 1.772, 1.402 },
+ UNITY
+};
+
+static const struct colorspace smpte170m = {
+ /* SMPTE 170M chromaticity */
+ { { 0.6300, 0.3400 },
+ { 0.3100, 0.5950 },
+ { 0.1550, 0.0700 } },
+ /* D65 */
+ { { 0.95047, 1, 1.08883 } },
+ /* BT.601 R'G'B' to Y'CbCr coefficients */
+ { { 0.299, 0.587, 0.114 },
+ 1.772, 1.402 },
+ UNITY
+};
+
+static const struct colorspace smpte240m = {
+ /* SMPTE 240M chromaticity */
+ { { 0.6300, 0.3400 },
+ { 0.3100, 0.5950 },
+ { 0.1550, 0.0700 } },
+ /* D65 */
+ { { 0.95047, 1, 1.08883 } },
+ /* SMPTE 240M R'G'B' to Y'CbCr coefficients */
+ { { 0.2122, 0.7013, 0.0865 },
+ 1.827, 1.5756 },
+ UNITY
+};
+
+static const struct colorspace rec709 = {
+ /* Rec 709 chromaticity */
+ { { 0.64, 0.33 },
+ { 0.3, 0.6 },
+ { 0.15, 0.06 } },
+ /* D65 */
+ { { 0.95047, 1, 1.08883 } },
+ /* Rec 709 R'G'B' to Y'CbCr coefficients */
+ { { 0.2126, 0.7152, 0.0722 },
+ 1.8556, 1.5748 },
+ UNITY
+};
+
+static const struct colorspace adobergb = {
+ /* AdobeRGB chromaticity */
+ { { 0.6400, 0.3300 },
+ { 0.2100, 0.7100 },
+ { 0.1500, 0.0600 } },
+ /* D65 */
+ { { 0.95047, 1, 1.08883 } },
+ /* BT.601 R'G'B' to Y'CbCr coefficients */
+ { { 0.299, 0.587, 0.114 },
+ 1.772, 1.402 },
+ UNITY
+};
+
+static const struct colorspace bt2020 = {
+ /* BT.2020 chromaticity */
+ { { 0.708, 0.292 },
+ { 0.170, 0.797 },
+ { 0.131, 0.046 } },
+ /* D65 */
+ { { 0.95047, 1, 1.08883 } },
+ /* BT.2020 R'G'B' to Y'CbCr coefficients */
+ { { 0.2627, 0.6780, 0.0593 },
+ 1.8814, 1.4746 },
+ UNITY
+};
+
+/* http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices */
+static struct matrix invert(const struct matrix m)
+{
+ struct matrix r;
+ double det;
+ int i, j;
+
+ det = m.m[0][0] * (m.m[1][1] * m.m[2][2] - m.m[1][2] * m.m[2][1]) -
+ m.m[0][1] * (m.m[2][2] * m.m[1][0] - m.m[1][2] * m.m[2][0]) +
+ m.m[0][2] * (m.m[1][0] * m.m[2][1] - m.m[1][1] * m.m[2][0]);
+
+ r.m[0][0] = m.m[1][1] * m.m[2][2] - m.m[1][2] * m.m[2][1];
+ r.m[1][0] = -m.m[1][0] * m.m[2][2] + m.m[1][2] * m.m[2][0];
+ r.m[2][0] = m.m[1][0] * m.m[2][1] - m.m[1][1] * m.m[2][0];
+ r.m[0][1] = -m.m[0][1] * m.m[2][2] + m.m[0][2] * m.m[2][1];
+ r.m[1][1] = m.m[0][0] * m.m[2][2] - m.m[0][2] * m.m[2][0];
+ r.m[2][1] = -m.m[0][0] * m.m[2][1] + m.m[0][1] * m.m[2][0];
+ r.m[0][2] = m.m[0][1] * m.m[1][2] - m.m[0][2] * m.m[1][1];
+ r.m[1][2] = -m.m[0][0] * m.m[1][2] + m.m[0][2] * m.m[1][0];
+ r.m[2][2] = m.m[0][0] * m.m[1][1] - m.m[0][1] * m.m[1][0];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ r.m[i][j] /= det;
+ return r;
+}
+
+static struct vector vec_add(const struct vector v1, const struct vector v2)
+{
+ struct vector res;
+ int i;
+
+ for (i = 0; i < 3; i++)
+ res.v[i] = v1.v[i] + v2.v[i];
+ return res;
+}
+
+static struct vector mult_mat_vec(const struct matrix m, const struct vector v)
+{
+ struct vector res;
+ int i;
+
+ for (i = 0; i < 3; i++)
+ res.v[i] = m.m[i][0] * v.v[0] + m.m[i][1] * v.v[1] + m.m[i][2] * v.v[2];
+ return res;
+}
+
+static struct matrix mult_vec_mat(const struct vector v, const struct matrix m)
+{
+ struct matrix res;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ res.m[0][i] = m.m[0][i] * v.v[i];
+ res.m[1][i] = m.m[1][i] * v.v[i];
+ res.m[2][i] = m.m[2][i] * v.v[i];
+ }
+ return res;
+}
+
+static struct matrix mult_mat(const struct matrix m1, const struct matrix m2)
+{
+ struct matrix res;
+ int i, j;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ res.m[i][j] = m1.m[i][0] * m2.m[0][j] + m1.m[i][1] * m2.m[1][j] + m1.m[i][2] * m2.m[2][j];
+ return res;
+}
+
+static struct matrix cs2chrXYZ(const struct colorspace cs)
+{
+ struct matrix m;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ m.m[0][i] = cs.chr[i][0] / cs.chr[i][1];
+ m.m[1][i] = 1;
+ m.m[2][i] = (1.0 - cs.chr[i][0] - cs.chr[i][1]) / cs.chr[i][1];
+ }
+ return m;
+}
+
+static struct matrix XYZ2xyz(const struct matrix m)
+{
+ struct matrix r;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ double z = m.m[0][i] + m.m[1][i] + m.m[2][i];
+
+ r.m[0][i] = m.m[0][i] / z;;
+ r.m[1][i] = m.m[2][i] / z;
+ r.m[2][i] = 1 - r.m[0][i] - r.m[1][i];
+ }
+ return r;
+}
+
+static struct matrix cs2RGB2XYZ(const struct colorspace cs)
+{
+ struct matrix m = cs2chrXYZ(cs);
+ struct matrix invm = invert(m);
+ struct vector s = mult_mat_vec(invm, cs.white_pnt);
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ m.m[i][0] *= s.v[0];
+ m.m[i][1] *= s.v[1];
+ m.m[i][2] *= s.v[2];
+ }
+ return m;
+}
+
+static struct matrix cs2ycbcr(const struct colorspace cs)
+{
+ struct matrix m;
+ int i;
+
+ for (i = 0; i < 3; i++)
+ m.m[1][i] = cs.coeffs.y[i];
+
+ m.m[2][0] = -cs.coeffs.y[0] / cs.coeffs.cb_div;
+ m.m[2][1] = -cs.coeffs.y[1] / cs.coeffs.cb_div;
+ m.m[2][2] = (1 - cs.coeffs.y[2]) / cs.coeffs.cb_div;
+ m.m[0][0] = (1 - cs.coeffs.y[0]) / cs.coeffs.cr_div;
+ m.m[0][1] = -cs.coeffs.y[1] / cs.coeffs.cr_div;
+ m.m[0][2] = -cs.coeffs.y[2] / cs.coeffs.cr_div;
+ return m;
+}
+
+static const struct matrix unity = { {
+ { 1, 0, 0 },
+ { 0, 1, 0 },
+ { 0, 0, 1 } } };
+
+static const struct matrix bt601_to_ycbcr = { {
+ { 0.2990000, 0.5870000, 0.1140000 },
+ { -0.1687359, -0.3312641, 0.5000000 },
+ { 0.5000000, -0.4186876, -0.0813124 } } };
+static const struct matrix bt601_from_ycbcr = { {
+ { 1.0000000, 0.0000000, 1.4020000 },
+ { 1.0000000, -0.3441363, -0.7141363 },
+ { 1.0000000, 1.7720000, 0.0000000 } } };
+
+static const struct matrix xv601_to_ycbcr = { {
+ { 0.2567882, 0.5156392, 0.1001412 },
+ { -0.1449144, -0.2909928, 0.4392157 },
+ { 0.4294118, -0.3677883, -0.0714274 } } };
+static const struct matrix xv601_from_ycbcr = { {
+ { 1.1643836, -0.0000000, 1.6324657 },
+ { 1.1383929, -0.3917623, -0.8129676 },
+ { 1.1383929, 2.0172321, 0.0000000 } } };
+
+static const struct matrix rec709_to_ycbcr = { {
+ { 0.2126000, 0.7152000, 0.0722000 },
+ { -0.1145721, -0.3854279, 0.5000000 },
+ { 0.5000000, -0.4541529, -0.0458471 } } };
+static const struct matrix rec709_from_ycbcr = { {
+ { 1.0000000, 0.0000000, 1.5748000 },
+ { 1.0000000, -0.1873243, -0.4681243 },
+ { 1.0000000, 1.8556000, 0.0000000 } } };
+
+static const struct matrix xv709_to_ycbcr = { {
+ { 0.1825859, 0.6282541, 0.0634227 },
+ { -0.0983972, -0.3385720, 0.4392157 },
+ { 0.4294118, -0.3989422, -0.0402735 } } };
+static const struct matrix xv709_from_ycbcr = { {
+ { 1.1643836, 0.0000000, 1.8336712 },
+ { 1.1383929, -0.2132486, -0.5329093 },
+ { 1.1383929, 2.1124018, -0.0000000 } } };
+
+static const struct matrix bt2020_to_ycbcr = { {
+ { 0.2627000, 0.6780000, 0.0593000 },
+ { -0.1396301, -0.3603699, 0.5000000 },
+ { 0.5000000, -0.4597857, -0.0402143 } } };
+static const struct matrix bt2020_from_ycbcr = { {
+ { 1.0000000, 0.0000000, 1.4746000 },
+ { 1.0000000, -0.1645531, -0.5713531 },
+ { 1.0000000, 1.8814000, 0.0000000 } } };
+
+static void print_fmatrix(const struct matrix m)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ printf("{ %.7lf, %.7lf, %.7lf },\n", m.m[i][0], m.m[i][1], m.m[i][2]);
+}
+
+static void print_vector(const struct vector v)
+{
+ printf("{ %.7lf, %.7lf, %.7lf },\n", v.v[0], v.v[1], v.v[2]);
+}
+
+static void print_matrix2(const struct matrix m, const struct vector v)
+{
+ print_fmatrix(m);
+ print_vector(v);
+ if (0)
+ printf("{ %d, %d, %d },\n",
+ (int)(v.v[0] * 255.0 + 0.5),
+ (int)(v.v[1] * 255.0 + 0.5),
+ (int)(v.v[2] * 255.0 + 0.5));
+}
+
+static void print_matrix(const struct matrix m, const struct vector v)
+{
+ double fac = 4096;
+ double max = 0;
+ int n = 0;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ int j;
+ for (j = 0; j < 3; j++) {
+ double a = fabs(m.m[i][j]);
+ if (a > max)
+ max = a;
+ }
+ }
+ for (i = 0; i < 3; i++) {
+ double a = fabs(v.v[i] / 255.0);
+ if (a > max)
+ max = a;
+ }
+ if (max >= 2.0) {
+ n = 2;
+ fac /= 4;
+ } else if (max >= 1.0) {
+ n = 1;
+ fac /= 2;
+ }
+ n = 0x8000 | (n << 13);
+
+ for (i = 0; i < 3; i++)
+ printf("{ 0x%04x, 0x%04x, 0x%04x },\n",
+ (((int)(fac * m.m[i][0])) & 0x1fff) | (i == 0 ? n : 0),
+ ((int)(fac * m.m[i][1])) & 0x1fff,
+ ((int)(fac * m.m[i][2])) & 0x1fff);
+
+ printf("{ 0x%04x, 0x%04x, 0x%04x },\n",
+ ((int)(fac * v.v[0])) & 0x1fff,
+ ((int)(fac * v.v[1])) & 0x1fff,
+ ((int)(fac * v.v[2])) & 0x1fff);
+}
+
+static struct matrix to_rgb_matrix(bool rgb, int enc)
+{
+ if (rgb)
+ return unity;
+ switch (enc) {
+ case V4L2_YCBCR_ENC_601:
+ case V4L2_YCBCR_ENC_SYCC:
+ case V4L2_YCBCR_ENC_XV601:
+ default:
+ return bt601_from_ycbcr;
+ case V4L2_YCBCR_ENC_709:
+ case V4L2_YCBCR_ENC_XV709:
+ return rec709_from_ycbcr;
+ case V4L2_YCBCR_ENC_BT2020:
+ return bt2020_from_ycbcr;
+ }
+}
+
+static struct matrix to_ycbcr_matrix(bool rgb, int enc)
+{
+ if (rgb)
+ return unity;
+ switch (enc) {
+ case V4L2_YCBCR_ENC_601:
+ case V4L2_YCBCR_ENC_SYCC:
+ case V4L2_YCBCR_ENC_XV601:
+ default:
+ return bt601_to_ycbcr;
+ case V4L2_YCBCR_ENC_709:
+ case V4L2_YCBCR_ENC_XV709:
+ return rec709_to_ycbcr;
+ case V4L2_YCBCR_ENC_BT2020:
+ return bt2020_to_ycbcr;
+ }
+}
+
+static void quant_matrix(const char *s, bool from_rgb, bool from_lim, int from_enc,
+ bool to_rgb, bool to_lim, int to_enc)
+{
+ struct matrix m1 = to_rgb_matrix(from_rgb, from_enc);
+ struct matrix m2 = to_ycbcr_matrix(to_rgb, to_enc);
+ struct matrix m = mult_mat(m1, m2);
+ struct vector v_from, v_to;
+ struct vector v;
+
+ const struct vector rgb_from_offset = { -16.0 / 256.0, -16.0 / 256.0, -16.0 / 256.0 };
+ const struct vector rgb_to_offset = { 16.0 / 256.0, 16.0 / 256.0, 16.0 / 256.0 };
+ const struct vector ycbcr_lim_from_offset = { -0.5, -16.0 / 256.0, -0.5 };
+ const struct vector ycbcr_lim_to_offset = { 0.5, 16.0 / 256.0, 0.5 };
+ const struct vector ycbcr_full_from_offset = { -0.5, 0, -0.5 };
+ const struct vector ycbcr_full_to_offset = { 0.5, 0, 0.5 };
+ const struct vector zero = { 0, 0, 0 };
+
+ const struct vector x2x[4][4] = {
+ /* from ycc full range */
+ {
+ /* to ycc full range */
+ { 1, 1, 1 },
+ /* to ycc limited range */
+ { 219.0 / 255.0, 224.0 / 255.0, 224.0 / 255.0 },
+ /* to rgb full range */
+ { 1, 1, 1 },
+ /* to rgb limited range */
+ { 219.0 / 255.0, 219.0 / 255.0, 219.0 / 255.0 },
+ },
+ /* from ycc limited range */
+ {
+ /* to ycc full range */
+ { 255.0 / 219.0, 255.0 / 224.0, 255.0 / 224.0 },
+ /* to ycc limited range */
+ { 1, 1, 1 },
+ /* to rgb full range */
+ { 255.0 / 219.0, 255.0 / 224.0, 255.0 / 224.0 },
+ /* to rgb limited range */
+ { 1, 219.0 / 224.0, 219.0 / 224.0 },
+ },
+ /* from rgb full range */
+ {
+ /* to ycc full range */
+ { 1, 1, 1 },
+ /* to ycc limited range */
+ { 219.0 / 255.0, 224.0 / 255.0, 224.0 / 255.0 },
+ /* to rgb full range */
+ { 1, 1, 1 },
+ /* to rgb limited range */
+ { 219.0 / 255.0, 219.0 / 255.0, 219.0 / 255.0 },
+ },
+ /* from rgb limited range */
+ {
+ /* to ycc full range */
+ { 255.0 / 219.0, 255.0 / 219.0, 255.0 / 219.0 },
+ /* to ycc limited range */
+ { 1, 224.0 / 219.0, 224.0 / 219.0 },
+ /* to rgb full range */
+ { 255.0 / 219.0, 255.0 / 219.0, 255.0 / 219.0 },
+ /* to rgb limited range */
+ { 1, 1, 1 },
+ },
+ };
+
+ v = x2x[from_rgb * 2 + from_lim][to_rgb * 2 + to_lim];
+ m = mult_vec_mat(v, m);
+ if (from_rgb)
+ v_from = from_lim ? rgb_from_offset : zero;
+ else
+ v_from = from_lim ? ycbcr_lim_from_offset : ycbcr_full_from_offset;
+ if (to_rgb)
+ v_to = to_lim ? rgb_to_offset : zero;
+ else
+ v_to = to_lim ? ycbcr_lim_to_offset : ycbcr_full_to_offset;
+ v_from = mult_mat_vec(m, v_from);
+ v = vec_add(v_from, v_to);
+ printf("\n%s:\n", s);
+ print_matrix2(m, v);
+}
+
+#if 0
+static void quant_matrix(const char *s, bool from_rgb, bool to_rgb, const struct matrix m)
+{
+ const double lim2full_fac = 255.0 / 219.0;
+ const double lim2full_cbcr_fac = 255.0 / 224.0;
+ const double full2lim_fac = 1.0 / lim2full_fac;
+ const double full2lim_cbcr_fac = 1.0 / lim2full_cbcr_fac;
+
+ const struct vector zero = { 0, 0, 0 };
+ const struct vector ycbcr_to_norm_offset = { -0.5, -16.0 / 256.0, -0.5 };
+ const struct vector ycbcr_from_norm_offset = { 0.5, 16.0 / 256.0, 0.5 };
+ const struct vector lim2full_offset_ycbcr = { 0, (-16.0 / 256.0) * lim2full_fac, 0 };
+ const struct vector lim2full_offset_rgb = { (-16.0 / 256.0) * lim2full_fac,
+ (-16.0 / 256.0) * lim2full_fac,
+ (-16.0 / 256.0) * lim2full_fac };
+ const struct vector lim2full_ycbcr = { lim2full_cbcr_fac, lim2full_fac, lim2full_cbcr_fac };
+ const struct vector lim2full_rgb = { lim2full_fac, lim2full_fac, lim2full_fac };
+
+ const struct vector full2lim_offset_ycbcr = { 0, 16.0 / 256.0, 0 };
+ const struct vector full2lim_offset_rgb = { 16.0 / 256.0, 16.0 / 256.0, 16.0 / 256.0 };
+ const struct vector full2lim_ycbcr = { full2lim_cbcr_fac, full2lim_fac, full2lim_cbcr_fac };
+ const struct vector full2lim_rgb = { full2lim_fac, full2lim_fac, full2lim_fac };
+ struct matrix tmp;
+ struct vector v;
+
+ printf("\n%s limited to limited:\n", s);
+ print_matrix(m, zero);
+ printf("\n%s full to full:\n", s);
+ print_matrix(m, zero);
+ printf("\n%s limited to full:\n", s);
+ tmp = mult_vec_mat(from_rgb ? lim2full_rgb : lim2full_ycbcr, m);
+ v = from_rgb ? lim2full_offset_rgb : lim2full_offset_ycbcr;
+ if (from_rgb && !to_rgb)
+ v = ycbcr_from_norm_offset;
+ else if (!from_rgb && to_rgb)
+ v = mult_mat_vec(m, ycbcr_to_norm_offset);
+ print_matrix(tmp, v);
+ printf("\n%s full to limited:\n", s);
+ tmp = mult_vec_mat(to_rgb ? full2lim_rgb : full2lim_ycbcr, m);
+ v = to_rgb ? full2lim_offset_rgb : full2lim_offset_ycbcr;
+ if (from_rgb && !to_rgb)
+ v = ycbcr_from_norm_offset;
+ else if (!from_rgb && to_rgb)
+ v = mult_mat_vec(m, ycbcr_to_norm_offset);
+ print_matrix(tmp, v);
+}
+
+int main(int argc, char **argv)
+{
+ struct matrix m_rgb_to_709, m_rgb_to_601, m_601_to_709, m_709_to_601;
+ struct matrix unity = UNITY;
+ struct matrix invm;
+
+ m_rgb_to_709 = cs2ycbcr(rec709);
+ quant_matrix("RGB to 709", true, false, m_rgb_to_709);
+ m_rgb_to_601 = cs2ycbcr(smpte170m);
+ quant_matrix("RGB to 601", true, false, m_rgb_to_601);
+ invm = invert(m_rgb_to_601);
+ quant_matrix("601 to RBG", false, true, invm);
+ m_601_to_709 = mult_mat(invm, m_rgb_to_709);
+ quant_matrix("601 to 709", false, false, m_601_to_709);
+ invm = invert(m_rgb_to_709);
+ quant_matrix("709 to RGB", false, true, invm);
+ m_709_to_601 = mult_mat(invm, m_rgb_to_601);
+ quant_matrix("709 to 601", false, false, m_709_to_601);
+ quant_matrix("YCbCr to YCbCr", false, false, unity);
+ quant_matrix("RGB to RGB", true, true, unity);
+ return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+ static const char *encs[] = {
+ "",
+ " (601)",
+ " (709)",
+ " (XV601)",
+ " (XV709)",
+ " (SYCC)",
+ " (BT2020)",
+ };
+ unsigned from_rgb, to_rgb, from_lim, to_lim, from_enc, to_enc;
+ struct vector v = { 219.0 / 255.0, 224.0 / 255.0, 224.0 / 255.0 };
+
+ print_fmatrix(mult_vec_mat(v, rec709_to_ycbcr));
+ print_fmatrix(invert(mult_vec_mat(v, rec709_to_ycbcr)));
+ if (0)
+ for (from_rgb = 0; from_rgb <= 1; from_rgb++)
+ for (to_rgb = 0; to_rgb <= 1; to_rgb++)
+ for (from_enc = from_rgb ? V4L2_YCBCR_ENC_BT2020 : V4L2_YCBCR_ENC_601;
+ from_enc <= V4L2_YCBCR_ENC_BT2020; from_enc++)
+ for (to_enc = to_rgb ? V4L2_YCBCR_ENC_BT2020 : V4L2_YCBCR_ENC_601;
+ to_enc <= V4L2_YCBCR_ENC_BT2020; to_enc++)
+ for (from_lim = 0; from_lim <= 1; from_lim++)
+ for (to_lim = 0; to_lim <= 1; to_lim++) {
+ char s[256];
+
+ sprintf(s, "%s %s%s to %s %s%s",
+ from_lim ? "Limited" : "Full",
+ from_rgb ? "RGB" : "YCbCr",
+ from_rgb ? "" : encs[from_enc],
+ to_lim ? "Limited" : "Full",
+ to_rgb ? "RGB" : "YCbCr",
+ to_rgb ? "" : encs[to_enc]);
+ quant_matrix(s, from_rgb, from_lim, from_enc,
+ to_rgb, to_lim, to_enc);
+ }
+}

Privacy Policy