From: Niklas Haas <ffmpeg@haasn.xyz> To: ffmpeg-devel@ffmpeg.org Cc: Niklas Haas <git@haasn.dev> Subject: [FFmpeg-devel] [PATCH 4/5] lavfi: add vf_iccgen for generating ICC profiles Date: Mon, 11 Apr 2022 17:36:53 +0200 Message-ID: <20220411153654.116722-4-ffmpeg@haasn.xyz> (raw) In-Reply-To: <20220411153654.116722-1-ffmpeg@haasn.xyz> From: Niklas Haas <git@haasn.dev> This filter is designed to specifically cover the task of generating ICC profiles (and attaching them to output frames) on demand. Other tasks, such as ICC profile loading/stripping, or ICC profile application, are better left to separate filters (or included into e.g. vf_setparams). Signed-off-by: Niklas Haas <git@haasn.dev> --- configure | 1 + doc/filters.texi | 21 +++++ libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/vf_iccgen.c | 179 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 libavfilter/vf_iccgen.c diff --git a/configure b/configure index 1a9c3dcd3c..d64ccf7181 100755 --- a/configure +++ b/configure @@ -3659,6 +3659,7 @@ gblur_vulkan_filter_deps="vulkan spirv_compiler" hflip_vulkan_filter_deps="vulkan spirv_compiler" histeq_filter_deps="gpl" hqdn3d_filter_deps="gpl" +iccgen_filter_deps="lcms2" interlace_filter_deps="gpl" kerndeint_filter_deps="gpl" ladspa_filter_deps="ladspa libdl" diff --git a/doc/filters.texi b/doc/filters.texi index 4e9b0e0111..9673858355 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -14304,6 +14304,27 @@ By default value is 0. The @code{hysteresis} filter also supports the @ref{framesync} options. +@section iccgen + +Generate ICC profiles and attach them to frames. + +This filter accepts the following options: + +@table @option +@item color_primaries +@item color_trc +Configure the colorspace that the ICC profile will be generated for. The +default value of @code{auto} infers the value from the input frame's metadata, +defaulting to BT.709/sRGB as appropriate. + +See the @ref{setparams} filter for a list of possible values, but note that +@code{unknown} are not valid values for this filter. + +@item force +If true, an ICC profile will be generated even if it would overwrite an +already existing ICC profile. Disabled by default. +@end table + @section identity Obtain the identity score between two input videos. diff --git a/libavfilter/Makefile b/libavfilter/Makefile index c4c946a988..8ffc53d751 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -320,6 +320,7 @@ OBJS-$(CONFIG_HWMAP_FILTER) += vf_hwmap.o OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o OBJS-$(CONFIG_HWUPLOAD_FILTER) += vf_hwupload.o OBJS-$(CONFIG_HYSTERESIS_FILTER) += vf_hysteresis.o framesync.o +OBJS-$(CONFIG_ICCGEN_FILTER) += vf_iccgen.o fflcms2.o colorspace.o OBJS-$(CONFIG_IDENTITY_FILTER) += vf_identity.o OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o OBJS-$(CONFIG_IL_FILTER) += vf_il.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 9fbaaacf47..d43f4b45b1 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -303,6 +303,7 @@ extern const AVFilter ff_vf_hwmap; extern const AVFilter ff_vf_hwupload; extern const AVFilter ff_vf_hwupload_cuda; extern const AVFilter ff_vf_hysteresis; +extern const AVFilter ff_vf_iccgen; extern const AVFilter ff_vf_identity; extern const AVFilter ff_vf_idet; extern const AVFilter ff_vf_il; diff --git a/libavfilter/vf_iccgen.c b/libavfilter/vf_iccgen.c new file mode 100644 index 0000000000..afc924e291 --- /dev/null +++ b/libavfilter/vf_iccgen.c @@ -0,0 +1,179 @@ +/* + * 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 + * filter for generating ICC profiles + */ + +#include <lcms2.h> + +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "fflcms2.h" +#include "internal.h" + +typedef struct IccGenContext { + const AVClass *class; + FFIccContext icc; + /* options */ + int color_prim; + int color_trc; + int force; + /* (cached) generated ICC profile */ + cmsHPROFILE profile; + int profile_prim; + int profile_trc; +} IccGenContext; + +#define OFFSET(x) offsetof(IccGenContext, x) +#define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption iccgen_options[] = { + {"color_primaries", "select color primaries", OFFSET(color_prim), AV_OPT_TYPE_INT, {.i64=0}, 0, AVCOL_PRI_NB-1, VF, "color_primaries"}, + {"auto", "infer based on frame", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, VF, "color_primaries"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709}, 0, 0, VF, "color_primaries"}, + {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470M}, 0, 0, VF, "color_primaries"}, + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470BG}, 0, 0, VF, "color_primaries"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE170M}, 0, 0, VF, "color_primaries"}, + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE240M}, 0, 0, VF, "color_primaries"}, + {"film", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_FILM}, 0, 0, VF, "color_primaries"}, + {"bt2020", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT2020}, 0, 0, VF, "color_primaries"}, + {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE428}, 0, 0, VF, "color_primaries"}, + {"smpte431", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE431}, 0, 0, VF, "color_primaries"}, + {"smpte432", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE432}, 0, 0, VF, "color_primaries"}, + {"jedec-p22", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_JEDEC_P22}, 0, 0, VF, "color_primaries"}, + {"ebu3213", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_EBU3213}, 0, 0, VF, "color_primaries"}, + {"color_trc", "select color transfer", OFFSET(color_trc), AV_OPT_TYPE_INT, {.i64=0}, 0, AVCOL_TRC_NB-1, VF, "color_trc"}, + {"auto", "infer based on frame", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, VF, "color_trc"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709}, 0, 0, VF, "color_trc"}, + {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA22}, 0, 0, VF, "color_trc"}, + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA28}, 0, 0, VF, "color_trc"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE170M}, 0, 0, VF, "color_trc"}, + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE240M}, 0, 0, VF, "color_trc"}, + {"linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LINEAR}, 0, 0, VF, "color_trc"}, + {"iec61966-2-4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_4}, 0, 0, VF, "color_trc"}, + {"bt1361e", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT1361_ECG}, 0, 0, VF, "color_trc"}, + {"iec61966-2-1", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_1}, 0, 0, VF, "color_trc"}, + {"bt2020-10", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_10}, 0, 0, VF, "color_trc"}, + {"bt2020-12", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_12}, 0, 0, VF, "color_trc"}, + {"smpte2084", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE2084}, 0, 0, VF, "color_trc"}, + {"arib-std-b67", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_ARIB_STD_B67}, 0, 0, VF, "color_trc"}, + { "force", "overwrite existing ICC profile", OFFSET(force), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, VF }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(iccgen); + +static av_cold void iccgen_uninit(AVFilterContext *avctx) +{ + IccGenContext *s = avctx->priv; + cmsCloseProfile(s->profile); + ff_icc_context_uninit(&s->icc); +} + +static av_cold int iccgen_init(AVFilterContext *avctx) +{ + IccGenContext *s = avctx->priv; + return ff_icc_context_init(&s->icc, avctx); +} + +static int iccgen_filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + AVFilterContext *avctx = inlink->dst; + IccGenContext *s = avctx->priv; + enum AVColorTransferCharacteristic trc; + enum AVColorPrimaries prim; + int ret; + + if (av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE)) { + if (s->force) { + av_frame_remove_side_data(frame, AV_FRAME_DATA_ICC_PROFILE); + } else { + return ff_filter_frame(inlink->dst->outputs[0], frame); + } + } + + trc = s->color_trc ? s->color_trc : frame->color_trc; + if (!trc || trc == AVCOL_TRC_UNSPECIFIED) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + if (!desc) + return AVERROR_INVALIDDATA; + + if ((desc->flags & AV_PIX_FMT_FLAG_RGB) || frame->color_range == AVCOL_RANGE_JPEG) { + /* Default to sRGB for RGB or full-range content */ + trc = AVCOL_TRC_IEC61966_2_1; + } else { + /* Default to an ITU-R transfer depending on the bit-depth */ + trc = desc->comp[0].depth >= 12 ? AVCOL_TRC_BT2020_12 + : desc->comp[0].depth >= 10 ? AVCOL_TRC_BT2020_10 + : AVCOL_TRC_BT709; + } + } + + prim = s->color_prim ? s->color_prim : frame->color_primaries; + if (!prim || prim == AVCOL_PRI_UNSPECIFIED) { + /* Simply always default to sRGB/BT.709 primaries to avoid surprises */ + prim = AVCOL_PRI_BT709; + } + + if (s->profile && prim != s->profile_prim && trc != s->profile_trc) { + cmsCloseProfile(s->profile); + s->profile = NULL; + } + + if (!s->profile) { + if ((ret = ff_icc_profile_generate(&s->icc, prim, trc, &s->profile)) < 0) + return ret; + } + + if ((ret = ff_icc_profile_attach(&s->icc, s->profile, frame)) < 0) + return ret; + + return ff_filter_frame(inlink->dst->outputs[0], frame); +} + +static const AVFilterPad iccgen_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = iccgen_filter_frame, + }, +}; + +static const AVFilterPad iccgen_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, +}; + +const AVFilter ff_vf_iccgen = { + .name = "iccgen", + .description = NULL_IF_CONFIG_SMALL("Generate and attach ICC profiles."), + .priv_size = sizeof(IccGenContext), + .priv_class = &iccgen_class, + .flags = AVFILTER_FLAG_METADATA_ONLY, + .init = &iccgen_init, + .uninit = &iccgen_uninit, + FILTER_INPUTS(iccgen_inputs), + FILTER_OUTPUTS(iccgen_outputs), +}; -- 2.35.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
next prev parent reply other threads:[~2022-04-11 15:37 UTC|newest] Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top 2022-04-11 15:36 [FFmpeg-devel] [PATCH 1/5] lavfi: generalize colorspace coefficent helpers Niklas Haas 2022-04-11 15:36 ` [FFmpeg-devel] [PATCH 2/5] lavfi: add ff_detect_color_primaries helper Niklas Haas 2022-04-11 15:36 ` [FFmpeg-devel] [PATCH 3/5] lavfi: add ICC profile support via lcms2 Niklas Haas 2022-04-11 15:36 ` Niklas Haas [this message] 2022-04-11 15:36 ` [FFmpeg-devel] [PATCH 5/5] lavfi: add vf_iccdetect for parsing ICC profiles Niklas Haas
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20220411153654.116722-4-ffmpeg@haasn.xyz \ --to=ffmpeg@haasn.xyz \ --cc=ffmpeg-devel@ffmpeg.org \ --cc=git@haasn.dev \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git