• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2019 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  * Redistribution and use in source and binary forms, with or without modification,
20  * are permitted provided that the following conditions are met:
21  */
22 
23 #include "libavutil/avassert.h"
24 #include "avfilter.h"
25 #include "formats.h"
26 #include "internal.h"
27 #include "video.h"
28 
29 #undef pixel
30 #if DEPTH == 8
31 #define pixel uint8_t
32 #else
33 #define pixel uint16_t
34 #endif
35 
36 #undef htype
37 #define htype uint16_t
38 
39 #undef fn
40 #undef fn2
41 #undef fn3
42 #define SHIFT   ((DEPTH + 1) / 2)
43 #define BINS    (1 << SHIFT)
44 #define MASK    (BINS - 1)
45 #define fn3(a,b)   a##_##b
46 #define fn2(a,b)   fn3(a,b)
47 #define fn(a)      fn2(a, DEPTH)
48 
49 #define PICK_COARSE_BIN(x, y) (BINS * (x) + ((y) >> SHIFT))
50 #define PICK_FINE_BIN(x, y, z) (BINS * ((x) * ((y) >> SHIFT) + (z)) + ((y) & MASK))
51 
fn(filter_plane)52 static void fn(filter_plane)(AVFilterContext *ctx, const uint8_t *ssrc, int src_linesize,
53                              uint8_t *ddst, int dst_linesize, int width, int height,
54                              int slice_h_start, int slice_h_end, int jobnr)
55 {
56     MedianContext *s = ctx->priv;
57     htype *ccoarse = s->coarse[jobnr];
58     htype *cfine = s->fine[jobnr];
59     const int radius = s->radius;
60     const int radiusV = s->radiusV;
61     const int t = s->t;
62     const pixel *src = (const pixel *)ssrc;
63     pixel *dst = (pixel *)ddst;
64     const pixel *srcp;
65     const pixel *p;
66 
67     src_linesize /= sizeof(pixel);
68     dst_linesize /= sizeof(pixel);
69 
70     memset(cfine, 0, s->fine_size * sizeof(*cfine));
71     memset(ccoarse, 0, s->coarse_size * sizeof(*ccoarse));
72 
73     srcp = src + FFMAX(0, slice_h_start - radiusV) * src_linesize;
74     if (jobnr == 0) {
75         for (int i = 0; i < width; i++) {
76             cfine[PICK_FINE_BIN(width, srcp[i], i)] += radiusV + 1;
77             ccoarse[PICK_COARSE_BIN(i, srcp[i])] += radiusV + 1;
78         }
79     }
80 
81     srcp = src + FFMAX(0, slice_h_start - radiusV - (jobnr != 0)) * src_linesize;
82     for (int i = 0; i < radiusV + (jobnr != 0) * (1 + radiusV); i++) {
83         for (int j = 0; j < width; j++) {
84             cfine[PICK_FINE_BIN(width, srcp[j], j)]++;
85             ccoarse[PICK_COARSE_BIN(j, srcp[j])]++;
86         }
87         srcp += src_linesize;
88     }
89 
90     srcp = src;
91 
92     for (int i = slice_h_start; i < slice_h_end; i++) {
93         htype coarse[BINS] = { 0 };
94         htype fine[BINS][BINS] = { { 0 } };
95         htype luc[BINS] = { 0 };
96 
97         p = srcp + src_linesize * FFMAX(0, i - radiusV - 1);
98         for (int j = 0; j < width; j++) {
99             cfine[PICK_FINE_BIN(width, p[j], j)]--;
100             ccoarse[PICK_COARSE_BIN(j, p[j])]--;
101         }
102 
103         p = srcp + src_linesize * FFMIN(height - 1, i + radiusV);
104         for (int j = 0; j < width; j++) {
105             cfine[PICK_FINE_BIN(width, p[j], j)]++;
106             ccoarse[PICK_COARSE_BIN(j, p[j])]++;
107         }
108 
109         s->hmuladd(coarse, &ccoarse[0], radius, BINS);
110         for (int j = 0; j < radius; j++)
111             s->hadd(coarse, &ccoarse[BINS * j], BINS);
112         for (int k = 0; k < BINS; k++)
113             s->hmuladd(&fine[k][0], &cfine[BINS * width * k], 2 * radius + 1, BINS);
114 
115         for (int j = 0; j < width; j++) {
116             int sum = 0, k, b;
117             htype *segment;
118 
119             s->hadd(coarse, &ccoarse[BINS * FFMIN(j + radius, width - 1)], BINS);
120 
121             for (k = 0; k < BINS; k++) {
122                 sum += coarse[k];
123                 if (sum > t) {
124                     sum -= coarse[k];
125                     break;
126                 }
127             }
128             av_assert0(k < BINS);
129 
130             if (luc[k] <= j - radius) {
131                 memset(&fine[k], 0, BINS * sizeof(htype));
132                 for (luc[k] = j - radius; luc[k] < FFMIN(j + radius + 1, width); luc[k]++)
133                     s->hadd(fine[k], &cfine[BINS * (width * k + luc[k])], BINS);
134                 if (luc[k] < j + radius + 1) {
135                     s->hmuladd(&fine[k][0], &cfine[BINS * (width * k + width - 1)], j + radius + 1 - width, BINS);
136                     luc[k] = j + radius + 1;
137                 }
138             } else {
139                 for (; luc[k] < j + radius + 1; luc[k]++) {
140                     s->hsub(fine[k], &cfine[BINS * (width * k + FFMAX(luc[k] - 2 * radius - 1, 0))], BINS);
141                     s->hadd(fine[k], &cfine[BINS * (width * k + FFMIN(luc[k], width - 1))], BINS);
142                 }
143             }
144 
145             s->hsub(coarse, &ccoarse[BINS * FFMAX(j - radius, 0)], BINS);
146 
147             segment = fine[k];
148             for (b = 0; b < BINS; b++) {
149                 sum += segment[b];
150                 if (sum > t) {
151                     dst[j] = BINS * k + b;
152                     break;
153                 }
154             }
155             av_assert0(b < BINS);
156         }
157 
158         dst += dst_linesize;
159     }
160 }
161