summaryrefslogtreecommitdiff
path: root/libavfilter/median_template.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2019-01-15 11:32:49 +0100
committerPaul B Mahol <onemda@gmail.com>2019-10-29 10:56:04 +0100
commit1c3b70e2e078bf0901b3af5491f923818809de37 (patch)
treeb97e20f26684a6859c03a1ea52f8ad74ef14729c /libavfilter/median_template.c
parent68f623d64451a6ee8c81b6071ec68d6097c0f213 (diff)
avfilter: add median filter
Diffstat (limited to 'libavfilter/median_template.c')
-rw-r--r--libavfilter/median_template.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/libavfilter/median_template.c b/libavfilter/median_template.c
new file mode 100644
index 0000000000..6953a23a5b
--- /dev/null
+++ b/libavfilter/median_template.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2019 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ */
+
+#include "libavutil/avassert.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+
+#undef pixel
+#if DEPTH == 8
+#define pixel uint8_t
+#else
+#define pixel uint16_t
+#endif
+
+#undef htype
+#define htype uint16_t
+
+#undef fn
+#undef fn2
+#undef fn3
+#define SHIFT ((DEPTH + 1) / 2)
+#define BINS (1 << SHIFT)
+#define MASK (BINS - 1)
+#define fn3(a,b) a##_##b
+#define fn2(a,b) fn3(a,b)
+#define fn(a) fn2(a, DEPTH)
+
+#define PICK_COARSE_BIN(x, y) (BINS * (x) + ((y) >> SHIFT))
+#define PICK_FINE_BIN(x, y, z) (BINS * ((x) * ((y) >> SHIFT) + (z)) + ((y) & MASK))
+
+static void fn(filter_plane)(AVFilterContext *ctx, const uint8_t *ssrc, int src_linesize,
+ uint8_t *ddst, int dst_linesize, int width, int height,
+ int slice_h_start, int slice_h_end, int jobnr)
+{
+ MedianContext *s = ctx->priv;
+ htype *ccoarse = s->coarse[jobnr];
+ htype *cfine = s->fine[jobnr];
+ const int radius = s->radius;
+ const int t = s->t;
+ const pixel *src = (const pixel *)ssrc;
+ pixel *dst = (pixel *)ddst;
+ const pixel *srcp;
+ const pixel *p;
+
+ src_linesize /= sizeof(pixel);
+ dst_linesize /= sizeof(pixel);
+
+ memset(cfine, 0, s->fine_size * sizeof(*cfine));
+ memset(ccoarse, 0, s->coarse_size * sizeof(*ccoarse));
+
+ srcp = src + FFMAX(0, slice_h_start - radius) * src_linesize;
+ if (jobnr == 0) {
+ for (int i = 0; i < width; i++) {
+ cfine[PICK_FINE_BIN(width, srcp[i], i)] += radius + 1;
+ ccoarse[PICK_COARSE_BIN(i, srcp[i])] += radius + 1;
+ }
+ }
+
+ srcp = src + FFMAX(0, slice_h_start - radius - (jobnr != 0)) * src_linesize;
+ for (int i = 0; i < radius + (jobnr != 0) * (1 + radius); i++) {
+ for (int j = 0; j < width; j++) {
+ cfine[PICK_FINE_BIN(width, srcp[j], j)]++;
+ ccoarse[PICK_COARSE_BIN(j, srcp[j])]++;
+ }
+ srcp += src_linesize;
+ }
+
+ srcp = src;
+
+ for (int i = slice_h_start; i < slice_h_end; i++) {
+ htype coarse[BINS] = { 0 };
+ htype fine[BINS][BINS] = { { 0 } };
+ htype luc[BINS] = { 0 };
+
+ p = srcp + src_linesize * FFMAX(0, i - radius - 1);
+ for (int j = 0; j < width; j++) {
+ cfine[PICK_FINE_BIN(width, p[j], j)]--;
+ ccoarse[PICK_COARSE_BIN(j, p[j])]--;
+ }
+
+ p = srcp + src_linesize * FFMIN(height - 1, i + radius);
+ for (int j = 0; j < width; j++) {
+ cfine[PICK_FINE_BIN(width, p[j], j)]++;
+ ccoarse[PICK_COARSE_BIN(j, p[j])]++;
+ }
+
+ s->hmuladd(coarse, &ccoarse[0], radius, BINS);
+ for (int j = 0; j < radius; j++)
+ s->hadd(coarse, &ccoarse[BINS * j], BINS);
+ for (int k = 0; k < BINS; k++)
+ s->hmuladd(&fine[k][0], &cfine[BINS * width * k], 2 * radius + 1, BINS);
+
+ for (int j = 0; j < width; j++) {
+ int sum = 0, k, b;
+ htype *segment;
+
+ s->hadd(coarse, &ccoarse[BINS * FFMIN(j + radius, width - 1)], BINS);
+
+ for (k = 0; k < BINS; k++) {
+ sum += coarse[k];
+ if (sum > t) {
+ sum -= coarse[k];
+ break;
+ }
+ }
+ av_assert0(k < BINS);
+
+ if (luc[k] <= j - radius) {
+ memset(&fine[k], 0, BINS * sizeof(htype));
+ for (luc[k] = j - radius; luc[k] < FFMIN(j + radius + 1, width); luc[k]++)
+ s->hadd(fine[k], &cfine[BINS * (width * k + luc[k])], BINS);
+ if (luc[k] < j + radius + 1) {
+ s->hmuladd(&fine[k][0], &cfine[BINS * (width * k + width - 1)], j + radius + 1 - width, BINS);
+ luc[k] = j + radius + 1;
+ }
+ } else {
+ for (; luc[k] < j + radius + 1; luc[k]++) {
+ s->hsub(fine[k], &cfine[BINS * (width * k + FFMAX(luc[k] - 2 * radius - 1, 0))], BINS);
+ s->hadd(fine[k], &cfine[BINS * (width * k + FFMIN(luc[k], width - 1))], BINS);
+ }
+ }
+
+ s->hsub(coarse, &ccoarse[BINS * FFMAX(j - radius, 0)], BINS);
+
+ segment = fine[k];
+ for (b = 0; b < BINS; b++) {
+ sum += segment[b];
+ if (sum > t) {
+ dst[j] = BINS * k + b;
+ break;
+ }
+ }
+ av_assert0(b < BINS);
+ }
+
+ dst += dst_linesize;
+ }
+}