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
322OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o322OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o
323OBJS-$(CONFIG_HWUPLOAD_FILTER) += vf_hwupload.o323OBJS-$(CONFIG_HWUPLOAD_FILTER) += vf_hwupload.o
324OBJS-$(CONFIG_HYSTERESIS_FILTER) += vf_hysteresis.o framesync.o324OBJS-$(CONFIG_HYSTERESIS_FILTER) += vf_hysteresis.o framesync.o
325OBJS-$(CONFIG_ICCDETECT_FILTER) += vf_iccdetect.o fflcms2.o colorspace.o
325OBJS-$(CONFIG_ICCGEN_FILTER) += vf_iccgen.o fflcms2.o colorspace.o326OBJS-$(CONFIG_ICCGEN_FILTER) += vf_iccgen.o fflcms2.o colorspace.o
326OBJS-$(CONFIG_IDENTITY_FILTER) += vf_identity.o327OBJS-$(CONFIG_IDENTITY_FILTER) += vf_identity.o
327OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o328OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o
libavfilter/allfilters.c+1−0
@@ -305,6 +305,7 @@ extern const AVFilter ff_vf_hwmap; · 304 unmodified lines
305extern const AVFilter ff_vf_hwupload;305extern const AVFilter ff_vf_hwupload;
306extern const AVFilter ff_vf_hwupload_cuda;306extern const AVFilter ff_vf_hwupload_cuda;
307extern const AVFilter ff_vf_hysteresis;307extern const AVFilter ff_vf_hysteresis;
308extern const AVFilter ff_vf_iccdetect;
308extern const AVFilter ff_vf_iccgen;309extern const AVFilter ff_vf_iccgen;
309extern const AVFilter ff_vf_identity;310extern const AVFilter ff_vf_identity;
310extern const AVFilter ff_vf_idet;311extern 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
34typedef 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
47static const AVOption iccdetect_options[] = {
48 { "force", "overwrite existing tags", OFFSET(force), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, VF },
49 { NULL }
50};
51
52AVFILTER_DEFINE_CLASS(iccdetect);
53
54static 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
61static av_cold int iccdetect_init(AVFilterContext *avctx)
62{
63 IccDetectContext *s = avctx->priv;
64 return ff_icc_context_init(&s->icc, avctx);
65}
66
67static 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
103done:
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
117static const AVFilterPad iccdetect_inputs[] = {
118 {
119 .name = "default",
120 .type = AVMEDIA_TYPE_VIDEO,
121 .filter_frame = iccdetect_filter_frame,
122 },
123};
124
125static const AVFilterPad iccdetect_outputs[] = {
126 {
127 .name = "default",
128 .type = AVMEDIA_TYPE_VIDEO,
129 },
130};
131
132const 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