#include <linux/videodev2.h>
#include <media/tpg/v4l2-tpg.h>
const struct tpg_rbg_color8 tpg_colors[TPG_COLOR_MAX] = …;
#ifndef COMPILE_APP
const unsigned short tpg_rec709_to_linear[255 * 16 + 1] = …;
const unsigned short tpg_linear_to_rec709[255 * 16 + 1] = …;
const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_SMPTE2084 + 1][TPG_COLOR_CSC_BLACK + 1] = …;
#else
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
static const double rec709_to_ntsc1953[3][3] = {
{ 0.6785011, 0.2883441, 0.0331548 },
{ 0.0165284, 1.0518725, -0.0684009 },
{ 0.0179230, 0.0506096, 0.9314674 }
};
static const double rec709_to_ebu[3][3] = {
{ 0.9578221, 0.0421779, -0.0000000 },
{ -0.0000000, 1.0000000, 0.0000000 },
{ -0.0000000, -0.0119367, 1.0119367 }
};
static const double rec709_to_170m[3][3] = {
{ 1.0653640, -0.0553900, -0.0099740 },
{ -0.0196361, 1.0363630, -0.0167269 },
{ 0.0016327, 0.0044133, 0.9939540 },
};
static const double rec709_to_240m[3][3] = {
{ 1.0653640, -0.0553900, -0.0099740 },
{ -0.0196361, 1.0363630, -0.0167269 },
{ 0.0016327, 0.0044133, 0.9939540 },
};
static const double rec709_to_oprgb[3][3] = {
{ 0.7151627, 0.2848373, -0.0000000 },
{ 0.0000000, 1.0000000, 0.0000000 },
{ -0.0000000, 0.0411705, 0.9588295 },
};
static const double rec709_to_bt2020[3][3] = {
{ 0.6274524, 0.3292485, 0.0432991 },
{ 0.0691092, 0.9195311, 0.0113597 },
{ 0.0163976, 0.0880301, 0.8955723 },
};
static const double rec709_to_dcip3[3][3] = {
{ 0.8686648, 0.1288456, 0.0024896 },
{ 0.0345479, 0.9618084, 0.0036437 },
{ 0.0167785, 0.0710559, 0.9121655 }
};
static void mult_matrix(double *r, double *g, double *b, const double m[3][3])
{
double ir, ig, ib;
ir = m[0][0] * (*r) + m[0][1] * (*g) + m[0][2] * (*b);
ig = m[1][0] * (*r) + m[1][1] * (*g) + m[1][2] * (*b);
ib = m[2][0] * (*r) + m[2][1] * (*g) + m[2][2] * (*b);
*r = ir;
*g = ig;
*b = ib;
}
static double transfer_srgb_to_rgb(double v)
{
if (v < -0.04045)
return pow((-v + 0.055) / 1.055, 2.4);
return (v <= 0.04045) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4);
}
static double transfer_rgb_to_srgb(double v)
{
if (v <= -0.0031308)
return -1.055 * pow(-v, 1.0 / 2.4) + 0.055;
if (v <= 0.0031308)
return v * 12.92;
return 1.055 * pow(v, 1.0 / 2.4) - 0.055;
}
static double transfer_rgb_to_smpte240m(double v)
{
return (v <= 0.0228) ? v * 4.0 : 1.1115 * pow(v, 0.45) - 0.1115;
}
static double transfer_rgb_to_rec709(double v)
{
if (v <= -0.018)
return -1.099 * pow(-v, 0.45) + 0.099;
return (v < 0.018) ? v * 4.5 : 1.099 * pow(v, 0.45) - 0.099;
}
static double transfer_rec709_to_rgb(double v)
{
return (v < 0.081) ? v / 4.5 : pow((v + 0.099) / 1.099, 1.0 / 0.45);
}
static double transfer_rgb_to_oprgb(double v)
{
return pow(v, 1.0 / 2.19921875);
}
static double transfer_rgb_to_dcip3(double v)
{
return pow(v, 1.0 / 2.6);
}
static double transfer_rgb_to_smpte2084(double v)
{
const double m1 = (2610.0 / 4096.0) / 4.0;
const double m2 = 128.0 * 2523.0 / 4096.0;
const double c1 = 3424.0 / 4096.0;
const double c2 = 32.0 * 2413.0 / 4096.0;
const double c3 = 32.0 * 2392.0 / 4096.0;
v /= 100.0;
v = pow(v, m1);
return pow((c1 + c2 * v) / (1 + c3 * v), m2);
}
static double transfer_srgb_to_rec709(double v)
{
return transfer_rgb_to_rec709(transfer_srgb_to_rgb(v));
}
static void csc(enum v4l2_colorspace colorspace, enum v4l2_xfer_func xfer_func,
double *r, double *g, double *b)
{
int clamp = 1;
*r = transfer_srgb_to_rgb(*r);
*g = transfer_srgb_to_rgb(*g);
*b = transfer_srgb_to_rgb(*b);
switch (colorspace) {
case V4L2_COLORSPACE_SMPTE240M:
mult_matrix(r, g, b, rec709_to_240m);
break;
case V4L2_COLORSPACE_SMPTE170M:
mult_matrix(r, g, b, rec709_to_170m);
break;
case V4L2_COLORSPACE_470_SYSTEM_BG:
mult_matrix(r, g, b, rec709_to_ebu);
break;
case V4L2_COLORSPACE_470_SYSTEM_M:
mult_matrix(r, g, b, rec709_to_ntsc1953);
break;
case V4L2_COLORSPACE_OPRGB:
mult_matrix(r, g, b, rec709_to_oprgb);
break;
case V4L2_COLORSPACE_BT2020:
mult_matrix(r, g, b, rec709_to_bt2020);
break;
case V4L2_COLORSPACE_DCI_P3:
mult_matrix(r, g, b, rec709_to_dcip3);
break;
case V4L2_COLORSPACE_SRGB:
case V4L2_COLORSPACE_REC709:
break;
default:
break;
}
if (clamp) {
*r = ((*r) < 0) ? 0 : (((*r) > 1) ? 1 : (*r));
*g = ((*g) < 0) ? 0 : (((*g) > 1) ? 1 : (*g));
*b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b));
}
switch (xfer_func) {
case V4L2_XFER_FUNC_709:
*r = transfer_rgb_to_rec709(*r);
*g = transfer_rgb_to_rec709(*g);
*b = transfer_rgb_to_rec709(*b);
break;
case V4L2_XFER_FUNC_SRGB:
*r = transfer_rgb_to_srgb(*r);
*g = transfer_rgb_to_srgb(*g);
*b = transfer_rgb_to_srgb(*b);
break;
case V4L2_XFER_FUNC_OPRGB:
*r = transfer_rgb_to_oprgb(*r);
*g = transfer_rgb_to_oprgb(*g);
*b = transfer_rgb_to_oprgb(*b);
break;
case V4L2_XFER_FUNC_DCI_P3:
*r = transfer_rgb_to_dcip3(*r);
*g = transfer_rgb_to_dcip3(*g);
*b = transfer_rgb_to_dcip3(*b);
break;
case V4L2_XFER_FUNC_SMPTE2084:
*r = transfer_rgb_to_smpte2084(*r);
*g = transfer_rgb_to_smpte2084(*g);
*b = transfer_rgb_to_smpte2084(*b);
break;
case V4L2_XFER_FUNC_SMPTE240M:
*r = transfer_rgb_to_smpte240m(*r);
*g = transfer_rgb_to_smpte240m(*g);
*b = transfer_rgb_to_smpte240m(*b);
break;
case V4L2_XFER_FUNC_NONE:
break;
}
}
int main(int argc, char **argv)
{
static const unsigned colorspaces[] = {
0,
V4L2_COLORSPACE_SMPTE170M,
V4L2_COLORSPACE_SMPTE240M,
V4L2_COLORSPACE_REC709,
0,
V4L2_COLORSPACE_470_SYSTEM_M,
V4L2_COLORSPACE_470_SYSTEM_BG,
0,
V4L2_COLORSPACE_SRGB,
V4L2_COLORSPACE_OPRGB,
V4L2_COLORSPACE_BT2020,
0,
V4L2_COLORSPACE_DCI_P3,
};
static const char * const colorspace_names[] = {
"",
"V4L2_COLORSPACE_SMPTE170M",
"V4L2_COLORSPACE_SMPTE240M",
"V4L2_COLORSPACE_REC709",
"",
"V4L2_COLORSPACE_470_SYSTEM_M",
"V4L2_COLORSPACE_470_SYSTEM_BG",
"",
"V4L2_COLORSPACE_SRGB",
"V4L2_COLORSPACE_OPRGB",
"V4L2_COLORSPACE_BT2020",
"",
"V4L2_COLORSPACE_DCI_P3",
};
static const char * const xfer_func_names[] = {
"",
"V4L2_XFER_FUNC_709",
"V4L2_XFER_FUNC_SRGB",
"V4L2_XFER_FUNC_OPRGB",
"V4L2_XFER_FUNC_SMPTE240M",
"V4L2_XFER_FUNC_NONE",
"V4L2_XFER_FUNC_DCI_P3",
"V4L2_XFER_FUNC_SMPTE2084",
};
int i;
int x;
int c;
printf("/* Generated table */\n");
printf("const unsigned short tpg_rec709_to_linear[255 * 16 + 1] = {");
for (i = 0; i <= 255 * 16; i++) {
if (i % 16 == 0)
printf("\n\t");
printf("%4d,%s",
(int)(0.5 + 16.0 * 255.0 *
transfer_rec709_to_rgb(i / (16.0 * 255.0))),
i % 16 == 15 || i == 255 * 16 ? "" : " ");
}
printf("\n};\n\n");
printf("/* Generated table */\n");
printf("const unsigned short tpg_linear_to_rec709[255 * 16 + 1] = {");
for (i = 0; i <= 255 * 16; i++) {
if (i % 16 == 0)
printf("\n\t");
printf("%4d,%s",
(int)(0.5 + 16.0 * 255.0 *
transfer_rgb_to_rec709(i / (16.0 * 255.0))),
i % 16 == 15 || i == 255 * 16 ? "" : " ");
}
printf("\n};\n\n");
printf("/* Generated table */\n");
printf("const struct tpg_rbg_color16 tpg_csc_colors[V4L2_COLORSPACE_DCI_P3 + 1][V4L2_XFER_FUNC_SMPTE2084 + 1][TPG_COLOR_CSC_BLACK + 1] = {\n");
for (c = 0; c <= V4L2_COLORSPACE_DCI_P3; c++) {
for (x = 1; x <= V4L2_XFER_FUNC_SMPTE2084; x++) {
for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) {
double r, g, b;
if (colorspaces[c] == 0)
continue;
r = tpg_colors[i].r / 255.0;
g = tpg_colors[i].g / 255.0;
b = tpg_colors[i].b / 255.0;
csc(c, x, &r, &g, &b);
printf("\t[%s][%s][%d] = { %d, %d, %d },\n",
colorspace_names[c],
xfer_func_names[x], i,
(int)(r * 4080), (int)(g * 4080), (int)(b * 4080));
}
}
}
printf("};\n\n");
return 0;
}
#endif