FFmpeg
vf_iccgen.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2022 Niklas Haas
3  * This file is part of FFmpeg.
4  *
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.
9  *
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.
14  *
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
18  */
19 
20 /**
21  * @file
22  * filter for generating ICC profiles
23  */
24 
25 #include <lcms2.h>
26 
27 #include "libavutil/opt.h"
28 #include "libavutil/pixdesc.h"
29 
30 #include "avfilter.h"
31 #include "fflcms2.h"
32 #include "internal.h"
33 #include "video.h"
34 
35 typedef struct IccGenContext {
36  const AVClass *class;
38  /* options */
40  int color_trc;
41  int force;
42  /* (cached) generated ICC profile */
43  cmsHPROFILE profile;
47 
48 #define OFFSET(x) offsetof(IccGenContext, x)
49 #define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
50 
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 }
83 };
84 
85 AVFILTER_DEFINE_CLASS(iccgen);
86 
88 {
89  IccGenContext *s = avctx->priv;
90  cmsCloseProfile(s->profile);
91  ff_icc_context_uninit(&s->icc);
92 }
93 
95 {
96  IccGenContext *s = avctx->priv;
97  return ff_icc_context_init(&s->icc, avctx);
98 }
99 
101 {
102  AVFilterContext *avctx = inlink->dst;
103  IccGenContext *s = avctx->priv;
105  enum AVColorPrimaries prim;
106  int ret;
107 
109  if (s->force) {
111  } else {
112  return ff_filter_frame(inlink->dst->outputs[0], frame);
113  }
114  }
115 
116  trc = s->color_trc ? s->color_trc : frame->color_trc;
117  if (trc == AVCOL_TRC_UNSPECIFIED) {
119  if (!desc)
120  return AVERROR_INVALIDDATA;
121 
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 */
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;
130  }
131  }
132 
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;
137  }
138 
139  if (s->profile && prim != s->profile_prim && trc != s->profile_trc) {
140  cmsCloseProfile(s->profile);
141  s->profile = NULL;
142  }
143 
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;
149  }
150 
151  if ((ret = ff_icc_profile_attach(&s->icc, s->profile, frame)) < 0)
152  return ret;
153 
154  return ff_filter_frame(inlink->dst->outputs[0], frame);
155 }
156 
157 static const AVFilterPad iccgen_inputs[] = {
158  {
159  .name = "default",
160  .type = AVMEDIA_TYPE_VIDEO,
161  .filter_frame = iccgen_filter_frame,
162  },
163 };
164 
166  .name = "iccgen",
167  .description = NULL_IF_CONFIG_SMALL("Generate and attach ICC profiles."),
168  .priv_size = sizeof(IccGenContext),
169  .priv_class = &iccgen_class,
171  .init = &iccgen_init,
172  .uninit = &iccgen_uninit,
175 };
IccGenContext
Definition: vf_iccgen.c:35
AVCOL_PRI_EBU3213
@ AVCOL_PRI_EBU3213
EBU Tech. 3213-E (nothing there) / one of JEDEC P22 group phosphors.
Definition: pixfmt.h:571
opt.h
AVColorTransferCharacteristic
AVColorTransferCharacteristic
Color Transfer Characteristic.
Definition: pixfmt.h:580
av_frame_get_side_data
AVFrameSideData * av_frame_get_side_data(const AVFrame *frame, enum AVFrameSideDataType type)
Definition: frame.c:947
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1015
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:2965
AVCOL_TRC_LINEAR
@ AVCOL_TRC_LINEAR
"Linear transfer characteristics"
Definition: pixfmt.h:589
inlink
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
Definition: filter_design.txt:212
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:374
AVCOL_TRC_NB
@ AVCOL_TRC_NB
Not part of ABI.
Definition: pixfmt.h:602
pixdesc.h
AVCOL_RANGE_JPEG
@ AVCOL_RANGE_JPEG
Full range content.
Definition: pixfmt.h:686
AVOption
AVOption.
Definition: opt.h:346
AVCOL_TRC_UNSPECIFIED
@ AVCOL_TRC_UNSPECIFIED
Definition: pixfmt.h:583
iccgen_init
static av_cold int iccgen_init(AVFilterContext *avctx)
Definition: vf_iccgen.c:94
AVCOL_PRI_JEDEC_P22
@ AVCOL_PRI_JEDEC_P22
Definition: pixfmt.h:572
AVCOL_TRC_BT2020_12
@ AVCOL_TRC_BT2020_12
ITU-R BT2020 for 12-bit system.
Definition: pixfmt.h:596
AVColorPrimaries
AVColorPrimaries
Chromaticity coordinates of the source primaries.
Definition: pixfmt.h:555
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:170
fflcms2.h
ff_icc_profile_attach
int ff_icc_profile_attach(FFIccContext *s, cmsHPROFILE profile, AVFrame *frame)
Attach an ICC profile to a frame.
Definition: fflcms2.c:172
video.h
ff_vf_iccgen
const AVFilter ff_vf_iccgen
Definition: vf_iccgen.c:165
AVCOL_TRC_IEC61966_2_1
@ AVCOL_TRC_IEC61966_2_1
IEC 61966-2-1 (sRGB or sYCC)
Definition: pixfmt.h:594
AVFilterContext::priv
void * priv
private data for use by the filter
Definition: avfilter.h:422
ff_icc_context_init
int ff_icc_context_init(FFIccContext *s, void *avctx)
Initializes an FFIccContext.
Definition: fflcms2.c:30
AVCOL_TRC_GAMMA28
@ AVCOL_TRC_GAMMA28
also ITU-R BT470BG
Definition: pixfmt.h:586
IccGenContext::color_prim
int color_prim
Definition: vf_iccgen.c:39
AVCOL_TRC_GAMMA22
@ AVCOL_TRC_GAMMA22
also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM
Definition: pixfmt.h:585
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:33
av_cold
#define av_cold
Definition: attributes.h:90
ff_video_default_filterpad
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition: video.c:37
s
#define s(width, name)
Definition: cbs_vp9.c:198
AVCOL_PRI_NB
@ AVCOL_PRI_NB
Not part of ABI.
Definition: pixfmt.h:573
AVCOL_TRC_BT1361_ECG
@ AVCOL_TRC_BT1361_ECG
ITU-R BT1361 Extended Colour Gamut.
Definition: pixfmt.h:593
IccGenContext::force
int force
Definition: vf_iccgen.c:41
AVCOL_PRI_SMPTE428
@ AVCOL_PRI_SMPTE428
SMPTE ST 428-1 (CIE 1931 XYZ)
Definition: pixfmt.h:567
ff_icc_context_uninit
void ff_icc_context_uninit(FFIccContext *s)
Definition: fflcms2.c:42
AVCOL_PRI_SMPTE240M
@ AVCOL_PRI_SMPTE240M
identical to above, also called "SMPTE C" even though it uses D65
Definition: pixfmt.h:564
AVCOL_PRI_UNSPECIFIED
@ AVCOL_PRI_UNSPECIFIED
Definition: pixfmt.h:558
FILTER_INPUTS
#define FILTER_INPUTS(array)
Definition: internal.h:182
AVCOL_PRI_BT470BG
@ AVCOL_PRI_BT470BG
also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM
Definition: pixfmt.h:562
AVCOL_PRI_SMPTE170M
@ AVCOL_PRI_SMPTE170M
also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC
Definition: pixfmt.h:563
IccGenContext::profile_trc
int profile_trc
Definition: vf_iccgen.c:45
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
AVCOL_TRC_IEC61966_2_4
@ AVCOL_TRC_IEC61966_2_4
IEC 61966-2-4.
Definition: pixfmt.h:592
AVCOL_PRI_BT709
@ AVCOL_PRI_BT709
also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP 177 Annex B
Definition: pixfmt.h:557
AV_FRAME_DATA_ICC_PROFILE
@ AV_FRAME_DATA_ICC_PROFILE
The data contains an ICC profile as an opaque octet buffer following the format described by ISO 1507...
Definition: frame.h:144
AVCOL_TRC_BT2020_10
@ AVCOL_TRC_BT2020_10
ITU-R BT2020 for 10-bit system.
Definition: pixfmt.h:595
AVCOL_PRI_BT2020
@ AVCOL_PRI_BT2020
ITU-R BT2020.
Definition: pixfmt.h:566
ff_icc_profile_generate
int ff_icc_profile_generate(FFIccContext *s, enum AVColorPrimaries color_prim, enum AVColorTransferCharacteristic color_trc, cmsHPROFILE *out_profile)
Generate an ICC profile for a given combination of color primaries and transfer function.
Definition: fflcms2.c:145
AVCOL_TRC_SMPTE2084
@ AVCOL_TRC_SMPTE2084
SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems.
Definition: pixfmt.h:597
AVCOL_PRI_SMPTE431
@ AVCOL_PRI_SMPTE431
SMPTE ST 431-2 (2011) / DCI P3.
Definition: pixfmt.h:569
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:366
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
AVCOL_TRC_SMPTE240M
@ AVCOL_TRC_SMPTE240M
Definition: pixfmt.h:588
AVCOL_PRI_FILM
@ AVCOL_PRI_FILM
colour filters using Illuminant C
Definition: pixfmt.h:565
AV_PIX_FMT_FLAG_RGB
#define AV_PIX_FMT_FLAG_RGB
The pixel format contains RGB-like data (as opposed to YUV/grayscale).
Definition: pixdesc.h:136
iccgen_uninit
static av_cold void iccgen_uninit(AVFilterContext *avctx)
Definition: vf_iccgen.c:87
av_frame_remove_side_data
void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type)
Remove and free all side data instances of the given type.
Definition: frame.c:1013
OFFSET
#define OFFSET(x)
Definition: vf_iccgen.c:48
AVCOL_TRC_BT709
@ AVCOL_TRC_BT709
also ITU-R BT1361
Definition: pixfmt.h:582
internal.h
uninit
static void uninit(AVBSFContext *ctx)
Definition: pcm_rechunk.c:68
FFIccContext
Definition: fflcms2.h:34
VF
#define VF
Definition: vf_iccgen.c:49
iccgen_inputs
static const AVFilterPad iccgen_inputs[]
Definition: vf_iccgen.c:157
IccGenContext::icc
FFIccContext icc
Definition: vf_iccgen.c:37
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:39
AVFilter
Filter definition.
Definition: avfilter.h:166
AVCOL_PRI_BT470M
@ AVCOL_PRI_BT470M
also FCC Title 47 Code of Federal Regulations 73.682 (a)(20)
Definition: pixfmt.h:560
ret
ret
Definition: filter_design.txt:187
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(iccgen)
AVCOL_TRC_ARIB_STD_B67
@ AVCOL_TRC_ARIB_STD_B67
ARIB STD-B67, known as "Hybrid log-gamma".
Definition: pixfmt.h:601
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:235
avfilter.h
AVFILTER_FLAG_METADATA_ONLY
#define AVFILTER_FLAG_METADATA_ONLY
The filter is a "metadata" filter - it does not modify the frame data in any way.
Definition: avfilter.h:133
AVCOL_TRC_SMPTE170M
@ AVCOL_TRC_SMPTE170M
also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC
Definition: pixfmt.h:587
IccGenContext::profile_prim
int profile_prim
Definition: vf_iccgen.c:44
AVFilterContext
An instance of a filter.
Definition: avfilter.h:407
desc
const char * desc
Definition: libsvtav1.c:79
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
IccGenContext::color_trc
int color_trc
Definition: vf_iccgen.c:40
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
AVCOL_PRI_SMPTE432
@ AVCOL_PRI_SMPTE432
SMPTE ST 432-1 (2010) / P3 D65 / Display P3.
Definition: pixfmt.h:570
IccGenContext::profile
cmsHPROFILE profile
Definition: vf_iccgen.c:43
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:251
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:183
iccgen_options
static const AVOption iccgen_options[]
Definition: vf_iccgen.c:51
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
iccgen_filter_frame
static int iccgen_filter_frame(AVFilterLink *inlink, AVFrame *frame)
Definition: vf_iccgen.c:100
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:244