History

swscale: add ICC intent enum and option

This setting can be used to infuence the type of tone and gamut mapping used internally when color space conversions are required. As discussed at VDD'24, the default was set to relative colorimetric clipping, which is approximately associative, surjective and idempotent. As such, it roundtrips well, although it is strictly speaking not associative on out-of-gamut colors.

Niklas Haas committed 1 year ago

Commit 45f0a7a1 parent 7b7c3238 files · +62 −8Browse files

Unified · Split

8 files
  1. doc/APIchanges +3 −0
  2. doc/filters.texi +31 −0
  3. libswscale/graph.c +6 −5
  4. libswscale/options.c +6 −0
  5. libswscale/swscale.h +13 −0
  6. libswscale/swscale_internal.h +1 −1
  7. libswscale/version.h +1 −1
  8. libswscale/x86/output.asm +1 −1
doc/APIchanges+3−0
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07 · 1 unmodified line
22
33 API changes, most recent first:
44
5+2024-12-xx - xxxxxxxxxx - lsws 8.13.100 - swscale.h
6+ Add enum SwsIntent and SwsContext.intent.
7+
58 2024-12-15 - xxxxxxxxxx - lavc 61.27.100 packet.h
69 Add av_container_fifo_alloc_avpacket().
710
doc/filters.texi+31−0
@@ -21071,7 +21071,38 @@ Set libswscale input parameters for scaling algorithms that need them. See · 21070 unmodified lines
2107121071 complete documentation. If not explicitly specified the filter applies
2107221072 empty parameters.
2107321073
21074+@item intent
21075+Set the ICC rendering intent to use when transforming between different color
21076+spaces. It accepts the following values:
2107421077
21078+@table @samp
21079+@item perceptual
21080+Use a perceptually guided tone and gamut mapping curve. The exact details of
21081+the mapping used may change at any time and should not be relied on as stable.
21082+This intent is recommended for final viewing of image/video content in typical
21083+viewing settings.
21084+
21085+@item relative_colorimetric
21086+Statically clip out-of-gamut colors using a colorimetric clipping curve which
21087+attempts to find the colorimetrically least dissimilar in-gamut color. This
21088+intent performs white point adaptation and black point adaptation. This is
21089+the default. This intent is recommended wherever faithful color reproduction
21090+is of the utmost importance, even at the cost of clipping.
21091+
21092+@item absolute_colorimetric
21093+Hard clip out-of-gamut colors with no attempt at white or black point
21094+reproduction. This intent will reproduce in-gamut colors 1:1 on the output
21095+display as they would appear on the reference display, assuming the output
21096+display is appropriately calibrated.
21097+
21098+@item saturation
21099+Performs saturation mapping - that is, stretches the input color volume
21100+directly onto the output color volume, in non-linear fashion that preserves the
21101+original signal appearance as much as possible. This intent is recommended for
21102+signal content evaluation, as it will not lead to any clipping. It is roughly
21103+analogous to not performing any color mapping, although it still takes into
21104+account the mastering display primaries and any differences in encoding TRC.
21105+@end table
2107521106
2107621107 @item size, s
2107721108 Set the video size. For the syntax of this option, check the
libswscale/graph.c+6−5
@@ -570,15 +570,16 @@ void sws_graph_free(SwsGraph **pgraph) · 569 unmodified lines
570570 /* Tests only options relevant to SwsGraph */
571571 static int opts_equal(const SwsContext *c1, const SwsContext *c2)
572572 {
573− return c1->flags == c2->flags &&
574− c1->threads == c2->threads &&
575− c1->dither == c2->dither &&
576− c1->alpha_blend == c2->alpha_blend &&
577− c1->gamma_flag == c2->gamma_flag &&
573+ return c1->flags == c2->flags &&
574+ c1->threads == c2->threads &&
575+ c1->dither == c2->dither &&
576+ c1->alpha_blend == c2->alpha_blend &&
577+ c1->gamma_flag == c2->gamma_flag &&
578578 c1->src_h_chr_pos == c2->src_h_chr_pos &&
579579 c1->src_v_chr_pos == c2->src_v_chr_pos &&
580580 c1->dst_h_chr_pos == c2->dst_h_chr_pos &&
581581 c1->dst_v_chr_pos == c2->dst_v_chr_pos &&
582+ c1->intent == c2->intent &&
582583 !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params));
583584
584585 }
libswscale/options.c+6−0
@@ -84,6 +84,12 @@ static const AVOption swscale_options[] = { · 83 unmodified lines
8484 { "threads", "number of threads", OFFSET(threads), AV_OPT_TYPE_INT, {.i64 = 1 }, .flags = VE, .unit = "threads", .max = INT_MAX },
8585 { "auto", "automatic selection", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, .flags = VE, .unit = "threads" },
8686
87+ { "intent", "color mapping intent", OFFSET(intent), AV_OPT_TYPE_INT, { .i64 = SWS_INTENT_RELATIVE_COLORIMETRIC }, .flags = VE, .unit = "intent", .max = SWS_INTENT_NB - 1 },
88+ { "perceptual", "perceptual tone mapping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_PERCEPTUAL }, .flags = VE, .unit = "intent" },
89+ { "relative_colorimetric", "relative colorimetric clipping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_RELATIVE_COLORIMETRIC }, .flags = VE, .unit = "intent" },
90+ { "saturation", "saturation mapping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_SATURATION }, .flags = VE, .unit = "intent" },
91+ { "absolute_colorimetric", "absolute colorimetric clipping", 0, AV_OPT_TYPE_CONST, { .i64 = SWS_INTENT_ABSOLUTE_COLORIMETRIC }, .flags = VE, .unit = "intent" },
92+
8793 { NULL }
8894 };
8995
libswscale/swscale.h+13−0
@@ -162,6 +162,14 @@ typedef enum SwsFlags { · 161 unmodified lines
162162 SWS_ERROR_DIFFUSION = 1 << 23, ///< Set `SwsContext.dither` instead
163163 } SwsFlags;
164164
165+typedef enum SwsIntent {
166+ SWS_INTENT_PERCEPTUAL = 0, ///< Perceptual tone mapping
167+ SWS_INTENT_RELATIVE_COLORIMETRIC = 1, ///< Relative colorimetric clipping
168+ SWS_INTENT_SATURATION = 2, ///< Saturation mapping
169+ SWS_INTENT_ABSOLUTE_COLORIMETRIC = 3, ///< Absolute colorimetric clipping
170+ SWS_INTENT_NB, ///< not part of the ABI
171+} SwsIntent;
172+
165173 /***********************************
166174 * Context creation and management *
167175 ***********************************/
@@ -226,6 +234,11 @@ typedef struct SwsContext { · 58 unmodified lines
226234 int dst_v_chr_pos; ///< Destination vertical chroma position
227235 int dst_h_chr_pos; ///< Destination horizontal chroma position
228236
237+ /**
238+ * Desired ICC intent for color space conversions.
239+ */
240+ int intent;
241+
229242 /* Remember to add new fields to graph.c:opts_equal() */
230243 } SwsContext;
231244
libswscale/swscale_internal.h+1−1
@@ -699,7 +699,7 @@ static_assert(offsetof(SwsInternal, redDither) + DITHER32_INT == offsetof(SwsInt · 698 unmodified lines
699699 #if ARCH_X86_64
700700 /* x86 yuv2gbrp uses the SwsInternal for yuv coefficients
701701 if struct offsets change the asm needs to be updated too */
702−static_assert(offsetof(SwsInternal, yuv2rgb_y_offset) == 40332,
702+static_assert(offsetof(SwsInternal, yuv2rgb_y_offset) == 40348,
703703 "yuv2rgb_y_offset must be updated in x86 asm");
704704 #endif
705705
libswscale/version.h+1−1
@@ -28,7 +28,7 @@ · 27 unmodified lines
2828
2929 #include "version_major.h"
3030
31−#define LIBSWSCALE_VERSION_MINOR 12
31+#define LIBSWSCALE_VERSION_MINOR 13
3232 #define LIBSWSCALE_VERSION_MICRO 100
3333
3434 #define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \
libswscale/x86/output.asm+1−1
@@ -582,7 +582,7 @@ yuv2nv12cX_fn yuv2nv21 · 581 unmodified lines
582582
583583 %if ARCH_X86_64
584584 struc SwsInternal
585− .padding: resb 40332 ; offsetof(SwsInternal, yuv2rgb_y_offset)
585+ .padding: resb 40348 ; offsetof(SwsInternal, yuv2rgb_y_offset)
586586 .yuv2rgb_y_offset: resd 1
587587 .yuv2rgb_y_coeff: resd 1
588588 .yuv2rgb_v2r_coeff: resd 1

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t