History

lavfi: add vf_iccdetect for parsing ICC profiles

This filter is designed to parse embedded ICC profiles and attempt extracting colorspace tags from them, updating the AVFrame metadata accordingly. This is intentionally made a separate filter, rather than being part of libavcodec itself, so that it's an opt-in behavior for the time being. This also gives the user more flexibility to e.g. first attach an ICC profile and then also set the colorspace tags from it. This makes #9673 possible, though not automatic.

Niklas Haas committed 4 years ago

Commit 2cb0ceb1 parent 5cfeaee5 files · +159 −0Browse files

Showing the changes to libavfilter (3 of 5 files). Show all

Unified · Split

3 files
  1. libavfilter/Makefile +1 −0
  2. libavfilter/allfilters.c +1 −0
  3. libavfilter/vf_iccdetect.c +142 −0
libavfilter/Makefile+1−0
@@ -322,6 +322,7 @@ OBJS-$(CONFIG_HWMAP_FILTER) += vf_hwmap.o · 321 unmodified lines
322322 OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o
323323 OBJS-$(CONFIG_HWUPLOAD_FILTER) += vf_hwupload.o
324324 OBJS-$(CONFIG_HYSTERESIS_FILTER) += vf_hysteresis.o framesync.o
325+OBJS-$(CONFIG_ICCDETECT_FILTER) += vf_iccdetect.o fflcms2.o colorspace.o
325326 OBJS-$(CONFIG_ICCGEN_FILTER) += vf_iccgen.o fflcms2.o colorspace.o
326327 OBJS-$(CONFIG_IDENTITY_FILTER) += vf_identity.o
327328 OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o
libavfilter/allfilters.c+1−0
@@ -305,6 +305,7 @@ extern const AVFilter ff_vf_hwmap; · 304 unmodified lines
305305 extern const AVFilter ff_vf_hwupload;
306306 extern const AVFilter ff_vf_hwupload_cuda;
307307 extern const AVFilter ff_vf_hysteresis;
308+extern const AVFilter ff_vf_iccdetect;
308309 extern const AVFilter ff_vf_iccgen;
309310 extern const AVFilter ff_vf_identity;
310311 extern const AVFilter ff_vf_idet;
libavfilter/vf_iccdetect.c+142−0
@@ -0,0 +1,142 @@
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+
34+typedef struct IccDetectContext {
35+ const AVClass *class;
36+ FFIccContext icc;
37+ int force;
38+ /* (cached) detected ICC profile values */
39+ AVBufferRef *profile;
40+ enum AVColorPrimaries profile_prim;
41+ enum AVColorTransferCharacteristic profile_trc;
42+} IccDetectContext;
43+
44+#define OFFSET(x) offsetof(IccDetectContext, x)
45+#define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
46+
47+static const AVOption iccdetect_options[] = {
48+ { "force", "overwrite existing tags", OFFSET(force), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, VF },
49+ { NULL }
50+};
51+
52+AVFILTER_DEFINE_CLASS(iccdetect);
53+
54+static av_cold void iccdetect_uninit(AVFilterContext *avctx)
55+{
56+ IccDetectContext *s = avctx->priv;
57+ av_buffer_unref(&s->profile);
58+ ff_icc_context_uninit(&s->icc);
59+}
60+
61+static av_cold int iccdetect_init(AVFilterContext *avctx)
62+{
63+ IccDetectContext *s = avctx->priv;
64+ return ff_icc_context_init(&s->icc, avctx);
65+}
66+
67+static int iccdetect_filter_frame(AVFilterLink *inlink, AVFrame *frame)
68+{
69+ AVFilterContext *avctx = inlink->dst;
70+ IccDetectContext *s = avctx->priv;
71+ const AVFrameSideData *sd;
72+ struct ColorPrimaries coeffs;
73+ cmsHPROFILE profile;
74+ int ret;
75+
76+ sd = av_frame_get_side_data(frame, AV_FRAME_DATA_ICC_PROFILE);
77+ if (!sd)
78+ return ff_filter_frame(inlink->dst->outputs[0], frame);
79+
80+ if (s->profile && s->profile->data == sd->buf->data) {
81+ /* No change from previous ICC profile */
82+ goto done;
83+ }
84+
85+ if ((ret = av_buffer_replace(&s->profile, sd->buf)) < 0)
86+ return ret;
87+ s->profile_prim = AVCOL_PRI_UNSPECIFIED;
88+ s->profile_trc = AVCOL_TRC_UNSPECIFIED;
89+
90+ profile = cmsOpenProfileFromMemTHR(s->icc.ctx, sd->data, sd->size);
91+ if (!profile)
92+ return AVERROR_INVALIDDATA;
93+
94+ ret = ff_icc_profile_read_primaries(&s->icc, profile, &coeffs);
95+ if (!ret)
96+ ret = ff_icc_profile_detect_transfer(&s->icc, profile, &s->profile_trc);
97+ cmsCloseProfile(profile);
98+ if (ret < 0)
99+ return ret;
100+
101+ s->profile_prim = ff_detect_color_primaries(&coeffs);
102+
103+done:
104+ if (s->profile_prim != AVCOL_PRI_UNSPECIFIED) {
105+ if (s->force || frame->color_primaries == AVCOL_PRI_UNSPECIFIED)
106+ frame->color_primaries = s->profile_prim;
107+ }
108+
109+ if (s->profile_trc != AVCOL_TRC_UNSPECIFIED) {
110+ if (s->force || frame->color_trc == AVCOL_TRC_UNSPECIFIED)
111+ frame->color_trc = s->profile_trc;
112+ }
113+
114+ return ff_filter_frame(inlink->dst->outputs[0], frame);
115+}
116+
117+static const AVFilterPad iccdetect_inputs[] = {
118+ {
119+ .name = "default",
120+ .type = AVMEDIA_TYPE_VIDEO,
121+ .filter_frame = iccdetect_filter_frame,
122+ },
123+};
124+
125+static const AVFilterPad iccdetect_outputs[] = {
126+ {
127+ .name = "default",
128+ .type = AVMEDIA_TYPE_VIDEO,
129+ },
130+};
131+
132+const AVFilter ff_vf_iccdetect = {
133+ .name = "iccdetect",
134+ .description = NULL_IF_CONFIG_SMALL("Detect and parse ICC profiles."),
135+ .priv_size = sizeof(IccDetectContext),
136+ .priv_class = &iccdetect_class,
137+ .flags = AVFILTER_FLAG_METADATA_ONLY,
138+ .init = &iccdetect_init,
139+ .uninit = &iccdetect_uninit,
140+ FILTER_INPUTS(iccdetect_inputs),
141+ FILTER_OUTPUTS(iccdetect_outputs),
142+};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t