From patchwork Tue Jul 19 12:26:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 36833 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:1649:b0:8b:613a:194d with SMTP id no9csp1714378pzb; Tue, 19 Jul 2022 05:26:29 -0700 (PDT) X-Google-Smtp-Source: AGRyM1skXE2A9faVRJQ3W8HUSrt8Zyrrg3wkyhheU85imdEmwMhmLSIm0Vzr6qMffngby3R8bnM9 X-Received: by 2002:a05:6402:1d51:b0:41f:cf6c:35a5 with SMTP id dz17-20020a0564021d5100b0041fcf6c35a5mr44597932edb.25.1658233589255; Tue, 19 Jul 2022 05:26:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658233589; cv=none; d=google.com; s=arc-20160816; b=Fm3noq6YzRAAFiPaWSdvywiYERnkibhATXzroeNBac1iEqy8nZAVHxif+tMwg83R7d BOH0hT+ESYjQJjMsJrx0IHLpDGf3+YKKqG6WLnvP6n0cwh/1wo9r5rGEhBWto2oV2vQr 1rfdR29MGgRjeaO5sOgEBUsw1CgsjQh8od93or6Wqi5vng/aLk7h417tAIwS6g2f6smk +e1DAzOrrRagvl2z4XxgYxpI2Zb/aDApZiP/lCmsKEDKd1uJEkF8nfrvRT6Zg17zQTc3 UP4EJ9BeicuCu2ve4lTSHt47jUfII22KMfddvibfIBwYHuosX5VZfZqSepahxvHdlPZG C1Fg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=OHBE1KHmV4he153PERxW7Z5Xo+AzwJgbBNSY7hus96w=; b=epPNuKpPHChvMsIw3He3NtsGC/hb7+zqPXNE07O2etZls+wPWBV+1yurxlr2+GpXfg aAxg652wjplGp0MlTVlBufqSM/pMwh920Wfmn08/hNn42XixyrmFbVtY2L+xXU1RQWDO 2AkvxrW5hYRPI3nCrC2bUcxHkYenKgI4H7HX1eDI5n+Fch+DJEiFElHOtBzvCeL/0lMn DwSfKerWeNoiBl/2/x4Ct1izN9KmfvcS6eH/HEPba/9Pmj/MQWrZwkXwgtVUmhdVrJux N9xe8JEIirNSNdU8uS/JSJ+XRdd5up8Yxwfp38zE6vBm1N9i4H0TNZ58PplSBtrF6Uhm FC7Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=YzL+WDWk; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id di14-20020a170906730e00b0072b97b3288dsi23963307ejc.510.2022.07.19.05.26.28; Tue, 19 Jul 2022 05:26:29 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=YzL+WDWk; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3E28B68B63E; Tue, 19 Jul 2022 15:26:17 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0E49F68B5A5 for ; Tue, 19 Jul 2022 15:26:10 +0300 (EEST) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id D24744A9C0; Tue, 19 Jul 2022 14:26:09 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1658233569; bh=d1TAlwgzm2gFLcAVq9GKS0yTYkzcIbLGg8pNcSBWhuY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YzL+WDWkWQSGHjBvDm27EnytkK+/ZLmbHbiNVHkIlHpmjmdYE1cM6/h27jw6kgl2L sONKTnumKTv4MSLBZJo4J+PZl+WU6ieos1KB2NUOSYZgqgLCxz7B6FL8pc9iPYLmp7 iHYVxv/SjCeNGMrf+WMUQiwF2aYyGyOlZWRuCy9g= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Tue, 19 Jul 2022 14:26:03 +0200 Message-Id: <20220719122608.43974-2-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220719122608.43974-1-ffmpeg@haasn.xyz> References: <20220719122608.43974-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 1/6] fflcms2: move to libavcodec X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: Okmp1HTuiMWU From: Niklas Haas We will need this helper inside libavcodec in the future, so move it there, leaving behind an #include to the raw source file in its old location in libvfilter. This approach is inspired by the handling of vulkan.c, and avoids us needing to expose any of it publicly (or semi-publicly) in e.g. libavutil, thus avoiding any ABI headaches. It's debatable whether the actual code belongs in libavcodec or libavfilter, but I decided to put it into libavcodec because it conceptually deals with encoding and decoding ICC profiles, and will be used to decode embedded ICC profiles in image files. Signed-off-by: Niklas Haas --- libavcodec/Makefile | 1 + libavcodec/fflcms2.c | 311 ++++++++++++++++++++++++++++++++++++++++++ libavcodec/fflcms2.h | 87 ++++++++++++ libavfilter/fflcms2.c | 294 +-------------------------------------- libavfilter/fflcms2.h | 65 +-------- 5 files changed, 401 insertions(+), 357 deletions(-) create mode 100644 libavcodec/fflcms2.c create mode 100644 libavcodec/fflcms2.h diff --git a/libavcodec/Makefile b/libavcodec/Makefile index ef2318438b..ac9fb575c5 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1240,6 +1240,7 @@ SKIPHEADERS-$(CONFIG_AMF) += amfenc.h SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h SKIPHEADERS-$(CONFIG_JNI) += ffjni.h +SKIPHEADERS-$(CONFIG_LCMS2) += fflcms2.h SKIPHEADERS-$(CONFIG_LIBJXL) += libjxl.h SKIPHEADERS-$(CONFIG_LIBVPX) += libvpx.h SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.h diff --git a/libavcodec/fflcms2.c b/libavcodec/fflcms2.c new file mode 100644 index 0000000000..fd370fb310 --- /dev/null +++ b/libavcodec/fflcms2.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2022 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 + */ + +#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; +} diff --git a/libavcodec/fflcms2.h b/libavcodec/fflcms2.h new file mode 100644 index 0000000000..af63c9a13c --- /dev/null +++ b/libavcodec/fflcms2.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022 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 + */ + +/** + * @file + * Various functions for dealing with ICC profiles + */ + +#ifndef AVCODEC_FFLCMS2_H +#define AVCODEC_FFLCMS2_H + +#include "libavutil/csp.h" +#include "libavutil/frame.h" +#include "libavutil/pixfmt.h" + +#include + +typedef struct FFIccContext { + void *avctx; + cmsContext ctx; + cmsToneCurve *curves[AVCOL_TRC_NB]; /* tone curve cache */ +} FFIccContext; + +/** + * Initializes an FFIccContext. This must be done prior to using it. + * + * Returns 0 on success, or a negative error code. + */ +int ff_icc_context_init(FFIccContext *s, void *avctx); +void ff_icc_context_uninit(FFIccContext *s); + +/** + * Generate an ICC profile for a given combination of color primaries and + * transfer function. Both values must be set to valid entries (not + * "undefined") for this function to work. + * + * Returns 0 on success, or a negative error code. + */ +int ff_icc_profile_generate(FFIccContext *s, + enum AVColorPrimaries color_prim, + enum AVColorTransferCharacteristic color_trc, + cmsHPROFILE *out_profile); + +/** + * Attach an ICC profile to a frame. Helper wrapper around cmsSaveProfileToMem + * and av_frame_new_side_data_from_buf. + * + * Returns 0 on success, or a negative error code. + */ +int ff_icc_profile_attach(FFIccContext *s, cmsHPROFILE profile, AVFrame *frame); + +/** + * Read the color primaries and white point coefficients encoded by an ICC + * profile, and return the raw values in `out_primaries`. + * + * Returns 0 on success, or a negative error code. + */ +int ff_icc_profile_read_primaries(FFIccContext *s, cmsHPROFILE profile, + AVColorPrimariesDesc *out_primaries); + +/** + * Attempt detecting the transfer characteristic that best approximates the + * transfer function encoded by an ICC profile. Sets `out_trc` to + * AVCOL_TRC_UNSPECIFIED if no clear match can be identified. + * + * Returns 0 on success (including no match), or a negative error code. + */ +int ff_icc_profile_detect_transfer(FFIccContext *s, cmsHPROFILE profile, + enum AVColorTransferCharacteristic *out_trc); + +#endif /* AVCODEC_FFLCMS2_H */ 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" diff --git a/libavfilter/fflcms2.h b/libavfilter/fflcms2.h index 0d238c679f..1ac29e357b 100644 --- a/libavfilter/fflcms2.h +++ b/libavfilter/fflcms2.h @@ -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,71 +16,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/** - * @file - * Various functions for dealing with ICC profiles - */ - #ifndef AVFILTER_FFLCMS2_H #define AVFILTER_FFLCMS2_H -#include "libavutil/csp.h" -#include "libavutil/frame.h" -#include "libavutil/pixfmt.h" - -#include - -typedef struct FFIccContext { - void *avctx; - cmsContext ctx; - cmsToneCurve *curves[AVCOL_TRC_NB]; /* tone curve cache */ -} FFIccContext; - -/** - * Initializes an FFIccContext. This must be done prior to using it. - * - * Returns 0 on success, or a negative error code. - */ -int ff_icc_context_init(FFIccContext *s, void *avctx); -void ff_icc_context_uninit(FFIccContext *s); - -/** - * Generate an ICC profile for a given combination of color primaries and - * transfer function. Both values must be set to valid entries (not - * "undefined") for this function to work. - * - * Returns 0 on success, or a negative error code. - */ -int ff_icc_profile_generate(FFIccContext *s, - enum AVColorPrimaries color_prim, - enum AVColorTransferCharacteristic color_trc, - cmsHPROFILE *out_profile); - -/** - * Attach an ICC profile to a frame. Helper wrapper around cmsSaveProfileToMem - * and av_frame_new_side_data_from_buf. - * - * Returns 0 on success, or a negative error code. - */ -int ff_icc_profile_attach(FFIccContext *s, cmsHPROFILE profile, AVFrame *frame); - -/** - * Read the color primaries and white point coefficients encoded by an ICC - * profile, and return the raw values in `out_primaries`. - * - * Returns 0 on success, or a negative error code. - */ -int ff_icc_profile_read_primaries(FFIccContext *s, cmsHPROFILE profile, - AVColorPrimariesDesc *out_primaries); - -/** - * Attempt detecting the transfer characteristic that best approximates the - * transfer function encoded by an ICC profile. Sets `out_trc` to - * AVCOL_TRC_UNSPECIFIED if no clear match can be identified. - * - * Returns 0 on success (including no match), or a negative error code. - */ -int ff_icc_profile_detect_transfer(FFIccContext *s, cmsHPROFILE profile, - enum AVColorTransferCharacteristic *out_trc); +#include "libavcodec/fflcms2.h" #endif /* AVFILTER_FFLCMS2_H */ From patchwork Tue Jul 19 12:26:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 36834 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:1649:b0:8b:613a:194d with SMTP id no9csp1714475pzb; Tue, 19 Jul 2022 05:26:38 -0700 (PDT) X-Google-Smtp-Source: AGRyM1sAVlKqO7uB4O9oXodIavc/Uzo0bMtDm85nFye6XNGWoa90yAgLCFwCY3+jsW428QSpo+7h X-Received: by 2002:a05:6402:484:b0:43b:6e02:71af with SMTP id k4-20020a056402048400b0043b6e0271afmr9769825edv.176.1658233598059; Tue, 19 Jul 2022 05:26:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658233598; cv=none; d=google.com; s=arc-20160816; b=edKXCbfYk8eejuWFZEh5+RuGPFMr6K9L8rs5hf9w+qRVCjxX/dsDtNqhUGAAhfZJ5c J1ujvM9EyLV9RSdzeWo+exgTeQHMEN85vS2YS8Aj4ghZ+T3ozSOkyzIsI/H1CdD8wi4d Q+oVOFUW+B89cVNAawz45epOWUvwuAH5wx2q0rq8UMx3K7tkl2lb1QQA6P7NyTm6kgUk ou/6lcI456nic6875YyAGVWTLNxX98VnRjaUl/9o5NkNmcKWsdgRhUTZTp1sOUgjDF95 kBGXWB1zxJK5Gb3uPFPVvZhPyKux/xQD9SZ7ESG6fiBEATKLbGBJpq5tQIBsK9hj8Ugt z3ag== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=nMBcJffgWWv7azwq0JV2sSVEj30QRl8ikz2wR21wsXM=; b=XvfsKAuoXutEnbjDmCH472M5n8oAlWw6tr3AFn6ch4rLcCOcxQhwucyyiadA0KdA8W wbja0KQyoYRTvpa8sSRR8xG2bqDpj9djGlVJK7l4MihXeYCFG19Ra7HnohSoohVaCKjz CS9kQGoa1cMifcPUqKDUNUL5gnIM4GlCbzjxMKUdYFu3BUrsx/NLiB8rbTdgHL2MfjNR NvuaXF6CDh+YBCMmbkOL1cnmNozJLWQV9x0fpPDTGjY3ZUl36AkeXrZmsymFcq2rFkkr KRwS/hvprfkD7vbPhw54WqQJcu9BsxfBvS40Iu1ynn3Ypxg3BQyfxXRFewNjiu/Z39TP JAxQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=TQtxwgj4; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id t2-20020a1709063e4200b00726bd755998si15111702eji.967.2022.07.19.05.26.37; Tue, 19 Jul 2022 05:26:38 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=TQtxwgj4; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 368F468B671; Tue, 19 Jul 2022 15:26:19 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 558FB68B5A5 for ; Tue, 19 Jul 2022 15:26:10 +0300 (EEST) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 104DC4A9C1; Tue, 19 Jul 2022 14:26:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1658233570; bh=qhIYQfrqCo+6K2YyiniZla+QgL+dgMffpck5sM3tLO4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TQtxwgj4M7ZVV86ssHqb9sy18ZGQMjJaNju7o2w3dBboQ+nzthK6YN60wkBaPoOwU SAADTLlwpKWUsg/zamqo/l0kAAsAyCO7mOKNi0lH+AJjpV2+/H7feeCwA12HvTPl4B 4laS9TILpzN2wicaplJcitM7F3nrbJrS5JY8N83I= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Tue, 19 Jul 2022 14:26:04 +0200 Message-Id: <20220719122608.43974-3-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220719122608.43974-1-ffmpeg@haasn.xyz> References: <20220719122608.43974-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 2/6] avcodec/codec_internal: add cap for ICC profile support X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: qJjsGU6a7fVf From: Niklas Haas Codecs that can read/write ICC profiles deserve a special capability so the common logic in encode.c/decode.c can decide whether or not there needs to be any special handling for ICC profiles. The motivation here is to be able to use it to decide whether or not an ICC profile needs to be generated in the encode path, but it might as well get added to decoders as well for purely informative reasons. It's not entirely clear to me whether the "thp" and "smvjpeg" variants of "mjpeg" should have this capability set or not, given that the code technically supports it but I somehow doubt these files may contain them. In either case, this cap is purely informative for decoders so it doesn't matter too much either way. It's also not entirely clear whether the "amv" encoder should signal ICC profile support, but again erring on the side of caution, we probably *shouldn't* be generating (and encoding!) ICC profiles for this type of media file. Signed-off-by: Niklas Haas --- libavcodec/codec_internal.h | 4 ++++ libavcodec/libjxldec.c | 3 ++- libavcodec/libjxlenc.c | 3 ++- libavcodec/mjpegdec.c | 4 +++- libavcodec/mjpegenc.c | 2 +- libavcodec/pngdec.c | 6 ++++-- libavcodec/pngenc.c | 2 ++ libavcodec/tiff.c | 2 +- libavcodec/webp.c | 1 + 9 files changed, 20 insertions(+), 7 deletions(-) diff --git a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h index 3619d04090..62ea91cf4d 100644 --- a/libavcodec/codec_internal.h +++ b/libavcodec/codec_internal.h @@ -75,6 +75,10 @@ * internal logic derive them from AVCodecInternal.last_pkt_props. */ #define FF_CODEC_CAP_SETS_FRAME_PROPS (1 << 8) +/** + * Codec supports embedded ICC profiles (AV_FRAME_DATA_ICC_PROFILE). + */ +#define FF_CODEC_CAP_ICC_PROFILES (1 << 9) /** * FFCodec.codec_tags termination value diff --git a/libavcodec/libjxldec.c b/libavcodec/libjxldec.c index b9322b082a..f54701596b 100644 --- a/libavcodec/libjxldec.c +++ b/libavcodec/libjxldec.c @@ -456,6 +456,7 @@ const FFCodec ff_libjxl_decoder = { .close = libjxl_decode_close, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_OTHER_THREADS, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | - FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP, + FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_ICC_PROFILES, .p.wrapper_name = "libjxl", }; diff --git a/libavcodec/libjxlenc.c b/libavcodec/libjxlenc.c index dd85fcbc8e..7e97237cd1 100644 --- a/libavcodec/libjxlenc.c +++ b/libavcodec/libjxlenc.c @@ -469,7 +469,8 @@ const FFCodec ff_libjxl_encoder = { .close = libjxl_encode_close, .p.capabilities = AV_CODEC_CAP_OTHER_THREADS, .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | - FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP, + FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_ICC_PROFILES, .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64, diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index 816eb1ce5d..5f058d026f 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -3027,7 +3027,9 @@ const FFCodec ff_mjpeg_decoder = { .p.priv_class = &mjpegdec_class, .p.profiles = NULL_IF_CONFIG_SMALL(ff_mjpeg_profiles), .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | - FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_SETS_PKT_DTS, + FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | + FF_CODEC_CAP_SETS_PKT_DTS | + FF_CODEC_CAP_ICC_PROFILES, .hw_configs = (const AVCodecHWConfigInternal *const []) { #if CONFIG_MJPEG_NVDEC_HWACCEL HWACCEL_NVDEC(mjpeg), diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c index 63862a5043..3df0b51bb4 100644 --- a/libavcodec/mjpegenc.c +++ b/libavcodec/mjpegenc.c @@ -652,7 +652,7 @@ const FFCodec ff_mjpeg_encoder = { FF_CODEC_ENCODE_CB(ff_mpv_encode_picture), .close = mjpeg_encode_close, .p.capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, - .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_ICC_PROFILES, .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index 6e1214401d..3b888199d4 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -1727,7 +1727,8 @@ const FFCodec ff_apng_decoder = { .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | - FF_CODEC_CAP_ALLOCATE_PROGRESS, + FF_CODEC_CAP_ALLOCATE_PROGRESS | + FF_CODEC_CAP_ICC_PROFILES, }; #endif @@ -1744,6 +1745,7 @@ const FFCodec ff_png_decoder = { .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/, .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | - FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP, + FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_ICC_PROFILES, }; #endif diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c index 25cf769931..8ef863a6c1 100644 --- a/libavcodec/pngenc.c +++ b/libavcodec/pngenc.c @@ -1210,6 +1210,7 @@ const FFCodec ff_png_encoder = { AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE }, .p.priv_class = &pngenc_class, + .caps_internal = FF_CODEC_CAP_ICC_PROFILES, }; const FFCodec ff_apng_encoder = { @@ -1231,4 +1232,5 @@ const FFCodec ff_apng_encoder = { AV_PIX_FMT_NONE }, .p.priv_class = &pngenc_class, + .caps_internal = FF_CODEC_CAP_ICC_PROFILES, }; diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c index 349df14035..5457eb1dae 100644 --- a/libavcodec/tiff.c +++ b/libavcodec/tiff.c @@ -2190,6 +2190,6 @@ const FFCodec ff_tiff_decoder = { .close = tiff_end, FF_CODEC_DECODE_CB(decode_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, - .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_ICC_PROFILES, .p.priv_class = &tiff_decoder_class, }; diff --git a/libavcodec/webp.c b/libavcodec/webp.c index bbc10ba2df..fb5688fc95 100644 --- a/libavcodec/webp.c +++ b/libavcodec/webp.c @@ -1565,4 +1565,5 @@ const FFCodec ff_webp_decoder = { FF_CODEC_DECODE_CB(webp_decode_frame), .close = webp_decode_close, .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_ICC_PROFILES, }; From patchwork Tue Jul 19 12:26:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 36835 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:1649:b0:8b:613a:194d with SMTP id no9csp1714562pzb; Tue, 19 Jul 2022 05:26:47 -0700 (PDT) X-Google-Smtp-Source: AGRyM1s39rDnxvYNYU0x1OZ48m26aj7ZVloet/LFXglmldw0+jFRITMN1+in1ts/Y5BBCQcwrhHR X-Received: by 2002:a17:907:1c8c:b0:72b:6b8f:4add with SMTP id nb12-20020a1709071c8c00b0072b6b8f4addmr29970836ejc.556.1658233607097; Tue, 19 Jul 2022 05:26:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658233607; cv=none; d=google.com; s=arc-20160816; b=JAMuk0iwm8u+csiaA9kqeS5+Z5rgD3MldJGHLzD3ab9JhL2hNxx2psiYWRrQLI20rO hJdSa5uEPks5BS+tXvx8NYCgP5PNuCTcpa+WJVqlpwC5J5UULmymnMw9x37EoLY0hBTw oFH9IHL5AxI2BKLfRDACDC0P1V1gEQFzdRkrov1MCcb66aWMDmHxGDhaO5Noiwug5Z67 NK1Q5N2Dj6RIGOoW3sF2CTO0solq6l6IQGmLNgTdIyF/yJderX521G/Dk1vWNvGdL5bl /fxt4ndMYrh8e6Ooj02FAdvpv5tR9sLa6tToddhJn4POG05stkk9kkbCcNOUnfiOGHdY mRvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=MhdTUffdozCG+h0ujwp3bwT/Yl6lLVTsj3TY3I5kglY=; b=cWP7j525Iv23xdpBVHzTAqsMZmzf5/79Dpvvxh93HBWRdyp8U8L1JEDtNE9ck1D3VX 0x316obNa8yToY+PB/ZdkOKBFkrOncvByJUh0oSQE5nygjcTbmegXyko3++7hLraIsGW N8ZZ0N5eLYZuNpOb3JEo1OkcQ+4qeQKxSpjM+2H2yqspgDOp26h0jRk/RKtGRRVbYuuH mNn2TxQOUEUL57eabQZdbDW7NxBE8t0OTJihIpLds+bBTd9BynbSOYEjiAGHVBaObGFr 0PdtVk9Ab2IOELZJfcK+YMhBC533caWylkh/SPIJ8vEjdq/uqEApLnqaxYdqN1LbInTj xP2w== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=EQCkh2Mu; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id qu16-20020a170907111000b0072642bbc8cfsi17081368ejb.914.2022.07.19.05.26.46; Tue, 19 Jul 2022 05:26:47 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=EQCkh2Mu; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 4721968B6A1; Tue, 19 Jul 2022 15:26:20 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 891BC68B590 for ; Tue, 19 Jul 2022 15:26:10 +0300 (EEST) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 4AA254A9C8; Tue, 19 Jul 2022 14:26:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1658233570; bh=LKvAv0huqSSjfxwu/67t5x5AkfMy5P/jdnymE+Rr1ps=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EQCkh2Mu5ksuxeyvYD7+fA0Ug2ZsyBUhLnEC+wROG5SQBNYI49WomWrGWp8Ai08QG EUJU22x1aQJEHMOgO7S+xMtWMAXGiH0sCu5WCMoz8ZRtHqnzuRxybOawtpwqi/v7iQ Ca7G37iNdhCF4ZpTcXx45FevDV5WvhxO9MZ9OF+4= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Tue, 19 Jul 2022 14:26:05 +0200 Message-Id: <20220719122608.43974-4-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220719122608.43974-1-ffmpeg@haasn.xyz> References: <20220719122608.43974-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 3/6] avcodec: add API for automatic handling of icc profiles X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 7chal5tzo0Dr From: Niklas Haas This functionally already exists, but as pointed out in #9672 and #9673, requiring users to manually include filters is clumsy, error-prone and hard to use together with tools like ffplay. To streamline ICC profile support, add a new AVCodecContext flag to globally enable reading and writing ICC profiles, automatically, for all appropriate media types. Note that this commit only includes the new API. The implementation is split off to separate commits for readability. Signed-off-by: Niklas Haas --- doc/APIchanges | 5 ++++- libavcodec/avcodec.h | 6 ++++++ libavcodec/version.h | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/APIchanges b/doc/APIchanges index b3563cd528..2dab01ab96 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -14,12 +14,15 @@ libavutil: 2021-04-27 API changes, most recent first: +2022-07-xx - xxxxxxxxx - lavc 59.40.100 - avcodec.h + Add the AV_CODEC_FLAG2_ICC_PROFILES flag to AVCodecContext, to enable + automatic reading and writing of embedded ICC profiles in image files. + 2022-07-xx - xxxxxxxxxx - lavu 57.30.100 - frame.h Add AVFrame.duration, deprecate AVFrame.pkt_duration. -------- 8< --------- FFmpeg 5.1 was cut here -------- 8< --------- -2022-06-12 - 7cae3d8b76 - lavf 59.25.100 - avio.h Add avio_vprintf(), similar to avio_printf() but allow to use it from within a function taking a variable argument list as input. diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index cb5c25bf63..60b215d2e9 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -331,6 +331,12 @@ typedef struct RcOverride{ * Do not reset ASS ReadOrder field on flush (subtitles decoding) */ #define AV_CODEC_FLAG2_RO_FLUSH_NOOP (1 << 30) +/** + * Generate/parse ICC profiles on encode/decode, as appropriate for the type of + * file. No effect on codecs which cannot contain embedded ICC profiles, or + * when compiled without support for lcms2. + */ +#define AV_CODEC_FLAG2_ICC_PROFILES (1U << 31) /* Unsupported options : * Syntax Arithmetic coding (SAC) diff --git a/libavcodec/version.h b/libavcodec/version.h index f2f14eaed1..19f3f4a272 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 39 +#define LIBAVCODEC_VERSION_MINOR 40 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ From patchwork Tue Jul 19 12:26:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 36836 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:1649:b0:8b:613a:194d with SMTP id no9csp1714643pzb; Tue, 19 Jul 2022 05:26:56 -0700 (PDT) X-Google-Smtp-Source: AGRyM1ucm2wv8ExuSaRMOJdpYKJc9nbNsCf0GCxxhynCvNrmAE4OjElPdeIFX+Vd27mfG9DCgZUR X-Received: by 2002:a05:6402:190b:b0:43a:c95d:ec93 with SMTP id e11-20020a056402190b00b0043ac95dec93mr42595383edz.44.1658233616084; Tue, 19 Jul 2022 05:26:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658233616; cv=none; d=google.com; s=arc-20160816; b=YhofblZsoJs14Mw1OObgaqsihRpS09clhPl59NA7OMZ4xOw9BtMgQMq4xgtQ93D+zg BRmmhcrXJGIqxCjVmlkIdmwhmddbvdeJkHM7aocm2YCIRIYv7x91gwy6KtTtSaKSQKeO 3hsrIc6K/pFcMOla7Jw37d6/Mbk+A0BJxnooejPdfJgdCLsEiw9x6LimHmaQcusSGyVM JtU22gs1pcoj5RZWU+j7Rv2192GbJXpSwbBVj2o/ESzrpK6pBbKA56bXqX3G10nDKxVe kS69cHw3riLnQRmlqpiB/QfcopCPenSLyZVc5y3so2wrK+hCDOI3Kj01K59wX3tEMA19 8+6A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=ij1+/c7Hgrhn7MMTmBo5HVvissFz+fKI69E/puJ3cwM=; b=aTVLEVA0kGi078pDIzug9/2hd5mTwRK7cA/prdbkER+xlFGe7+8zvFJv4TVg4Lks2+ qp6QN/OuiQ1Y1Sk94mei6w8eY/vj107LPYBzxvcJSAo2NL4L4qAd3F53Dv18y+waSbTg UqKVVXmrqx5U70GcKX0LxVIeEDjgdgB8VcuCtUEJsgXljB45x5WZrHgmbvNZ4BNTjT60 AMvuaKScaXElG34dV+/NI7jSuKuBeCs1Qe/WjLs6xmhATmiwdSDzIHg3zflygSRFqnAb NMaaFzDdnKa6/RgDBSd+CKexF2VuqX9YI5SXhl1bcz8fk5oGrCduxy/mEVs6OwnzMtR8 Z5bw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=Xt1UuDm6; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id o8-20020a170906974800b0072a9ec4c1fdsi22885854ejy.594.2022.07.19.05.26.55; Tue, 19 Jul 2022 05:26:56 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=Xt1UuDm6; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 2639D68B6EC; Tue, 19 Jul 2022 15:26:21 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D71C668B590 for ; Tue, 19 Jul 2022 15:26:10 +0300 (EEST) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 7F2B24A9CF; Tue, 19 Jul 2022 14:26:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1658233570; bh=yQ4UbZitGbuh8cPYgqDh2k2OdPjCdHDXTVy0bS3MfWI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Xt1UuDm6mzfbxSb82go5XqqoAhfzKRRD9joFJn+7lZ7U9cOdWPdoxefgRC44Ed+bx mmO3eAYKW9Ofuf3K0YrsllOTQcZcQOFYePSzqK9GBOpx51omoufyb+UtJkDZtgxv26 ewbKdcCmK8VgDHvIPiJXsGOC8tTqZtqXaH+VX3+E= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Tue, 19 Jul 2022 14:26:06 +0200 Message-Id: <20220719122608.43974-5-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220719122608.43974-1-ffmpeg@haasn.xyz> References: <20220719122608.43974-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 4/6] avcodec: add common fflcms2 boilerplate X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: mYTzxBQVsrDR From: Niklas Haas Handling this in general code makes more sense than handling it in individual codec files, because it would be a lot of unnecessary code duplication for the plenty of formats that support exporting ICC profiles (jpg, png, tiff, webp, jxl, ...). encode.c and decode.c will be in charge of initializing this state as needed, so we merely need to make sure to uninit it afterwards from the common destructor path. Signed-off-by: Niklas Haas --- configure | 2 +- libavcodec/Makefile | 1 + libavcodec/avcodec.c | 4 ++++ libavcodec/decode.c | 4 ++++ libavcodec/internal.h | 8 ++++++++ 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 91444cdc53..f7dbe29bfb 100755 --- a/configure +++ b/configure @@ -3813,7 +3813,7 @@ swresample_suggest="libm libsoxr stdatomic" swscale_deps="avutil" swscale_suggest="libm stdatomic" -avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs" +avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs lcms2_extralibs" avfilter_extralibs="pthreads_extralibs" avutil_extralibs="d3d11va_extralibs nanosleep_extralibs pthreads_extralibs vaapi_drm_extralibs vaapi_x11_extralibs vdpau_x11_extralibs" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index ac9fb575c5..b9a612558d 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -114,6 +114,7 @@ OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.o msmpeg4data.o OBJS-$(CONFIG_IVIDSP) += ivi_dsp.o OBJS-$(CONFIG_JNI) += ffjni.o jni.o OBJS-$(CONFIG_JPEGTABLES) += jpegtables.o +OBJS-$(CONFIG_LCMS2) += fflcms2.o OBJS-$(CONFIG_LLAUDDSP) += lossless_audiodsp.o OBJS-$(CONFIG_LLVIDDSP) += lossless_videodsp.o OBJS-$(CONFIG_LLVIDENCDSP) += lossless_videoencdsp.o diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c index fb11440e5d..7098a28b76 100644 --- a/libavcodec/avcodec.c +++ b/libavcodec/avcodec.c @@ -481,6 +481,10 @@ av_cold int avcodec_close(AVCodecContext *avctx) av_channel_layout_uninit(&avci->initial_ch_layout); +#if CONFIG_LCMS2 + ff_icc_context_uninit(&avci->icc); +#endif + av_freep(&avctx->internal); } diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 14ce4c2e2f..cc4fe3b1d5 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -49,6 +49,10 @@ #include "internal.h" #include "thread.h" +#if CONFIG_LCMS2 +# include "fflcms2.h" +#endif + static int apply_param_change(AVCodecContext *avctx, const AVPacket *avpkt) { int ret; diff --git a/libavcodec/internal.h b/libavcodec/internal.h index 17e1de8127..e284816705 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -33,6 +33,10 @@ #include "avcodec.h" #include "config.h" +#if CONFIG_LCMS2 +# include "fflcms2.h" +#endif + #define FF_SANE_NB_CHANNELS 512U #if HAVE_SIMD_ALIGN_64 @@ -148,6 +152,10 @@ typedef struct AVCodecInternal { uint64_t initial_channel_layout; #endif AVChannelLayout initial_ch_layout; + +#if CONFIG_LCMS2 + FFIccContext icc; /* used to read and write embedded ICC profiles */ +#endif } AVCodecInternal; /** From patchwork Tue Jul 19 12:26:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 36837 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:1649:b0:8b:613a:194d with SMTP id no9csp1714735pzb; Tue, 19 Jul 2022 05:27:05 -0700 (PDT) X-Google-Smtp-Source: AGRyM1vYaablKAwSMbWedpTf3a8mJPBssjLqeJhsPdLt3U9R7Wm9nOJxuXY6r4msFZgSAYz82lqI X-Received: by 2002:a17:906:ef90:b0:72b:50d5:7383 with SMTP id ze16-20020a170906ef9000b0072b50d57383mr30616322ejb.485.1658233625379; Tue, 19 Jul 2022 05:27:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658233625; cv=none; d=google.com; s=arc-20160816; b=mzblgDu8k2rkwlwT+/+Or7qXIU1YLvHUuU2GVlmKjpNbwpVQBSbtDvNl6Z1mdp3c6X LAQLeInNvCgwJrLsZ5hJgdAJPKmd4mjcw+NMhr9eDfskgMKGGXvDIH7eR4ouGfCDBbj9 DYGSr0nQMmQPh+F15krluD9TAaiGkNcYB61mxL2mXQpH5ESaMQDqYhmLdU170Aqz1xeT jNLvHdzmq+5jIWRUfDJeXyTGZopwqv13WfzT4MjzgopB2kDRJLOTmkld7YGYmTuAtdBY y9ZkowRZM86tMD1h40ju9qDDpwUQEwnD1IWk8ZoktxhOjNsZr8ugHL4bBgOUjJfLHfgm jc+A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=6lJe2g3LXyU20uILkqRPkCYt8zMYxFcztDRqAJ+8SOE=; b=0gqMTZhiSd/PsTMAFGzEj9DMeh9aJsktUp93ucXtE3Uxl2LoeEQ6xGxPOw1pRICDex 5i0v4e6ObTqVor9le0/18YxxVGelAHGahCcUDAwrwBcUKAk3RzlPNjCSHdCIMfl4nFgm Li/53RUP7QLQY4dDeRPzyXCm/CqDt8b5a0NysjfQqP9VHoyb46XENzCJXtDVv5cEyeZs PJPmPbUzMywrW5aDkqr6wydUZ24H1mYyAb0Hz1eU8C1LW8v0dbv0nh4kbi7exiXVy0mf ry7u1THWwXpay1mdI867JgIUnzF8M1YilhS16EFwuynhGN6+CGRGUDMSPJbvChLoVB7t RXWw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=vAgbNLPb; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id f24-20020a056402329800b0043a897d1de2si19119588eda.128.2022.07.19.05.27.05; Tue, 19 Jul 2022 05:27:05 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=vAgbNLPb; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 0408468B5A5; Tue, 19 Jul 2022 15:26:22 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 1C2E268B682 for ; Tue, 19 Jul 2022 15:26:15 +0300 (EEST) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id B6FEF4A9D1; Tue, 19 Jul 2022 14:26:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1658233570; bh=7m3kbu4txKsgAtPIlgIq79+cMwDOEAhBa8d6xEA+Soc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vAgbNLPb3QdINuIPr2aDbNps07ypdMp2uN9ldyqZE1Ww025a5nSLMZ+pLJ8MwZ7wS 0f1vX/tzOuHJ6opdoL0b/E6G4hjquRsdumAO+4VtpeKoGcWtYSWmeQWFFu+OEsK/8o q8AgKs6K4pqu3DNNDT7JTefe7O/0tls8G5oGC0iE= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Tue, 19 Jul 2022 14:26:07 +0200 Message-Id: <20220719122608.43974-6-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220719122608.43974-1-ffmpeg@haasn.xyz> References: <20220719122608.43974-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 5/6] avcodec/decode: parse ICC profiles X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 7AMc4l7cXC74 From: Niklas Haas Implementation for the decode side of the ICC profile API, roughly matching the behavior of the existing vf_iccdetect filter. Closes: #9673 Signed-off-by: Niklas Haas --- libavcodec/decode.c | 61 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/libavcodec/decode.c b/libavcodec/decode.c index cc4fe3b1d5..9f37d36f78 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -49,10 +49,6 @@ #include "internal.h" #include "thread.h" -#if CONFIG_LCMS2 -# include "fflcms2.h" -#endif - static int apply_param_change(AVCodecContext *avctx, const AVPacket *avpkt) { int ret; @@ -508,6 +504,54 @@ FF_ENABLE_DEPRECATION_WARNINGS return ret < 0 ? ret : 0; } +#if CONFIG_LCMS2 +static int detect_colorspace(AVCodecContext *avctx, AVFrame *frame) +{ + AVCodecInternal *avci = avctx->internal; + enum AVColorTransferCharacteristic trc; + AVColorPrimariesDesc coeffs; + enum AVColorPrimaries prim; + cmsHPROFILE profile; + AVFrameSideData *sd; + int ret; + if (!avctx->flags2 & AV_CODEC_FLAG2_ICC_PROFILES) + return 0; + + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE); + if (!sd || !sd->size) + return 0; + + if (!avci->icc.avctx) { + ret = ff_icc_context_init(&avci->icc, avctx); + if (ret < 0) + return ret; + } + + profile = cmsOpenProfileFromMemTHR(avci->icc.ctx, sd->data, sd->size); + if (!profile) + return AVERROR_INVALIDDATA; + + ret = ff_icc_profile_read_primaries(&avci->icc, profile, &coeffs); + if (!ret) + ret = ff_icc_profile_detect_transfer(&avci->icc, profile, &trc); + cmsCloseProfile(profile); + if (ret < 0) + return ret; + + prim = av_csp_primaries_id_from_desc(&coeffs); + if (prim != AVCOL_PRI_UNSPECIFIED) + frame->color_primaries = prim; + if (trc != AVCOL_TRC_UNSPECIFIED) + frame->color_trc = trc; + return 0; +} +#else /* !CONFIG_LCMS2 */ +static int detect_colorspace(av_unused AVCodecContext *c, av_unused AVFrame *f) +{ + return 0; +} +#endif + static int decode_simple_receive_frame(AVCodecContext *avctx, AVFrame *frame) { int ret; @@ -528,7 +572,7 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) { AVCodecInternal *avci = avctx->internal; const FFCodec *const codec = ffcodec(avctx->codec); - int ret; + int ret, ok; av_assert0(!frame->buf[0]); @@ -542,6 +586,13 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) if (ret == AVERROR_EOF) avci->draining_done = 1; + /* preserve ret */ + ok = detect_colorspace(avctx, frame); + if (ok < 0) { + av_frame_unref(frame); + return ok; + } + if (!(codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS) && IS_EMPTY(avci->last_pkt_props)) { // May fail if the FIFO is empty. From patchwork Tue Jul 19 12:26:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 36838 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:1649:b0:8b:613a:194d with SMTP id no9csp1714823pzb; Tue, 19 Jul 2022 05:27:14 -0700 (PDT) X-Google-Smtp-Source: AGRyM1vGxYoCLdkUGYOhk30qUszEiRFjZf18wzMyxiuetiJCkQhZdYpTaLy2k4musbQhn8Fc9Pkh X-Received: by 2002:a05:6402:1e94:b0:43a:9e92:bf2 with SMTP id f20-20020a0564021e9400b0043a9e920bf2mr43365765edf.248.1658233634479; Tue, 19 Jul 2022 05:27:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658233634; cv=none; d=google.com; s=arc-20160816; b=iqx9Rtls7gEmTWRgC5Q2OysW8IGhzILmqGwBGulqL6mOjZ907GUPioPkF3p6KAk+IO //3bCP/NIvBV89uW3N5AH7Prl/hxs3oolWG/DifR+o3WMJa1TZnjinDm1Q5qO3RpxK36 XSqr5Z3SiesuIqoT4FoyHUIDsHl8A9cYaroxnO/07F8KtedcHPy36K52oUmOEvSsz8zU xK7jJ8/P+GnUYyNJn5L2Lh4iNiNsg2GWg22+2h9oN00xLb7mMY8JGrQ3LMrnlbJTXE9w FV4nlrk9tEm163oGW7tSV4I1hlJJRfzf67rf5VvsLp8Gd/++7A3uubMvZ1r4+eAO/KFw lglA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:delivered-to; bh=5zuMXp9W21+feCk617YcssrMLHB0/WV4H0TcFJDoHtM=; b=uB9ZgoA7bbjECl1Gdr9A/mn6mt9rEjppG6DM6NR1dVg3oq+dfOuE4qt3nbIWtDpzxl JpnefxDGCrSaJUPcjyZUjKKCmVu558b97xGpSkF4qOpEoMq/t35BugqM/a1RxPbF5ltD OLDU9ci3Y8e1GbRKkjRnUIz4I2iKF6m088zrgoRLwlcsNWS2GCPfkGdzYX5D0FB7I82a K1c9qdrm8M6Ie3eZ7c0zMjIyaPsszuPFLPHoNE558ukwLD9rvV26mr3Ih24lop/rLEcV PVltZpNxe/nb+rSW0qPsD3/sYz9g2bvzQzDJQdQPsECu8iQ7Of/aIHrvQ9HumId50dzL bokw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=vePTWLYr; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id mp27-20020a1709071b1b00b0072b1307863esi19961471ejc.122.2022.07.19.05.27.14; Tue, 19 Jul 2022 05:27:14 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=vePTWLYr; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id CD84668B704; Tue, 19 Jul 2022 15:26:22 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 242DD68B687 for ; Tue, 19 Jul 2022 15:26:15 +0300 (EEST) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id E9E7A4A9D2; Tue, 19 Jul 2022 14:26:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1658233571; bh=iFqvF3U3BuDklpCMX6gZa/dYI+aDcl6UfpXve6uOnSY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vePTWLYrGVaC/hGLtPvKEux4PFtA+kIo05kSdJnI7Uk9ZJjLcV+sLN8sBh2V7GG6y DSmdABJmlmIjdz/gHMpXeO9STBRA8gh8v8xDIv+ENZ41x3/6eCuzKxbczekox/APXC qHBMMjAmbHQwyq9bn8c1zLOPdVgX/F+zCgMxDgxU= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Tue, 19 Jul 2022 14:26:08 +0200 Message-Id: <20220719122608.43974-7-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.37.1 In-Reply-To: <20220719122608.43974-1-ffmpeg@haasn.xyz> References: <20220719122608.43974-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v3 6/6] avcodec/encode:: generate ICC profiles X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: p9PlPUvo6D3a From: Niklas Haas Only if requested, and only if the codec signals support for ICC profiles. Implementation roughly matches the functionality of the existing vf_iccgen filter, albeit with some reduced flexibility and no caching. Ideally, we'd also only do this on the first frame (e.g. mjpeg, apng), but there's no meaningful way for us to distinguish between this case and e.g. somebody using the image2 muxer, in which case we'd want to attach ICC profiles to every frame in the stream. Closes: #9672 Signed-off-by: Niklas Haas --- libavcodec/encode.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/libavcodec/encode.c b/libavcodec/encode.c index 310fe20777..7cf13bf6d6 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -308,6 +308,53 @@ static int encode_receive_packet_internal(AVCodecContext *avctx, AVPacket *avpkt return ret; } +#if CONFIG_LCMS2 +static int encode_generate_icc_profile(AVCodecContext *avctx, AVFrame *frame) +{ + enum AVColorTransferCharacteristic trc = frame->color_trc; + enum AVColorPrimaries prim = frame->color_primaries; + const FFCodec *const codec = ffcodec(avctx->codec); + AVCodecInternal *avci = avctx->internal; + cmsHPROFILE profile; + int ret; + + /* don't generate ICC profiles if disabled or unsupported */ + if (!(avctx->flags2 & AV_CODEC_FLAG2_ICC_PROFILES)) + return 0; + if (!(codec->caps_internal & FF_CODEC_CAP_ICC_PROFILES)) + return 0; + + if (trc == AVCOL_TRC_UNSPECIFIED) + trc = avctx->color_trc; + if (prim == AVCOL_PRI_UNSPECIFIED) + prim = avctx->color_primaries; + if (trc == AVCOL_TRC_UNSPECIFIED || prim == AVCOL_PRI_UNSPECIFIED) + return 0; /* can't generate ICC profile with missing csp tags */ + + if (av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE)) + return 0; /* don't overwrite existing ICC profile */ + + if (!avci->icc.avctx) { + ret = ff_icc_context_init(&avci->icc, avctx); + if (ret < 0) + return ret; + } + + ret = ff_icc_profile_generate(&avci->icc, prim, trc, &profile); + if (ret < 0) + return ret; + + ret = ff_icc_profile_attach(&avci->icc, profile, frame); + cmsCloseProfile(profile); + return ret; +} +#else /* !CONFIG_LCMS2 */ +static int encode_generate_icc_profile(av_unused AVCodecContext *c, av_unused AVFrame *f) +{ + return 0; +} +#endif + static int encode_send_frame_internal(AVCodecContext *avctx, const AVFrame *src) { AVCodecInternal *avci = avctx->internal; @@ -360,6 +407,12 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif + if (avctx->codec->type == AVMEDIA_TYPE_VIDEO) { + ret = encode_generate_icc_profile(avctx, dst); + if (ret < 0) + return ret; + } + return 0; }