summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKacper Michajłow <kasper93@gmail.com>2023-11-04 06:27:38 +0100
committerDudemanguy <random342@airmail.cc>2024-01-22 14:54:55 +0000
commit475f76dc6d0154a109cb83d123e1839d22455ef8 (patch)
tree8cf0c2b2b8b352e654345485776afb2f44f669fc
parent47be5ad4aaa20df4bb1577110198d5aab3c88925 (diff)
downloadmpv-475f76dc6d0154a109cb83d123e1839d22455ef8.tar.bz2
mpv-475f76dc6d0154a109cb83d123e1839d22455ef8.tar.xz
csputils: replace more primitives with pl_
We can go deeper, but need to stop somewhere to not reimplement vo_gpu using libplacebo...
-rw-r--r--demux/demux_disc.c2
-rw-r--r--sub/sd_ass.c8
-rw-r--r--video/csputils.c430
-rw-r--r--video/csputils.h57
-rw-r--r--video/mp_image.c4
-rw-r--r--video/out/gpu/lcms.c14
-rw-r--r--video/out/gpu/video.c16
-rw-r--r--video/out/gpu/video_shaders.c35
-rw-r--r--video/vdpau_mixer.c4
-rw-r--r--video/zimg.c2
10 files changed, 98 insertions, 474 deletions
diff --git a/demux/demux_disc.c b/demux/demux_disc.c
index 3dfff45403..8cd4b7b5e9 100644
--- a/demux/demux_disc.c
+++ b/demux/demux_disc.c
@@ -94,7 +94,7 @@ static void add_dvd_streams(demuxer_t *demuxer)
// emulate the extradata
struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS;
- struct mp_cmat cmatrix;
+ struct pl_transform3x3 cmatrix;
mp_get_csp_matrix(&csp, &cmatrix);
char *s = talloc_strdup(sh, "");
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index 28ed23aecf..d191145f10 100644
--- a/sub/sd_ass.c
+++ b/sub/sd_ass.c
@@ -967,14 +967,14 @@ static void mangle_colors(struct sd *sd, struct sub_bitmaps *parts)
struct mp_csp_params vs_params = MP_CSP_PARAMS_DEFAULTS;
vs_params.repr.sys = csp;
vs_params.repr.levels = levels;
- struct mp_cmat vs_yuv2rgb, vs_rgb2yuv;
+ struct pl_transform3x3 vs_yuv2rgb;
mp_get_csp_matrix(&vs_params, &vs_yuv2rgb);
- mp_invert_cmat(&vs_rgb2yuv, &vs_yuv2rgb);
+ pl_transform3x3_invert(&vs_yuv2rgb);
// Proper conversion to RGB
struct mp_csp_params rgb_params = MP_CSP_PARAMS_DEFAULTS;
rgb_params.color = params.color;
- struct mp_cmat vs2rgb;
+ struct pl_transform3x3 vs2rgb;
mp_get_csp_matrix(&rgb_params, &vs2rgb);
for (int n = 0; n < parts->num_parts; n++) {
@@ -985,7 +985,7 @@ static void mangle_colors(struct sd *sd, struct sub_bitmaps *parts)
int b = (color >> 8u) & 0xff;
int a = 0xff - (color & 0xff);
int rgb[3] = {r, g, b}, yuv[3];
- mp_map_fixp_color(&vs_rgb2yuv, 8, rgb, 8, yuv);
+ mp_map_fixp_color(&vs_yuv2rgb, 8, rgb, 8, yuv);
mp_map_fixp_color(&vs2rgb, 8, yuv, 8, rgb);
sb->libass.color = MP_ASS_RGBA(rgb[0], rgb[1], rgb[2], a);
}
diff --git a/video/csputils.c b/video/csputils.c
index 6b708f7525..3a12fda9f0 100644
--- a/video/csputils.c
+++ b/video/csputils.c
@@ -3,8 +3,6 @@
*
* Copyleft (C) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de>
*
- * mp_invert_cmat based on DarkPlaces engine (relicensed from GPL to LGPL)
- *
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
@@ -170,260 +168,17 @@ enum pl_color_primaries mp_csp_guess_primaries(int width, int height)
}
}
-void mp_invert_matrix3x3(float m[3][3])
-{
- float m00 = m[0][0], m01 = m[0][1], m02 = m[0][2],
- m10 = m[1][0], m11 = m[1][1], m12 = m[1][2],
- m20 = m[2][0], m21 = m[2][1], m22 = m[2][2];
-
- // calculate the adjoint
- m[0][0] = (m11 * m22 - m21 * m12);
- m[0][1] = -(m01 * m22 - m21 * m02);
- m[0][2] = (m01 * m12 - m11 * m02);
- m[1][0] = -(m10 * m22 - m20 * m12);
- m[1][1] = (m00 * m22 - m20 * m02);
- m[1][2] = -(m00 * m12 - m10 * m02);
- m[2][0] = (m10 * m21 - m20 * m11);
- m[2][1] = -(m00 * m21 - m20 * m01);
- m[2][2] = (m00 * m11 - m10 * m01);
-
- // calculate the determinant (as inverse == 1/det * adjoint,
- // adjoint * m == identity * det, so this calculates the det)
- float det = m00 * m[0][0] + m10 * m[0][1] + m20 * m[0][2];
- det = 1.0f / det;
-
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++)
- m[i][j] *= det;
- }
-}
-
-// A := A * B
-static void mp_mul_matrix3x3(float a[3][3], float b[3][3])
-{
- float a00 = a[0][0], a01 = a[0][1], a02 = a[0][2],
- a10 = a[1][0], a11 = a[1][1], a12 = a[1][2],
- a20 = a[2][0], a21 = a[2][1], a22 = a[2][2];
-
- for (int i = 0; i < 3; i++) {
- a[0][i] = a00 * b[0][i] + a01 * b[1][i] + a02 * b[2][i];
- a[1][i] = a10 * b[0][i] + a11 * b[1][i] + a12 * b[2][i];
- a[2][i] = a20 * b[0][i] + a21 * b[1][i] + a22 * b[2][i];
- }
-}
-
-// return the primaries associated with a certain mp_csp_primaries val
-struct mp_csp_primaries mp_get_csp_primaries(enum pl_color_primaries spc)
-{
- /*
- Values from: ITU-R Recommendations BT.470-6, BT.601-7, BT.709-5, BT.2020-0
-
- https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-6-199811-S!!PDF-E.pdf
- https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.601-7-201103-I!!PDF-E.pdf
- https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-5-200204-I!!PDF-E.pdf
- https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2020-0-201208-I!!PDF-E.pdf
-
- Other colorspaces from https://en.wikipedia.org/wiki/RGB_color_space#Specifications
- */
-
- // CIE standard illuminant series
- static const struct mp_csp_col_xy
- d50 = {0.34577, 0.35850},
- d65 = {0.31271, 0.32902},
- c = {0.31006, 0.31616},
- dci = {0.31400, 0.35100},
- e = {1.0/3.0, 1.0/3.0};
-
- switch (spc) {
- case PL_COLOR_PRIM_BT_470M:
- return (struct mp_csp_primaries) {
- .red = {0.670, 0.330},
- .green = {0.210, 0.710},
- .blue = {0.140, 0.080},
- .white = c
- };
- case PL_COLOR_PRIM_BT_601_525:
- return (struct mp_csp_primaries) {
- .red = {0.630, 0.340},
- .green = {0.310, 0.595},
- .blue = {0.155, 0.070},
- .white = d65
- };
- case PL_COLOR_PRIM_BT_601_625:
- return (struct mp_csp_primaries) {
- .red = {0.640, 0.330},
- .green = {0.290, 0.600},
- .blue = {0.150, 0.060},
- .white = d65
- };
- // This is the default assumption if no colorspace information could
- // be determined, eg. for files which have no video channel.
- case PL_COLOR_PRIM_UNKNOWN:
- case PL_COLOR_PRIM_BT_709:
- return (struct mp_csp_primaries) {
- .red = {0.640, 0.330},
- .green = {0.300, 0.600},
- .blue = {0.150, 0.060},
- .white = d65
- };
- case PL_COLOR_PRIM_BT_2020:
- return (struct mp_csp_primaries) {
- .red = {0.708, 0.292},
- .green = {0.170, 0.797},
- .blue = {0.131, 0.046},
- .white = d65
- };
- case PL_COLOR_PRIM_APPLE:
- return (struct mp_csp_primaries) {
- .red = {0.625, 0.340},
- .green = {0.280, 0.595},
- .blue = {0.115, 0.070},
- .white = d65
- };
- case PL_COLOR_PRIM_ADOBE:
- return (struct mp_csp_primaries) {
- .red = {0.640, 0.330},
- .green = {0.210, 0.710},
- .blue = {0.150, 0.060},
- .white = d65
- };
- case PL_COLOR_PRIM_PRO_PHOTO:
- return (struct mp_csp_primaries) {
- .red = {0.7347, 0.2653},
- .green = {0.1596, 0.8404},
- .blue = {0.0366, 0.0001},
- .white = d50
- };
- case PL_COLOR_PRIM_CIE_1931:
- return (struct mp_csp_primaries) {
- .red = {0.7347, 0.2653},
- .green = {0.2738, 0.7174},
- .blue = {0.1666, 0.0089},
- .white = e
- };
- // From SMPTE RP 431-2 and 432-1
- case PL_COLOR_PRIM_DCI_P3:
- case PL_COLOR_PRIM_DISPLAY_P3:
- return (struct mp_csp_primaries) {
- .red = {0.680, 0.320},
- .green = {0.265, 0.690},
- .blue = {0.150, 0.060},
- .white = spc == PL_COLOR_PRIM_DCI_P3 ? dci : d65
- };
- // From Panasonic VARICAM reference manual
- case PL_COLOR_PRIM_V_GAMUT:
- return (struct mp_csp_primaries) {
- .red = {0.730, 0.280},
- .green = {0.165, 0.840},
- .blue = {0.100, -0.03},
- .white = d65
- };
- // From Sony S-Log reference manual
- case PL_COLOR_PRIM_S_GAMUT:
- return (struct mp_csp_primaries) {
- .red = {0.730, 0.280},
- .green = {0.140, 0.855},
- .blue = {0.100, -0.05},
- .white = d65
- };
- // from EBU Tech. 3213-E
- case PL_COLOR_PRIM_EBU_3213:
- return (struct mp_csp_primaries) {
- .red = {0.630, 0.340},
- .green = {0.295, 0.605},
- .blue = {0.155, 0.077},
- .white = d65
- };
- // From H.273, traditional film with Illuminant C
- case PL_COLOR_PRIM_FILM_C:
- return (struct mp_csp_primaries) {
- .red = {0.681, 0.319},
- .green = {0.243, 0.692},
- .blue = {0.145, 0.049},
- .white = c
- };
- // From libplacebo source code
- case PL_COLOR_PRIM_ACES_AP0:
- return (struct mp_csp_primaries) {
- .red = {0.7347, 0.2653},
- .green = {0.0000, 1.0000},
- .blue = {0.0001, -0.0770},
- .white = {0.32168, 0.33767},
- };
- // From libplacebo source code
- case PL_COLOR_PRIM_ACES_AP1:
- return (struct mp_csp_primaries) {
- .red = {0.713, 0.293},
- .green = {0.165, 0.830},
- .blue = {0.128, 0.044},
- .white = {0.32168, 0.33767},
- };
- default:
- return (struct mp_csp_primaries) {{0}};
- }
-}
-
-// Get the nominal peak for a given colorspace, relative to the reference white
-// level. In other words, this returns the brightest encodable value that can
-// be represented by a given transfer curve.
-float mp_trc_nom_peak(enum pl_color_transfer trc)
-{
- switch (trc) {
- case PL_COLOR_TRC_PQ: return 10000.0 / MP_REF_WHITE;
- case PL_COLOR_TRC_HLG: return 12.0 / MP_REF_WHITE_HLG;
- case PL_COLOR_TRC_V_LOG: return 46.0855;
- case PL_COLOR_TRC_S_LOG1: return 6.52;
- case PL_COLOR_TRC_S_LOG2: return 9.212;
- }
-
- return 1.0;
-}
-
-bool mp_trc_is_hdr(enum pl_color_transfer trc)
-{
- return mp_trc_nom_peak(trc) > 1.0;
-}
-
-// Compute the RGB/XYZ matrix as described here:
-// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-void mp_get_rgb2xyz_matrix(struct mp_csp_primaries space, float m[3][3])
-{
- float S[3], X[4], Z[4];
-
- // Convert from CIE xyY to XYZ. Note that Y=1 holds true for all primaries
- X[0] = space.red.x / space.red.y;
- X[1] = space.green.x / space.green.y;
- X[2] = space.blue.x / space.blue.y;
- X[3] = space.white.x / space.white.y;
-
- Z[0] = (1 - space.red.x - space.red.y) / space.red.y;
- Z[1] = (1 - space.green.x - space.green.y) / space.green.y;
- Z[2] = (1 - space.blue.x - space.blue.y) / space.blue.y;
- Z[3] = (1 - space.white.x - space.white.y) / space.white.y;
-
- // S = XYZ^-1 * W
- for (int i = 0; i < 3; i++) {
- m[0][i] = X[i];
- m[1][i] = 1;
- m[2][i] = Z[i];
- }
-
- mp_invert_matrix3x3(m);
-
- for (int i = 0; i < 3; i++)
- S[i] = m[i][0] * X[3] + m[i][1] * 1 + m[i][2] * Z[3];
-
- // M = [Sc * XYZc]
- for (int i = 0; i < 3; i++) {
- m[0][i] = S[i] * X[i];
- m[1][i] = S[i] * 1;
- m[2][i] = S[i] * Z[i];
- }
-}
+// LMS<-XYZ revised matrix from CIECAM97, based on a linear transform and
+// normalized for equal energy on monochrome inputs
+static const pl_matrix3x3 m_cat97 = {{
+ { 0.8562, 0.3372, -0.1934 },
+ { -0.8360, 1.8327, 0.0033 },
+ { 0.0357, -0.0469, 1.0112 },
+}};
// M := M * XYZd<-XYZs
-static void mp_apply_chromatic_adaptation(struct mp_csp_col_xy src,
- struct mp_csp_col_xy dest, float m[3][3])
+static void apply_chromatic_adaptation(struct pl_cie_xy src,
+ struct pl_cie_xy dest, pl_matrix3x3 *mat)
{
// If the white points are nearly identical, this is a wasteful identity
// operation.
@@ -432,98 +187,33 @@ static void mp_apply_chromatic_adaptation(struct mp_csp_col_xy src,
// XYZd<-XYZs = Ma^-1 * (I*[Cd/Cs]) * Ma
// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
- float C[3][2], tmp[3][3] = {{0}};
-
- // Ma = Bradford matrix, arguably most popular method in use today.
- // This is derived experimentally and thus hard-coded.
- float bradford[3][3] = {
- { 0.8951, 0.2664, -0.1614 },
- { -0.7502, 1.7135, 0.0367 },
- { 0.0389, -0.0685, 1.0296 },
- };
+ // For Ma, we use the CIECAM97 revised (linear) matrix
+ float C[3][2];
for (int i = 0; i < 3; i++) {
// source cone
- C[i][0] = bradford[i][0] * mp_xy_X(src)
- + bradford[i][1] * 1
- + bradford[i][2] * mp_xy_Z(src);
+ C[i][0] = m_cat97.m[i][0] * pl_cie_X(src)
+ + m_cat97.m[i][1] * 1
+ + m_cat97.m[i][2] * pl_cie_Z(src);
// dest cone
- C[i][1] = bradford[i][0] * mp_xy_X(dest)
- + bradford[i][1] * 1
- + bradford[i][2] * mp_xy_Z(dest);
+ C[i][1] = m_cat97.m[i][0] * pl_cie_X(dest)
+ + m_cat97.m[i][1] * 1
+ + m_cat97.m[i][2] * pl_cie_Z(dest);
}
// tmp := I * [Cd/Cs] * Ma
+ pl_matrix3x3 tmp = {0};
for (int i = 0; i < 3; i++)
- tmp[i][i] = C[i][1] / C[i][0];
+ tmp.m[i][i] = C[i][1] / C[i][0];
- mp_mul_matrix3x3(tmp, bradford);
+ pl_matrix3x3_mul(&tmp, &m_cat97);
// M := M * Ma^-1 * tmp
- mp_invert_matrix3x3(bradford);
- mp_mul_matrix3x3(m, bradford);
- mp_mul_matrix3x3(m, tmp);
-}
-
-// get the coefficients of the source -> dest cms matrix
-void mp_get_cms_matrix(struct mp_csp_primaries src, struct mp_csp_primaries dest,
- enum mp_render_intent intent, float m[3][3])
-{
- float tmp[3][3];
-
- // In saturation mapping, we don't care about accuracy and just want
- // primaries to map to primaries, making this an identity transformation.
- if (intent == MP_INTENT_SATURATION) {
- for (int i = 0; i < 3; i++)
- m[i][i] = 1;
- return;
- }
-
- // RGBd<-RGBs = RGBd<-XYZd * XYZd<-XYZs * XYZs<-RGBs
- // Equations from: http://www.brucelindbloom.com/index.html?Math.html
- // Note: Perceptual is treated like relative colorimetric. There's no
- // definition for perceptual other than "make it look good".
-
- // RGBd<-XYZd, inverted from XYZd<-RGBd
- mp_get_rgb2xyz_matrix(dest, m);
- mp_invert_matrix3x3(m);
-
- // Chromatic adaptation, except in absolute colorimetric intent
- if (intent != MP_INTENT_ABSOLUTE_COLORIMETRIC)
- mp_apply_chromatic_adaptation(src.white, dest.white, m);
-
- // XYZs<-RGBs
- mp_get_rgb2xyz_matrix(src, tmp);
- mp_mul_matrix3x3(m, tmp);
-}
-
-// get the coefficients of an ST 428-1 xyz -> rgb conversion matrix
-// intent = the rendering intent used to convert to the target primaries
-static void mp_get_xyz2rgb_coeffs(struct mp_csp_params *params,
- enum mp_render_intent intent, struct mp_cmat *m)
-{
- // Convert to DCI-P3
- struct mp_csp_primaries prim = mp_get_csp_primaries(PL_COLOR_PRIM_DCI_P3);
- float brightness = params->brightness;
- mp_get_rgb2xyz_matrix(prim, m->m);
- mp_invert_matrix3x3(m->m);
-
- // All non-absolute mappings want to map source white to target white
- if (intent != MP_INTENT_ABSOLUTE_COLORIMETRIC) {
- // SMPTE EG 432-1 Annex H defines the white point as equal energy
- static const struct mp_csp_col_xy smpte432 = {1.0/3.0, 1.0/3.0};
- mp_apply_chromatic_adaptation(smpte432, prim.white, m->m);
- }
-
- // Since this outputs linear RGB rather than companded RGB, we
- // want to linearize any brightness additions. 2 is a reasonable
- // approximation for any sort of gamma function that could be in use.
- // As this is an aesthetic setting only, any exact values do not matter.
- brightness *= fabs(brightness);
-
- for (int i = 0; i < 3; i++)
- m->c[i] = brightness;
+ pl_matrix3x3 ma_inv = m_cat97;
+ pl_matrix3x3_invert(&ma_inv);
+ pl_matrix3x3_mul(mat, &ma_inv);
+ pl_matrix3x3_mul(mat, &tmp);
}
// Get multiplication factor required if image data is fit within the LSBs of a
@@ -608,19 +298,19 @@ void mp_get_csp_uint_mul(enum pl_color_system csp, enum pl_color_levels levels,
* Under these conditions the given parameters lr, lg, lb uniquely
* determine the mapping of Y, U, V to R, G, B.
*/
-static void luma_coeffs(struct mp_cmat *mat, float lr, float lg, float lb)
+static void luma_coeffs(struct pl_transform3x3 *mat, float lr, float lg, float lb)
{
assert(fabs(lr+lg+lb - 1) < 1e-6);
- *mat = (struct mp_cmat) {
- { {1, 0, 2 * (1-lr) },
- {1, -2 * (1-lb) * lb/lg, -2 * (1-lr) * lr/lg },
- {1, 2 * (1-lb), 0 } },
+ *mat = (struct pl_transform3x3) {
+ { {{1, 0, 2 * (1-lr) },
+ {1, -2 * (1-lb) * lb/lg, -2 * (1-lr) * lr/lg },
+ {1, 2 * (1-lb), 0 }} },
// Constant coefficients (mat->c) not set here
};
}
// get the coefficients of the yuv -> rgb conversion matrix
-void mp_get_csp_matrix(struct mp_csp_params *params, struct mp_cmat *m)
+void mp_get_csp_matrix(struct mp_csp_params *params, struct pl_transform3x3 *m)
{
enum pl_color_system colorspace = params->repr.sys;
if (colorspace <= PL_COLOR_SYSTEM_UNKNOWN || colorspace >= PL_COLOR_SYSTEM_COUNT)
@@ -639,29 +329,30 @@ void mp_get_csp_matrix(struct mp_csp_params *params, struct mp_cmat *m)
// If this clips on any VO, a constant 0.5 coefficient can be added
// to the chroma channels to normalize them into [0,1]. This is not
// currently needed by anything, though.
- *m = (struct mp_cmat){{{0, 0, 1}, {1, 0, 0}, {0, 1, 0}}};
+ *m = (struct pl_transform3x3){{{{0, 0, 1}, {1, 0, 0}, {0, 1, 0}}}};
break;
}
case PL_COLOR_SYSTEM_RGB: {
- *m = (struct mp_cmat){{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}};
+ *m = (struct pl_transform3x3){{{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}}};
levels_in = -1;
break;
}
case PL_COLOR_SYSTEM_XYZ: {
- // The vo should probably not be using a matrix generated by this
- // function for XYZ sources, but if it does, let's just convert it to
- // an equivalent RGB space based on the colorimetry metadata it
- // provided in mp_csp_params. (At the risk of clipping, if the
- // chosen primaries are too small to fit the actual data)
- mp_get_xyz2rgb_coeffs(params, MP_INTENT_RELATIVE_COLORIMETRIC, m);
+ // For lack of anything saner to do, just assume the caller wants
+ // DCI-P3 primaries, which is a reasonable assumption.
+ const struct pl_raw_primaries *dst = pl_raw_primaries_get(PL_COLOR_PRIM_DCI_P3);
+ pl_matrix3x3 mat = pl_get_xyz2rgb_matrix(dst);
+ // DCDM X'Y'Z' is expected to have equal energy white point (EG 432-1 Annex H)
+ apply_chromatic_adaptation((struct pl_cie_xy){1.0/3.0, 1.0/3.0}, dst->white, &mat);
+ *m = (struct pl_transform3x3) { .mat = mat };
levels_in = -1;
break;
}
case PL_COLOR_SYSTEM_YCGCO: {
- *m = (struct mp_cmat) {
- {{1, -1, 1},
- {1, 1, 0},
- {1, -1, -1}},
+ *m = (struct pl_transform3x3) {
+ {{{1, -1, 1},
+ {1, 1, 0},
+ {1, -1, -1}}},
};
break;
}
@@ -680,9 +371,9 @@ void mp_get_csp_matrix(struct mp_csp_params *params, struct mp_cmat *m)
float huecos = params->gray ? 0 : params->saturation * cos(params->hue);
float huesin = params->gray ? 0 : params->saturation * sin(params->hue);
for (int i = 0; i < 3; i++) {
- float u = m->m[i][1], v = m->m[i][2];
- m->m[i][1] = huecos * u - huesin * v;
- m->m[i][2] = huesin * u + huecos * v;
+ float u = m->mat.m[i][1], v = m->mat.m[i][2];
+ m->mat.m[i][1] = huecos * u - huesin * v;
+ m->mat.m[i][2] = huesin * u + huecos * v;
}
}
@@ -728,13 +419,13 @@ void mp_get_csp_matrix(struct mp_csp_params *params, struct mp_cmat *m)
cmul *= params->contrast;
for (int i = 0; i < 3; i++) {
- m->m[i][0] *= ymul;
- m->m[i][1] *= cmul;
- m->m[i][2] *= cmul;
+ m->mat.m[i][0] *= ymul;
+ m->mat.m[i][1] *= cmul;
+ m->mat.m[i][2] *= cmul;
// Set c so that Y=umin,UV=cmid maps to RGB=min (black to black),
// also add brightness offset (black lift)
- m->c[i] = rgblev.min - m->m[i][0] * yuvlev.ymin
- - (m->m[i][1] + m->m[i][2]) * yuvlev.cmid
+ m->c[i] = rgblev.min - m->mat.m[i][0] * yuvlev.ymin
+ - (m->mat.m[i][1] + m->mat.m[i][2]) * yuvlev.cmid
+ params->brightness;
}
}
@@ -822,32 +513,17 @@ void mp_csp_equalizer_state_get(struct mp_csp_equalizer_state *state,
mp_csp_copy_equalizer_values(params, opts);
}
-void mp_invert_cmat(struct mp_cmat *out, struct mp_cmat *in)
-{
- *out = *in;
- mp_invert_matrix3x3(out->m);
-
- // fix the constant coefficient
- // rgb = M * yuv + C
- // M^-1 * rgb = yuv + M^-1 * C
- // yuv = M^-1 * rgb - M^-1 * C
- // ^^^^^^^^^^
- out->c[0] = -(out->m[0][0] * in->c[0] + out->m[0][1] * in->c[1] + out->m[0][2] * in->c[2]);
- out->c[1] = -(out->m[1][0] * in->c[0] + out->m[1][1] * in->c[1] + out->m[1][2] * in->c[2]);
- out->c[2] = -(out->m[2][0] * in->c[0] + out->m[2][1] * in->c[1] + out->m[2][2] * in->c[2]);
-}
-
// Multiply the color in c with the given matrix.
// i/o is {R, G, B} or {Y, U, V} (depending on input/output and matrix), using
// a fixed point representation with the given number of bits (so for bits==8,
// [0,255] maps to [0,1]). The output is clipped to the range as needed.
-void mp_map_fixp_color(struct mp_cmat *matrix, int ibits, int in[3],
+void mp_map_fixp_color(struct pl_transform3x3 *matrix, int ibits, int in[3],
int obits, int out[3])
{
for (int i = 0; i < 3; i++) {
double val = matrix->c[i];
for (int x = 0; x < 3; x++)
- val += matrix->m[i][x] * in[x] / ((1 << ibits) - 1);
+ val += matrix->mat.m[i][x] * in[x] / ((1 << ibits) - 1);
int ival = lrint(val * ((1 << obits) - 1));
out[i] = av_clip(ival, 0, (1 << obits) - 1);
}
diff --git a/video/csputils.h b/video/csputils.h
index 9b2d0378df..5ab1287d9c 100644
--- a/video/csputils.h
+++ b/video/csputils.h
@@ -46,15 +46,6 @@ enum mp_csp_light {
extern const struct m_opt_choice_alternatives mp_csp_light_names[];
-// These constants are based on the ICC specification (Table 23) and match
-// up with the API of LittleCMS, which treats them as integers.
-enum mp_render_intent {
- MP_INTENT_PERCEPTUAL = 0,
- MP_INTENT_RELATIVE_COLORIMETRIC = 1,
- MP_INTENT_SATURATION = 2,
- MP_INTENT_ABSOLUTE_COLORIMETRIC = 3
-};
-
// The numeric values (except -1) match the Matroska StereoMode element value.
enum mp_stereo3d_mode {
MP_STEREO3D_INVALID = -1,
@@ -123,59 +114,15 @@ bool mp_csp_equalizer_state_changed(struct mp_csp_equalizer_state *state);
void mp_csp_equalizer_state_get(struct mp_csp_equalizer_state *state,
struct mp_csp_params *params);
-struct mp_csp_col_xy {
- float x, y;
-};
-
-static inline float mp_xy_X(struct mp_csp_col_xy xy) {
- return xy.x / xy.y;
-}
-
-static inline float mp_xy_Z(struct mp_csp_col_xy xy) {
- return (1 - xy.x - xy.y) / xy.y;
-}
-
-struct mp_csp_primaries {
- struct mp_csp_col_xy red, green, blue, white;
-};
-
enum pl_color_system mp_csp_guess_colorspace(int width, int height);
enum pl_color_primaries mp_csp_guess_primaries(int width, int height);
-struct mp_csp_primaries mp_get_csp_primaries(enum pl_color_primaries csp);
-float mp_trc_nom_peak(enum pl_color_transfer trc);
-bool mp_trc_is_hdr(enum pl_color_transfer trc);
-
-/* Color conversion matrix: RGB = m * YUV + c
- * m is in row-major matrix, with m[row][col], e.g.:
- * [ a11 a12 a13 ] float m[3][3] = { { a11, a12, a13 },
- * [ a21 a22 a23 ] { a21, a22, a23 },
- * [ a31 a32 a33 ] { a31, a32, a33 } };
- * This is accessed as e.g.: m[2-1][1-1] = a21
- * In particular, each row contains all the coefficients for one of R, G, B,
- * while each column contains all the coefficients for one of Y, U, V:
- * m[r,g,b][y,u,v] = ...
- * The matrix could also be viewed as group of 3 vectors, e.g. the 1st column
- * is the Y vector (1, 1, 1), the 2nd is the U vector, the 3rd the V vector.
- * The matrix might also be used for other conversions and colorspaces.
- */
-struct mp_cmat {
- float m[3][3];
- float c[3];
-};
-
-void mp_get_rgb2xyz_matrix(struct mp_csp_primaries space, float m[3][3]);
-void mp_get_cms_matrix(struct mp_csp_primaries src, struct mp_csp_primaries dest,
- enum mp_render_intent intent, float cms_matrix[3][3]);
-
double mp_get_csp_mul(enum pl_color_system csp, int input_bits, int texture_bits);
void mp_get_csp_uint_mul(enum pl_color_system csp, enum pl_color_levels levels,
int bits, int component, double *out_m, double *out_o);
-void mp_get_csp_matrix(struct mp_csp_params *params, struct mp_cmat *out);
+void mp_get_csp_matrix(struct mp_csp_params *params, struct pl_transform3x3 *out);
-void mp_invert_matrix3x3(float m[3][3]);
-void mp_invert_cmat(struct mp_cmat *out, struct mp_cmat *in);
-void mp_map_fixp_color(struct mp_cmat *matrix, int ibits, int in[3],
+void mp_map_fixp_color(struct pl_transform3x3 *matrix, int ibits, int in[3],
int obits, int out[3]);
#endif /* MPLAYER_CSPUTILS_H */
diff --git a/video/mp_image.c b/video/mp_image.c
index b86ecb9b6a..e8e1690463 100644
--- a/video/mp_image.c
+++ b/video/mp_image.c
@@ -961,11 +961,11 @@ void mp_image_params_guess_csp(struct mp_image_params *params)
} else {
// If the signal peak is unknown, we're forced to pick the TRC's
// nominal range as the signal peak to prevent clipping
- params->color.hdr.max_luma = mp_trc_nom_peak(params->color.transfer) * MP_REF_WHITE;
+ params->color.hdr.max_luma = pl_color_transfer_nominal_peak(params->color.transfer) * MP_REF_WHITE;
}
}
- if (!mp_trc_is_hdr(params->color.transfer)) {
+ if (!pl_color_space_is_hdr(&params->color)) {
// Some clips have leftover HDR metadata after conversion to SDR, so to
// avoid blowing up the tone mapping code, strip/sanitize it
params->color.hdr = pl_hdr_metadata_empty;
diff --git a/video/out/gpu/lcms.c b/video/out/gpu/lcms.c
index 00d819d2f0..1e451aa7a2 100644
--- a/video/out/gpu/lcms.c
+++ b/video/out/gpu/lcms.c
@@ -197,12 +197,12 @@ static cmsHPROFILE get_vid_profile(struct gl_lcms *p, cmsContext cms,
// The input profile for the transformation is dependent on the video
// primaries and transfer characteristics
- struct mp_csp_primaries csp = mp_get_csp_primaries(prim);
- cmsCIExyY wp_xyY = {csp.white.x, csp.white.y, 1.0};
+ const struct pl_raw_primaries *csp = pl_raw_primaries_get(prim);
+ cmsCIExyY wp_xyY = {csp->white.x, csp->white.y, 1.0};
cmsCIExyYTRIPLE prim_xyY = {
- .Red = {csp.red.x, csp.red.y, 1.0},
- .Green = {csp.green.x, csp.green.y, 1.0},
- .Blue = {csp.blue.x, csp.blue.y, 1.0},
+ .Red = {csp->red.x, csp->red.y, 1.0},
+ .Green = {csp->green.x, csp->green.y, 1.0},
+ .Blue = {csp->blue.x, csp->blue.y, 1.0},
};
cmsToneCurve *tonecurve[3] = {0};
@@ -242,7 +242,7 @@ static cmsHPROFILE get_vid_profile(struct gl_lcms *p, cmsContext cms,
// function. Relative colorimetric is used since we want to
// approximate the BT.1886 to the target device's actual black
// point even in e.g. perceptual mode
- const int intent = MP_INTENT_RELATIVE_COLORIMETRIC;
+ const int intent = PL_INTENT_RELATIVE_COLORIMETRIC;
cmsCIEXYZ bp_XYZ;
if (!cmsDetectBlackPoint(&bp_XYZ, disp_profile, intent, 0))
return false;
@@ -519,7 +519,7 @@ const struct m_sub_options mp_icc_conf = {
.size = sizeof(struct mp_icc_opts),
.defaults = &(const struct mp_icc_opts) {
.size_str = "auto",
- .intent = MP_INTENT_RELATIVE_COLORIMETRIC,
+ .intent = PL_INTENT_RELATIVE_COLORIMETRIC,
.use_embedded = true,
.cache = true,
},
diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c
index 5e0175366a..fcde3cd5c9 100644
--- a/video/out/gpu/video.c
+++ b/video/out/gpu/video.c
@@ -2344,9 +2344,9 @@ static void pass_convert_yuv(struct gl_video *p)
// Conversion to RGB. For RGB itself, this still applies e.g. brightness
// and contrast controls, or expansion of e.g. LSB-packed 10 bit data.
- struct mp_cmat m = {{{0}}};
+ struct pl_transform3x3 m = {0};
mp_get_csp_matrix(&cparams, &m);
- gl_sc_uniform_mat3(sc, "colormatrix", true, &m.m[0][0]);
+ gl_sc_uniform_mat3(sc, "colormatrix", true, &m.mat.m[0][0]);
gl_sc_uniform_vec3(sc, "colormatrix_c", m.c);
GLSL(color.rgb = mat3(colormatrix) * color.rgb + colormatrix_c;)
@@ -2482,7 +2482,7 @@ static void pass_scale_main(struct gl_video *p)
// Linear light downscaling results in nasty artifacts for HDR curves
// due to the potentially extreme brightness differences severely
// compounding any ringing. So just scale in gamma light instead.
- if (mp_trc_is_hdr(p->image_params.color.transfer))
+ if (pl_color_space_is_hdr(&p->image_params.color))
use_linear = false;
} else if (upscaling) {
use_linear = p->opts.linear_upscaling || p->opts.sigmoid_upscaling;
@@ -2592,7 +2592,7 @@ static void pass_colormanage(struct gl_video *p, struct pl_color_space src,
// limitation reasons, so we use a gamma 2.2 input curve here instead.
// We could pick any value we want here, the difference is just coding
// efficiency.
- if (mp_trc_is_hdr(trc_orig))
+ if (pl_color_space_is_hdr(&p->image_params.color))
trc_orig = PL_COLOR_TRC_GAMMA22;
if (gl_video_get_lut3d(p, prim_orig, trc_orig)) {
@@ -2629,7 +2629,7 @@ static void pass_colormanage(struct gl_video *p, struct pl_color_space src,
// Avoid outputting linear light or HDR content "by default". For these
// just pick gamma 2.2 as a default, since it's a good estimate for
// the response of typical displays
- if (dst.transfer == PL_COLOR_TRC_LINEAR || mp_trc_is_hdr(dst.transfer))
+ if (dst.transfer == PL_COLOR_TRC_LINEAR || pl_color_space_is_hdr(&dst))
dst.transfer = PL_COLOR_TRC_GAMMA22;
}
@@ -2637,9 +2637,9 @@ static void pass_colormanage(struct gl_video *p, struct pl_color_space src,
// it from the chosen transfer function. Also normalize the src peak, in
// case it was unknown
if (!dst.hdr.max_luma)
- dst.hdr.max_luma = mp_trc_nom_peak(dst.transfer) * MP_REF_WHITE;
+ dst.hdr.max_luma = pl_color_transfer_nominal_peak(dst.transfer) * MP_REF_WHITE;
if (!src.hdr.max_luma)
- src.hdr.max_luma = mp_trc_nom_peak(src.transfer) * MP_REF_WHITE;
+ src.hdr.max_luma = pl_color_transfer_nominal_peak(src.transfer) * MP_REF_WHITE;
// Whitelist supported modes
switch (p->opts.tone_map.curve) {
@@ -2671,7 +2671,7 @@ static void pass_colormanage(struct gl_video *p, struct pl_color_space src,
}
struct gl_tone_map_opts tone_map = p->opts.tone_map;
- bool detect_peak = tone_map.compute_peak >= 0 && mp_trc_is_hdr(src.transfer)
+ bool detect_peak = tone_map.compute_peak >= 0 && pl_color_space_is_hdr(&src)
&& src.hdr.max_luma > dst.hdr.max_luma;
if (detect_peak && !p->hdr_peak_ssbo) {
diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c
index 2201e12d46..62fe11caae 100644
--- a/video/out/gpu/video_shaders.c
+++ b/video/out/gpu/video_shaders.c
@@ -17,6 +17,8 @@
#include <math.h>
+#include <libplacebo/colorspace.h>
+
#include "video_shaders.h"
#include "video.h"
@@ -337,7 +339,7 @@ static const float SLOG_A = 0.432699,
//
// These functions always output to a normalized scale of [0,1], for
// convenience of the video.c code that calls it. To get the values in an
-// absolute scale, multiply the result by `mp_trc_nom_peak(trc)`
+// absolute scale, multiply the result by `pl_color_transfer_nominal_peak(trc)`
void pass_linearize(struct gl_shader_cache *sc, enum pl_color_transfer trc)
{
if (trc == PL_COLOR_TRC_LINEAR)
@@ -430,7 +432,7 @@ void pass_linearize(struct gl_shader_cache *sc, enum pl_color_transfer trc)
}
// Rescale to prevent clipping on non-float textures
- GLSLF("color.rgb *= vec3(1.0/%f);\n", mp_trc_nom_peak(trc));
+ GLSLF("color.rgb *= vec3(1.0/%f);\n", pl_color_transfer_nominal_peak(trc));
}
// Delinearize (compress), given a TRC as output. This corresponds to the
@@ -445,7 +447,7 @@ void pass_delinearize(struct gl_shader_cache *sc, enum pl_color_transfer trc)
GLSLF("// delinearize\n");
GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);)
- GLSLF("color.rgb *= vec3(%f);\n", mp_trc_nom_peak(trc));
+ GLSLF("color.rgb *= vec3(%f);\n", pl_color_transfer_nominal_peak(trc));
switch (trc) {
case PL_COLOR_TRC_SRGB:
@@ -842,11 +844,10 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear,
// Some operations need access to the video's luma coefficients, so make
// them available
- float rgb2xyz[3][3];
- mp_get_rgb2xyz_matrix(mp_get_csp_primaries(src.primaries), rgb2xyz);
- gl_sc_uniform_vec3(sc, "src_luma", rgb2xyz[1]);
- mp_get_rgb2xyz_matrix(mp_get_csp_primaries(dst.primaries), rgb2xyz);
- gl_sc_uniform_vec3(sc, "dst_luma", rgb2xyz[1]);
+ pl_matrix3x3 rgb2xyz = pl_get_rgb2xyz_matrix(pl_raw_primaries_get(src.primaries));
+ gl_sc_uniform_vec3(sc, "src_luma", rgb2xyz.m[1]);
+ rgb2xyz = pl_get_rgb2xyz_matrix(pl_raw_primaries_get(dst.primaries));
+ gl_sc_uniform_vec3(sc, "dst_luma", rgb2x