2 * Copyright (c) 2003 Daniel Moreno <comac AT comac DOT darktech DOT org>
3 * Copyright (c) 2010 Baptiste Coudurier
4 * Copyright (c) 2012 Loren Merritt
6 * This file is part of Libav, ported from MPlayer.
8 * Libav is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * Libav is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with Libav; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * high quality 3d video denoiser, ported from MPlayer
26 * libmpcodecs/vf_hqdn3d.c.
29 #include "libavutil/common.h"
30 #include "libavutil/pixdesc.h"
31 #include "libavutil/intreadwrite.h"
40 uint16_t *frame_prev
[3];
44 void (*denoise_row
[17])(uint8_t *src
, uint8_t *dst
, uint16_t *line_ant
, uint16_t *frame_ant
, ptrdiff_t w
, int16_t *spatial
, int16_t *temporal
);
47 void ff_hqdn3d_row_8_x86(uint8_t *src
, uint8_t *dst
, uint16_t *line_ant
, uint16_t *frame_ant
, ptrdiff_t w
, int16_t *spatial
, int16_t *temporal
);
48 void ff_hqdn3d_row_9_x86(uint8_t *src
, uint8_t *dst
, uint16_t *line_ant
, uint16_t *frame_ant
, ptrdiff_t w
, int16_t *spatial
, int16_t *temporal
);
49 void ff_hqdn3d_row_10_x86(uint8_t *src
, uint8_t *dst
, uint16_t *line_ant
, uint16_t *frame_ant
, ptrdiff_t w
, int16_t *spatial
, int16_t *temporal
);
50 void ff_hqdn3d_row_16_x86(uint8_t *src
, uint8_t *dst
, uint16_t *line_ant
, uint16_t *frame_ant
, ptrdiff_t w
, int16_t *spatial
, int16_t *temporal
);
52 #define LUT_BITS (depth==16 ? 8 : 4)
53 #define RIGHTSHIFT(a,b) (((a)+(((1<<(b))-1)>>1))>>(b))
54 #define LOAD(x) ((depth==8 ? src[x] : AV_RN16A(src+(x)*2)) << (16-depth))
55 #define STORE(x,val) (depth==8 ? dst[x] = RIGHTSHIFT(val, 16-depth)\
56 : AV_WN16A(dst+(x)*2, RIGHTSHIFT(val, 16-depth)))
59 static uint32_t lowpass(int prev
, int cur
, int16_t *coef
, int depth
)
61 int d
= (prev
- cur
) >> (8 - LUT_BITS
);
66 static void denoise_temporal(uint8_t *src
, uint8_t *dst
,
68 int w
, int h
, int sstride
, int dstride
,
69 int16_t *temporal
, int depth
)
74 temporal
+= 256 << LUT_BITS
;
76 for (y
= 0; y
< h
; y
++) {
77 for (x
= 0; x
< w
; x
++) {
78 frame_ant
[x
] = tmp
= lowpass(frame_ant
[x
], LOAD(x
), temporal
, depth
);
88 static void denoise_spatial(HQDN3DContext
*hqdn3d
,
89 uint8_t *src
, uint8_t *dst
,
90 uint16_t *line_ant
, uint16_t *frame_ant
,
91 int w
, int h
, int sstride
, int dstride
,
92 int16_t *spatial
, int16_t *temporal
, int depth
)
98 spatial
+= 256 << LUT_BITS
;
99 temporal
+= 256 << LUT_BITS
;
101 /* First line has no top neighbor. Only left one for each tmp and
104 for (x
= 0; x
< w
; x
++) {
105 line_ant
[x
] = tmp
= pixel_ant
= lowpass(pixel_ant
, LOAD(x
), spatial
, depth
);
106 frame_ant
[x
] = tmp
= lowpass(frame_ant
[x
], tmp
, temporal
, depth
);
110 for (y
= 1; y
< h
; y
++) {
114 if (hqdn3d
->denoise_row
[depth
]) {
115 hqdn3d
->denoise_row
[depth
](src
, dst
, line_ant
, frame_ant
, w
, spatial
, temporal
);
119 for (x
= 0; x
< w
-1; x
++) {
120 line_ant
[x
] = tmp
= lowpass(line_ant
[x
], pixel_ant
, spatial
, depth
);
121 pixel_ant
= lowpass(pixel_ant
, LOAD(x
+1), spatial
, depth
);
122 frame_ant
[x
] = tmp
= lowpass(frame_ant
[x
], tmp
, temporal
, depth
);
125 line_ant
[x
] = tmp
= lowpass(line_ant
[x
], pixel_ant
, spatial
, depth
);
126 frame_ant
[x
] = tmp
= lowpass(frame_ant
[x
], tmp
, temporal
, depth
);
132 static void denoise_depth(HQDN3DContext
*hqdn3d
,
133 uint8_t *src
, uint8_t *dst
,
134 uint16_t *line_ant
, uint16_t **frame_ant_ptr
,
135 int w
, int h
, int sstride
, int dstride
,
136 int16_t *spatial
, int16_t *temporal
, int depth
)
138 // FIXME: For 16bit depth, frame_ant could be a pointer to the previous
139 // filtered frame rather than a separate buffer.
141 uint16_t *frame_ant
= *frame_ant_ptr
;
143 uint8_t *frame_src
= src
;
144 *frame_ant_ptr
= frame_ant
= av_malloc(w
*h
*sizeof(uint16_t));
145 for (y
= 0; y
< h
; y
++, src
+= sstride
, frame_ant
+= w
)
146 for (x
= 0; x
< w
; x
++)
147 frame_ant
[x
] = LOAD(x
);
149 frame_ant
= *frame_ant_ptr
;
153 denoise_spatial(hqdn3d
, src
, dst
, line_ant
, frame_ant
,
154 w
, h
, sstride
, dstride
, spatial
, temporal
, depth
);
156 denoise_temporal(src
, dst
, frame_ant
,
157 w
, h
, sstride
, dstride
, temporal
, depth
);
160 #define denoise(...) \
161 switch (hqdn3d->depth) {\
162 case 8: denoise_depth(__VA_ARGS__, 8); break;\
163 case 9: denoise_depth(__VA_ARGS__, 9); break;\
164 case 10: denoise_depth(__VA_ARGS__, 10); break;\
165 case 16: denoise_depth(__VA_ARGS__, 16); break;\
168 static int16_t *precalc_coefs(double dist25
, int depth
)
171 double gamma
, simil
, C
;
172 int16_t *ct
= av_malloc((512<<LUT_BITS
)*sizeof(int16_t));
176 gamma
= log(0.25) / log(1.0 - FFMIN(dist25
,252.0)/255.0 - 0.00001);
178 for (i
= -255<<LUT_BITS
; i
<= 255<<LUT_BITS
; i
++) {
179 double f
= ((i
<<(9-LUT_BITS
)) + (1<<(8-LUT_BITS
)) - 1) / 512.0; // midpoint of the bin
180 simil
= 1.0 - FFABS(f
) / 255.0;
181 C
= pow(simil
, gamma
) * 256.0 * f
;
182 ct
[(256<<LUT_BITS
)+i
] = lrint(C
);
189 #define PARAM1_DEFAULT 4.0
190 #define PARAM2_DEFAULT 3.0
191 #define PARAM3_DEFAULT 6.0
193 static int init(AVFilterContext
*ctx
, const char *args
)
195 HQDN3DContext
*hqdn3d
= ctx
->priv
;
196 double lum_spac
, lum_tmp
, chrom_spac
, chrom_tmp
;
197 double param1
, param2
, param3
, param4
;
199 lum_spac
= PARAM1_DEFAULT
;
200 chrom_spac
= PARAM2_DEFAULT
;
201 lum_tmp
= PARAM3_DEFAULT
;
202 chrom_tmp
= lum_tmp
* chrom_spac
/ lum_spac
;
205 switch (sscanf(args
, "%lf:%lf:%lf:%lf",
206 ¶m1
, ¶m2
, ¶m3
, ¶m4
)) {
209 chrom_spac
= PARAM2_DEFAULT
* param1
/ PARAM1_DEFAULT
;
210 lum_tmp
= PARAM3_DEFAULT
* param1
/ PARAM1_DEFAULT
;
211 chrom_tmp
= lum_tmp
* chrom_spac
/ lum_spac
;
216 lum_tmp
= PARAM3_DEFAULT
* param1
/ PARAM1_DEFAULT
;
217 chrom_tmp
= lum_tmp
* chrom_spac
/ lum_spac
;
223 chrom_tmp
= lum_tmp
* chrom_spac
/ lum_spac
;
234 hqdn3d
->strength
[0] = lum_spac
;
235 hqdn3d
->strength
[1] = lum_tmp
;
236 hqdn3d
->strength
[2] = chrom_spac
;
237 hqdn3d
->strength
[3] = chrom_tmp
;
239 av_log(ctx
, AV_LOG_VERBOSE
, "ls:%f cs:%f lt:%f ct:%f\n",
240 lum_spac
, chrom_spac
, lum_tmp
, chrom_tmp
);
241 if (lum_spac
< 0 || chrom_spac
< 0 || isnan(chrom_tmp
)) {
242 av_log(ctx
, AV_LOG_ERROR
,
243 "Invalid negative value for luma or chroma spatial strength, "
244 "or resulting value for chroma temporal strength is nan.\n");
245 return AVERROR(EINVAL
);
251 static void uninit(AVFilterContext
*ctx
)
253 HQDN3DContext
*hqdn3d
= ctx
->priv
;
255 av_freep(&hqdn3d
->coefs
[0]);
256 av_freep(&hqdn3d
->coefs
[1]);
257 av_freep(&hqdn3d
->coefs
[2]);
258 av_freep(&hqdn3d
->coefs
[3]);
259 av_freep(&hqdn3d
->line
);
260 av_freep(&hqdn3d
->frame_prev
[0]);
261 av_freep(&hqdn3d
->frame_prev
[1]);
262 av_freep(&hqdn3d
->frame_prev
[2]);
265 static int query_formats(AVFilterContext
*ctx
)
267 static const enum AVPixelFormat pix_fmts
[] = {
278 AV_NE( AV_PIX_FMT_YUV420P9BE
, AV_PIX_FMT_YUV420P9LE
),
279 AV_NE( AV_PIX_FMT_YUV422P9BE
, AV_PIX_FMT_YUV422P9LE
),
280 AV_NE( AV_PIX_FMT_YUV444P9BE
, AV_PIX_FMT_YUV444P9LE
),
281 AV_NE( AV_PIX_FMT_YUV420P10BE
, AV_PIX_FMT_YUV420P10LE
),
282 AV_NE( AV_PIX_FMT_YUV422P10BE
, AV_PIX_FMT_YUV422P10LE
),
283 AV_NE( AV_PIX_FMT_YUV444P10BE
, AV_PIX_FMT_YUV444P10LE
),
284 AV_NE( AV_PIX_FMT_YUV420P16BE
, AV_PIX_FMT_YUV420P16LE
),
285 AV_NE( AV_PIX_FMT_YUV422P16BE
, AV_PIX_FMT_YUV422P16LE
),
286 AV_NE( AV_PIX_FMT_YUV444P16BE
, AV_PIX_FMT_YUV444P16LE
),
290 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
295 static int config_input(AVFilterLink
*inlink
)
297 HQDN3DContext
*hqdn3d
= inlink
->dst
->priv
;
298 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
301 hqdn3d
->hsub
= desc
->log2_chroma_w
;
302 hqdn3d
->vsub
= desc
->log2_chroma_h
;
303 hqdn3d
->depth
= desc
->comp
[0].depth_minus1
+1;
305 hqdn3d
->line
= av_malloc(inlink
->w
* sizeof(*hqdn3d
->line
));
307 return AVERROR(ENOMEM
);
309 for (i
= 0; i
< 4; i
++) {
310 hqdn3d
->coefs
[i
] = precalc_coefs(hqdn3d
->strength
[i
], hqdn3d
->depth
);
311 if (!hqdn3d
->coefs
[i
])
312 return AVERROR(ENOMEM
);
316 hqdn3d
->denoise_row
[ 8] = ff_hqdn3d_row_8_x86
;
317 hqdn3d
->denoise_row
[ 9] = ff_hqdn3d_row_9_x86
;
318 hqdn3d
->denoise_row
[10] = ff_hqdn3d_row_10_x86
;
319 hqdn3d
->denoise_row
[16] = ff_hqdn3d_row_16_x86
;
325 static int filter_frame(AVFilterLink
*inlink
, AVFilterBufferRef
*in
)
327 HQDN3DContext
*hqdn3d
= inlink
->dst
->priv
;
328 AVFilterLink
*outlink
= inlink
->dst
->outputs
[0];
329 AVFilterBufferRef
*out
;
332 if ((in
->perms
& AV_PERM_WRITE
) && !(in
->perms
& AV_PERM_PRESERVE
)) {
336 out
= ff_get_video_buffer(outlink
, AV_PERM_WRITE
, outlink
->w
, outlink
->h
);
338 avfilter_unref_bufferp(&in
);
339 return AVERROR(ENOMEM
);
342 avfilter_copy_buffer_ref_props(out
, in
);
343 out
->video
->w
= outlink
->w
;
344 out
->video
->h
= outlink
->h
;
347 for (c
= 0; c
< 3; c
++) {
348 denoise(hqdn3d
, in
->data
[c
], out
->data
[c
],
349 hqdn3d
->line
, &hqdn3d
->frame_prev
[c
],
350 in
->video
->w
>> (!!c
* hqdn3d
->hsub
),
351 in
->video
->h
>> (!!c
* hqdn3d
->vsub
),
352 in
->linesize
[c
], out
->linesize
[c
],
353 hqdn3d
->coefs
[c
?2:0], hqdn3d
->coefs
[c
?3:1]);
357 avfilter_unref_bufferp(&in
);
359 return ff_filter_frame(outlink
, out
);
362 static const AVFilterPad avfilter_vf_hqdn3d_inputs
[] = {
365 .type
= AVMEDIA_TYPE_VIDEO
,
366 .config_props
= config_input
,
367 .filter_frame
= filter_frame
,
372 static const AVFilterPad avfilter_vf_hqdn3d_outputs
[] = {
375 .type
= AVMEDIA_TYPE_VIDEO
380 AVFilter avfilter_vf_hqdn3d
= {
382 .description
= NULL_IF_CONFIG_SMALL("Apply a High Quality 3D Denoiser."),
384 .priv_size
= sizeof(HQDN3DContext
),
387 .query_formats
= query_formats
,
389 .inputs
= avfilter_vf_hqdn3d_inputs
,
391 .outputs
= avfilter_vf_hqdn3d_outputs
,