1 /*
2 * Copyright (c) 2015 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 /**
22 * @file
23 * Adaptive Temporal Averaging Denoiser,
24 * based on paper "Video Denoising Based on Adaptive Temporal Averaging" by
25 * David Bartovčak and Miroslav Vrankić
26 */
27
32
33 #define FF_BUFQUEUE_SIZE 129
35
40
41 #define SIZE FF_BUFQUEUE_SIZE
42
45
50
56
63
65
68
69 #define OFFSET(x) offsetof(ATADenoiseContext, x)
70 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
71 #define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
72
89 };
90
92
121 };
122
124 {
126
127 if (!(
s->size & 1)) {
130 }
131 s->radius =
s->size / 2;
133
134 return 0;
135 }
136
140
141 #define WFILTER_ROW(type, name) \
142 static void fweight_row##name(const uint8_t *ssrc, uint8_t *ddst, \
143 const uint8_t *ssrcf[SIZE], \
144 int w, int mid, int size, \
145 int thra, int thrb, const float *weights) \
146 { \
147 const type *src = (const type *)ssrc; \
148 const type **srcf = (const type **)ssrcf; \
149 type *dst = (type *)ddst; \
150 \
151 for (int x = 0; x < w; x++) { \
152 const int srcx = src[x]; \
153 unsigned lsumdiff = 0, rsumdiff = 0; \
154 unsigned ldiff, rdiff; \
155 float sum = srcx; \
156 float wsum = 1.f; \
157 int srcjx, srcix; \
158 \
159 for (int j = mid - 1, i = mid + 1; j >= 0 && i < size; j--, i++) { \
160 srcjx = srcf[j][x]; \
161 \
162 ldiff = FFABS(srcx - srcjx); \
163 lsumdiff += ldiff; \
164 if (ldiff > thra || \
165 lsumdiff > thrb) \
166 break; \
167 sum += srcjx * weights[j]; \
168 wsum += weights[j]; \
169 \
170 srcix = srcf[i][x]; \
171 \
172 rdiff = FFABS(srcx - srcix); \
173 rsumdiff += rdiff; \
174 if (rdiff > thra || \
175 rsumdiff > thrb) \
176 break; \
177 sum += srcix * weights[i]; \
178 wsum += weights[i]; \
179 } \
180 \
181 dst[x] = lrintf(sum / wsum); \
182 } \
183 }
184
187
188 #define WFILTER_ROW_SERIAL(type, name) \
189 static void fweight_row##name##_serial(const uint8_t *ssrc, uint8_t *ddst, \
190 const uint8_t *ssrcf[SIZE], \
191 int w, int mid, int size, \
192 int thra, int thrb, \
193 const float *weights) \
194 { \
195 const type *src = (const type *)ssrc; \
196 const type **srcf = (const type **)ssrcf; \
197 type *dst = (type *)ddst; \
198 \
199 for (int x = 0; x < w; x++) { \
200 const int srcx = src[x]; \
201 unsigned lsumdiff = 0, rsumdiff = 0; \
202 unsigned ldiff, rdiff; \
203 float sum = srcx; \
204 float wsum = 1.f; \
205 int srcjx, srcix; \
206 \
207 for (int j = mid - 1; j >= 0; j--) { \
208 srcjx = srcf[j][x]; \
209 \
210 ldiff = FFABS(srcx - srcjx); \
211 lsumdiff += ldiff; \
212 if (ldiff > thra || \
213 lsumdiff > thrb) \
214 break; \
215 sum += srcjx * weights[j]; \
216 wsum += weights[j]; \
217 } \
218 \
219 for (int i = mid + 1; i < size; i++) { \
220 srcix = srcf[i][x]; \
221 \
222 rdiff = FFABS(srcx - srcix); \
223 rsumdiff += rdiff; \
224 if (rdiff > thra || \
225 rsumdiff > thrb) \
226 break; \
227 sum += srcix * weights[i]; \
228 wsum += weights[i]; \
229 } \
230 \
231 dst[x] = lrintf(sum / wsum); \
232 } \
233 }
234
237
238 #define FILTER_ROW(type, name) \
239 static void filter_row##name(const uint8_t *ssrc, uint8_t *ddst, \
240 const uint8_t *ssrcf[SIZE], \
241 int w, int mid, int size, \
242 int thra, int thrb, const float *weights) \
243 { \
244 const type *src = (const type *)ssrc; \
245 const type **srcf = (const type **)ssrcf; \
246 type *dst = (type *)ddst; \
247 \
248 for (int x = 0; x < w; x++) { \
249 const int srcx = src[x]; \
250 unsigned lsumdiff = 0, rsumdiff = 0; \
251 unsigned ldiff, rdiff; \
252 unsigned sum = srcx; \
253 int l = 0, r = 0; \
254 int srcjx, srcix; \
255 \
256 for (int j = mid - 1, i = mid + 1; j >= 0 && i < size; j--, i++) { \
257 srcjx = srcf[j][x]; \
258 \
259 ldiff = FFABS(srcx - srcjx); \
260 lsumdiff += ldiff; \
261 if (ldiff > thra || \
262 lsumdiff > thrb) \
263 break; \
264 l++; \
265 sum += srcjx; \
266 \
267 srcix = srcf[i][x]; \
268 \
269 rdiff = FFABS(srcx - srcix); \
270 rsumdiff += rdiff; \
271 if (rdiff > thra || \
272 rsumdiff > thrb) \
273 break; \
274 r++; \
275 sum += srcix; \
276 } \
277 \
278 dst[x] = (sum + ((r + l + 1) >> 1)) / (r + l + 1); \
279 } \
280 }
281
284
285 #define FILTER_ROW_SERIAL(type, name) \
286 static void filter_row##name##_serial(const uint8_t *ssrc, uint8_t *ddst, \
287 const uint8_t *ssrcf[SIZE], \
288 int w, int mid, int size, \
289 int thra, int thrb, \
290 const float *weights) \
291 { \
292 const type *src = (const type *)ssrc; \
293 const type **srcf = (const type **)ssrcf; \
294 type *dst = (type *)ddst; \
295 \
296 for (int x = 0; x < w; x++) { \
297 const int srcx = src[x]; \
298 unsigned lsumdiff = 0, rsumdiff = 0; \
299 unsigned ldiff, rdiff; \
300 unsigned sum = srcx; \
301 int l = 0, r = 0; \
302 int srcjx, srcix; \
303 \
304 for (int j = mid - 1; j >= 0; j--) { \
305 srcjx = srcf[j][x]; \
306 \
307 ldiff = FFABS(srcx - srcjx); \
308 lsumdiff += ldiff; \
309 if (ldiff > thra || \
310 lsumdiff > thrb) \
311 break; \
312 l++; \
313 sum += srcjx; \
314 } \
315 \
316 for (int i = mid + 1; i < size; i++) { \
317 srcix = srcf[i][x]; \
318 \
319 rdiff = FFABS(srcx - srcix); \
320 rsumdiff += rdiff; \
321 if (rdiff > thra || \
322 rsumdiff > thrb) \
323 break; \
324 r++; \
325 sum += srcix; \
326 } \
327 \
328 dst[x] = (sum + ((r + l + 1) >> 1)) / (r + l + 1); \
329 } \
330 }
331
334
336 {
341 const int size =
s->size;
342 const int mid =
s->mid;
344
345 for (p = 0; p <
s->nb_planes; p++) {
346 const float *
weights =
s->weights[p];
347 const int h =
s->planeheight[p];
348 const int w =
s->planewidth[p];
349 const int slice_start = (
h * jobnr) / nb_jobs;
350 const int slice_end = (
h * (jobnr+1)) / nb_jobs;
352 uint8_t *dst =
out->data[p] + slice_start *
out->linesize[p];
353 const int thra =
s->thra[p];
354 const int thrb =
s->thrb[p];
355 const uint8_t **
data = (
const uint8_t **)
s->data[p];
356 const int *linesize = (
const int *)
s->linesize[p];
357 const uint8_t *srcf[
SIZE];
358
359 if (!((1 << p) &
s->planes)) {
362 continue;
363 }
364
366 srcf[
i] =
data[
i] + slice_start * linesize[
i];
367
368 for (y = slice_start; y <
slice_end; y++) {
370
371 dst +=
out->linesize[p];
373
375 srcf[
i] += linesize[
i];
376 }
377 }
378
379 return 0;
380 }
381
383 {
388
389 s->nb_planes =
desc->nb_components;
390
392 s->planeheight[0] =
s->planeheight[3] =
inlink->h;
394 s->planewidth[0] =
s->planewidth[3] =
inlink->w;
395
396 depth =
desc->comp[0].depth;
398
401
402 for (
int p = 0; p <
s->nb_planes; p++) {
403 if (depth == 8 &&
s->sigma[p] == INT16_MAX)
404 s->dsp.filter_row[p] =
s->algorithm ==
PARALLEL ? filter_row8 : filter_row8_serial;
405 else if (
s->sigma[p] == INT16_MAX)
406 s->dsp.filter_row[p] =
s->algorithm ==
PARALLEL ? filter_row16 : filter_row16_serial;
407 else if (depth == 8 &&
s->sigma[p] < INT16_MAX)
408 s->dsp.filter_row[p] =
s->algorithm ==
PARALLEL ? fweight_row8 : fweight_row8_serial;
409 else if (
s->sigma[p] < INT16_MAX)
410 s->dsp.filter_row[p] =
s->algorithm ==
PARALLEL ? fweight_row16 : fweight_row16_serial;
411 }
412
413 s->thra[0] =
s->fthra[0] * (1 << depth) - 1;
414 s->thra[1] =
s->fthra[1] * (1 << depth) - 1;
415 s->thra[2] =
s->fthra[2] * (1 << depth) - 1;
416 s->thrb[0] =
s->fthrb[0] * (1 << depth) - 1;
417 s->thrb[1] =
s->fthrb[1] * (1 << depth) - 1;
418 s->thrb[2] =
s->fthrb[2] * (1 << depth) - 1;
419
420 for (
int p = 0; p <
s->nb_planes; p++) {
421 float sigma =
s->radius *
s->sigma[p];
422
423 s->weights[p][
s->radius] = 1.f;
424 for (
int n = 1; n <=
s->radius; n++) {
425 s->weights[p][
s->radius + n] =
426 s->weights[p][
s->radius - n] =
expf(-0.5 * (n + 1) * (n + 1) / (sigma * sigma));
427 }
428 }
429
430 #if ARCH_X86
432 #endif
433
434 return 0;
435 }
436
438 {
444
445 if (
s->q.available !=
s->size) {
446 if (
s->q.available <
s->mid) {
447 for (
i = 0;
i <
s->mid;
i++) {
452 }
454 }
455 }
456 if (
s->q.available <
s->size) {
459 }
460 return 0;
461 }
462
464
465 if (!
ctx->is_disabled) {
467
472 }
473
474 for (
i = 0;
i <
s->size;
i++) {
476
477 s->data[0][
i] =
frame->data[0];
478 s->data[1][
i] =
frame->data[1];
479 s->data[2][
i] =
frame->data[2];
480 s->linesize[0][
i] =
frame->linesize[0];
481 s->linesize[1][
i] =
frame->linesize[1];
482 s->linesize[2][
i] =
frame->linesize[2];
483 }
484
491 } else {
496 }
497 }
498
502
504 }
505
507 {
511
513
516 if (!buf)
518
521 }
522
524 }
525
527 {
529
531 }
532
534 const char *cmd,
536 char *res,
537 int res_len,
539 {
541
544
546 }
547
549 {
554 },
555 };
556
558 {
562 },
563 };
564
566 .
name =
"atadenoise",
569 .priv_class = &atadenoise_class,
577 };