FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_deflicker.c
Date: 2024-04-19 17:50:32
Exec Total Coverage
Lines: 0 185 0.0%
Functions: 0 16 0.0%
Branches: 0 110 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2017 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "libavutil/imgutils.h"
22 #include "libavutil/mem.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/pixdesc.h"
25 #include "libavutil/qsort.h"
26 #include "avfilter.h"
27
28 #define FF_BUFQUEUE_SIZE 129
29 #include "bufferqueue.h"
30
31 #include "internal.h"
32 #include "video.h"
33
34 #define SIZE FF_BUFQUEUE_SIZE
35
36 enum smooth_mode {
37 ARITHMETIC_MEAN,
38 GEOMETRIC_MEAN,
39 HARMONIC_MEAN,
40 QUADRATIC_MEAN,
41 CUBIC_MEAN,
42 POWER_MEAN,
43 MEDIAN,
44 NB_SMOOTH_MODE,
45 };
46
47 typedef struct DeflickerContext {
48 const AVClass *class;
49
50 int size;
51 int mode;
52 int bypass;
53
54 int eof;
55 int depth;
56 int nb_planes;
57 int planewidth[4];
58 int planeheight[4];
59
60 uint64_t *histogram;
61 float luminance[SIZE];
62 float sorted[SIZE];
63
64 struct FFBufQueue q;
65 int available;
66
67 void (*get_factor)(AVFilterContext *ctx, float *f);
68 float (*calc_avgy)(AVFilterContext *ctx, AVFrame *in);
69 int (*deflicker)(AVFilterContext *ctx, const uint8_t *src, ptrdiff_t src_linesize,
70 uint8_t *dst, ptrdiff_t dst_linesize, int w, int h, float f);
71 } DeflickerContext;
72
73 #define OFFSET(x) offsetof(DeflickerContext, x)
74 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
75
76 static const AVOption deflicker_options[] = {
77 { "size", "set how many frames to use", OFFSET(size), AV_OPT_TYPE_INT, {.i64=5}, 2, SIZE, FLAGS },
78 { "s", "set how many frames to use", OFFSET(size), AV_OPT_TYPE_INT, {.i64=5}, 2, SIZE, FLAGS },
79 { "mode", "set how to smooth luminance", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SMOOTH_MODE-1, FLAGS, .unit = "mode" },
80 { "m", "set how to smooth luminance", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SMOOTH_MODE-1, FLAGS, .unit = "mode" },
81 { "am", "arithmetic mean", 0, AV_OPT_TYPE_CONST, {.i64=ARITHMETIC_MEAN}, 0, 0, FLAGS, .unit = "mode" },
82 { "gm", "geometric mean", 0, AV_OPT_TYPE_CONST, {.i64=GEOMETRIC_MEAN}, 0, 0, FLAGS, .unit = "mode" },
83 { "hm", "harmonic mean", 0, AV_OPT_TYPE_CONST, {.i64=HARMONIC_MEAN}, 0, 0, FLAGS, .unit = "mode" },
84 { "qm", "quadratic mean", 0, AV_OPT_TYPE_CONST, {.i64=QUADRATIC_MEAN}, 0, 0, FLAGS, .unit = "mode" },
85 { "cm", "cubic mean", 0, AV_OPT_TYPE_CONST, {.i64=CUBIC_MEAN}, 0, 0, FLAGS, .unit = "mode" },
86 { "pm", "power mean", 0, AV_OPT_TYPE_CONST, {.i64=POWER_MEAN}, 0, 0, FLAGS, .unit = "mode" },
87 { "median", "median", 0, AV_OPT_TYPE_CONST, {.i64=MEDIAN}, 0, 0, FLAGS, .unit = "mode" },
88 { "bypass", "leave frames unchanged", OFFSET(bypass), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
89 { NULL }
90 };
91
92 AVFILTER_DEFINE_CLASS(deflicker);
93
94 static const enum AVPixelFormat pixel_fmts[] = {
95 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10,
96 AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16,
97 AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
98 AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
99 AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
100 AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
101 AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
102 AV_PIX_FMT_YUVJ411P,
103 AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
104 AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
105 AV_PIX_FMT_YUV440P10,
106 AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12,
107 AV_PIX_FMT_YUV440P12,
108 AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14,
109 AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
110 AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
111 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA444P16,
112 AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA422P16,
113 AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16,
114 AV_PIX_FMT_NONE
115 };
116
117 static int deflicker8(AVFilterContext *ctx,
118 const uint8_t *src, ptrdiff_t src_linesize,
119 uint8_t *dst, ptrdiff_t dst_linesize,
120 int w, int h, float f)
121 {
122 int x, y;
123
124 for (y = 0; y < h; y++) {
125 for (x = 0; x < w; x++) {
126 dst[x] = av_clip_uint8(src[x] * f);
127 }
128
129 dst += dst_linesize;
130 src += src_linesize;
131 }
132
133 return 0;
134 }
135
136 static int deflicker16(AVFilterContext *ctx,
137 const uint8_t *ssrc, ptrdiff_t src_linesize,
138 uint8_t *ddst, ptrdiff_t dst_linesize,
139 int w, int h, float f)
140 {
141 DeflickerContext *s = ctx->priv;
142 const uint16_t *src = (const uint16_t *)ssrc;
143 uint16_t *dst = (uint16_t *)ddst;
144 const int max = (1 << s->depth) - 1;
145 int x, y;
146
147 for (y = 0; y < h; y++) {
148 for (x = 0; x < w; x++) {
149 dst[x] = av_clip(src[x] * f, 0, max);
150 }
151
152 dst += dst_linesize / 2;
153 src += src_linesize / 2;
154 }
155
156 return 0;
157 }
158
159 static float calc_avgy8(AVFilterContext *ctx, AVFrame *in)
160 {
161 DeflickerContext *s = ctx->priv;
162 const uint8_t *src = in->data[0];
163 int64_t sum = 0;
164 int y, x;
165
166 memset(s->histogram, 0, (1 << s->depth) * sizeof(*s->histogram));
167
168 for (y = 0; y < s->planeheight[0]; y++) {
169 for (x = 0; x < s->planewidth[0]; x++) {
170 s->histogram[src[x]]++;
171 }
172 src += in->linesize[0];
173 }
174
175 for (y = 0; y < 1 << s->depth; y++) {
176 sum += s->histogram[y] * y;
177 }
178
179 return 1.0f * sum / (s->planeheight[0] * s->planewidth[0]);
180 }
181
182 static float calc_avgy16(AVFilterContext *ctx, AVFrame *in)
183 {
184 DeflickerContext *s = ctx->priv;
185 const uint16_t *src = (const uint16_t *)in->data[0];
186 int64_t sum = 0;
187 int y, x;
188
189 memset(s->histogram, 0, (1 << s->depth) * sizeof(*s->histogram));
190
191 for (y = 0; y < s->planeheight[0]; y++) {
192 for (x = 0; x < s->planewidth[0]; x++) {
193 s->histogram[src[x]]++;
194 }
195 src += in->linesize[0] / 2;
196 }
197
198 for (y = 0; y < 1 << s->depth; y++) {
199 sum += s->histogram[y] * y;
200 }
201
202 return 1.0f * sum / (s->planeheight[0] * s->planewidth[0]);
203 }
204
205 static void get_am_factor(AVFilterContext *ctx, float *f)
206 {
207 DeflickerContext *s = ctx->priv;
208 int y;
209
210 *f = 0.0f;
211
212 for (y = 0; y < s->size; y++) {
213 *f += s->luminance[y];
214 }
215
216 *f /= s->size;
217 *f /= s->luminance[0];
218 }
219
220 static void get_gm_factor(AVFilterContext *ctx, float *f)
221 {
222 DeflickerContext *s = ctx->priv;
223 int y;
224
225 *f = 1;
226
227 for (y = 0; y < s->size; y++) {
228 *f *= s->luminance[y];
229 }
230
231 *f = pow(*f, 1.0f / s->size);
232 *f /= s->luminance[0];
233 }
234
235 static void get_hm_factor(AVFilterContext *ctx, float *f)
236 {
237 DeflickerContext *s = ctx->priv;
238 int y;
239
240 *f = 0.0f;
241
242 for (y = 0; y < s->size; y++) {
243 *f += 1.0f / s->luminance[y];
244 }
245
246 *f = s->size / *f;
247 *f /= s->luminance[0];
248 }
249
250 static void get_qm_factor(AVFilterContext *ctx, float *f)
251 {
252 DeflickerContext *s = ctx->priv;
253 int y;
254
255 *f = 0.0f;
256
257 for (y = 0; y < s->size; y++) {
258 *f += s->luminance[y] * s->luminance[y];
259 }
260
261 *f /= s->size;
262 *f = sqrtf(*f);
263 *f /= s->luminance[0];
264 }
265
266 static void get_cm_factor(AVFilterContext *ctx, float *f)
267 {
268 DeflickerContext *s = ctx->priv;
269 int y;
270
271 *f = 0.0f;
272
273 for (y = 0; y < s->size; y++) {
274 *f += s->luminance[y] * s->luminance[y] * s->luminance[y];
275 }
276
277 *f /= s->size;
278 *f = cbrtf(*f);
279 *f /= s->luminance[0];
280 }
281
282 static void get_pm_factor(AVFilterContext *ctx, float *f)
283 {
284 DeflickerContext *s = ctx->priv;
285 int y;
286
287 *f = 0.0f;
288
289 for (y = 0; y < s->size; y++) {
290 *f += powf(s->luminance[y], s->size);
291 }
292
293 *f /= s->size;
294 *f = powf(*f, 1.0f / s->size);
295 *f /= s->luminance[0];
296 }
297
298 static int comparef(const void *a, const void *b)
299 {
300 const float *aa = a, *bb = b;
301 return round(aa - bb);
302 }
303
304 static void get_median_factor(AVFilterContext *ctx, float *f)
305 {
306 DeflickerContext *s = ctx->priv;
307
308 memcpy(s->sorted, s->luminance, sizeof(s->sorted));
309 AV_QSORT(s->sorted, s->size, float, comparef);
310
311 *f = s->sorted[s->size >> 1] / s->luminance[0];
312 }
313
314 static int config_input(AVFilterLink *inlink)
315 {
316 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
317 AVFilterContext *ctx = inlink->dst;
318 DeflickerContext *s = ctx->priv;
319
320 s->nb_planes = desc->nb_components;
321
322 s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
323 s->planeheight[0] = s->planeheight[3] = inlink->h;
324 s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
325 s->planewidth[0] = s->planewidth[3] = inlink->w;
326
327 s->depth = desc->comp[0].depth;
328 if (s->depth == 8) {
329 s->deflicker = deflicker8;
330 s->calc_avgy = calc_avgy8;
331 } else {
332 s->deflicker = deflicker16;
333 s->calc_avgy = calc_avgy16;
334 }
335
336 s->histogram = av_calloc(1 << s->depth, sizeof(*s->histogram));
337 if (!s->histogram)
338 return AVERROR(ENOMEM);
339
340 switch (s->mode) {
341 case MEDIAN: s->get_factor = get_median_factor; break;
342 case ARITHMETIC_MEAN: s->get_factor = get_am_factor; break;
343 case GEOMETRIC_MEAN: s->get_factor = get_gm_factor; break;
344 case HARMONIC_MEAN: s->get_factor = get_hm_factor; break;
345 case QUADRATIC_MEAN: s->get_factor = get_qm_factor; break;
346 case CUBIC_MEAN: s->get_factor = get_cm_factor; break;
347 case POWER_MEAN: s->get_factor = get_pm_factor; break;
348 }
349
350 return 0;
351 }
352
353 static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
354 {
355 AVFilterContext *ctx = inlink->dst;
356 AVFilterLink *outlink = ctx->outputs[0];
357 DeflickerContext *s = ctx->priv;
358 AVDictionary **metadata;
359 AVFrame *out, *in;
360 float f;
361 int y;
362
363 if (s->q.available < s->size && !s->eof) {
364 s->luminance[s->available] = s->calc_avgy(ctx, buf);
365 ff_bufqueue_add(ctx, &s->q, buf);
366 s->available++;
367 return 0;
368 }
369
370 in = ff_bufqueue_peek(&s->q, 0);
371
372 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
373 if (!out) {
374 av_frame_free(&buf);
375 return AVERROR(ENOMEM);
376 }
377
378 s->get_factor(ctx, &f);
379 if (!s->bypass)
380 s->deflicker(ctx, in->data[0], in->linesize[0], out->data[0], out->linesize[0],
381 outlink->w, outlink->h, f);
382 for (y = 1 - s->bypass; y < s->nb_planes; y++) {
383 av_image_copy_plane(out->data[y], out->linesize[y],
384 in->data[y], in->linesize[y],
385 s->planewidth[y] * (1 + (s->depth > 8)), s->planeheight[y]);
386 }
387
388 av_frame_copy_props(out, in);
389 metadata = &out->metadata;
390 if (metadata) {
391 uint8_t value[128];
392
393 snprintf(value, sizeof(value), "%f", s->luminance[0]);
394 av_dict_set(metadata, "lavfi.deflicker.luminance", value, 0);
395
396 snprintf(value, sizeof(value), "%f", s->luminance[0] * f);
397 av_dict_set(metadata, "lavfi.deflicker.new_luminance", value, 0);
398
399 snprintf(value, sizeof(value), "%f", f - 1.0f);
400 av_dict_set(metadata, "lavfi.deflicker.relative_change", value, 0);
401 }
402
403 in = ff_bufqueue_get(&s->q);
404 av_frame_free(&in);
405 memmove(&s->luminance[0], &s->luminance[1], sizeof(*s->luminance) * (s->size - 1));
406 s->luminance[s->available - 1] = s->calc_avgy(ctx, buf);
407 ff_bufqueue_add(ctx, &s->q, buf);
408
409 return ff_filter_frame(outlink, out);
410 }
411
412 static int request_frame(AVFilterLink *outlink)
413 {
414 AVFilterContext *ctx = outlink->src;
415 DeflickerContext *s = ctx->priv;
416 int ret;
417
418 ret = ff_request_frame(ctx->inputs[0]);
419 if (ret == AVERROR_EOF && s->available > 0) {
420 AVFrame *buf = ff_bufqueue_peek(&s->q, s->available - 1);
421 if (!buf)
422 return AVERROR(ENOMEM);
423 buf = av_frame_clone(buf);
424 if (!buf)
425 return AVERROR(ENOMEM);
426
427 s->eof = 1;
428 ret = filter_frame(ctx->inputs[0], buf);
429 s->available--;
430 }
431
432 return ret;
433 }
434
435 static av_cold void uninit(AVFilterContext *ctx)
436 {
437 DeflickerContext *s = ctx->priv;
438
439 ff_bufqueue_discard_all(&s->q);
440 av_freep(&s->histogram);
441 }
442
443 static const AVFilterPad inputs[] = {
444 {
445 .name = "default",
446 .type = AVMEDIA_TYPE_VIDEO,
447 .filter_frame = filter_frame,
448 .config_props = config_input,
449 },
450 };
451
452 static const AVFilterPad outputs[] = {
453 {
454 .name = "default",
455 .type = AVMEDIA_TYPE_VIDEO,
456 .request_frame = request_frame,
457 },
458 };
459
460 const AVFilter ff_vf_deflicker = {
461 .name = "deflicker",
462 .description = NULL_IF_CONFIG_SMALL("Remove temporal frame luminance variations."),
463 .priv_size = sizeof(DeflickerContext),
464 .priv_class = &deflicker_class,
465 .uninit = uninit,
466 FILTER_INPUTS(inputs),
467 FILTER_OUTPUTS(outputs),
468 FILTER_PIXFMTS_ARRAY(pixel_fmts),
469 };
470