swscale/cms: add color management subsystem
The underlying color mapping logic was ported as straightforwardly as possible
from libplacebo, although the API and glue code has been very heavily
refactored / rewritten. In particular, the generalization of gamut mapping
methods is replaced by a single ICC intent selection, and constants have been
hard-coded.
To minimize the amount of overall operations, this gamut mapping LUT now embeds
a direct end-to-end transformation to the output color space; something that
libplacebo does in shaders, but which is prohibitively expensive in software.
In order to preserve compatibility with dynamic tone mapping without severely
regressing performance, we add the ability to generate a pair of "split" LUTS,
one for encoding the input and output to the perceptual color space, and a
third to embed the tone mapping operation. Additionally, this intermediate
space could be used for additional subjective effect (e.g. changing
saturation or brightness).
The big downside of the new approach is that generating a static color mapping
LUT is now fairly slow, as the chromaticity lobe peaks have to be recomputed
for every single RGB value, since correlated RGB colors are not necessarily
aligned in ICh space. Generating a split 3DLUT significantly alleviates this
problem because the expensive step is done as part of the IPT input LUT, which
can share the same hue peak calculation at least for all input intensities.
2024-11-29 15:05:26 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2024 Niklas Haas
|
|
|
|
*
|
|
|
|
* This file is part of FFmpeg.
|
|
|
|
*
|
|
|
|
* FFmpeg 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.
|
|
|
|
*
|
|
|
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef SWSCALE_CMS_H
|
|
|
|
#define SWSCALE_CMS_H
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
|
|
#include "libavutil/csp.h"
|
|
|
|
|
|
|
|
#include "csputils.h"
|
|
|
|
#include "swscale.h"
|
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
/* Minimum, maximum, and default knee point for perceptual tone mapping [0,1] */
|
|
|
|
#define PERCEPTUAL_KNEE_MIN 0.10f
|
|
|
|
#define PERCEPTUAL_KNEE_MAX 0.80f
|
|
|
|
#define PERCEPTUAL_KNEE_DEF 0.40f
|
|
|
|
|
|
|
|
/* Ratio between source average and target average. */
|
|
|
|
#define PERCEPTUAL_ADAPTATION 0.40f
|
|
|
|
|
|
|
|
/* (Relative) chromaticity protection zone for perceptual mapping [0,1] */
|
|
|
|
#define PERCEPTUAL_DEADZONE 0.30f
|
|
|
|
|
|
|
|
/* Contrast setting for perceptual tone mapping. [0,1.5] */
|
|
|
|
#define PERCEPTUAL_CONTRAST 0.50f
|
|
|
|
|
|
|
|
/* Tuning constants for overriding the contrast near extremes */
|
|
|
|
#define SLOPE_TUNING 1.50f /* [0,10] */
|
|
|
|
#define SLOPE_OFFSET 0.20f /* [0,1] */
|
|
|
|
|
|
|
|
/* Strength of the perceptual saturation mapping component [0,1] */
|
|
|
|
#define PERCEPTUAL_STRENGTH 0.80f
|
|
|
|
|
|
|
|
/* Knee point to use for perceptual soft clipping [0,1] */
|
|
|
|
#define SOFTCLIP_KNEE 0.70f
|
|
|
|
|
|
|
|
/* I vs C curve gamma to use for colorimetric clipping [0,10] */
|
|
|
|
#define COLORIMETRIC_GAMMA 1.80f
|
|
|
|
|
|
|
|
/* Struct describing a color mapping operation */
|
|
|
|
typedef struct SwsColorMap {
|
|
|
|
SwsColor src;
|
|
|
|
SwsColor dst;
|
|
|
|
SwsIntent intent;
|
|
|
|
} SwsColorMap;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if the given color map is a semantic no-op - that is,
|
|
|
|
* the overall RGB end to end transform would an identity mapping.
|
|
|
|
*/
|
2025-01-08 21:22:37 +01:00
|
|
|
bool ff_sws_color_map_noop(const SwsColorMap *map);
|
swscale/cms: add color management subsystem
The underlying color mapping logic was ported as straightforwardly as possible
from libplacebo, although the API and glue code has been very heavily
refactored / rewritten. In particular, the generalization of gamut mapping
methods is replaced by a single ICC intent selection, and constants have been
hard-coded.
To minimize the amount of overall operations, this gamut mapping LUT now embeds
a direct end-to-end transformation to the output color space; something that
libplacebo does in shaders, but which is prohibitively expensive in software.
In order to preserve compatibility with dynamic tone mapping without severely
regressing performance, we add the ability to generate a pair of "split" LUTS,
one for encoding the input and output to the perceptual color space, and a
third to embed the tone mapping operation. Additionally, this intermediate
space could be used for additional subjective effect (e.g. changing
saturation or brightness).
The big downside of the new approach is that generating a static color mapping
LUT is now fairly slow, as the chromaticity lobe peaks have to be recomputed
for every single RGB value, since correlated RGB colors are not necessarily
aligned in ICh space. Generating a split 3DLUT significantly alleviates this
problem because the expensive step is done as part of the IPT input LUT, which
can share the same hue peak calculation at least for all input intensities.
2024-11-29 15:05:26 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates a single end-to-end color mapping 3DLUT embedding a static tone
|
|
|
|
* mapping curve.
|
|
|
|
*
|
|
|
|
* Returns 0 on success, or a negative error code on failure.
|
|
|
|
*/
|
2025-01-08 21:22:37 +01:00
|
|
|
int ff_sws_color_map_generate_static(v3u16_t *lut, int size, const SwsColorMap *map);
|
swscale/cms: add color management subsystem
The underlying color mapping logic was ported as straightforwardly as possible
from libplacebo, although the API and glue code has been very heavily
refactored / rewritten. In particular, the generalization of gamut mapping
methods is replaced by a single ICC intent selection, and constants have been
hard-coded.
To minimize the amount of overall operations, this gamut mapping LUT now embeds
a direct end-to-end transformation to the output color space; something that
libplacebo does in shaders, but which is prohibitively expensive in software.
In order to preserve compatibility with dynamic tone mapping without severely
regressing performance, we add the ability to generate a pair of "split" LUTS,
one for encoding the input and output to the perceptual color space, and a
third to embed the tone mapping operation. Additionally, this intermediate
space could be used for additional subjective effect (e.g. changing
saturation or brightness).
The big downside of the new approach is that generating a static color mapping
LUT is now fairly slow, as the chromaticity lobe peaks have to be recomputed
for every single RGB value, since correlated RGB colors are not necessarily
aligned in ICh space. Generating a split 3DLUT significantly alleviates this
problem because the expensive step is done as part of the IPT input LUT, which
can share the same hue peak calculation at least for all input intensities.
2024-11-29 15:05:26 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates a split pair of 3DLUTS, going to IPT and back, allowing an
|
|
|
|
* arbitrary dynamic EETF to be nestled in between these two operations.
|
|
|
|
*
|
2025-01-08 21:22:37 +01:00
|
|
|
* See ff_sws_tone_map_generate().
|
swscale/cms: add color management subsystem
The underlying color mapping logic was ported as straightforwardly as possible
from libplacebo, although the API and glue code has been very heavily
refactored / rewritten. In particular, the generalization of gamut mapping
methods is replaced by a single ICC intent selection, and constants have been
hard-coded.
To minimize the amount of overall operations, this gamut mapping LUT now embeds
a direct end-to-end transformation to the output color space; something that
libplacebo does in shaders, but which is prohibitively expensive in software.
In order to preserve compatibility with dynamic tone mapping without severely
regressing performance, we add the ability to generate a pair of "split" LUTS,
one for encoding the input and output to the perceptual color space, and a
third to embed the tone mapping operation. Additionally, this intermediate
space could be used for additional subjective effect (e.g. changing
saturation or brightness).
The big downside of the new approach is that generating a static color mapping
LUT is now fairly slow, as the chromaticity lobe peaks have to be recomputed
for every single RGB value, since correlated RGB colors are not necessarily
aligned in ICh space. Generating a split 3DLUT significantly alleviates this
problem because the expensive step is done as part of the IPT input LUT, which
can share the same hue peak calculation at least for all input intensities.
2024-11-29 15:05:26 +01:00
|
|
|
*
|
|
|
|
* Returns 0 on success, or a negative error code on failure.
|
|
|
|
*/
|
2025-01-08 21:22:37 +01:00
|
|
|
int ff_sws_color_map_generate_dynamic(v3u16_t *input, v3u16_t *output,
|
|
|
|
int size_input, int size_I, int size_PT,
|
|
|
|
const SwsColorMap *map);
|
swscale/cms: add color management subsystem
The underlying color mapping logic was ported as straightforwardly as possible
from libplacebo, although the API and glue code has been very heavily
refactored / rewritten. In particular, the generalization of gamut mapping
methods is replaced by a single ICC intent selection, and constants have been
hard-coded.
To minimize the amount of overall operations, this gamut mapping LUT now embeds
a direct end-to-end transformation to the output color space; something that
libplacebo does in shaders, but which is prohibitively expensive in software.
In order to preserve compatibility with dynamic tone mapping without severely
regressing performance, we add the ability to generate a pair of "split" LUTS,
one for encoding the input and output to the perceptual color space, and a
third to embed the tone mapping operation. Additionally, this intermediate
space could be used for additional subjective effect (e.g. changing
saturation or brightness).
The big downside of the new approach is that generating a static color mapping
LUT is now fairly slow, as the chromaticity lobe peaks have to be recomputed
for every single RGB value, since correlated RGB colors are not necessarily
aligned in ICh space. Generating a split 3DLUT significantly alleviates this
problem because the expensive step is done as part of the IPT input LUT, which
can share the same hue peak calculation at least for all input intensities.
2024-11-29 15:05:26 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a 1D LUT of size `size` adapting intensity (I) levels from the
|
|
|
|
* source to the destination color space. The LUT is normalized to the
|
|
|
|
* relevant intensity range directly. The second channel of each entry returns
|
|
|
|
* the corresponding 15-bit scaling factor for the P/T channels. The scaling
|
|
|
|
* factor k may be applied as `(1 << 15) - k + (PT * k >> 15)`.
|
|
|
|
*
|
|
|
|
* This is designed to be used with sws_gamut_map_generate_dynamic().
|
|
|
|
*
|
|
|
|
* Returns 0 on success, or a negative error code on failure.
|
|
|
|
*/
|
2025-01-08 21:22:37 +01:00
|
|
|
void ff_sws_tone_map_generate(v2u16_t *lut, int size, const SwsColorMap *map);
|
swscale/cms: add color management subsystem
The underlying color mapping logic was ported as straightforwardly as possible
from libplacebo, although the API and glue code has been very heavily
refactored / rewritten. In particular, the generalization of gamut mapping
methods is replaced by a single ICC intent selection, and constants have been
hard-coded.
To minimize the amount of overall operations, this gamut mapping LUT now embeds
a direct end-to-end transformation to the output color space; something that
libplacebo does in shaders, but which is prohibitively expensive in software.
In order to preserve compatibility with dynamic tone mapping without severely
regressing performance, we add the ability to generate a pair of "split" LUTS,
one for encoding the input and output to the perceptual color space, and a
third to embed the tone mapping operation. Additionally, this intermediate
space could be used for additional subjective effect (e.g. changing
saturation or brightness).
The big downside of the new approach is that generating a static color mapping
LUT is now fairly slow, as the chromaticity lobe peaks have to be recomputed
for every single RGB value, since correlated RGB colors are not necessarily
aligned in ICh space. Generating a split 3DLUT significantly alleviates this
problem because the expensive step is done as part of the IPT input LUT, which
can share the same hue peak calculation at least for all input intensities.
2024-11-29 15:05:26 +01:00
|
|
|
|
|
|
|
#endif // SWSCALE_GAMUT_MAPPING_H
|