History

avfilter/vf_colorlevels: add preserve color option

Paul B Mahol committed 5 years ago

Commit 34102f81 parent 4727e303 files · +166 −11Browse files

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

Unified · Split

2 files
  1. libavfilter/preserve_color.h +83 −0
  2. libavfilter/vf_colorlevels.c +64 −11
libavfilter/preserve_color.h+83−0
@@ -0,0 +1,83 @@
1+/*
2+ * This file is part of FFmpeg.
3+ *
4+ * FFmpeg is free software; you can redistribute it and/or
5+ * modify it under the terms of the GNU Lesser General Public
6+ * License as published by the Free Software Foundation; either
7+ * version 2.1 of the License, or (at your option) any later version.
8+ *
9+ * FFmpeg is distributed in the hope that it will be useful,
10+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ * Lesser General Public License for more details.
13+ *
14+ * You should have received a copy of the GNU Lesser General Public
15+ * License along with FFmpeg; if not, write to the Free Software
16+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+#ifndef AVFILTER_PRESERVE_COLOR_H
20+#define AVFILTER_PRESERVE_COLOR_H
21+
22+enum {
23+ P_NONE,
24+ P_LUM,
25+ P_MAX,
26+ P_AVG,
27+ P_SUM,
28+ P_NRM,
29+ P_PWR,
30+ NB_PRESERVE
31+};
32+
33+static inline float normalize(float r, float g, float b, float max)
34+{
35+ r /= max;
36+ g /= max;
37+ b /= max;
38+ return sqrtf(r * r + g * g + b * b);
39+}
40+
41+static inline float power(float r, float g, float b, float max)
42+{
43+ r /= max;
44+ g /= max;
45+ b /= max;
46+ return cbrtf(r * r * r + g * g * g + b * b * b);
47+}
48+
49+static inline void preserve_color(int preserve_color,
50+ float ir, float ig, float ib,
51+ float r, float g, float b,
52+ float max,
53+ float *icolor, float *ocolor)
54+{
55+ switch (preserve_color) {
56+ case P_LUM:
57+ *icolor = FFMAX3(ir, ig, ib) + FFMIN3(ir, ig, ib);
58+ *ocolor = FFMAX3( r, g, b) + FFMIN3( r, g, b);
59+ break;
60+ case P_MAX:
61+ *icolor = FFMAX3(ir, ig, ib);
62+ *ocolor = FFMAX3( r, g, b);
63+ break;
64+ case P_AVG:
65+ *icolor = (ir + ig + ib + 1.f) / 3.f;
66+ *ocolor = ( r + g + b + 1.f) / 3.f;
67+ break;
68+ case P_SUM:
69+ *icolor = ir + ig + ib;
70+ *ocolor = r + g + b;
71+ break;
72+ case P_NRM:
73+ *icolor = normalize(ir, ig, ib, max);
74+ *ocolor = normalize( r, g, b, max);
75+ break;
76+ case P_PWR:
77+ *icolor = power(ir, ig, ib, max);
78+ *ocolor = power( r, g, b, max);
79+ break;
80+ }
81+}
82+
83+#endif /* AVFILTER_PRESERVE_COLOR_H */
libavfilter/vf_colorlevels.c+64−11
@@ -26,6 +26,7 @@ · 25 unmodified lines
2626 #include "formats.h"
2727 #include "internal.h"
2828 #include "video.h"
29+#include "preserve_color.h"
2930
3031 #define R 0
3132 #define G 1
@@ -40,6 +41,7 @@ typedef struct Range { · 8 unmodified lines
4041 typedef struct ColorLevelsContext {
4142 const AVClass *class;
4243 Range range[4];
44+ int preserve_color;
4345
4446 int nb_comp;
4547 int bpp;
@@ -47,7 +49,7 @@ typedef struct ColorLevelsContext { · 1 unmodified line
4749 uint8_t rgba_map[4];
4850 int linesize;
4951
50− int (*colorlevels_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
52+ int (*colorlevels_slice[2])(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
5153 } ColorLevelsContext;
5254
5355 #define OFFSET(x) offsetof(ColorLevelsContext, x)
@@ -69,6 +71,14 @@ static const AVOption colorlevels_options[] = { · 15 unmodified lines
6971 { "gomax", "set output green white point", OFFSET(range[G].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
7072 { "bomax", "set output blue white point", OFFSET(range[B].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
7173 { "aomax", "set output alpha white point", OFFSET(range[A].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
74+ { "preserve", "set preserve color mode", OFFSET(preserve_color), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_PRESERVE-1, FLAGS, "preserve" },
75+ { "none", "disabled", 0, AV_OPT_TYPE_CONST, {.i64=P_NONE}, 0, 0, FLAGS, "preserve" },
76+ { "lum", "luminance", 0, AV_OPT_TYPE_CONST, {.i64=P_LUM}, 0, 0, FLAGS, "preserve" },
77+ { "max", "max", 0, AV_OPT_TYPE_CONST, {.i64=P_MAX}, 0, 0, FLAGS, "preserve" },
78+ { "avg", "average", 0, AV_OPT_TYPE_CONST, {.i64=P_AVG}, 0, 0, FLAGS, "preserve" },
79+ { "sum", "sum", 0, AV_OPT_TYPE_CONST, {.i64=P_SUM}, 0, 0, FLAGS, "preserve" },
80+ { "nrm", "norm", 0, AV_OPT_TYPE_CONST, {.i64=P_NRM}, 0, 0, FLAGS, "preserve" },
81+ { "pwr", "power", 0, AV_OPT_TYPE_CONST, {.i64=P_PWR}, 0, 0, FLAGS, "preserve" },
7282 { NULL }
7383 };
7484
@@ -104,7 +114,7 @@ typedef struct ThreadData { · 29 unmodified lines
104114 int omin[4];
105115 } ThreadData;
106116
107−#define DO_COMMON(type, clip) \
117+#define DO_COMMON(type, clip, preserve) \
108118 ColorLevelsContext *s = ctx->priv; \
109119 const ThreadData *td = arg; \
110120 const int linesize = s->linesize; \
@@ -143,9 +153,35 @@ typedef struct ThreadData { · 32 unmodified lines
143153 \
144154 for (int y = slice_start; y < slice_end; y++) { \
145155 for (int x = 0; x < linesize; x += step) { \
146− dst_r[x] = clip((src_r[x] - imin_r) * coeff_r + omin_r); \
147− dst_g[x] = clip((src_g[x] - imin_g) * coeff_g + omin_g); \
148− dst_b[x] = clip((src_b[x] - imin_b) * coeff_b + omin_b); \
156+ int ir, ig, ib, or, og, ob; \
157+ ir = src_r[x]; \
158+ ig = src_g[x]; \
159+ ib = src_b[x]; \
160+ if (preserve) { \
161+ float ratio, icolor, ocolor, max = (1<<(8*sizeof(type)))-1; \
162+ \
163+ or = (ir - imin_r) * coeff_r + omin_r; \
164+ og = (ig - imin_g) * coeff_g + omin_g; \
165+ ob = (ib - imin_b) * coeff_b + omin_b; \
166+ \
167+ preserve_color(s->preserve_color, ir, ig, ib, or, og, ob, max, \
168+ &icolor, &ocolor); \
169+ if (ocolor > 0.f) { \
170+ ratio = icolor / ocolor; \
171+ \
172+ or *= ratio; \
173+ og *= ratio; \
174+ ob *= ratio; \
175+ } \
176+ \
177+ dst_r[x] = clip(or); \
178+ dst_g[x] = clip(og); \
179+ dst_b[x] = clip(ob); \
180+ } else { \
181+ dst_r[x] = clip((ir - imin_r) * coeff_r + omin_r); \
182+ dst_g[x] = clip((ig - imin_g) * coeff_g + omin_g); \
183+ dst_b[x] = clip((ib - imin_b) * coeff_b + omin_b); \
184+ } \
149185 } \
150186 \
151187 for (int x = 0; x < linesize && s->nb_comp == 4; x += step) \
@@ -164,14 +200,28 @@ typedef struct ThreadData { · 12 unmodified lines
164200
165201 static int colorlevels_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
166202 {
167− DO_COMMON(uint8_t, av_clip_uint8)
203+ DO_COMMON(uint8_t, av_clip_uint8, 0)
168204
169205 return 0;
170206 }
171207
172208 static int colorlevels_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
173209 {
174− DO_COMMON(uint16_t, av_clip_uint16)
210+ DO_COMMON(uint16_t, av_clip_uint16, 0)
211+
212+ return 0;
213+}
214+
215+static int colorlevels_preserve_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
216+{
217+ DO_COMMON(uint8_t, av_clip_uint8, 1)
218+
219+ return 0;
220+}
221+
222+static int colorlevels_preserve_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
223+{
224+ DO_COMMON(uint16_t, av_clip_uint16, 1)
175225
176226 return 0;
177227 }
@@ -188,9 +238,12 @@ static int config_input(AVFilterLink *inlink) · 10 unmodified lines
188238 s->linesize = inlink->w * s->step;
189239 ff_fill_rgba_map(s->rgba_map, inlink->format);
190240
191− s->colorlevels_slice = colorlevels_slice_8;
192− if (s->bpp == 2)
193− s->colorlevels_slice = colorlevels_slice_16;
241+ s->colorlevels_slice[0] = colorlevels_slice_8;
242+ s->colorlevels_slice[1] = colorlevels_preserve_slice_8;
243+ if (s->bpp == 2) {
244+ s->colorlevels_slice[0] = colorlevels_slice_16;
245+ s->colorlevels_slice[1] = colorlevels_preserve_slice_16;
246+ }
194247
195248 return 0;
196249 }
@@ -304,7 +357,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) · 107 unmodified lines
304357 break;
305358 }
306359
307− ff_filter_execute(ctx, s->colorlevels_slice, &td, NULL,
360+ ff_filter_execute(ctx, s->colorlevels_slice[s->preserve_color > 0], &td, NULL,
308361 FFMIN(inlink->h, ff_filter_get_nb_threads(ctx)));
309362
310363 if (in != out)

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