avformat/mxfdec: Check edit unit for overflow in mxf_set_current_edit_unit()
[FFMpeg-mirror.git] / libavfilter / vf_iccgen.c
blob06c5b4ebdc20a3e7805b788e1a9b61f122ac54e6
1 /*
2 * Copyright (c) 2022 Niklas Haas
3 * This file is part of FFmpeg.
5 * FFmpeg is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * FFmpeg is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with FFmpeg; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 /**
21 * @file
22 * filter for generating ICC profiles
25 #include <lcms2.h>
27 #include "libavutil/opt.h"
28 #include "libavutil/pixdesc.h"
30 #include "avfilter.h"
31 #include "fflcms2.h"
32 #include "filters.h"
33 #include "video.h"
35 typedef struct IccGenContext {
36 const AVClass *class;
37 FFIccContext icc;
38 /* options */
39 int color_prim;
40 int color_trc;
41 int force;
42 /* (cached) generated ICC profile */
43 cmsHPROFILE profile;
44 int profile_prim;
45 int profile_trc;
46 } IccGenContext;
48 #define OFFSET(x) offsetof(IccGenContext, x)
49 #define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
51 static const AVOption iccgen_options[] = {
52 {"color_primaries", "select color primaries", OFFSET(color_prim), AV_OPT_TYPE_INT, {.i64=0}, 0, AVCOL_PRI_NB-1, VF, .unit = "color_primaries"},
53 {"auto", "infer based on frame", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, VF, .unit = "color_primaries"},
54 {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709}, 0, 0, VF, .unit = "color_primaries"},
55 {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470M}, 0, 0, VF, .unit = "color_primaries"},
56 {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470BG}, 0, 0, VF, .unit = "color_primaries"},
57 {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE170M}, 0, 0, VF, .unit = "color_primaries"},
58 {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE240M}, 0, 0, VF, .unit = "color_primaries"},
59 {"film", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_FILM}, 0, 0, VF, .unit = "color_primaries"},
60 {"bt2020", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT2020}, 0, 0, VF, .unit = "color_primaries"},
61 {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE428}, 0, 0, VF, .unit = "color_primaries"},
62 {"smpte431", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE431}, 0, 0, VF, .unit = "color_primaries"},
63 {"smpte432", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE432}, 0, 0, VF, .unit = "color_primaries"},
64 {"jedec-p22", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_JEDEC_P22}, 0, 0, VF, .unit = "color_primaries"},
65 {"ebu3213", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_EBU3213}, 0, 0, VF, .unit = "color_primaries"},
66 {"color_trc", "select color transfer", OFFSET(color_trc), AV_OPT_TYPE_INT, {.i64=0}, 0, AVCOL_TRC_NB-1, VF, .unit = "color_trc"},
67 {"auto", "infer based on frame", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, VF, .unit = "color_trc"},
68 {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709}, 0, 0, VF, .unit = "color_trc"},
69 {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA22}, 0, 0, VF, .unit = "color_trc"},
70 {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA28}, 0, 0, VF, .unit = "color_trc"},
71 {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE170M}, 0, 0, VF, .unit = "color_trc"},
72 {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE240M}, 0, 0, VF, .unit = "color_trc"},
73 {"linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LINEAR}, 0, 0, VF, .unit = "color_trc"},
74 {"iec61966-2-4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_4}, 0, 0, VF, .unit = "color_trc"},
75 {"bt1361e", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT1361_ECG}, 0, 0, VF, .unit = "color_trc"},
76 {"iec61966-2-1", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_1}, 0, 0, VF, .unit = "color_trc"},
77 {"bt2020-10", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_10}, 0, 0, VF, .unit = "color_trc"},
78 {"bt2020-12", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_12}, 0, 0, VF, .unit = "color_trc"},
79 {"smpte2084", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE2084}, 0, 0, VF, .unit = "color_trc"},
80 {"arib-std-b67", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_ARIB_STD_B67}, 0, 0, VF, .unit = "color_trc"},
81 { "force", "overwrite existing ICC profile", OFFSET(force), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, VF },
82 { NULL }
85 AVFILTER_DEFINE_CLASS(iccgen);
87 static av_cold void iccgen_uninit(AVFilterContext *avctx)
89 IccGenContext *s = avctx->priv;
90 cmsCloseProfile(s->profile);
91 ff_icc_context_uninit(&s->icc);
94 static av_cold int iccgen_init(AVFilterContext *avctx)
96 IccGenContext *s = avctx->priv;
97 return ff_icc_context_init(&s->icc, avctx);
100 static int iccgen_filter_frame(AVFilterLink *inlink, AVFrame *frame)
102 AVFilterContext *avctx = inlink->dst;
103 IccGenContext *s = avctx->priv;
104 enum AVColorTransferCharacteristic trc;
105 enum AVColorPrimaries prim;
106 int ret;
108 if (av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE)) {
109 if (s->force) {
110 av_frame_remove_side_data(frame, AV_FRAME_DATA_ICC_PROFILE);
111 } else {
112 return ff_filter_frame(inlink->dst->outputs[0], frame);
116 trc = s->color_trc ? s->color_trc : frame->color_trc;
117 if (trc == AVCOL_TRC_UNSPECIFIED) {
118 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
119 if (!desc)
120 return AVERROR_INVALIDDATA;
122 if ((desc->flags & AV_PIX_FMT_FLAG_RGB) || frame->color_range == AVCOL_RANGE_JPEG) {
123 /* Default to sRGB for RGB or full-range content */
124 trc = AVCOL_TRC_IEC61966_2_1;
125 } else {
126 /* Default to an ITU-R transfer depending on the bit-depth */
127 trc = desc->comp[0].depth >= 12 ? AVCOL_TRC_BT2020_12
128 : desc->comp[0].depth >= 10 ? AVCOL_TRC_BT2020_10
129 : AVCOL_TRC_BT709;
133 prim = s->color_prim ? s->color_prim : frame->color_primaries;
134 if (prim == AVCOL_PRI_UNSPECIFIED) {
135 /* Simply always default to sRGB/BT.709 primaries to avoid surprises */
136 prim = AVCOL_PRI_BT709;
139 if (s->profile && prim != s->profile_prim && trc != s->profile_trc) {
140 cmsCloseProfile(s->profile);
141 s->profile = NULL;
144 if (!s->profile) {
145 if ((ret = ff_icc_profile_generate(&s->icc, prim, trc, &s->profile)) < 0)
146 return ret;
147 s->profile_prim = prim;
148 s->profile_trc = trc;
151 if ((ret = ff_icc_profile_attach(&s->icc, s->profile, frame)) < 0)
152 return ret;
154 return ff_filter_frame(inlink->dst->outputs[0], frame);
157 static const AVFilterPad iccgen_inputs[] = {
159 .name = "default",
160 .type = AVMEDIA_TYPE_VIDEO,
161 .filter_frame = iccgen_filter_frame,
165 const FFFilter ff_vf_iccgen = {
166 .p.name = "iccgen",
167 .p.description = NULL_IF_CONFIG_SMALL("Generate and attach ICC profiles."),
168 .p.priv_class = &iccgen_class,
169 .p.flags = AVFILTER_FLAG_METADATA_ONLY,
170 .priv_size = sizeof(IccGenContext),
171 .init = &iccgen_init,
172 .uninit = &iccgen_uninit,
173 FILTER_INPUTS(iccgen_inputs),
174 FILTER_OUTPUTS(ff_video_default_filterpad),