summaryrefslogtreecommitdiff
path: root/libavfilter/fflcms2.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavfilter/fflcms2.c')
-rw-r--r--libavfilter/fflcms2.c294
1 files changed, 1 insertions, 293 deletions
diff --git a/libavfilter/fflcms2.c b/libavfilter/fflcms2.c
index fd370fb310..822462de87 100644
--- a/libavfilter/fflcms2.c
+++ b/libavfilter/fflcms2.c
@@ -1,5 +1,4 @@
/*
- * Copyright (c) 2022 Niklas Haas
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
@@ -17,295 +16,4 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libavutil/color_utils.h"
-#include "libavutil/csp.h"
-
-#include "fflcms2.h"
-
-static void log_cb(cmsContext ctx, cmsUInt32Number error, const char *str)
-{
- FFIccContext *s = cmsGetContextUserData(ctx);
- av_log(s->avctx, AV_LOG_ERROR, "lcms2: [%"PRIu32"] %s\n", error, str);
-}
-
-int ff_icc_context_init(FFIccContext *s, void *avctx)
-{
- memset(s, 0, sizeof(*s));
- s->avctx = avctx;
- s->ctx = cmsCreateContext(NULL, s);
- if (!s->ctx)
- return AVERROR(ENOMEM);
-
- cmsSetLogErrorHandlerTHR(s->ctx, log_cb);
- return 0;
-}
-
-void ff_icc_context_uninit(FFIccContext *s)
-{
- for (int i = 0; i < FF_ARRAY_ELEMS(s->curves); i++)
- cmsFreeToneCurve(s->curves[i]);
- cmsDeleteContext(s->ctx);
- memset(s, 0, sizeof(*s));
-}
-
-static int get_curve(FFIccContext *s, enum AVColorTransferCharacteristic trc,
- cmsToneCurve **out_curve)
-{
- if (trc >= AVCOL_TRC_NB)
- return AVERROR_INVALIDDATA;
-
- if (s->curves[trc])
- goto done;
-
- switch (trc) {
- case AVCOL_TRC_LINEAR:
- s->curves[trc] = cmsBuildGamma(s->ctx, 1.0);
- break;
- case AVCOL_TRC_GAMMA22:
- s->curves[trc] = cmsBuildGamma(s->ctx, 2.2);
- break;
- case AVCOL_TRC_GAMMA28:
- s->curves[trc] = cmsBuildGamma(s->ctx, 2.8);
- break;
- case AVCOL_TRC_BT709:
- case AVCOL_TRC_SMPTE170M:
- case AVCOL_TRC_BT2020_10:
- case AVCOL_TRC_BT2020_12:
- s->curves[trc] = cmsBuildParametricToneCurve(s->ctx, 4, (double[5]) {
- /* γ = */ 1/0.45,
- /* a = */ 1/1.099296826809442,
- /* b = */ 1 - 1/1.099296826809442,
- /* c = */ 1/4.5,
- /* d = */ 4.5 * 0.018053968510807,
- });
- break;
- case AVCOL_TRC_SMPTE240M:
- s->curves[trc] = cmsBuildParametricToneCurve(s->ctx, 4, (double[5]) {
- /* γ = */ 1/0.45,
- /* a = */ 1/1.1115,
- /* b = */ 1 - 1/1.1115,
- /* c = */ 1/4.0,
- /* d = */ 4.0 * 0.0228,
- });
- break;
- case AVCOL_TRC_LOG:
- s->curves[trc] = cmsBuildParametricToneCurve(s->ctx, 8, (double[5]) {
- /* a = */ 1.0,
- /* b = */ 10.0,
- /* c = */ 2.0,
- /* d = */ -1.0,
- /* e = */ 0.0
- });
- break;
- case AVCOL_TRC_LOG_SQRT:
- s->curves[trc] = cmsBuildParametricToneCurve(s->ctx, 8, (double[5]) {
- /* a = */ 1.0,
- /* b = */ 10.0,
- /* c = */ 2.5,
- /* d = */ -1.0,
- /* e = */ 0.0
- });
- break;
- case AVCOL_TRC_IEC61966_2_1:
- s->curves[trc] = cmsBuildParametricToneCurve(s->ctx, 4, (double[5]) {
- /* γ = */ 2.4,
- /* a = */ 1/1.055,
- /* b = */ 1 - 1/1.055,
- /* c = */ 1/12.92,
- /* d = */ 12.92 * 0.0031308,
- });
- break;
- case AVCOL_TRC_SMPTE428:
- s->curves[trc] = cmsBuildParametricToneCurve(s->ctx, 2, (double[3]) {
- /* γ = */ 2.6,
- /* a = */ pow(52.37/48.0, 1/2.6),
- /* b = */ 0.0
- });
- break;
-
- /* Can't be represented using the existing parametric tone curves.
- * FIXME: use cmsBuildTabulatedToneCurveFloat instead */
- case AVCOL_TRC_IEC61966_2_4:
- case AVCOL_TRC_BT1361_ECG:
- case AVCOL_TRC_SMPTE2084:
- case AVCOL_TRC_ARIB_STD_B67:
- return AVERROR_PATCHWELCOME;
-
- default:
- return AVERROR_INVALIDDATA;
- }
-
- if (!s->curves[trc])
- return AVERROR(ENOMEM);
-
-done:
- *out_curve = s->curves[trc];
- return 0;
-}
-
-int ff_icc_profile_generate(FFIccContext *s,
- enum AVColorPrimaries color_prim,
- enum AVColorTransferCharacteristic color_trc,
- cmsHPROFILE *out_profile)
-{
- cmsToneCurve *tonecurve;
- const AVColorPrimariesDesc *prim;
- int ret;
-
- if (!(prim = av_csp_primaries_desc_from_id(color_prim)))
- return AVERROR_INVALIDDATA;
- if ((ret = get_curve(s, color_trc, &tonecurve)) < 0)
- return ret;
-
- *out_profile = cmsCreateRGBProfileTHR(s->ctx,
- &(cmsCIExyY) { av_q2d(prim->wp.x), av_q2d(prim->wp.y), 1.0 },
- &(cmsCIExyYTRIPLE) {
- .Red = { av_q2d(prim->prim.r.x), av_q2d(prim->prim.r.y), 1.0 },
- .Green = { av_q2d(prim->prim.g.x), av_q2d(prim->prim.g.y), 1.0 },
- .Blue = { av_q2d(prim->prim.b.x), av_q2d(prim->prim.b.y), 1.0 },
- },
- (cmsToneCurve *[3]) { tonecurve, tonecurve, tonecurve }
- );
-
- return *out_profile == NULL ? AVERROR(ENOMEM) : 0;
-}
-
-int ff_icc_profile_attach(FFIccContext *s, cmsHPROFILE profile, AVFrame *frame)
-{
- cmsUInt32Number size;
- AVBufferRef *buf;
-
- if (!cmsSaveProfileToMem(profile, NULL, &size))
- return AVERROR_EXTERNAL;
-
- buf = av_buffer_alloc(size);
- if (!buf)
- return AVERROR(ENOMEM);
-
- if (!cmsSaveProfileToMem(profile, buf->data, &size) || size != buf->size) {
- av_buffer_unref(&buf);
- return AVERROR_EXTERNAL;
- }
-
- if (!av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_ICC_PROFILE, buf)) {
- av_buffer_unref(&buf);
- return AVERROR(ENOMEM);
- }
-
- return 0;
-}
-
-static av_always_inline void XYZ_xy(cmsCIEXYZ XYZ, AVCIExy *xy)
-{
- double k = 1.0 / (XYZ.X + XYZ.Y + XYZ.Z);
- xy->x = av_d2q(k * XYZ.X, 100000);
- xy->y = av_d2q(k * XYZ.Y, 100000);
-}
-
-int ff_icc_profile_read_primaries(FFIccContext *s, cmsHPROFILE profile,
- AVColorPrimariesDesc *out_primaries)
-{
- static const uint8_t testprimaries[4][3] = {
- { 0xFF, 0, 0 }, /* red */
- { 0, 0xFF, 0 }, /* green */
- { 0, 0, 0xFF }, /* blue */
- { 0xFF, 0xFF, 0xFF }, /* white */
- };
-
- AVWhitepointCoefficients *wp = &out_primaries->wp;
- AVPrimaryCoefficients *prim = &out_primaries->prim;
- cmsFloat64Number prev_adapt;
- cmsHPROFILE xyz;
- cmsHTRANSFORM tf;
- cmsCIEXYZ dst[4];
-
- xyz = cmsCreateXYZProfileTHR(s->ctx);
- if (!xyz)
- return AVERROR(ENOMEM);
-
- /* We need to use an unadapted observer to get the raw values */
- prev_adapt = cmsSetAdaptationStateTHR(s->ctx, 0.0);
- tf = cmsCreateTransformTHR(s->ctx, profile, TYPE_RGB_8, xyz, TYPE_XYZ_DBL,
- INTENT_ABSOLUTE_COLORIMETRIC,
- /* Note: These flags mostly don't do anything
- * anyway, but specify them regardless */
- cmsFLAGS_NOCACHE |
- cmsFLAGS_NOOPTIMIZE |
- cmsFLAGS_LOWRESPRECALC |
- cmsFLAGS_GRIDPOINTS(2));
- cmsSetAdaptationStateTHR(s->ctx, prev_adapt);
- cmsCloseProfile(xyz);
- if (!tf) {
- av_log(s->avctx, AV_LOG_ERROR, "Invalid ICC profile (e.g. CMYK)\n");
- return AVERROR_INVALIDDATA;
- }
-
- cmsDoTransform(tf, testprimaries, dst, 4);
- cmsDeleteTransform(tf);
- XYZ_xy(dst[0], &prim->r);
- XYZ_xy(dst[1], &prim->g);
- XYZ_xy(dst[2], &prim->b);
- XYZ_xy(dst[3], wp);
- return 0;
-}
-
-int ff_icc_profile_detect_transfer(FFIccContext *s, cmsHPROFILE profile,
- enum AVColorTransferCharacteristic *out_trc)
-{
- /* 8-bit linear grayscale ramp */
- static const uint8_t testramp[16][3] = {
- { 1, 1, 1}, /* avoid exact zero due to log100 etc. */
- { 17, 17, 17},
- { 34, 34, 34},
- { 51, 51, 51},
- { 68, 68, 68},
- { 85, 85, 85},
- { 02, 02, 02},
- {119, 119, 119},
- {136, 136, 136},
- {153, 153, 153},
- {170, 170, 170},
- {187, 187, 187},
- {204, 204, 204},
- {221, 221, 221},
- {238, 238, 238},
- {255, 255, 255},
- };
-
- double dst[FF_ARRAY_ELEMS(testramp)];
-
- for (enum AVColorTransferCharacteristic trc = 0; trc < AVCOL_TRC_NB; trc++) {
- cmsToneCurve *tonecurve;
- cmsHPROFILE ref;
- cmsHTRANSFORM tf;
- double delta = 0.0;
- if (get_curve(s, trc, &tonecurve) < 0)
- continue;
-
- ref = cmsCreateGrayProfileTHR(s->ctx, cmsD50_xyY(), tonecurve);
- if (!ref)
- return AVERROR(ENOMEM);
-
- tf = cmsCreateTransformTHR(s->ctx, profile, TYPE_RGB_8, ref, TYPE_GRAY_DBL,
- INTENT_RELATIVE_COLORIMETRIC,
- cmsFLAGS_NOCACHE | cmsFLAGS_NOOPTIMIZE);
- cmsCloseProfile(ref);
- if (!tf) {
- av_log(s->avctx, AV_LOG_ERROR, "Invalid ICC profile (e.g. CMYK)\n");
- return AVERROR_INVALIDDATA;
- }
-
- cmsDoTransform(tf, testramp, dst, FF_ARRAY_ELEMS(dst));
- cmsDeleteTransform(tf);
-
- for (int i = 0; i < FF_ARRAY_ELEMS(dst); i++)
- delta += fabs(testramp[i][0] / 255.0 - dst[i]);
- if (delta < 0.01) {
- *out_trc = trc;
- return 0;
- }
- }
-
- *out_trc = AVCOL_TRC_UNSPECIFIED;
- return 0;
-}
+#include "libavcodec/fflcms2.c"