diff options
Diffstat (limited to 'src/include/libplacebo/colorspace.h')
-rw-r--r-- | src/include/libplacebo/colorspace.h | 719 |
1 files changed, 719 insertions, 0 deletions
diff --git a/src/include/libplacebo/colorspace.h b/src/include/libplacebo/colorspace.h new file mode 100644 index 0000000..6663019 --- /dev/null +++ b/src/include/libplacebo/colorspace.h @@ -0,0 +1,719 @@ +/* + * This file is part of libplacebo. + * + * libplacebo is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * libplacebo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef LIBPLACEBO_COLORSPACE_H_ +#define LIBPLACEBO_COLORSPACE_H_ + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include <libplacebo/common.h> + +PL_API_BEGIN + +// The underlying color representation (e.g. RGB, XYZ or YCbCr) +enum pl_color_system { + PL_COLOR_SYSTEM_UNKNOWN = 0, + // YCbCr-like color systems: + PL_COLOR_SYSTEM_BT_601, // ITU-R Rec. BT.601 (SD) + PL_COLOR_SYSTEM_BT_709, // ITU-R Rec. BT.709 (HD) + PL_COLOR_SYSTEM_SMPTE_240M, // SMPTE-240M + PL_COLOR_SYSTEM_BT_2020_NC, // ITU-R Rec. BT.2020 (non-constant luminance) + PL_COLOR_SYSTEM_BT_2020_C, // ITU-R Rec. BT.2020 (constant luminance) + PL_COLOR_SYSTEM_BT_2100_PQ, // ITU-R Rec. BT.2100 ICtCp PQ variant + PL_COLOR_SYSTEM_BT_2100_HLG, // ITU-R Rec. BT.2100 ICtCp HLG variant + PL_COLOR_SYSTEM_DOLBYVISION, // Dolby Vision (see pl_dovi_metadata) + PL_COLOR_SYSTEM_YCGCO, // YCgCo (derived from RGB) + // Other color systems: + PL_COLOR_SYSTEM_RGB, // Red, Green and Blue + PL_COLOR_SYSTEM_XYZ, // Digital Cinema Distribution Master (XYZ) + PL_COLOR_SYSTEM_COUNT +}; + +PL_API bool pl_color_system_is_ycbcr_like(enum pl_color_system sys); + +// Returns true for color systems that are linear transformations of the RGB +// equivalent, i.e. are simple matrix multiplications. For color systems with +// this property, `pl_color_repr_decode` is sufficient for conversion to RGB. +PL_API bool pl_color_system_is_linear(enum pl_color_system sys); + +// Guesses the best YCbCr-like colorspace based on a image given resolution. +// This only picks conservative values. (In particular, BT.2020 is never +// auto-guessed, even for 4K resolution content) +PL_API enum pl_color_system pl_color_system_guess_ycbcr(int width, int height); + +// Friendly names for the canonical channel names and order. +enum pl_channel { + PL_CHANNEL_NONE = -1, + PL_CHANNEL_A = 3, // alpha + // RGB system + PL_CHANNEL_R = 0, + PL_CHANNEL_G = 1, + PL_CHANNEL_B = 2, + // YCbCr-like systems + PL_CHANNEL_Y = 0, + PL_CHANNEL_CB = 1, + PL_CHANNEL_CR = 2, + // Aliases for Cb/Cr + PL_CHANNEL_U = 1, + PL_CHANNEL_V = 2 + // There are deliberately no names for the XYZ system to avoid + // confusion due to PL_CHANNEL_Y. +}; + +// The numerical range of the representation (where applicable). +enum pl_color_levels { + PL_COLOR_LEVELS_UNKNOWN = 0, + PL_COLOR_LEVELS_LIMITED, // Limited/TV range, e.g. 16-235 + PL_COLOR_LEVELS_FULL, // Full/PC range, e.g. 0-255 + PL_COLOR_LEVELS_COUNT, + + // Compatibility aliases + PL_COLOR_LEVELS_TV = PL_COLOR_LEVELS_LIMITED, + PL_COLOR_LEVELS_PC = PL_COLOR_LEVELS_FULL, +}; + +// The alpha representation mode. +enum pl_alpha_mode { + PL_ALPHA_UNKNOWN = 0, // or no alpha channel present + PL_ALPHA_INDEPENDENT, // alpha channel is separate from the video + PL_ALPHA_PREMULTIPLIED, // alpha channel is multiplied into the colors + PL_ALPHA_MODE_COUNT, +}; + +// The underlying bit-wise representation of a color sample. For example, +// a 10-bit TV-range YCbCr value uploaded to a 16 bit texture would have +// sample_depth=16 color_depth=10 bit_shift=0. +// +// For another example, a 12-bit XYZ full range sample shifted to 16-bits with +// the lower 4 bits all set to 0 would have sample_depth=16 color_depth=12 +// bit_shift=4. (libavcodec likes outputting this type of `xyz12`) +// +// To explain the meaning of `sample_depth` further; the consideration factor +// here is the fact that GPU sampling will normalized the sampled color to the +// range 0.0 - 1.0 in a manner dependent on the number of bits in the texture +// format. So if you upload a 10-bit YCbCr value unpadded as 16-bit color +// samples, all of the sampled values will be extremely close to 0.0. In such a +// case, `pl_color_repr_normalize` would return a high scaling factor, which +// would pull the color up to their 16-bit range. +struct pl_bit_encoding { + int sample_depth; // the number of bits the color is stored/sampled as + int color_depth; // the effective number of bits of the color information + int bit_shift; // a representational bit shift applied to the color +}; + +// Returns whether two bit encodings are exactly identical. +PL_API bool pl_bit_encoding_equal(const struct pl_bit_encoding *b1, + const struct pl_bit_encoding *b2); + +// Parsed metadata from the Dolby Vision RPU +struct pl_dovi_metadata { + // Colorspace transformation metadata + float nonlinear_offset[3]; // input offset ("ycc_to_rgb_offset") + pl_matrix3x3 nonlinear; // before PQ, also called "ycc_to_rgb" + pl_matrix3x3 linear; // after PQ, also called "rgb_to_lms" + + // Reshape data, grouped by component + struct pl_reshape_data { + uint8_t num_pivots; + float pivots[9]; // normalized to [0.0, 1.0] based on BL bit depth + uint8_t method[8]; // 0 = polynomial, 1 = MMR + // Note: these must be normalized (divide by coefficient_log2_denom) + float poly_coeffs[8][3]; // x^0, x^1, x^2, unused must be 0 + uint8_t mmr_order[8]; // 1, 2 or 3 + float mmr_constant[8]; + float mmr_coeffs[8][3 /* order */][7]; + } comp[3]; +}; + +// Struct describing the underlying color system and representation. This +// information is needed to convert an encoded color to a normalized RGB triple +// in the range 0-1. +struct pl_color_repr { + enum pl_color_system sys; + enum pl_color_levels levels; + enum pl_alpha_mode alpha; + struct pl_bit_encoding bits; // or {0} if unknown + + // Metadata for PL_COLOR_SYSTEM_DOLBYVISION. Note that, for the sake of + // efficiency, this is treated purely as an opaque reference - functions + // like pl_color_repr_equal will merely do a pointer equality test. + // + // The only functions that actually dereference it in any way are + // pl_color_repr_decode, pl_shader_decode_color and pl_render_image(_mix). + const struct pl_dovi_metadata *dovi; +}; + +// Some common color representations. It's worth pointing out that all of these +// presets leave `alpha` and `bits` as unknown - that is, only the system and +// levels are predefined +PL_API extern const struct pl_color_repr pl_color_repr_unknown; +PL_API extern const struct pl_color_repr pl_color_repr_rgb; +PL_API extern const struct pl_color_repr pl_color_repr_sdtv; +PL_API extern const struct pl_color_repr pl_color_repr_hdtv; // also Blu-ray +PL_API extern const struct pl_color_repr pl_color_repr_uhdtv; // SDR, NCL system +PL_API extern const struct pl_color_repr pl_color_repr_jpeg; + +// Returns whether two colorspace representations are exactly identical. +PL_API bool pl_color_repr_equal(const struct pl_color_repr *c1, + const struct pl_color_repr *c2); + +// Replaces unknown values in the first struct by those of the second struct. +PL_API void pl_color_repr_merge(struct pl_color_repr *orig, + const struct pl_color_repr *update); + +// This function normalizes the color representation such that +// color_depth=sample_depth and bit_shift=0; and returns the scaling factor +// that must be multiplied into the color value to accomplish this, assuming +// it has already been sampled by the GPU. If unknown, the color and sample +// depth will both be inferred as 8 bits for the purposes of this conversion. +PL_API float pl_color_repr_normalize(struct pl_color_repr *repr); + +// Guesses the best color levels based on the specified color levels and +// falling back to using the color system instead. YCbCr-like systems are +// assumed to be TV range, otherwise this defaults to PC range. +PL_API enum pl_color_levels pl_color_levels_guess(const struct pl_color_repr *repr); + +// The colorspace's primaries (gamut) +enum pl_color_primaries { + PL_COLOR_PRIM_UNKNOWN = 0, + // Standard gamut: + PL_COLOR_PRIM_BT_601_525, // ITU-R Rec. BT.601 (525-line = NTSC, SMPTE-C) + PL_COLOR_PRIM_BT_601_625, // ITU-R Rec. BT.601 (625-line = PAL, SECAM) + PL_COLOR_PRIM_BT_709, // ITU-R Rec. BT.709 (HD), also sRGB + PL_COLOR_PRIM_BT_470M, // ITU-R Rec. BT.470 M + PL_COLOR_PRIM_EBU_3213, // EBU Tech. 3213-E / JEDEC P22 phosphors + // Wide gamut: + PL_COLOR_PRIM_BT_2020, // ITU-R Rec. BT.2020 (UltraHD) + PL_COLOR_PRIM_APPLE, // Apple RGB + PL_COLOR_PRIM_ADOBE, // Adobe RGB (1998) + PL_COLOR_PRIM_PRO_PHOTO, // ProPhoto RGB (ROMM) + PL_COLOR_PRIM_CIE_1931, // CIE 1931 RGB primaries + PL_COLOR_PRIM_DCI_P3, // DCI-P3 (Digital Cinema) + PL_COLOR_PRIM_DISPLAY_P3, // DCI-P3 (Digital Cinema) with D65 white point + PL_COLOR_PRIM_V_GAMUT, // Panasonic V-Gamut (VARICAM) + PL_COLOR_PRIM_S_GAMUT, // Sony S-Gamut + PL_COLOR_PRIM_FILM_C, // Traditional film primaries with Illuminant C + PL_COLOR_PRIM_ACES_AP0, // ACES Primaries #0 (ultra wide) + PL_COLOR_PRIM_ACES_AP1, // ACES Primaries #1 + PL_COLOR_PRIM_COUNT +}; + +PL_API bool pl_color_primaries_is_wide_gamut(enum pl_color_primaries prim); + +// Guesses the best primaries based on a resolution. This always guesses +// conservatively, i.e. it will never return a wide gamut color space even if +// the resolution is 4K. +PL_API enum pl_color_primaries pl_color_primaries_guess(int width, int height); + +// The colorspace's transfer function (gamma / EOTF) +enum pl_color_transfer { + PL_COLOR_TRC_UNKNOWN = 0, + // Standard dynamic range: + PL_COLOR_TRC_BT_1886, // ITU-R Rec. BT.1886 (CRT emulation + OOTF) + PL_COLOR_TRC_SRGB, // IEC 61966-2-4 sRGB (CRT emulation) + PL_COLOR_TRC_LINEAR, // Linear light content + PL_COLOR_TRC_GAMMA18, // Pure power gamma 1.8 + PL_COLOR_TRC_GAMMA20, // Pure power gamma 2.0 + PL_COLOR_TRC_GAMMA22, // Pure power gamma 2.2 + PL_COLOR_TRC_GAMMA24, // Pure power gamma 2.4 + PL_COLOR_TRC_GAMMA26, // Pure power gamma 2.6 + PL_COLOR_TRC_GAMMA28, // Pure power gamma 2.8 + PL_COLOR_TRC_PRO_PHOTO, // ProPhoto RGB (ROMM) + PL_COLOR_TRC_ST428, // Digital Cinema Distribution Master (XYZ) + // High dynamic range: + PL_COLOR_TRC_PQ, // ITU-R BT.2100 PQ (perceptual quantizer), aka SMPTE ST2048 + PL_COLOR_TRC_HLG, // ITU-R BT.2100 HLG (hybrid log-gamma), aka ARIB STD-B67 + PL_COLOR_TRC_V_LOG, // Panasonic V-Log (VARICAM) + PL_COLOR_TRC_S_LOG1, // Sony S-Log1 + PL_COLOR_TRC_S_LOG2, // Sony S-Log2 + PL_COLOR_TRC_COUNT +}; + +// Returns the nominal peak of a given transfer function, relative to the +// reference white. This refers to the highest encodable signal level. +// Always equal to 1.0 for SDR curves. +// +// Note: For HLG in particular, which is scene-referred, this returns the +// highest nominal peak in scene-referred space (3.77), which may be different +// from the actual peak in display space after application of the HLG OOTF. +PL_API float pl_color_transfer_nominal_peak(enum pl_color_transfer trc); + +static inline bool pl_color_transfer_is_hdr(enum pl_color_transfer trc) +{ + return pl_color_transfer_nominal_peak(trc) > 1.0; +} + +// This defines the display-space standard reference white level (in cd/m^2) +// that is assumed for SDR content, for use when mapping between HDR and SDR in +// display space. See ITU-R Report BT.2408 for more information. +#define PL_COLOR_SDR_WHITE 203.0f + +// This defines the assumed contrast level of an unknown SDR display. This +// will be used to determine the black point in the absence of any tagged +// minimum luminance, relative to the tagged maximum luminance (or +// PL_COLOR_SDR_WHITE in the absence of all tagging) +#define PL_COLOR_SDR_CONTRAST 1000.0f + +// This defines the default black point assumed for "infinite contrast" HDR +// displays. This is not exactly 0.0 because a value of 0.0 is interpreted +// as "unknown / missing metadata" inside struct pl_hdr_metadata, and also +// to avoid numerical issues in a variety of tone mapping functions. +// Essentially, a black level below this number is functionally meaningless +// inside libplacebo, and will be clamped to this value regardless. +// +// The value used here (1e-6) is about one 13-bit PQ step above absolute zero, +// which is a small fraction of the human JND at this brightness level, and also +// about 3 bits above the floating point machine epsilon. +#define PL_COLOR_HDR_BLACK 1e-6f + +// This defines the assumed peak brightness of a HLG display with no HDR10 +// metadata. This is set to the brightness of a "nominal" HLG reference display. +#define PL_COLOR_HLG_PEAK 1000.0f + +// Represents a single CIE xy coordinate (e.g. CIE Yxy with Y = 1.0) +struct pl_cie_xy { + float x, y; +}; + +// Creates a pl_cie_xyz from raw XYZ values +static inline struct pl_cie_xy pl_cie_from_XYZ(float X, float Y, float Z) +{ + float k = 1.0f / (X + Y + Z); + struct pl_cie_xy xy = { k * X, k * Y }; + return xy; +} + +// Recovers (X / Y) from a CIE xy value. +static inline float pl_cie_X(struct pl_cie_xy xy) +{ + return xy.x / xy.y; +} + +// Recovers (Z / Y) from a CIE xy value. +static inline float pl_cie_Z(struct pl_cie_xy xy) +{ + return (1 - xy.x - xy.y) / xy.y; +} + +static inline bool pl_cie_xy_equal(const struct pl_cie_xy *a, + const struct pl_cie_xy *b) +{ + return a->x == b->x && a->y == b->y; +} + +// Computes the CIE xy chromaticity coordinates of a CIE D-series illuminant +// with the given correlated color temperature. +// +// `temperature` must be between 2500 K and 25000 K, inclusive. +PL_API struct pl_cie_xy pl_white_from_temp(float temperature); + +// Represents the raw physical primaries corresponding to a color space. +struct pl_raw_primaries { + struct pl_cie_xy red, green, blue, white; +}; + +// Returns whether two raw primaries are exactly identical. +PL_API bool pl_raw_primaries_equal(const struct pl_raw_primaries *a, + const struct pl_raw_primaries *b); + +// Returns whether two raw primaries are approximately equal +PL_API bool pl_raw_primaries_similar(const struct pl_raw_primaries *a, + const struct pl_raw_primaries *b); + +// Replaces unknown values in the first struct by those of the second struct. +PL_API void pl_raw_primaries_merge(struct pl_raw_primaries *orig, + const struct pl_raw_primaries *update); + +// Returns the raw primaries for a given color space. +PL_API const struct pl_raw_primaries *pl_raw_primaries_get(enum pl_color_primaries prim); + +enum pl_hdr_scaling { + PL_HDR_NORM = 0, // 0.0 is absolute black, 1.0 is PL_COLOR_SDR_WHITE + PL_HDR_SQRT, // sqrt() of PL_HDR_NORM values + PL_HDR_NITS, // absolute brightness in raw cd/m² + PL_HDR_PQ, // absolute brightness in PQ (0.0 to 1.0) + PL_HDR_SCALING_COUNT, +}; + +// Generic helper for performing HDR scale conversions. +PL_API float pl_hdr_rescale(enum pl_hdr_scaling from, enum pl_hdr_scaling to, float x); + +enum pl_hdr_metadata_type { + PL_HDR_METADATA_ANY = 0, + PL_HDR_METADATA_NONE, + PL_HDR_METADATA_HDR10, // HDR10 static mastering display metadata + PL_HDR_METADATA_HDR10PLUS, // HDR10+ dynamic metadata + PL_HDR_METADATA_CIE_Y, // CIE Y derived dynamic luminance metadata + PL_HDR_METADATA_TYPE_COUNT, +}; + +// Bezier curve for HDR metadata +struct pl_hdr_bezier { + float target_luma; // target luminance (cd/m²) for this OOTF + float knee_x, knee_y; // cross-over knee point (0-1) + float anchors[15]; // intermediate bezier curve control points (0-1) + uint8_t num_anchors; +}; + +// Represents raw HDR metadata as defined by SMPTE 2086 / CTA 861.3, which is +// often attached to HDR sources and can be forwarded to HDR-capable displays, +// or used to guide the libplacebo built-in tone mapping. Values left as 0 +// are treated as unknown by libplacebo. +// +// Note: This means that a value of `min_luma == 0.0` gets treated as "minimum +// luminance not known", which in practice may end up inferring a default +// contrast of 1000:1 for SDR transfer functions. To avoid this, the user should +// set these fields to a low positive value, e.g. PL_COLOR_HDR_BLACK, to signal +// a "zero" black point (i.e. infinite contrast display). +struct pl_hdr_metadata { + // --- PL_HDR_METADATA_HDR10 + // Mastering display metadata. + struct pl_raw_primaries prim; // mastering display primaries + float min_luma, max_luma; // min/max luminance (in cd/m²) + + // Content light level. (Note: this is ignored by libplacebo itself) + float max_cll; // max content light level (in cd/m²) + float max_fall; // max frame average light level (in cd/m²) + + // --- PL_HDR_METADATA_HDR10PLUS + float scene_max[3]; // maxSCL in cd/m² per component (RGB) + float scene_avg; // average of maxRGB in cd/m² + struct pl_hdr_bezier ootf; // reference OOTF (optional) + + // --- PL_HDR_METADATA_CIE_Y + float max_pq_y; // maximum PQ luminance (in PQ, 0-1) + float avg_pq_y; // averaged PQ luminance (in PQ, 0-1) +}; + +PL_API extern const struct pl_hdr_metadata pl_hdr_metadata_empty; // equal to {0} +PL_API extern const struct pl_hdr_metadata pl_hdr_metadata_hdr10; // generic HDR10 display + +// Returns whether two sets of HDR metadata are exactly identical. +PL_API bool pl_hdr_metadata_equal(const struct pl_hdr_metadata *a, + const struct pl_hdr_metadata *b); + +// Replaces unknown values in the first struct by those of the second struct. +PL_API void pl_hdr_metadata_merge(struct pl_hdr_metadata *orig, + const struct pl_hdr_metadata *update); + +// Returns `true` if `data` contains a complete set of a given metadata type. +// Note: for PL_HDR_METADATA_HDR10, only `min_luma` and `max_luma` are +// considered - CLL/FALL and primaries are irrelevant for HDR tone-mapping. +PL_API bool pl_hdr_metadata_contains(const struct pl_hdr_metadata *data, + enum pl_hdr_metadata_type type); + +// Rendering intent for colorspace transformations. These constants match the +// ICC specification (Table 23) +enum pl_rendering_intent { + PL_INTENT_AUTO = -1, // not a valid ICC intent, but used to auto-infer + PL_INTENT_PERCEPTUAL = 0, + PL_INTENT_RELATIVE_COLORIMETRIC = 1, + PL_INTENT_SATURATION = 2, + PL_INTENT_ABSOLUTE_COLORIMETRIC = 3 +}; + +// Struct describing a physical color space. This information is needed to +// turn a normalized RGB triple into its physical meaning, as well as to convert +// between color spaces. +struct pl_color_space { + enum pl_color_primaries primaries; + enum pl_color_transfer transfer; + + // HDR metadata for this color space, if present. (Optional) + struct pl_hdr_metadata hdr; +}; + +#define pl_color_space(...) (&(struct pl_color_space) { __VA_ARGS__ }) + +// Returns whether or not a color space is considered as effectively HDR. +// This is true when the effective signal peak is greater than the SDR +// reference white (1.0), taking into account `csp->hdr`. +PL_API bool pl_color_space_is_hdr(const struct pl_color_space *csp); + +// Returns whether or not a color space is "black scaled", in which case 0.0 is +// the true black point. This is true for SDR signals other than BT.1886, as +// well as for HLG. +PL_API bool pl_color_space_is_black_scaled(const struct pl_color_space *csp); + +struct pl_nominal_luma_params { + // The color space to infer luminance from + const struct pl_color_space *color; + + // Which type of metadata to draw values from + enum pl_hdr_metadata_type metadata; + + // This field controls the scaling of `out_*` + enum pl_hdr_scaling scaling; + + // Fields to write the detected nominal luminance to. (Optional) + // + // For SDR displays, this will default to a contrast level of 1000:1 unless + // indicated otherwise in the `min/max_luma` static HDR10 metadata fields. + float *out_min; + float *out_max; + + // Field to write the detected average luminance to, or 0.0 in the absence + // of dynamic metadata. (Optional) + float *out_avg; +}; + +#define pl_nominal_luma_params(...) \ + (&(struct pl_nominal_luma_params) { __VA_ARGS__ }) + +// Returns the effective luminance described by a pl_color_space. +PL_API void pl_color_space_nominal_luma_ex(const struct pl_nominal_luma_params *params); + +// Backwards compatibility wrapper for `pl_color_space_nominal_luma_ex` +PL_DEPRECATED PL_API void pl_color_space_nominal_luma(const struct pl_color_space *csp, + float *out_min, float *out_max); + +// Replaces unknown values in the first struct by those of the second struct. +PL_API void pl_color_space_merge(struct pl_color_space *orig, + const struct pl_color_space *update); + +// Returns whether two colorspaces are exactly identical. +PL_API bool pl_color_space_equal(const struct pl_color_space *c1, + const struct pl_color_space *c2); + +// Go through a color-space and explicitly default all unknown fields to +// reasonable values. After this function is called, none of the values will be +// PL_COLOR_*_UNKNOWN or 0.0, except for the dynamic HDR metadata fields. +PL_API void pl_color_space_infer(struct pl_color_space *space); + +// Like `pl_color_space_infer`, but takes default values from the reference +// color space (excluding certain special cases like HDR or wide gamut). +PL_API void pl_color_space_infer_ref(struct pl_color_space *space, + const struct pl_color_space *ref); + +// Infer both the source and destination gamut simultaneously, and also adjust +// values for optimal display. This is mostly the same as +// `pl_color_space_infer(src)` followed by `pl_color_space_infer_ref`, but also +// takes into account the SDR contrast levels and PQ black points. This is +// basically the logic used by `pl_shader_color_map` and `pl_renderer` to +// decide the output color space in a conservative way and compute the final +// end-to-end color transformation that needs to be done. +PL_API void pl_color_space_infer_map(struct pl_color_space *src, + struct pl_color_space *dst); + +// Some common color spaces. Note: These don't necessarily have all fields +// filled, in particular `hdr` is left unset. +PL_API extern const struct pl_color_space pl_color_space_unknown; +PL_API extern const struct pl_color_space pl_color_space_srgb; +PL_API extern const struct pl_color_space pl_color_space_bt709; +PL_API extern const struct pl_color_space pl_color_space_hdr10; +PL_API extern const struct pl_color_space pl_color_space_bt2020_hlg; +PL_API extern const struct pl_color_space pl_color_space_monitor; // typical display + +// This represents metadata about extra operations to perform during colorspace +// conversion, which correspond to artistic adjustments of the color. +struct pl_color_adjustment { + // Brightness boost. 0.0 = neutral, 1.0 = solid white, -1.0 = solid black + float brightness; + // Contrast boost. 1.0 = neutral, 0.0 = solid black + float contrast; + // Saturation gain. 1.0 = neutral, 0.0 = grayscale + float saturation; + // Hue shift, corresponding to a rotation around the [U, V] subvector, in + // radians. 0.0 = neutral + float hue; + // Gamma adjustment. 1.0 = neutral, 0.0 = solid black + float gamma; + // Color temperature shift. 0.0 = 6500 K, -1.0 = 3000 K, 1.0 = 10000 K + float temperature; +}; + +#define PL_COLOR_ADJUSTMENT_NEUTRAL \ + .contrast = 1.0, \ + .saturation = 1.0, \ + .gamma = 1.0, + +#define pl_color_adjustment(...) (&(struct pl_color_adjustment) { PL_COLOR_ADJUSTMENT_NEUTRAL __VA_ARGS__ }) +PL_API extern const struct pl_color_adjustment pl_color_adjustment_neutral; + +// Represents the chroma placement with respect to the luma samples. This is +// only relevant for YCbCr-like colorspaces with chroma subsampling. +enum pl_chroma_location { + PL_CHROMA_UNKNOWN = 0, + PL_CHROMA_LEFT, // MPEG2/4, H.264 + PL_CHROMA_CENTER, // MPEG1, JPEG + PL_CHROMA_TOP_LEFT, + PL_CHROMA_TOP_CENTER, + PL_CHROMA_BOTTOM_LEFT, + PL_CHROMA_BOTTOM_CENTER, + PL_CHROMA_COUNT, +}; + +// Fills *x and *y with the offset in luma pixels corresponding to a given +// chroma location. +// +// Note: PL_CHROMA_UNKNOWN defaults to PL_CHROMA_LEFT +PL_API void pl_chroma_location_offset(enum pl_chroma_location loc, float *x, float *y); + +// Returns an RGB->XYZ conversion matrix for a given set of primaries. +// Multiplying this into the RGB color transforms it to CIE XYZ, centered +// around the color space's white point. +PL_API pl_matrix3x3 pl_get_rgb2xyz_matrix(const struct pl_raw_primaries *prim); + +// Similar to pl_get_rgb2xyz_matrix, but gives the inverse transformation. +PL_API pl_matrix3x3 pl_get_xyz2rgb_matrix(const struct pl_raw_primaries *prim); + +// Returns a primary adaptation matrix, which converts from one set of +// primaries to another. This is an RGB->RGB transformation. For rendering +// intents other than PL_INTENT_ABSOLUTE_COLORIMETRIC, the white point is +// adapted using the Bradford matrix. +PL_API pl_matrix3x3 pl_get_color_mapping_matrix(const struct pl_raw_primaries *src, + const struct pl_raw_primaries *dst, + enum pl_rendering_intent intent); + +// Return a chromatic adaptation matrix, which converts from one white point to +// another, using the Bradford matrix. This is an RGB->RGB transformation. +PL_API pl_matrix3x3 pl_get_adaptation_matrix(struct pl_cie_xy src, struct pl_cie_xy dst); + +// Returns true if 'b' is entirely contained in 'a'. Useful for figuring out if +// colorimetric clipping will occur or not. +PL_API bool pl_primaries_superset(const struct pl_raw_primaries *a, + const struct pl_raw_primaries *b); + +// Returns true if `prim` forms a nominally valid set of primaries. This does +// not check whether or not these primaries are actually physically realisable, +// merely that they satisfy the requirements for colorspace math (to avoid NaN). +PL_API bool pl_primaries_valid(const struct pl_raw_primaries *prim); + +// Returns true if two primaries are 'compatible', which is the case if +// they preserve the relationship between primaries (red=red, green=green, +// blue=blue). In other words, this is false for synthetic primaries that have +// channels misordered from the convention (e.g. for some test ICC profiles). +PL_API bool pl_primaries_compatible(const struct pl_raw_primaries *a, + const struct pl_raw_primaries *b); + +// Clip points in the first gamut (src) to be fully contained inside the second +// gamut (dst). Only works on compatible primaries (pl_primaries_compatible). +PL_API struct pl_raw_primaries +pl_primaries_clip(const struct pl_raw_primaries *src, + const struct pl_raw_primaries *dst); + +// Primary-dependent RGB->LMS matrix for the IPTPQc4 color system. This is +// derived from the HPE XYZ->LMS matrix with 4% crosstalk added. +PL_API pl_matrix3x3 pl_ipt_rgb2lms(const struct pl_raw_primaries *prim); +PL_API pl_matrix3x3 pl_ipt_lms2rgb(const struct pl_raw_primaries *prim); + +// Primary-independent L'M'S' -> IPT matrix for the IPTPQc4 color system, and +// its inverse. This is identical to the Ebner & Fairchild (1998) IPT matrix. +PL_API extern const pl_matrix3x3 pl_ipt_lms2ipt; +PL_API extern const pl_matrix3x3 pl_ipt_ipt2lms; + +// Cone types involved in human vision +enum pl_cone { + PL_CONE_L = 1 << 0, + PL_CONE_M = 1 << 1, + PL_CONE_S = 1 << 2, + + // Convenience aliases + PL_CONE_NONE = 0, + PL_CONE_LM = PL_CONE_L | PL_CONE_M, + PL_CONE_MS = PL_CONE_M | PL_CONE_S, + PL_CONE_LS = PL_CONE_L | PL_CONE_S, + PL_CONE_LMS = PL_CONE_L | PL_CONE_M | PL_CONE_S, +}; + +// Structure describing parameters for simulating color blindness +struct pl_cone_params { + enum pl_cone cones; // Which cones are *affected* by the vision model + float strength; // Coefficient for how strong the defect is + // (1.0 = Unaffected, 0.0 = Full blindness) +}; + +#define pl_cone_params(...) (&(struct pl_cone_params) { __VA_ARGS__ }) + +// Built-in color blindness models +PL_API extern const struct pl_cone_params pl_vision_normal; // No distortion (92%) +PL_API extern const struct pl_cone_params pl_vision_protanomaly; // Red deficiency (0.66%) +PL_API extern const struct pl_cone_params pl_vision_protanopia; // Red absence (0.59%) +PL_API extern const struct pl_cone_params pl_vision_deuteranomaly; // Green deficiency (2.7%) +PL_API extern const struct pl_cone_params pl_vision_deuteranopia; // Green absence (0.56%) +PL_API extern const struct pl_cone_params pl_vision_tritanomaly; // Blue deficiency (0.01%) +PL_API extern const struct pl_cone_params pl_vision_tritanopia; // Blue absence (0.016%) +PL_API extern const struct pl_cone_params pl_vision_monochromacy; // Blue cones only (<0.001%) +PL_API extern const struct pl_cone_params pl_vision_achromatopsia; // Rods only (<0.0001%) + +// Returns a cone adaptation matrix. Applying this to an RGB color in the given +// color space will apply the given cone adaptation coefficients for simulating +// a type of color blindness. +// +// For the color blindness models which don't entail complete loss of a cone, +// you can partially counteract the effect by using a similar model with the +// `strength` set to its inverse. For example, to partially counteract +// deuteranomaly, you could generate a cone matrix for PL_CONE_M with the +// strength 2.0 (or some other number above 1.0). +PL_API pl_matrix3x3 pl_get_cone_matrix(const struct pl_cone_params *params, + const struct pl_raw_primaries *prim); + +// Returns a color decoding matrix for a given combination of source color +// representation and adjustment parameters. This mutates `repr` to reflect the +// change. If `params` is NULL, it defaults to &pl_color_adjustment_neutral. +// +// This function always performs a conversion to RGB. To convert to other +// colorspaces (e.g. between YUV systems), obtain a second YUV->RGB matrix +// and invert it using `pl_transform3x3_invert`. +// +// Note: For BT.2020 constant-luminance, this outputs chroma information in the +// range [-0.5, 0.5]. Since the CL system conversion is non-linear, further +// processing must be done by the caller. The channel order is CrYCb. +// +// Note: For BT.2100 ICtCp, this outputs in the color space L'M'S'. Further +// non-linear processing must be done by the caller. +// +// Note: XYZ system is expected to be in DCDM X'Y'Z' encoding (ST 428-1), in +// practice this means normalizing by (48.0 / 52.37) factor and applying 2.6 gamma +PL_API pl_transform3x3 pl_color_repr_decode(struct pl_color_repr *repr, + const struct pl_color_adjustment *params); + +// Common struct to describe an ICC profile +struct pl_icc_profile { + // Points to the in-memory representation of the ICC profile. This is + // allowed to be NULL, in which case the `pl_icc_profile` represents "no + // profile”. + const void *data; + size_t len; + + // If a profile is set, this signature must uniquely identify it (including + // across restarts, for caching), ideally using a checksum of the profile + // contents. The user is free to choose the method of determining this + // signature, but note the existence of the + // `pl_icc_profile_compute_signature` helper. + uint64_t signature; +}; + +#define pl_icc_profile(...) &(struct pl_icc_profile) { __VA_ARGS__ } + +// This doesn't do a comparison of the actual contents, only of the signature. +PL_API bool pl_icc_profile_equal(const struct pl_icc_profile *p1, + const struct pl_icc_profile *p2); + +// Sets `signature` to a hash of `profile->data`, if non-NULL. Provided as a +// convenience function for the sake of users ingesting arbitrary ICC profiles +// from sources where they can't reliably detect profile changes. +// +// Note: This is based on a very fast hash, and will compute a signature for +// even large (10 MB) ICC profiles in, typically, a fraction of a millisecond. +PL_API void pl_icc_profile_compute_signature(struct pl_icc_profile *profile); + +PL_API_END + +#endif // LIBPLACEBO_COLORSPACE_H_ |