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.
Unified · Split
| @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2024-03-07 · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | API changes, most recent first: |
| 4 | 4 | |
| 5 | +2024-12-xx - xxxxxxxxxx - lsws 8.13.100 - swscale.h | |
| 6 | + Add enum SwsIntent and SwsContext.intent. | |
| 7 | + | |
| 5 | 8 | 2024-12-15 - xxxxxxxxxx - lavc 61.27.100 packet.h |
| 6 | 9 | Add av_container_fifo_alloc_avpacket(). |
| 7 | 10 | |
| @@ -21071,7 +21071,38 @@ Set libswscale input parameters for scaling algorithms that need them. See · 21070 unmodified lines | ||
| 21071 | 21071 | complete documentation. If not explicitly specified the filter applies |
| 21072 | 21072 | empty parameters. |
| 21073 | 21073 | |
| 21074 | +@item intent | |
| 21075 | +Set the ICC rendering intent to use when transforming between different color | |
| 21076 | +spaces. It accepts the following values: | |
| 21074 | 21077 | |
| 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 | |
| 21075 | 21106 | |
| 21076 | 21107 | @item size, s |
| 21077 | 21108 | Set the video size. For the syntax of this option, check the |
| @@ -570,15 +570,16 @@ void sws_graph_free(SwsGraph **pgraph) · 569 unmodified lines | ||
| 570 | 570 | /* Tests only options relevant to SwsGraph */ |
| 571 | 571 | static int opts_equal(const SwsContext *c1, const SwsContext *c2) |
| 572 | 572 | { |
| 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 && | |
| 578 | 578 | c1->src_h_chr_pos == c2->src_h_chr_pos && |
| 579 | 579 | c1->src_v_chr_pos == c2->src_v_chr_pos && |
| 580 | 580 | c1->dst_h_chr_pos == c2->dst_h_chr_pos && |
| 581 | 581 | c1->dst_v_chr_pos == c2->dst_v_chr_pos && |
| 582 | + c1->intent == c2->intent && | |
| 582 | 583 | !memcmp(c1->scaler_params, c2->scaler_params, sizeof(c1->scaler_params)); |
| 583 | 584 | |
| 584 | 585 | } |
| @@ -84,6 +84,12 @@ static const AVOption swscale_options[] = { · 83 unmodified lines | ||
| 84 | 84 | { "threads", "number of threads", OFFSET(threads), AV_OPT_TYPE_INT, {.i64 = 1 }, .flags = VE, .unit = "threads", .max = INT_MAX }, |
| 85 | 85 | { "auto", "automatic selection", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, .flags = VE, .unit = "threads" }, |
| 86 | 86 | |
| 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 | + | |
| 87 | 93 | { NULL } |
| 88 | 94 | }; |
| 89 | 95 | |
| @@ -162,6 +162,14 @@ typedef enum SwsFlags { · 161 unmodified lines | ||
| 162 | 162 | SWS_ERROR_DIFFUSION = 1 << 23, ///< Set `SwsContext.dither` instead |
| 163 | 163 | } SwsFlags; |
| 164 | 164 | |
| 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 | + | |
| 165 | 173 | /*********************************** |
| 166 | 174 | * Context creation and management * |
| 167 | 175 | ***********************************/ |
| @@ -226,6 +234,11 @@ typedef struct SwsContext { · 58 unmodified lines | ||
| 226 | 234 | int dst_v_chr_pos; ///< Destination vertical chroma position |
| 227 | 235 | int dst_h_chr_pos; ///< Destination horizontal chroma position |
| 228 | 236 | |
| 237 | + /** | |
| 238 | + * Desired ICC intent for color space conversions. | |
| 239 | + */ | |
| 240 | + int intent; | |
| 241 | + | |
| 229 | 242 | /* Remember to add new fields to graph.c:opts_equal() */ |
| 230 | 243 | } SwsContext; |
| 231 | 244 | |
| @@ -699,7 +699,7 @@ static_assert(offsetof(SwsInternal, redDither) + DITHER32_INT == offsetof(SwsInt · 698 unmodified lines | ||
| 699 | 699 | #if ARCH_X86_64 |
| 700 | 700 | /* x86 yuv2gbrp uses the SwsInternal for yuv coefficients |
| 701 | 701 | 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, | |
| 703 | 703 | "yuv2rgb_y_offset must be updated in x86 asm"); |
| 704 | 704 | #endif |
| 705 | 705 | |
| @@ -28,7 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | |
| 29 | 29 | #include "version_major.h" |
| 30 | 30 | |
| 31 | −#define LIBSWSCALE_VERSION_MINOR 12 | |
| 31 | +#define LIBSWSCALE_VERSION_MINOR 13 | |
| 32 | 32 | #define LIBSWSCALE_VERSION_MICRO 100 |
| 33 | 33 | |
| 34 | 34 | #define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ |
| @@ -582,7 +582,7 @@ yuv2nv12cX_fn yuv2nv21 · 581 unmodified lines | ||
| 582 | 582 | |
| 583 | 583 | %if ARCH_X86_64 |
| 584 | 584 | struc SwsInternal |
| 585 | − .padding: resb 40332 ; offsetof(SwsInternal, yuv2rgb_y_offset) | |
| 585 | + .padding: resb 40348 ; offsetof(SwsInternal, yuv2rgb_y_offset) | |
| 586 | 586 | .yuv2rgb_y_offset: resd 1 |
| 587 | 587 | .yuv2rgb_y_coeff: resd 1 |
| 588 | 588 | .yuv2rgb_v2r_coeff: resd 1 |