37 if (
map->src.prim !=
map->dst.prim ||
map->src.trc !=
map->dst.trc)
44 switch (
map->intent) {
62 return ((I - 6.0f) * I + 9.0f) * I;
121 const float Imax =
pq_oetf(Lw);
155 .I = 0.4000f * Lp + 0.4000f * Mp + 0.2000f * Sp,
156 .P = 4.4550f * Lp - 4.8510f * Mp + 0.3960f * Sp,
157 .T = 0.8056f * Lp + 0.3572f * Mp - 1.1628f * Sp,
163 const float Lp =
c.I + 0.0975689f *
c.P + 0.205226f *
c.T;
164 const float Mp =
c.I - 0.1138760f *
c.P + 0.133217f *
c.T;
165 const float Sp =
c.I + 0.0326151f *
c.P - 0.676887f *
c.T;
184 const float min_rgb = gamut.
Lb - 1e-4f;
185 const float max_rgb = gamut.
Lw + 1e-2f;
186 const float Lp =
c.I + 0.0975689f *
c.P + 0.205226f *
c.T;
187 const float Mp =
c.I - 0.1138760f *
c.P + 0.133217f *
c.T;
188 const float Sp =
c.I + 0.0326151f *
c.P - 0.676887f *
c.T;
189 if (Lp < gamut.Imin || Lp > gamut.
Imax ||
190 Mp < gamut.Imin || Mp > gamut.
Imax ||
191 Sp < gamut.Imin || Sp > gamut.
Imax)
210 return rgb.R >= min_rgb &&
rgb.R <= max_rgb &&
211 rgb.G >= min_rgb &&
rgb.G <= max_rgb &&
212 rgb.B >= min_rgb &&
rgb.B <= max_rgb;
223 return (
ICh) { .I = gamut.
Imin, .C = 0, .h =
h };
224 else if (I >= gamut.
Imax)
225 return (
ICh) { .I = gamut.
Imax, .C = 0, .h =
h };
228 ICh res = { .I = I, .C = (Cmin + Cmax) / 2, .
h =
h };
235 res.
C = (Cmin + Cmax) / 2;
236 }
while (Cmax - Cmin > maxDI);
245 static const float invphi = 0.6180339887498948f;
246 static const float invphi2 = 0.38196601125010515f;
248 ICh lo = { .I = gamut.
Imin, .h = hue };
249 ICh hi = { .I = gamut.
Imax, .h = hue };
250 float de = hi.
I - lo.
I;
251 ICh a = { .I = lo.
I + invphi2 * de };
252 ICh b = { .I = lo.
I + invphi * de };
261 a.I = lo.
I + invphi2 * de;
266 b.I = lo.
I + invphi * de;
271 return a.C >
b.C ?
a :
b;
281 peak = source / target;
283 if (x <= j || peak <= 1.0)
287 a = -j*j * (peak - 1.0f) / (j*j - 2.0f * j + peak);
288 b = (j*j - 2.0f * j * peak + peak) /
fmaxf(1e-6f, peak - 1.0f);
291 return scale * (x +
a) / (x +
b) * target;
314 const float Imin = gamut.
Imin;
315 const float Irel =
fmaxf((ich.
I - Imin) / (gamut.
peak.
I - Imin), 0.0f);
322 float lo = 0.0f, hi = 1.0f, x = 0.5f;
326 if (ipt.
I <= gamut.
Imin)
327 return (
IPT) { .I = gamut.
Imin };
343 x = (lo + hi) / 2.0f;
344 }
while (hi - lo > maxDI);
382 float dst_max,
float dst_min,
383 float *out_src_knee,
float *out_dst_knee)
388 const float src_knee_min =
fmixf(src_min, src_max, min_knee);
389 const float src_knee_max =
fmixf(src_min, src_max, max_knee);
390 const float dst_knee_min =
fmixf(dst_min, dst_max, min_knee);
391 const float dst_knee_max =
fmixf(dst_min, dst_max, max_knee);
392 float src_knee, target, adapted, tuning, adaptation, dst_knee;
395 src_knee = src_avg ? src_avg :
fmixf(src_min, src_max, def_knee);
396 src_knee =
av_clipf(src_knee, src_knee_min, src_knee_max);
399 target = (src_knee - src_min) / (src_max - src_min);
400 adapted =
fmixf(dst_min, dst_max, target);
413 dst_knee =
fmixf(src_knee, adapted, adaptation);
414 dst_knee =
av_clipf(dst_knee, dst_knee_min, dst_knee_max);
416 *out_src_knee = src_knee;
417 *out_dst_knee = dst_knee;
422 const float dst_min =
ctx->dst.Imin;
423 const float dst_max =
ctx->dst.Imax;
424 const float src_min =
ctx->src.Imin;
425 const float src_max = dynamic ?
ctx->src.Imax_frame :
ctx->src.Imax;
426 const float src_avg = dynamic ?
ctx->src.Iavg_frame : 0.0f;
427 float slope, ratio, in_min, in_max, out_min, out_max, t;
429 switch (
ctx->map.intent) {
432 &
ctx->src_knee, &
ctx->dst_knee);
435 slope = (
ctx->dst_knee - dst_min) / (
ctx->src_knee - src_min);
443 ratio = src_max / dst_max - 1.0f;
448 in_min = src_min -
ctx->src_knee;
449 in_max = src_max -
ctx->src_knee;
450 out_min = dst_min -
ctx->dst_knee;
451 out_max = dst_max -
ctx->dst_knee;
459 ctx->Pa = (out_min - slope * in_min) / (in_min * in_min);
469 t = 2 * in_max * in_max;
470 ctx->Qa = (slope * in_max - out_max) / (in_max * t);
471 ctx->Qb = -3 * (slope * in_max - out_max) / t;
476 ctx->I_scale = (dst_max - dst_min) / (src_max - src_min);
477 ctx->I_offset = dst_min - src_min *
ctx->I_scale;
481 ctx->I_scale = src_max / (src_max - src_min) /
482 (dst_max / (dst_max - dst_min));
483 ctx->I_offset = dst_min - src_min *
ctx->I_scale;
488 ctx->I_offset = 0.0f;
495 float I = ipt.
I, desat;
498 const float Pa =
ctx->Pa, Pb =
ctx->Pb;
499 const float Qa =
ctx->Qa, Qb =
ctx->Qb, Qc =
ctx->Qc;
501 I = I > 0 ? ((Qa * I + Qb) * I + Qc) * I : (Pa * I + Pb) * I;
504 I =
ctx->I_scale * I +
ctx->I_offset;
528 const float maxC =
fmaxf(
ctx->tmp.peak.C,
ctx->dst.peak.C);
579 switch (
ctx->map.intent) {
598 const int slice_stride =
ctx.size_input *
ctx.size_input;
602 const int output_slice_h = (
ctx.size_output_PT + nb_jobs - 1) / nb_jobs;
603 const int output_start = jobnr * output_slice_h;
604 const int output_stride =
ctx.size_output_PT *
ctx.size_output_I;
605 const int output_end =
FFMIN((jobnr + 1) * output_slice_h,
ctx.size_output_PT);
608 const float I_scale = 1.0f / (
ctx.src.Imax -
ctx.src.Imin);
609 const float I_offset = -
ctx.src.Imin * I_scale;
611 const float input_scale = 1.0f / (
ctx.size_input - 1);
612 const float output_scale_PT = 1.0f / (
ctx.size_output_PT - 1);
613 const float output_scale_I = (
ctx.tmp.Imax -
ctx.tmp.Imin) /
614 (
ctx.size_output_I - 1);
617 const float B = input_scale * Bx;
618 for (
int Gx = 0; Gx <
ctx.size_input; Gx++) {
619 const float G = input_scale * Gx;
620 for (
int Rx = 0; Rx <
ctx.size_input; Rx++) {
621 double c[3] = { input_scale * Rx,
G,
B };
640 ipt =
ctx.adapt_colors(&
ctx, ipt);
661 for (
int Tx = output_start; Tx < output_end; Tx++) {
662 const float T = output_scale_PT * Tx - 0.5f;
663 for (
int Px = 0; Px <
ctx.size_output_PT; Px++) {
664 const float P = output_scale_PT * Px - 0.5f;
667 for (
int Ix = 0; Ix <
ctx.size_output_I; Ix++) {
668 const float I = output_scale_I * Ix +
ctx.tmp.Imin;
691 int size_input,
int size_I,
int size_PT,
701 .size_input = size_input,
702 .size_output_I = size_I,
703 .size_output_PT = size_PT,
708 switch (
ctx.map.intent) {
713 default:
return AVERROR(EINVAL);
725 ctx.tmp.Imin =
ctx.dst.Imin;
726 ctx.tmp.Imax =
ctx.dst.Imax;
742 ctx.slice_size = (
ctx.size_input + ret - 1) / ret;
743 num_slices = (
ctx.size_input +
ctx.slice_size - 1) /
ctx.slice_size;
757 const float src_scale = (
ctx.src.Imax -
ctx.src.Imin) / (
size - 1);
758 const float src_offset =
ctx.src.Imin;
759 const float dst_scale = 1.0f / (
ctx.dst.Imax -
ctx.dst.Imin);
760 const float dst_offset = -
ctx.dst.Imin * dst_scale;
764 for (
int i = 0;
i <
size;
i++) {
765 const float I = src_scale *
i + src_offset;
static AVFormatContext * ctx
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert0(cond)
assert() equivalent, that is always enabled.
#define i(width, name, range_min, range_max)
static av_always_inline void update_hue_peaks(CmsCtx *ctx, float P, float T)
static av_always_inline av_const uint16_t round_pt16(float x)
static ICh mix_exp(ICh c, float x, float gamma, float base)
Something like fmixf(base, c, x) but follows an exponential curve, note that this can be used to exte...
static Gamut gamut_from_colorspace(const SwsColor *fmt)
static av_always_inline av_const uint16_t round_unorm16(float x)
static void st2094_pick_knee(float src_max, float src_min, float src_avg, float dst_max, float dst_min, float *out_src_knee, float *out_dst_knee)
Helper function to pick a knee point based on the * HDR10+ brightness metadata and scene brightness a...
int ff_sws_color_map_generate_static(v3u16_t *lut, int size, const SwsColorMap *map)
Generates a single end-to-end color mapping 3DLUT embedding a static tone mapping curve.
static const float maxDelta
static IPT perceptual(const CmsCtx *ctx, IPT ipt)
static av_always_inline ICh ipt2ich(IPT c)
static IPT relative(const CmsCtx *ctx, IPT ipt)
static ICh desat_bounded(float I, float h, float Cmin, float Cmax, Gamut gamut)
static av_always_inline IPT rgb2ipt(RGB c, const SwsMatrix3x3 rgb2lms)
static ICh saturate(float hue, Gamut gamut)
static float softclip(float value, float source, float target)
static float hull(float I)
void ff_sws_tone_map_generate(v2u16_t *lut, int size, const SwsColorMap *map)
Generate a 1D LUT of size size adapting intensity (I) levels from the source to the destination color...
bool ff_sws_color_map_noop(const SwsColorMap *map)
Returns true if the given color map is a semantic no-op - that is, the overall RGB end to end transfo...
static av_always_inline IPT tone_map_apply(const CmsCtx *ctx, IPT ipt)
static av_always_inline IPT ich2ipt(ICh c)
static bool ingamut(IPT c, Gamut gamut)
static IPT clip_gamma(IPT ipt, float gamma, Gamut gamut)
static av_always_inline RGB ipt2rgb(IPT c, const SwsMatrix3x3 lms2rgb)
static float scale_gamma(float gamma, ICh ich, Gamut gamut)
Drop gamma for colors approaching black and achromatic to avoid numerical instabilities,...
static IPT absolute(const CmsCtx *ctx, IPT ipt)
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)
Generates a split pair of 3DLUTS, going to IPT and back, allowing an arbitrary dynamic EETF to be nes...
static int generate_slice(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads)
static void tone_map_setup(CmsCtx *ctx, bool dynamic)
static IPT saturation(const CmsCtx *ctx, IPT ipt)
#define PERCEPTUAL_KNEE_MIN
#define PERCEPTUAL_DEADZONE
#define PERCEPTUAL_KNEE_DEF
#define PERCEPTUAL_CONTRAST
#define PERCEPTUAL_ADAPTATION
#define PERCEPTUAL_KNEE_MAX
#define COLORIMETRIC_GAMMA
#define PERCEPTUAL_STRENGTH
Colorspace value utility functions for libavutil.
SwsMatrix3x3 ff_sws_get_adaptation(const AVPrimaryCoefficients *prim, AVWhitepointCoefficients from, AVWhitepointCoefficients to)
SwsMatrix3x3 ff_sws_ipt_lms2rgb(const AVColorPrimariesDesc *prim)
bool ff_prim_superset(const AVPrimaryCoefficients *a, const AVPrimaryCoefficients *b)
Returns true if 'b' is entirely contained in 'a'.
void ff_sws_matrix3x3_apply(const SwsMatrix3x3 *mat, float vec[3])
SwsMatrix3x3 ff_sws_ipt_rgb2lms(const AVColorPrimariesDesc *prim)
static float smoothstepf(float edge0, float edge1, float x)
static float pq_oetf(float x)
static float pq_eotf(float x)
static __device__ float sqrtf(float a)
float fminf(float, float)
float fmaxf(float, float)
const AVColorPrimariesDesc * av_csp_primaries_desc_from_id(enum AVColorPrimaries prm)
Retrieves a complete gamut description from an enum constant describing the color primaries.
av_csp_eotf_function av_csp_itu_eotf_inv(enum AVColorTransferCharacteristic trc)
Returns the mathematical inverse of the corresponding EOTF.
void(* av_csp_eotf_function)(double Lw, double Lb, double c[3])
Function pointer representing an ITU EOTF transfer for a given reference display configuration.
av_csp_eotf_function av_csp_itu_eotf(enum AVColorTransferCharacteristic trc)
Returns the ITU EOTF corresponding to a given TRC.
static double av_q2d(AVRational a)
Convert an AVRational to a double.
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
@ SWS_INTENT_PERCEPTUAL
Perceptual tone mapping.
@ SWS_INTENT_ABSOLUTE_COLORIMETRIC
Absolute colorimetric clipping.
@ SWS_INTENT_RELATIVE_COLORIMETRIC
Relative colorimetric clipping.
@ SWS_INTENT_SATURATION
Saturation mapping.
const VDPAUPixFmtMap * map
static void scale(int *out, const int *in, const int w, const int h, const int shift)
Macro definitions for various function/variable attributes.
static int slice_end(AVCodecContext *avctx, AVFrame *pict, int *got_output)
Handle slice ends.
void avpriv_slicethread_free(AVSliceThread **pctx)
Destroy slice threading context.
int avpriv_slicethread_execute2(AVSliceThread *ctx, int nb_jobs, int execute_main)
Execute slice threading.
int avpriv_slicethread_create2(AVSliceThread **pctx, void *priv, int(*worker_func)(void *priv, int jobnr, int threadnr, int nb_jobs, int nb_threads), int(*main_func)(void *priv), int nb_threads)
Create slice threading context.
struct AVSliceThread AVSliceThread
Struct containing chromaticity x and y values for the standard CIE 1931 chromaticity definition.
Struct that contains both white point location and primaries location, providing the complete descrip...
AVWhitepointCoefficients wp
float(* tone_map)(const CmsCtx *ctx, float I)
IPT(* adapt_colors)(const CmsCtx *ctx, IPT ipt)
SwsMatrix3x3 encoding2lms
SwsMatrix3x3 lms2encoding
av_csp_eotf_function eotf
av_csp_eotf_function eotf_inv
AVPrimaryCoefficients gamut
enum AVColorPrimaries prim
enum AVColorTransferCharacteristic trc
static const float lms2rgb[3][3]
static const float rgb2lms[3][3]
static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, const CodedBitstreamUnit *unit, const int is_first_slice)