FFmpeg
median_template.c
Go to the documentation of this file.
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 "video.h"
26 
27 #undef pixel
28 #if DEPTH == 8
29 #define pixel uint8_t
30 #else
31 #define pixel uint16_t
32 #endif
33 
34 #undef htype
35 #define htype uint16_t
36 
37 #undef fn
38 #undef fn2
39 #undef fn3
40 #define SHIFT ((DEPTH + 1) / 2)
41 #define BINS (1 << SHIFT)
42 #define MASK (BINS - 1)
43 #define fn3(a,b) a##_##b
44 #define fn2(a,b) fn3(a,b)
45 #define fn(a) fn2(a, DEPTH)
46 
47 #define PICK_COARSE_BIN(x, y) (BINS * (x) + ((y) >> SHIFT))
48 #define PICK_FINE_BIN(x, y, z) (BINS * ((x) * ((y) >> SHIFT) + (z)) + ((y) & MASK))
49 
50 static void fn(filter_plane)(AVFilterContext *ctx, const uint8_t *ssrc, int src_linesize,
51  uint8_t *ddst, int dst_linesize, int width, int height,
52  int slice_h_start, int slice_h_end, int jobnr)
53 {
54  MedianContext *s = ctx->priv;
55  htype *ccoarse = s->coarse[jobnr];
56  htype *cfine = s->fine[jobnr];
57  const int radius = s->radius;
58  const int radiusV = s->radiusV;
59  const int t = s->t;
60  const pixel *src = (const pixel *)ssrc;
61  pixel *dst = (pixel *)ddst;
62  const pixel *srcp;
63  const pixel *p;
64 
65  src_linesize /= sizeof(pixel);
66  dst_linesize /= sizeof(pixel);
67 
68  memset(cfine, 0, s->fine_size * sizeof(*cfine));
69  memset(ccoarse, 0, s->coarse_size * sizeof(*ccoarse));
70 
71  srcp = src + FFMAX(0, slice_h_start - radiusV) * src_linesize;
72  if (jobnr == 0) {
73  for (int i = 0; i < width; i++) {
74  cfine[PICK_FINE_BIN(width, srcp[i], i)] += radiusV + 1;
75  ccoarse[PICK_COARSE_BIN(i, srcp[i])] += radiusV + 1;
76  }
77  }
78 
79  srcp = src + FFMAX(0, slice_h_start - radiusV - (jobnr != 0)) * src_linesize;
80  for (int i = 0; i < radiusV + (jobnr != 0) * (1 + radiusV); i++) {
81  for (int j = 0; j < width; j++) {
82  cfine[PICK_FINE_BIN(width, srcp[j], j)]++;
83  ccoarse[PICK_COARSE_BIN(j, srcp[j])]++;
84  }
85  srcp += src_linesize;
86  }
87 
88  srcp = src;
89 
90  for (int i = slice_h_start; i < slice_h_end; i++) {
91  htype coarse[BINS] = { 0 };
92  htype fine[BINS][BINS] = { { 0 } };
93  htype luc[BINS] = { 0 };
94 
95  p = srcp + src_linesize * FFMAX(0, i - radiusV - 1);
96  for (int j = 0; j < width; j++) {
97  cfine[PICK_FINE_BIN(width, p[j], j)]--;
98  ccoarse[PICK_COARSE_BIN(j, p[j])]--;
99  }
100 
101  p = srcp + src_linesize * FFMIN(height - 1, i + radiusV);
102  for (int j = 0; j < width; j++) {
103  cfine[PICK_FINE_BIN(width, p[j], j)]++;
104  ccoarse[PICK_COARSE_BIN(j, p[j])]++;
105  }
106 
107  s->hmuladd(coarse, &ccoarse[0], radius, BINS);
108  for (int j = 0; j < radius; j++)
109  s->hadd(coarse, &ccoarse[BINS * j], BINS);
110  for (int k = 0; k < BINS; k++)
111  s->hmuladd(&fine[k][0], &cfine[BINS * width * k], 2 * radius + 1, BINS);
112 
113  for (int j = 0; j < width; j++) {
114  int sum = 0, k, b;
115  htype *segment;
116 
117  s->hadd(coarse, &ccoarse[BINS * FFMIN(j + radius, width - 1)], BINS);
118 
119  for (k = 0; k < BINS; k++) {
120  sum += coarse[k];
121  if (sum > t) {
122  sum -= coarse[k];
123  break;
124  }
125  }
126  av_assert0(k < BINS);
127 
128  if (luc[k] <= j - radius) {
129  memset(&fine[k], 0, BINS * sizeof(htype));
130  for (luc[k] = j - radius; luc[k] < FFMIN(j + radius + 1, width); luc[k]++)
131  s->hadd(fine[k], &cfine[BINS * (width * k + luc[k])], BINS);
132  if (luc[k] < j + radius + 1) {
133  s->hmuladd(&fine[k][0], &cfine[BINS * (width * k + width - 1)], j + radius + 1 - width, BINS);
134  luc[k] = j + radius + 1;
135  }
136  } else {
137  for (; luc[k] < j + radius + 1; luc[k]++) {
138  s->hsub(fine[k], &cfine[BINS * (width * k + FFMAX(luc[k] - 2 * radius - 1, 0))], BINS);
139  s->hadd(fine[k], &cfine[BINS * (width * k + FFMIN(luc[k], width - 1))], BINS);
140  }
141  }
142 
143  s->hsub(coarse, &ccoarse[BINS * FFMAX(j - radius, 0)], BINS);
144 
145  segment = fine[k];
146  for (b = 0; b < BINS; b++) {
147  sum += segment[b];
148  if (sum > t) {
149  dst[j] = BINS * k + b;
150  break;
151  }
152  }
153  av_assert0(b < BINS);
154  }
155 
156  dst += dst_linesize;
157  }
158 }
BINS
#define BINS
Definition: median_template.c:41
htype
#define htype
Definition: median_template.c:35
MedianContext
Definition: median.h:28
fn
#define fn(a)
Definition: median_template.c:45
b
#define b
Definition: input.c:41
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
video.h
PICK_COARSE_BIN
#define PICK_COARSE_BIN(x, y)
Definition: median_template.c:47
avassert.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
ctx
AVFormatContext * ctx
Definition: movenc.c:49
pixel
uint8_t pixel
Definition: tiny_ssim.c:41
height
#define height
Definition: dsp.h:85
PICK_FINE_BIN
#define PICK_FINE_BIN(x, y, z)
Definition: median_template.c:48
dst
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition: dsp.h:83
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
filter_plane
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)
Definition: median_template.c:50
avfilter.h
segment
Definition: hls.c:77
AVFilterContext
An instance of a filter.
Definition: avfilter.h:457
pixel
#define pixel
Definition: median_template.c:31
width
#define width
Definition: dsp.h:85
src
#define src
Definition: vp8dsp.c:248