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.
30 #include "libavutil/common.h"
31 #include "libavutil/pixdesc.h"
32 #include "libavutil/intreadwrite.h"
37 #include "vf_hqdn3d.h"
39 #define LUT_BITS (depth==16 ? 8 : 4)
40 #define RIGHTSHIFT(a,b) (((a)+(((1<<(b))-1)>>1))>>(b))
41 #define LOAD(x) ((depth==8 ? src[x] : AV_RN16A(src+(x)*2)) << (16-depth))
42 #define STORE(x,val) (depth==8 ? dst[x] = RIGHTSHIFT(val, 16-depth)\
43 : AV_WN16A(dst+(x)*2, RIGHTSHIFT(val, 16-depth)))
46 static uint32_t lowpass(int prev
, int cur
, int16_t *coef
, int depth
)
48 int d
= (prev
- cur
) >> (8 - LUT_BITS
);
53 static void denoise_temporal(uint8_t *src
, uint8_t *dst
,
55 int w
, int h
, int sstride
, int dstride
,
56 int16_t *temporal
, int depth
)
61 temporal
+= 256 << LUT_BITS
;
63 for (y
= 0; y
< h
; y
++) {
64 for (x
= 0; x
< w
; x
++) {
65 frame_ant
[x
] = tmp
= lowpass(frame_ant
[x
], LOAD(x
), temporal
, depth
);
75 static void denoise_spatial(HQDN3DContext
*hqdn3d
,
76 uint8_t *src
, uint8_t *dst
,
77 uint16_t *line_ant
, uint16_t *frame_ant
,
78 int w
, int h
, int sstride
, int dstride
,
79 int16_t *spatial
, int16_t *temporal
, int depth
)
85 spatial
+= 256 << LUT_BITS
;
86 temporal
+= 256 << LUT_BITS
;
88 /* First line has no top neighbor. Only left one for each tmp and
91 for (x
= 0; x
< w
; x
++) {
92 line_ant
[x
] = tmp
= pixel_ant
= lowpass(pixel_ant
, LOAD(x
), spatial
, depth
);
93 frame_ant
[x
] = tmp
= lowpass(frame_ant
[x
], tmp
, temporal
, depth
);
97 for (y
= 1; y
< h
; y
++) {
101 if (hqdn3d
->denoise_row
[depth
]) {
102 hqdn3d
->denoise_row
[depth
](src
, dst
, line_ant
, frame_ant
, w
, spatial
, temporal
);
106 for (x
= 0; x
< w
-1; x
++) {
107 line_ant
[x
] = tmp
= lowpass(line_ant
[x
], pixel_ant
, spatial
, depth
);
108 pixel_ant
= lowpass(pixel_ant
, LOAD(x
+1), spatial
, depth
);
109 frame_ant
[x
] = tmp
= lowpass(frame_ant
[x
], tmp
, temporal
, depth
);
112 line_ant
[x
] = tmp
= lowpass(line_ant
[x
], pixel_ant
, spatial
, depth
);
113 frame_ant
[x
] = tmp
= lowpass(frame_ant
[x
], tmp
, temporal
, depth
);
119 static void denoise_depth(HQDN3DContext
*hqdn3d
,
120 uint8_t *src
, uint8_t *dst
,
121 uint16_t *line_ant
, uint16_t **frame_ant_ptr
,
122 int w
, int h
, int sstride
, int dstride
,
123 int16_t *spatial
, int16_t *temporal
, int depth
)
125 // FIXME: For 16bit depth, frame_ant could be a pointer to the previous
126 // filtered frame rather than a separate buffer.
128 uint16_t *frame_ant
= *frame_ant_ptr
;
130 uint8_t *frame_src
= src
;
131 *frame_ant_ptr
= frame_ant
= av_malloc(w
*h
*sizeof(uint16_t));
132 for (y
= 0; y
< h
; y
++, src
+= sstride
, frame_ant
+= w
)
133 for (x
= 0; x
< w
; x
++)
134 frame_ant
[x
] = LOAD(x
);
136 frame_ant
= *frame_ant_ptr
;
140 denoise_spatial(hqdn3d
, src
, dst
, line_ant
, frame_ant
,
141 w
, h
, sstride
, dstride
, spatial
, temporal
, depth
);
143 denoise_temporal(src
, dst
, frame_ant
,
144 w
, h
, sstride
, dstride
, temporal
, depth
);
147 #define denoise(...) \
148 switch (hqdn3d->depth) {\
149 case 8: denoise_depth(__VA_ARGS__, 8); break;\
150 case 9: denoise_depth(__VA_ARGS__, 9); break;\
151 case 10: denoise_depth(__VA_ARGS__, 10); break;\
152 case 16: denoise_depth(__VA_ARGS__, 16); break;\
155 static int16_t *precalc_coefs(double dist25
, int depth
)
158 double gamma
, simil
, C
;
159 int16_t *ct
= av_malloc((512<<LUT_BITS
)*sizeof(int16_t));
163 gamma
= log(0.25) / log(1.0 - FFMIN(dist25
,252.0)/255.0 - 0.00001);
165 for (i
= -255<<LUT_BITS
; i
<= 255<<LUT_BITS
; i
++) {
166 double f
= ((i
<<(9-LUT_BITS
)) + (1<<(8-LUT_BITS
)) - 1) / 512.0; // midpoint of the bin
167 simil
= 1.0 - FFABS(f
) / 255.0;
168 C
= pow(simil
, gamma
) * 256.0 * f
;
169 ct
[(256<<LUT_BITS
)+i
] = lrint(C
);
176 #define PARAM1_DEFAULT 4.0
177 #define PARAM2_DEFAULT 3.0
178 #define PARAM3_DEFAULT 6.0
180 static int init(AVFilterContext
*ctx
, const char *args
)
182 HQDN3DContext
*hqdn3d
= ctx
->priv
;
183 double lum_spac
, lum_tmp
, chrom_spac
, chrom_tmp
;
184 double param1
, param2
, param3
, param4
;
186 lum_spac
= PARAM1_DEFAULT
;
187 chrom_spac
= PARAM2_DEFAULT
;
188 lum_tmp
= PARAM3_DEFAULT
;
189 chrom_tmp
= lum_tmp
* chrom_spac
/ lum_spac
;
192 switch (sscanf(args
, "%lf:%lf:%lf:%lf",
193 ¶m1
, ¶m2
, ¶m3
, ¶m4
)) {
196 chrom_spac
= PARAM2_DEFAULT
* param1
/ PARAM1_DEFAULT
;
197 lum_tmp
= PARAM3_DEFAULT
* param1
/ PARAM1_DEFAULT
;
198 chrom_tmp
= lum_tmp
* chrom_spac
/ lum_spac
;
203 lum_tmp
= PARAM3_DEFAULT
* param1
/ PARAM1_DEFAULT
;
204 chrom_tmp
= lum_tmp
* chrom_spac
/ lum_spac
;
210 chrom_tmp
= lum_tmp
* chrom_spac
/ lum_spac
;
221 hqdn3d
->strength
[0] = lum_spac
;
222 hqdn3d
->strength
[1] = lum_tmp
;
223 hqdn3d
->strength
[2] = chrom_spac
;
224 hqdn3d
->strength
[3] = chrom_tmp
;
226 av_log(ctx
, AV_LOG_VERBOSE
, "ls:%f cs:%f lt:%f ct:%f\n",
227 lum_spac
, chrom_spac
, lum_tmp
, chrom_tmp
);
228 if (lum_spac
< 0 || chrom_spac
< 0 || isnan(chrom_tmp
)) {
229 av_log(ctx
, AV_LOG_ERROR
,
230 "Invalid negative value for luma or chroma spatial strength, "
231 "or resulting value for chroma temporal strength is nan.\n");
232 return AVERROR(EINVAL
);
238 static void uninit(AVFilterContext
*ctx
)
240 HQDN3DContext
*hqdn3d
= ctx
->priv
;
242 av_freep(&hqdn3d
->coefs
[0]);
243 av_freep(&hqdn3d
->coefs
[1]);
244 av_freep(&hqdn3d
->coefs
[2]);
245 av_freep(&hqdn3d
->coefs
[3]);
246 av_freep(&hqdn3d
->line
);
247 av_freep(&hqdn3d
->frame_prev
[0]);
248 av_freep(&hqdn3d
->frame_prev
[1]);
249 av_freep(&hqdn3d
->frame_prev
[2]);
252 static int query_formats(AVFilterContext
*ctx
)
254 static const enum AVPixelFormat pix_fmts
[] = {
265 AV_NE( AV_PIX_FMT_YUV420P9BE
, AV_PIX_FMT_YUV420P9LE
),
266 AV_NE( AV_PIX_FMT_YUV422P9BE
, AV_PIX_FMT_YUV422P9LE
),
267 AV_NE( AV_PIX_FMT_YUV444P9BE
, AV_PIX_FMT_YUV444P9LE
),
268 AV_NE( AV_PIX_FMT_YUV420P10BE
, AV_PIX_FMT_YUV420P10LE
),
269 AV_NE( AV_PIX_FMT_YUV422P10BE
, AV_PIX_FMT_YUV422P10LE
),
270 AV_NE( AV_PIX_FMT_YUV444P10BE
, AV_PIX_FMT_YUV444P10LE
),
271 AV_NE( AV_PIX_FMT_YUV420P16BE
, AV_PIX_FMT_YUV420P16LE
),
272 AV_NE( AV_PIX_FMT_YUV422P16BE
, AV_PIX_FMT_YUV422P16LE
),
273 AV_NE( AV_PIX_FMT_YUV444P16BE
, AV_PIX_FMT_YUV444P16LE
),
277 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
282 static int config_input(AVFilterLink
*inlink
)
284 HQDN3DContext
*hqdn3d
= inlink
->dst
->priv
;
285 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
288 hqdn3d
->hsub
= desc
->log2_chroma_w
;
289 hqdn3d
->vsub
= desc
->log2_chroma_h
;
290 hqdn3d
->depth
= desc
->comp
[0].depth_minus1
+1;
292 hqdn3d
->line
= av_malloc(inlink
->w
* sizeof(*hqdn3d
->line
));
294 return AVERROR(ENOMEM
);
296 for (i
= 0; i
< 4; i
++) {
297 hqdn3d
->coefs
[i
] = precalc_coefs(hqdn3d
->strength
[i
], hqdn3d
->depth
);
298 if (!hqdn3d
->coefs
[i
])
299 return AVERROR(ENOMEM
);
303 ff_hqdn3d_init_x86(hqdn3d
);
308 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
310 HQDN3DContext
*hqdn3d
= inlink
->dst
->priv
;
311 AVFilterLink
*outlink
= inlink
->dst
->outputs
[0];
315 if (av_frame_is_writable(in
)) {
319 out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
322 return AVERROR(ENOMEM
);
325 av_frame_copy_props(out
, in
);
326 out
->width
= outlink
->w
;
327 out
->height
= outlink
->h
;
330 for (c
= 0; c
< 3; c
++) {
331 denoise(hqdn3d
, in
->data
[c
], out
->data
[c
],
332 hqdn3d
->line
, &hqdn3d
->frame_prev
[c
],
333 in
->width
>> (!!c
* hqdn3d
->hsub
),
334 in
->height
>> (!!c
* hqdn3d
->vsub
),
335 in
->linesize
[c
], out
->linesize
[c
],
336 hqdn3d
->coefs
[c
?2:0], hqdn3d
->coefs
[c
?3:1]);
342 return ff_filter_frame(outlink
, out
);
345 static const AVFilterPad avfilter_vf_hqdn3d_inputs
[] = {
348 .type
= AVMEDIA_TYPE_VIDEO
,
349 .config_props
= config_input
,
350 .filter_frame
= filter_frame
,
355 static const AVFilterPad avfilter_vf_hqdn3d_outputs
[] = {
358 .type
= AVMEDIA_TYPE_VIDEO
363 AVFilter avfilter_vf_hqdn3d
= {
365 .description
= NULL_IF_CONFIG_SMALL("Apply a High Quality 3D Denoiser."),
367 .priv_size
= sizeof(HQDN3DContext
),
370 .query_formats
= query_formats
,
372 .inputs
= avfilter_vf_hqdn3d_inputs
,
374 .outputs
= avfilter_vf_hqdn3d_outputs
,