You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

595 lines
24KB

  1. /*
  2. * Copyright (c) 2016 Clément Bœsch <u pkh me>
  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. * @todo
  22. * - better automatic defaults? see "Parameters" @ http://www.ipol.im/pub/art/2011/bcm_nlm/
  23. * - temporal support (probably doesn't need any displacement according to
  24. * "Denoising image sequences does not require motion estimation")
  25. * - Bayer pixel format support for at least raw photos? (DNG support would be
  26. * handy here)
  27. * - FATE test (probably needs visual threshold test mechanism due to the use
  28. * of floats)
  29. */
  30. #include "libavutil/avassert.h"
  31. #include "libavutil/opt.h"
  32. #include "libavutil/pixdesc.h"
  33. #include "avfilter.h"
  34. #include "formats.h"
  35. #include "internal.h"
  36. #include "vf_nlmeans.h"
  37. #include "video.h"
  38. struct weighted_avg {
  39. float total_weight;
  40. float sum;
  41. };
  42. #define WEIGHT_LUT_NBITS 9
  43. #define WEIGHT_LUT_SIZE (1<<WEIGHT_LUT_NBITS)
  44. typedef struct NLMeansContext {
  45. const AVClass *class;
  46. int nb_planes;
  47. int chroma_w, chroma_h;
  48. double pdiff_scale; // invert of the filtering parameter (sigma*10) squared
  49. double sigma; // denoising strength
  50. int patch_size, patch_hsize; // patch size and half size
  51. int patch_size_uv, patch_hsize_uv; // patch size and half size for chroma planes
  52. int research_size, research_hsize; // research size and half size
  53. int research_size_uv, research_hsize_uv; // research size and half size for chroma planes
  54. uint32_t *ii_orig; // integral image
  55. uint32_t *ii; // integral image starting after the 0-line and 0-column
  56. int ii_w, ii_h; // width and height of the integral image
  57. ptrdiff_t ii_lz_32; // linesize in 32-bit units of the integral image
  58. struct weighted_avg *wa; // weighted average of every pixel
  59. ptrdiff_t wa_linesize; // linesize for wa in struct size unit
  60. float weight_lut[WEIGHT_LUT_SIZE]; // lookup table mapping (scaled) patch differences to their associated weights
  61. float pdiff_lut_scale; // scale factor for patch differences before looking into the LUT
  62. uint32_t max_meaningful_diff; // maximum difference considered (if the patch difference is too high we ignore the pixel)
  63. NLMeansDSPContext dsp;
  64. } NLMeansContext;
  65. #define OFFSET(x) offsetof(NLMeansContext, x)
  66. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  67. static const AVOption nlmeans_options[] = {
  68. { "s", "denoising strength", OFFSET(sigma), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, 1.0, 30.0, FLAGS },
  69. { "p", "patch size", OFFSET(patch_size), AV_OPT_TYPE_INT, { .i64 = 3*2+1 }, 0, 99, FLAGS },
  70. { "pc", "patch size for chroma planes", OFFSET(patch_size_uv), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 99, FLAGS },
  71. { "r", "research window", OFFSET(research_size), AV_OPT_TYPE_INT, { .i64 = 7*2+1 }, 0, 99, FLAGS },
  72. { "rc", "research window for chroma planes", OFFSET(research_size_uv), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 99, FLAGS },
  73. { NULL }
  74. };
  75. AVFILTER_DEFINE_CLASS(nlmeans);
  76. static int query_formats(AVFilterContext *ctx)
  77. {
  78. static const enum AVPixelFormat pix_fmts[] = {
  79. AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
  80. AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
  81. AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
  82. AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
  83. AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
  84. AV_PIX_FMT_YUVJ411P,
  85. AV_PIX_FMT_GRAY8, AV_PIX_FMT_GBRP,
  86. AV_PIX_FMT_NONE
  87. };
  88. AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
  89. if (!fmts_list)
  90. return AVERROR(ENOMEM);
  91. return ff_set_common_formats(ctx, fmts_list);
  92. }
  93. /**
  94. * Compute squared difference of the safe area (the zone where s1 and s2
  95. * overlap). It is likely the largest integral zone, so it is interesting to do
  96. * as little checks as possible; contrary to the unsafe version of this
  97. * function, we do not need any clipping here.
  98. *
  99. * The line above dst and the column to its left are always readable.
  100. */
  101. static void compute_safe_ssd_integral_image_c(uint32_t *dst, ptrdiff_t dst_linesize_32,
  102. const uint8_t *s1, ptrdiff_t linesize1,
  103. const uint8_t *s2, ptrdiff_t linesize2,
  104. int w, int h)
  105. {
  106. int x, y;
  107. const uint32_t *dst_top = dst - dst_linesize_32;
  108. /* SIMD-friendly assumptions allowed here */
  109. av_assert2(!(w & 0xf) && w >= 16 && h >= 1);
  110. for (y = 0; y < h; y++) {
  111. for (x = 0; x < w; x += 4) {
  112. const int d0 = s1[x ] - s2[x ];
  113. const int d1 = s1[x + 1] - s2[x + 1];
  114. const int d2 = s1[x + 2] - s2[x + 2];
  115. const int d3 = s1[x + 3] - s2[x + 3];
  116. dst[x ] = dst_top[x ] - dst_top[x - 1] + d0*d0;
  117. dst[x + 1] = dst_top[x + 1] - dst_top[x ] + d1*d1;
  118. dst[x + 2] = dst_top[x + 2] - dst_top[x + 1] + d2*d2;
  119. dst[x + 3] = dst_top[x + 3] - dst_top[x + 2] + d3*d3;
  120. dst[x ] += dst[x - 1];
  121. dst[x + 1] += dst[x ];
  122. dst[x + 2] += dst[x + 1];
  123. dst[x + 3] += dst[x + 2];
  124. }
  125. s1 += linesize1;
  126. s2 += linesize2;
  127. dst += dst_linesize_32;
  128. dst_top += dst_linesize_32;
  129. }
  130. }
  131. /**
  132. * Compute squared difference of an unsafe area (the zone nor s1 nor s2 could
  133. * be readable).
  134. *
  135. * On the other hand, the line above dst and the column to its left are always
  136. * readable.
  137. *
  138. * There is little point in having this function SIMDified as it is likely too
  139. * complex and only handle small portions of the image.
  140. *
  141. * @param dst integral image
  142. * @param dst_linesize_32 integral image linesize (in 32-bit integers unit)
  143. * @param startx integral starting x position
  144. * @param starty integral starting y position
  145. * @param src source plane buffer
  146. * @param linesize source plane linesize
  147. * @param offx source offsetting in x
  148. * @param offy source offsetting in y
  149. * @paran r absolute maximum source offsetting
  150. * @param sw source width
  151. * @param sh source height
  152. * @param w width to compute
  153. * @param h height to compute
  154. */
  155. static inline void compute_unsafe_ssd_integral_image(uint32_t *dst, ptrdiff_t dst_linesize_32,
  156. int startx, int starty,
  157. const uint8_t *src, ptrdiff_t linesize,
  158. int offx, int offy, int r, int sw, int sh,
  159. int w, int h)
  160. {
  161. int x, y;
  162. for (y = starty; y < starty + h; y++) {
  163. uint32_t acc = dst[y*dst_linesize_32 + startx - 1] - dst[(y-1)*dst_linesize_32 + startx - 1];
  164. const int s1y = av_clip(y - r, 0, sh - 1);
  165. const int s2y = av_clip(y - (r + offy), 0, sh - 1);
  166. for (x = startx; x < startx + w; x++) {
  167. const int s1x = av_clip(x - r, 0, sw - 1);
  168. const int s2x = av_clip(x - (r + offx), 0, sw - 1);
  169. const uint8_t v1 = src[s1y*linesize + s1x];
  170. const uint8_t v2 = src[s2y*linesize + s2x];
  171. const int d = v1 - v2;
  172. acc += d * d;
  173. dst[y*dst_linesize_32 + x] = dst[(y-1)*dst_linesize_32 + x] + acc;
  174. }
  175. }
  176. }
  177. /*
  178. * Compute the sum of squared difference integral image
  179. * http://www.ipol.im/pub/art/2014/57/
  180. * Integral Images for Block Matching - Gabriele Facciolo, Nicolas Limare, Enric Meinhardt-Llopis
  181. *
  182. * @param ii integral image of dimension (w+e*2) x (h+e*2) with
  183. * an additional zeroed top line and column already
  184. * "applied" to the pointer value
  185. * @param ii_linesize_32 integral image linesize (in 32-bit integers unit)
  186. * @param src source plane buffer
  187. * @param linesize source plane linesize
  188. * @param offx x-offsetting ranging in [-e;e]
  189. * @param offy y-offsetting ranging in [-e;e]
  190. * @param w source width
  191. * @param h source height
  192. * @param e research padding edge
  193. */
  194. static void compute_ssd_integral_image(const NLMeansDSPContext *dsp,
  195. uint32_t *ii, ptrdiff_t ii_linesize_32,
  196. const uint8_t *src, ptrdiff_t linesize, int offx, int offy,
  197. int e, int w, int h)
  198. {
  199. // ii has a surrounding padding of thickness "e"
  200. const int ii_w = w + e*2;
  201. const int ii_h = h + e*2;
  202. // we center the first source
  203. const int s1x = e;
  204. const int s1y = e;
  205. // 2nd source is the frame with offsetting
  206. const int s2x = e + offx;
  207. const int s2y = e + offy;
  208. // get the dimension of the overlapping rectangle where it is always safe
  209. // to compare the 2 sources pixels
  210. const int startx_safe = FFMAX(s1x, s2x);
  211. const int starty_safe = FFMAX(s1y, s2y);
  212. const int u_endx_safe = FFMIN(s1x + w, s2x + w); // unaligned
  213. const int endy_safe = FFMIN(s1y + h, s2y + h);
  214. // deduce the safe area width and height
  215. const int safe_pw = (u_endx_safe - startx_safe) & ~0xf;
  216. const int safe_ph = endy_safe - starty_safe;
  217. // adjusted end x position of the safe area after width of the safe area gets aligned
  218. const int endx_safe = startx_safe + safe_pw;
  219. // top part where only one of s1 and s2 is still readable, or none at all
  220. compute_unsafe_ssd_integral_image(ii, ii_linesize_32,
  221. 0, 0,
  222. src, linesize,
  223. offx, offy, e, w, h,
  224. ii_w, starty_safe);
  225. // fill the left column integral required to compute the central
  226. // overlapping one
  227. compute_unsafe_ssd_integral_image(ii, ii_linesize_32,
  228. 0, starty_safe,
  229. src, linesize,
  230. offx, offy, e, w, h,
  231. startx_safe, safe_ph);
  232. // main and safe part of the integral
  233. av_assert1(startx_safe - s1x >= 0); av_assert1(startx_safe - s1x < w);
  234. av_assert1(starty_safe - s1y >= 0); av_assert1(starty_safe - s1y < h);
  235. av_assert1(startx_safe - s2x >= 0); av_assert1(startx_safe - s2x < w);
  236. av_assert1(starty_safe - s2y >= 0); av_assert1(starty_safe - s2y < h);
  237. if (safe_pw && safe_ph)
  238. dsp->compute_safe_ssd_integral_image(ii + starty_safe*ii_linesize_32 + startx_safe, ii_linesize_32,
  239. src + (starty_safe - s1y) * linesize + (startx_safe - s1x), linesize,
  240. src + (starty_safe - s2y) * linesize + (startx_safe - s2x), linesize,
  241. safe_pw, safe_ph);
  242. // right part of the integral
  243. compute_unsafe_ssd_integral_image(ii, ii_linesize_32,
  244. endx_safe, starty_safe,
  245. src, linesize,
  246. offx, offy, e, w, h,
  247. ii_w - endx_safe, safe_ph);
  248. // bottom part where only one of s1 and s2 is still readable, or none at all
  249. compute_unsafe_ssd_integral_image(ii, ii_linesize_32,
  250. 0, endy_safe,
  251. src, linesize,
  252. offx, offy, e, w, h,
  253. ii_w, ii_h - endy_safe);
  254. }
  255. static int config_input(AVFilterLink *inlink)
  256. {
  257. AVFilterContext *ctx = inlink->dst;
  258. NLMeansContext *s = ctx->priv;
  259. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  260. const int e = FFMAX(s->research_hsize, s->research_hsize_uv)
  261. + FFMAX(s->patch_hsize, s->patch_hsize_uv);
  262. s->chroma_w = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
  263. s->chroma_h = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
  264. s->nb_planes = av_pix_fmt_count_planes(inlink->format);
  265. /* Allocate the integral image with extra edges of thickness "e"
  266. *
  267. * +_+-------------------------------+
  268. * |0|0000000000000000000000000000000|
  269. * +-x-------------------------------+
  270. * |0|\ ^ |
  271. * |0| ii | e |
  272. * |0| v |
  273. * |0| +-----------------------+ |
  274. * |0| | | |
  275. * |0|<->| | |
  276. * |0| e | | |
  277. * |0| | | |
  278. * |0| +-----------------------+ |
  279. * |0| |
  280. * |0| |
  281. * |0| |
  282. * +-+-------------------------------+
  283. */
  284. s->ii_w = inlink->w + e*2;
  285. s->ii_h = inlink->h + e*2;
  286. // align to 4 the linesize, "+1" is for the space of the left 0-column
  287. s->ii_lz_32 = FFALIGN(s->ii_w + 1, 4);
  288. // "+1" is for the space of the top 0-line
  289. s->ii_orig = av_mallocz_array(s->ii_h + 1, s->ii_lz_32 * sizeof(*s->ii_orig));
  290. if (!s->ii_orig)
  291. return AVERROR(ENOMEM);
  292. // skip top 0-line and left 0-column
  293. s->ii = s->ii_orig + s->ii_lz_32 + 1;
  294. // allocate weighted average for every pixel
  295. s->wa_linesize = inlink->w;
  296. s->wa = av_malloc_array(s->wa_linesize, inlink->h * sizeof(*s->wa));
  297. if (!s->wa)
  298. return AVERROR(ENOMEM);
  299. return 0;
  300. }
  301. struct thread_data {
  302. const uint8_t *src;
  303. ptrdiff_t src_linesize;
  304. int startx, starty;
  305. int endx, endy;
  306. const uint32_t *ii_start;
  307. int p;
  308. };
  309. static int nlmeans_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  310. {
  311. int x, y;
  312. NLMeansContext *s = ctx->priv;
  313. const struct thread_data *td = arg;
  314. const ptrdiff_t src_linesize = td->src_linesize;
  315. const int process_h = td->endy - td->starty;
  316. const int slice_start = (process_h * jobnr ) / nb_jobs;
  317. const int slice_end = (process_h * (jobnr+1)) / nb_jobs;
  318. const int starty = td->starty + slice_start;
  319. const int endy = td->starty + slice_end;
  320. const int p = td->p;
  321. const uint32_t *ii = td->ii_start + (starty - p - 1) * s->ii_lz_32 - p - 1;
  322. const int dist_b = 2*p + 1;
  323. const int dist_d = dist_b * s->ii_lz_32;
  324. const int dist_e = dist_d + dist_b;
  325. for (y = starty; y < endy; y++) {
  326. const uint8_t *src = td->src + y*src_linesize;
  327. struct weighted_avg *wa = s->wa + y*s->wa_linesize;
  328. for (x = td->startx; x < td->endx; x++) {
  329. /*
  330. * M is a discrete map where every entry contains the sum of all the entries
  331. * in the rectangle from the top-left origin of M to its coordinate. In the
  332. * following schema, "i" contains the sum of the whole map:
  333. *
  334. * M = +----------+-----------------+----+
  335. * | | | |
  336. * | | | |
  337. * | a| b| c|
  338. * +----------+-----------------+----+
  339. * | | | |
  340. * | | | |
  341. * | | X | |
  342. * | | | |
  343. * | d| e| f|
  344. * +----------+-----------------+----+
  345. * | | | |
  346. * | g| h| i|
  347. * +----------+-----------------+----+
  348. *
  349. * The sum of the X box can be calculated with:
  350. * X = e-d-b+a
  351. *
  352. * See https://en.wikipedia.org/wiki/Summed_area_table
  353. *
  354. * The compute*_ssd functions compute the integral image M where every entry
  355. * contains the sum of the squared difference of every corresponding pixels of
  356. * two input planes of the same size as M.
  357. */
  358. const uint32_t a = ii[x];
  359. const uint32_t b = ii[x + dist_b];
  360. const uint32_t d = ii[x + dist_d];
  361. const uint32_t e = ii[x + dist_e];
  362. const uint32_t patch_diff_sq = e - d - b + a;
  363. if (patch_diff_sq < s->max_meaningful_diff) {
  364. const unsigned weight_lut_idx = patch_diff_sq * s->pdiff_lut_scale;
  365. const float weight = s->weight_lut[weight_lut_idx]; // exp(-patch_diff_sq * s->pdiff_scale)
  366. wa[x].total_weight += weight;
  367. wa[x].sum += weight * src[x];
  368. }
  369. }
  370. ii += s->ii_lz_32;
  371. }
  372. return 0;
  373. }
  374. static void weight_averages(uint8_t *dst, ptrdiff_t dst_linesize,
  375. const uint8_t *src, ptrdiff_t src_linesize,
  376. struct weighted_avg *wa, ptrdiff_t wa_linesize,
  377. int w, int h)
  378. {
  379. int x, y;
  380. for (y = 0; y < h; y++) {
  381. for (x = 0; x < w; x++) {
  382. // Also weight the centered pixel
  383. wa[x].total_weight += 1.f;
  384. wa[x].sum += 1.f * src[x];
  385. dst[x] = av_clip_uint8(wa[x].sum / wa[x].total_weight);
  386. }
  387. dst += dst_linesize;
  388. src += src_linesize;
  389. wa += wa_linesize;
  390. }
  391. }
  392. static int nlmeans_plane(AVFilterContext *ctx, int w, int h, int p, int r,
  393. uint8_t *dst, ptrdiff_t dst_linesize,
  394. const uint8_t *src, ptrdiff_t src_linesize)
  395. {
  396. int offx, offy;
  397. NLMeansContext *s = ctx->priv;
  398. /* patches center points cover the whole research window so the patches
  399. * themselves overflow the research window */
  400. const int e = r + p;
  401. /* focus an integral pointer on the centered image (s1) */
  402. const uint32_t *centered_ii = s->ii + e*s->ii_lz_32 + e;
  403. memset(s->wa, 0, s->wa_linesize * h * sizeof(*s->wa));
  404. for (offy = -r; offy <= r; offy++) {
  405. for (offx = -r; offx <= r; offx++) {
  406. if (offx || offy) {
  407. struct thread_data td = {
  408. .src = src + offy*src_linesize + offx,
  409. .src_linesize = src_linesize,
  410. .startx = FFMAX(0, -offx),
  411. .starty = FFMAX(0, -offy),
  412. .endx = FFMIN(w, w - offx),
  413. .endy = FFMIN(h, h - offy),
  414. .ii_start = centered_ii + offy*s->ii_lz_32 + offx,
  415. .p = p,
  416. };
  417. compute_ssd_integral_image(&s->dsp, s->ii, s->ii_lz_32,
  418. src, src_linesize,
  419. offx, offy, e, w, h);
  420. ctx->internal->execute(ctx, nlmeans_slice, &td, NULL,
  421. FFMIN(td.endy - td.starty, ff_filter_get_nb_threads(ctx)));
  422. }
  423. }
  424. }
  425. weight_averages(dst, dst_linesize, src, src_linesize,
  426. s->wa, s->wa_linesize, w, h);
  427. return 0;
  428. }
  429. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  430. {
  431. int i;
  432. AVFilterContext *ctx = inlink->dst;
  433. NLMeansContext *s = ctx->priv;
  434. AVFilterLink *outlink = ctx->outputs[0];
  435. AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  436. if (!out) {
  437. av_frame_free(&in);
  438. return AVERROR(ENOMEM);
  439. }
  440. av_frame_copy_props(out, in);
  441. for (i = 0; i < s->nb_planes; i++) {
  442. const int w = i ? s->chroma_w : inlink->w;
  443. const int h = i ? s->chroma_h : inlink->h;
  444. const int p = i ? s->patch_hsize_uv : s->patch_hsize;
  445. const int r = i ? s->research_hsize_uv : s->research_hsize;
  446. nlmeans_plane(ctx, w, h, p, r,
  447. out->data[i], out->linesize[i],
  448. in->data[i], in->linesize[i]);
  449. }
  450. av_frame_free(&in);
  451. return ff_filter_frame(outlink, out);
  452. }
  453. #define CHECK_ODD_FIELD(field, name) do { \
  454. if (!(s->field & 1)) { \
  455. s->field |= 1; \
  456. av_log(ctx, AV_LOG_WARNING, name " size must be odd, " \
  457. "setting it to %d\n", s->field); \
  458. } \
  459. } while (0)
  460. void ff_nlmeans_init(NLMeansDSPContext *dsp)
  461. {
  462. dsp->compute_safe_ssd_integral_image = compute_safe_ssd_integral_image_c;
  463. if (ARCH_AARCH64)
  464. ff_nlmeans_init_aarch64(dsp);
  465. }
  466. static av_cold int init(AVFilterContext *ctx)
  467. {
  468. int i;
  469. NLMeansContext *s = ctx->priv;
  470. const double h = s->sigma * 10.;
  471. s->pdiff_scale = 1. / (h * h);
  472. s->max_meaningful_diff = -log(1/255.) / s->pdiff_scale;
  473. s->pdiff_lut_scale = 1./s->max_meaningful_diff * WEIGHT_LUT_SIZE;
  474. av_assert0((s->max_meaningful_diff - 1) * s->pdiff_lut_scale < FF_ARRAY_ELEMS(s->weight_lut));
  475. for (i = 0; i < WEIGHT_LUT_SIZE; i++)
  476. s->weight_lut[i] = exp(-i / s->pdiff_lut_scale * s->pdiff_scale);
  477. CHECK_ODD_FIELD(research_size, "Luma research window");
  478. CHECK_ODD_FIELD(patch_size, "Luma patch");
  479. if (!s->research_size_uv) s->research_size_uv = s->research_size;
  480. if (!s->patch_size_uv) s->patch_size_uv = s->patch_size;
  481. CHECK_ODD_FIELD(research_size_uv, "Chroma research window");
  482. CHECK_ODD_FIELD(patch_size_uv, "Chroma patch");
  483. s->research_hsize = s->research_size / 2;
  484. s->research_hsize_uv = s->research_size_uv / 2;
  485. s->patch_hsize = s->patch_size / 2;
  486. s->patch_hsize_uv = s->patch_size_uv / 2;
  487. av_log(ctx, AV_LOG_INFO, "Research window: %dx%d / %dx%d, patch size: %dx%d / %dx%d\n",
  488. s->research_size, s->research_size, s->research_size_uv, s->research_size_uv,
  489. s->patch_size, s->patch_size, s->patch_size_uv, s->patch_size_uv);
  490. ff_nlmeans_init(&s->dsp);
  491. return 0;
  492. }
  493. static av_cold void uninit(AVFilterContext *ctx)
  494. {
  495. NLMeansContext *s = ctx->priv;
  496. av_freep(&s->ii_orig);
  497. av_freep(&s->wa);
  498. }
  499. static const AVFilterPad nlmeans_inputs[] = {
  500. {
  501. .name = "default",
  502. .type = AVMEDIA_TYPE_VIDEO,
  503. .config_props = config_input,
  504. .filter_frame = filter_frame,
  505. },
  506. { NULL }
  507. };
  508. static const AVFilterPad nlmeans_outputs[] = {
  509. {
  510. .name = "default",
  511. .type = AVMEDIA_TYPE_VIDEO,
  512. },
  513. { NULL }
  514. };
  515. AVFilter ff_vf_nlmeans = {
  516. .name = "nlmeans",
  517. .description = NULL_IF_CONFIG_SMALL("Non-local means denoiser."),
  518. .priv_size = sizeof(NLMeansContext),
  519. .init = init,
  520. .uninit = uninit,
  521. .query_formats = query_formats,
  522. .inputs = nlmeans_inputs,
  523. .outputs = nlmeans_outputs,
  524. .priv_class = &nlmeans_class,
  525. .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
  526. };