1 /*****************************************************************************
2 * hqdn3d.c : high-quality denoise 3D ported from MPlayer
3 *****************************************************************************
4 * Copyright (C) 2011 VLC authors and VideoLAN
6 * Authors: Cheng Sun <chengsun9@gmail.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program 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 Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
25 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_filter.h>
34 #include <vlc_picture.h>
35 #include "filter_picture.h"
40 /*****************************************************************************
42 *****************************************************************************/
43 static int Open (filter_t
*);
44 static void Close (filter_t
*);
45 static picture_t
*Filter (filter_t
*, picture_t
*);
46 static int DenoiseCallback( vlc_object_t
*p_this
, char const *psz_var
,
47 vlc_value_t oldval
, vlc_value_t newval
,
50 /*****************************************************************************
52 *****************************************************************************/
54 #define FILTER_PREFIX "hqdn3d-"
56 #define LUMA_SPAT_TEXT N_("Spatial luma strength (0-254)")
57 #define CHROMA_SPAT_TEXT N_("Spatial chroma strength (0-254)")
58 #define LUMA_TEMP_TEXT N_("Temporal luma strength (0-254)")
59 #define CHROMA_TEMP_TEXT N_("Temporal chroma strength (0-254)")
62 set_shortname(N_("HQ Denoiser 3D"))
63 set_description(N_("High Quality 3D Denoiser filter"))
64 set_category(CAT_VIDEO
)
65 set_subcategory(SUBCAT_VIDEO_VFILTER
)
67 add_float_with_range(FILTER_PREFIX
"luma-spat", 4.0, 0.0, 254.0,
68 LUMA_SPAT_TEXT
, LUMA_SPAT_TEXT
, false)
69 add_float_with_range(FILTER_PREFIX
"chroma-spat", 3.0, 0.0, 254.0,
70 CHROMA_SPAT_TEXT
, CHROMA_SPAT_TEXT
, false)
71 add_float_with_range(FILTER_PREFIX
"luma-temp", 6.0, 0.0, 254.0,
72 LUMA_TEMP_TEXT
, LUMA_TEMP_TEXT
, false)
73 add_float_with_range(FILTER_PREFIX
"chroma-temp", 4.5, 0.0, 254.0,
74 CHROMA_TEMP_TEXT
, CHROMA_TEMP_TEXT
, false)
76 add_shortcut("hqdn3d")
78 set_callback_video_filter(Open
)
81 static const char *const filter_options
[] = {
82 "luma-spat", "chroma-spat", "luma-temp", "chroma-temp", NULL
85 /*****************************************************************************
87 *****************************************************************************/
90 const vlc_chroma_description_t
*chroma
;
95 vlc_mutex_t coefs_mutex
;
96 float luma_spat
, luma_temp
, chroma_spat
, chroma_temp
;
99 /*****************************************************************************
101 *****************************************************************************/
102 static int Open(filter_t
*filter
)
105 struct vf_priv_s
*cfg
;
106 const video_format_t
*fmt_in
= &filter
->fmt_in
.video
;
107 const video_format_t
*fmt_out
= &filter
->fmt_out
.video
;
108 const vlc_fourcc_t fourcc_in
= fmt_in
->i_chroma
;
109 const vlc_fourcc_t fourcc_out
= fmt_out
->i_chroma
;
112 const vlc_chroma_description_t
*chroma
=
113 vlc_fourcc_GetChromaDescription(fourcc_in
);
114 if (!chroma
|| chroma
->plane_count
!= 3 || chroma
->pixel_size
!= 1) {
115 msg_Err(filter
, "Unsupported chroma (%4.4s)", (char*)&fourcc_in
);
119 if (fourcc_in
!= fourcc_out
) {
120 msg_Err(filter
, "Input and output chromas don't match");
124 /* Allocate structure */
125 sys
= calloc(1, sizeof(filter_sys_t
));
131 sys
->chroma
= chroma
;
133 for (int i
= 0; i
< 3; ++i
) {
134 sys
->w
[i
] = fmt_in
->i_width
* chroma
->p
[i
].w
.num
/ chroma
->p
[i
].w
.den
;
135 if (sys
->w
[i
] > wmax
) wmax
= sys
->w
[i
];
136 sys
->h
[i
] = fmt_out
->i_height
* chroma
->p
[i
].h
.num
/ chroma
->p
[i
].h
.den
;
138 cfg
->Line
= malloc(wmax
*sizeof(unsigned int));
144 config_ChainParse(filter
, FILTER_PREFIX
, filter_options
,
148 vlc_mutex_init( &sys
->coefs_mutex
);
149 sys
->b_recalc_coefs
= true;
150 sys
->luma_spat
= var_CreateGetFloatCommand(filter
, FILTER_PREFIX
"luma-spat");
151 sys
->chroma_spat
= var_CreateGetFloatCommand(filter
, FILTER_PREFIX
"chroma-spat");
152 sys
->luma_temp
= var_CreateGetFloatCommand(filter
, FILTER_PREFIX
"luma-temp");
153 sys
->chroma_temp
= var_CreateGetFloatCommand(filter
, FILTER_PREFIX
"chroma-temp");
155 static const struct vlc_filter_operations filter_ops
=
157 .filter_video
= Filter
, .close
= Close
,
161 filter
->ops
= &filter_ops
;
163 var_AddCallback( filter
, FILTER_PREFIX
"luma-spat", DenoiseCallback
, sys
);
164 var_AddCallback( filter
, FILTER_PREFIX
"chroma-spat", DenoiseCallback
, sys
);
165 var_AddCallback( filter
, FILTER_PREFIX
"luma-temp", DenoiseCallback
, sys
);
166 var_AddCallback( filter
, FILTER_PREFIX
"chroma-temp", DenoiseCallback
, sys
);
171 /*****************************************************************************
173 *****************************************************************************/
174 static void Close(filter_t
*filter
)
176 filter_sys_t
*sys
= filter
->p_sys
;
177 struct vf_priv_s
*cfg
= &sys
->cfg
;
179 var_DelCallback( filter
, FILTER_PREFIX
"luma-spat", DenoiseCallback
, sys
);
180 var_DelCallback( filter
, FILTER_PREFIX
"chroma-spat", DenoiseCallback
, sys
);
181 var_DelCallback( filter
, FILTER_PREFIX
"luma-temp", DenoiseCallback
, sys
);
182 var_DelCallback( filter
, FILTER_PREFIX
"chroma-temp", DenoiseCallback
, sys
);
184 for (int i
= 0; i
< 3; ++i
) {
191 /*****************************************************************************
193 *****************************************************************************/
194 static picture_t
*Filter(filter_t
*filter
, picture_t
*src
)
197 filter_sys_t
*sys
= filter
->p_sys
;
198 struct vf_priv_s
*cfg
= &sys
->cfg
;
201 if (!src
) return NULL
;
203 dst
= filter_NewPicture(filter
);
204 if ( unlikely(!dst
) ) {
205 picture_Release(src
);
208 vlc_mutex_lock( &sys
->coefs_mutex
);
209 recalc
= sys
->b_recalc_coefs
;
210 sys
->b_recalc_coefs
= false;
212 if( unlikely( recalc
) )
214 msg_Dbg( filter
, "Changing coefs to %.2f %.2f %.2f %.2f",
215 sys
->luma_spat
, sys
->luma_temp
, sys
->chroma_spat
, sys
->chroma_temp
);
216 PrecalcCoefs(cfg
->Coefs
[0], sys
->luma_spat
);
217 PrecalcCoefs(cfg
->Coefs
[1], sys
->luma_temp
);
218 PrecalcCoefs(cfg
->Coefs
[2], sys
->chroma_spat
);
219 PrecalcCoefs(cfg
->Coefs
[3], sys
->chroma_temp
);
221 vlc_mutex_unlock( &sys
->coefs_mutex
);
223 deNoise(src
->p
[0].p_pixels
, dst
->p
[0].p_pixels
,
224 cfg
->Line
, &cfg
->Frame
[0], sys
->w
[0], sys
->h
[0],
225 src
->p
[0].i_pitch
, dst
->p
[0].i_pitch
,
229 deNoise(src
->p
[1].p_pixels
, dst
->p
[1].p_pixels
,
230 cfg
->Line
, &cfg
->Frame
[1], sys
->w
[1], sys
->h
[1],
231 src
->p
[1].i_pitch
, dst
->p
[1].i_pitch
,
235 deNoise(src
->p
[2].p_pixels
, dst
->p
[2].p_pixels
,
236 cfg
->Line
, &cfg
->Frame
[2], sys
->w
[2], sys
->h
[2],
237 src
->p
[2].i_pitch
, dst
->p
[2].i_pitch
,
242 if(unlikely(!cfg
->Frame
[0] || !cfg
->Frame
[1] || !cfg
->Frame
[2]))
244 picture_Release( src
);
245 picture_Release( dst
);
249 return CopyInfoAndRelease(dst
, src
);
253 static int DenoiseCallback( vlc_object_t
*p_this
, char const *psz_var
,
254 vlc_value_t oldval
, vlc_value_t newval
,
257 VLC_UNUSED(p_this
); VLC_UNUSED(oldval
);
259 filter_sys_t
*sys
= (filter_sys_t
*)p_data
;
261 /* Just take values and flag for recalc so we don't block UI thread calling this
262 * and don't right thread safety calcing coefs in here without mutex*/
263 vlc_mutex_lock( &sys
->coefs_mutex
);
264 if( !strcmp( psz_var
, FILTER_PREFIX
"luma-spat") )
265 sys
->luma_spat
= newval
.f_float
;
266 else if( !strcmp( psz_var
, FILTER_PREFIX
"luma-temp") )
267 sys
->luma_temp
= newval
.f_float
;
268 else if( !strcmp( psz_var
, FILTER_PREFIX
"chroma-temp") )
269 sys
->chroma_spat
= newval
.f_float
;
270 else if( !strcmp( psz_var
, FILTER_PREFIX
"chroma-spat") )
271 sys
->chroma_temp
= newval
.f_float
;
272 sys
->b_recalc_coefs
= true;
273 vlc_mutex_unlock( &sys
->coefs_mutex
);