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
22enum {
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
33static 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
41static 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
49static 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
26#include "formats.h"26#include "formats.h"
27#include "internal.h"27#include "internal.h"
28#include "video.h"28#include "video.h"
29#include "preserve_color.h"
29 30
30#define R 031#define R 0
31#define G 132#define G 1
@@ -40,6 +41,7 @@ typedef struct Range { · 8 unmodified lines
40typedef struct ColorLevelsContext {41typedef struct ColorLevelsContext {
41 const AVClass *class;42 const AVClass *class;
42 Range range[4];43 Range range[4];
44 int preserve_color;
43 45
44 int nb_comp;46 int nb_comp;
45 int bpp;47 int bpp;
@@ -47,7 +49,7 @@ typedef struct ColorLevelsContext { · 1 unmodified line
47 uint8_t rgba_map[4];49 uint8_t rgba_map[4];
48 int linesize;50 int linesize;
49 51
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);
51} ColorLevelsContext;53} ColorLevelsContext;
52 54
53#define OFFSET(x) offsetof(ColorLevelsContext, x)55#define OFFSET(x) offsetof(ColorLevelsContext, x)
@@ -69,6 +71,14 @@ static const AVOption colorlevels_options[] = { · 15 unmodified lines
69 { "gomax", "set output green white point", OFFSET(range[G].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },71 { "gomax", "set output green white point", OFFSET(range[G].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
70 { "bomax", "set output blue white point", OFFSET(range[B].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },72 { "bomax", "set output blue white point", OFFSET(range[B].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },
71 { "aomax", "set output alpha white point", OFFSET(range[A].out_max), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS },73 { "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" },
72 { NULL }82 { NULL }
73};83};
74 84
@@ -104,7 +114,7 @@ typedef struct ThreadData { · 29 unmodified lines
104 int omin[4];114 int omin[4];
105} ThreadData;115} ThreadData;
106 116
107#define DO_COMMON(type, clip) \117#define DO_COMMON(type, clip, preserve) \
108 ColorLevelsContext *s = ctx->priv; \118 ColorLevelsContext *s = ctx->priv; \
109 const ThreadData *td = arg; \119 const ThreadData *td = arg; \
110 const int linesize = s->linesize; \120 const int linesize = s->linesize; \
@@ -143,9 +153,35 @@ typedef struct ThreadData { · 32 unmodified lines
143 \153 \
144 for (int y = slice_start; y < slice_end; y++) { \154 for (int y = slice_start; y < slice_end; y++) { \
145 for (int x = 0; x < linesize; x += step) { \155 for (int x = 0; x < linesize; x += step) { \
146 dst_r[x] = clip((src_r[x] - imin_r) * coeff_r + omin_r); \156 int ir, ig, ib, or, og, ob; \
147 dst_g[x] = clip((src_g[x] - imin_g) * coeff_g + omin_g); \157 ir = src_r[x]; \
148 dst_b[x] = clip((src_b[x] - imin_b) * coeff_b + omin_b); \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 } \
149 } \185 } \
150 \186 \
151 for (int x = 0; x < linesize && s->nb_comp == 4; x += step) \187 for (int x = 0; x < linesize && s->nb_comp == 4; x += step) \
@@ -164,14 +200,28 @@ typedef struct ThreadData { · 12 unmodified lines
164 200
165static int colorlevels_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)201static int colorlevels_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
166{202{
167 DO_COMMON(uint8_t, av_clip_uint8)203 DO_COMMON(uint8_t, av_clip_uint8, 0)
168 204
169 return 0;205 return 0;
170}206}
171 207
172static int colorlevels_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)208static int colorlevels_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
173{209{
174 DO_COMMON(uint16_t, av_clip_uint16)210 DO_COMMON(uint16_t, av_clip_uint16, 0)
211
212 return 0;
213}
214
215static 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
222static int colorlevels_preserve_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
223{
224 DO_COMMON(uint16_t, av_clip_uint16, 1)
175 225
176 return 0;226 return 0;
177}227}
@@ -188,9 +238,12 @@ static int config_input(AVFilterLink *inlink) · 10 unmodified lines
188 s->linesize = inlink->w * s->step;238 s->linesize = inlink->w * s->step;
189 ff_fill_rgba_map(s->rgba_map, inlink->format);239 ff_fill_rgba_map(s->rgba_map, inlink->format);
190 240
191 s->colorlevels_slice = colorlevels_slice_8;241 s->colorlevels_slice[0] = colorlevels_slice_8;
192 if (s->bpp == 2)242 s->colorlevels_slice[1] = colorlevels_preserve_slice_8;
193 s->colorlevels_slice = colorlevels_slice_16;243 if (s->bpp == 2) {
244 s->colorlevels_slice[0] = colorlevels_slice_16;
245 s->colorlevels_slice[1] = colorlevels_preserve_slice_16;
246 }
194 247
195 return 0;248 return 0;
196}249}
@@ -304,7 +357,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) · 107 unmodified lines
304 break;357 break;
305 }358 }
306 359
307 ff_filter_execute(ctx, s->colorlevels_slice, &td, NULL,360 ff_filter_execute(ctx, s->colorlevels_slice[s->preserve_color > 0], &td, NULL,
308 FFMIN(inlink->h, ff_filter_get_nb_threads(ctx)));361 FFMIN(inlink->h, ff_filter_get_nb_threads(ctx)));
309 362
310 if (in != out)363 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