1 /*
2 * Copyright (c) 2021 Thilo Borgmann <thilo.borgmann _at_ mail.de>
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 /**
22 * @file
23 * No-reference blockdetect filter
24 *
25 * Implementing:
26 * Remco Muijs and Ihor Kirenko: "A no-reference blocking artifact measure for adaptive video processing." 2005 13th European signal processing conference. IEEE, 2005.
27 * http://www.eurasip.org/Proceedings/Eusipco/Eusipco2005/defevent/papers/cr1042.pdf
28 *
29 * @author Thilo Borgmann <thilo.borgmann _at_ mail.de>
30 */
31
35
38
41
44 int planes;
// number of planes to filter
45
48
51
52 #define OFFSET(x) offsetof(BLKContext, x)
53 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
59 };
60
62
64 {
69
74
75 s->gradients =
av_calloc(bufsize,
sizeof(*
s->gradients));
76
79
80 return 0;
81 }
82
84 float *grad, int grad_linesize,
85 uint8_t*
src,
int src_linesize)
86 {
88 float nonblock = 0.0f;
89 int block_count = 0;
90 int nonblock_count = 0;
92
93 // Calculate BS in horizontal and vertical directions according to (1)(2)(3).
94 // Also try to find integer pixel periods (grids) even for scaled images.
95 // In case of fractional periods, FFMAX of current and neighbor pixels
96 // can help improve the correlation with MQS.
97 // Skip linear correction term (4)(5), as it appears only valid for their own test samples.
98
99 // horizontal blockiness (fixed width)
100 for (
int j = 1; j <
h; j++) {
101 for (
int i = 3;
i <
w - 4;
i++) {
103 grad[j * grad_linesize +
i] =
104 abs(
src[j * src_linesize +
i + 0] -
src[j * src_linesize +
i + 1]);
105 temp +=
abs(
src[j * src_linesize +
i + 1] -
src[j * src_linesize +
i + 2]);
106 temp +=
abs(
src[j * src_linesize +
i + 2] -
src[j * src_linesize +
i + 3]);
107 temp +=
abs(
src[j * src_linesize +
i + 3] -
src[j * src_linesize +
i + 4]);
108 temp +=
abs(
src[j * src_linesize +
i - 0] -
src[j * src_linesize +
i - 1]);
109 temp +=
abs(
src[j * src_linesize +
i - 1] -
src[j * src_linesize +
i - 2]);
110 temp +=
abs(
src[j * src_linesize +
i - 2] -
src[j * src_linesize +
i - 3]);
112 grad[j * grad_linesize +
i] /=
temp;
113
114 // use first row to store acculated results
115 grad[
i] += grad[j * grad_linesize +
i];
116 }
117 }
118
119 // find horizontal period
120 for (
int period =
s->period_min; period < s->period_max + 1;
period++) {
123 nonblock = 0;
124 block_count = 0;
125 nonblock_count = 0;
126 for (
int i = 3;
i <
w - 4;
i++) {
129 block_count++;
130 } else {
132 nonblock_count++;
133 }
134 }
135 if (block_count && nonblock_count) {
136 temp = (
block / block_count) / (nonblock / nonblock_count);
138 }
139 }
140
141 // vertical blockiness (fixed height)
142 block_count = 0;
143 for (
int j = 3; j <
h - 4; j++) {
144 for (
int i = 1;
i <
w;
i++) {
146 grad[j * grad_linesize +
i] =
147 abs(
src[(j + 0) * src_linesize +
i] -
src[(j + 1) * src_linesize +
i]);
148 temp +=
abs(
src[(j + 1) * src_linesize +
i] -
src[(j + 2) * src_linesize +
i]);
149 temp +=
abs(
src[(j + 2) * src_linesize +
i] -
src[(j + 3) * src_linesize +
i]);
150 temp +=
abs(
src[(j + 3) * src_linesize +
i] -
src[(j + 4) * src_linesize +
i]);
151 temp +=
abs(
src[(j - 0) * src_linesize +
i] -
src[(j - 1) * src_linesize +
i]);
152 temp +=
abs(
src[(j - 1) * src_linesize +
i] -
src[(j - 2) * src_linesize +
i]);
153 temp +=
abs(
src[(j - 2) * src_linesize +
i] -
src[(j - 3) * src_linesize +
i]);
155 grad[j * grad_linesize +
i] /=
temp;
156
157 // use first column to store accumulated results
158 grad[j * grad_linesize] += grad[j * grad_linesize +
i];
159 }
160 }
161
162 // find vertical period
163 for (
int period =
s->period_min; period < s->period_max + 1;
period++) {
166 nonblock = 0;
167 block_count = 0;
168 nonblock_count = 0;
169 for (
int j = 3; j <
h - 4; j++) {
172 grad[(j + 1) * grad_linesize]),
173 grad[(j - 1) * grad_linesize]);
174 block_count++;
175 } else {
176 nonblock += grad[j * grad_linesize];
177 nonblock_count++;
178 }
179 }
180 if (block_count && nonblock_count) {
181 temp = (
block / block_count) / (nonblock / nonblock_count);
183 }
184 }
185
186 // return highest value of horz||vert
188 }
189
191 {
195 }
196
198 {
202
203 const int inw =
inlink->w;
204 const int inh =
inlink->h;
205
206 float *gradients =
s->gradients;
207
209 int nplanes = 0;
212
213 for (
int plane = 0; plane <
s->nb_planes; plane++) {
214 int hsub = plane == 1 || plane == 2 ?
s->hsub : 0;
215 int vsub = plane == 1 || plane == 2 ?
s->vsub : 0;
218
219 if (!((1 << plane) &
s->planes))
220 continue;
221
222 nplanes++;
223
225 }
226
227 if (nplanes)
229
231
232 // write stats
234
236
237 s->nb_frames =
inlink->frame_count_in;
238
240 }
241
243 {
245
246 if (
s->nb_frames > 0) {
248 s->block_total /
s->nb_frames);
249 }
250
252 }
253
264 };
265
267 {
272 },
273 };
274
276 {
279 },
280 };
281
283 .
name =
"blockdetect",
290 .priv_class = &blockdetect_class,
292 };