1 /*****************************************************************************
2 * antiflicker.c : antiflicker video effect plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2011 VLC authors and VideoLAN
7 * Authors: Dharani Prabhu <dharani.prabhu.s@gmail.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_filter.h>
35 #include <vlc_atomic.h>
36 #include <vlc_picture.h>
37 #include "filter_picture.h"
39 /*****************************************************************************
41 *****************************************************************************/
42 static int GetLuminanceAvg( picture_t
* p_pic
);
43 static picture_t
*Filter( filter_t
*, picture_t
* );
44 static int AntiFlickerCallback( vlc_object_t
*p_this
, char const *psz_var
,
45 vlc_value_t oldval
, vlc_value_t newval
,
48 static int Create ( vlc_object_t
* );
49 static void Destroy ( vlc_object_t
* );
51 #define WINDOW_TEXT N_("Window size")
52 #define WINDOW_LONGTEXT N_("Number of frames (0 to 100)")
54 #define SFTN_TEXT N_("Softening value")
55 #define SFTN_LONGTEXT N_("Number of frames consider for smoothening (0 to 30)")
57 #define FILTER_PREFIX "antiflicker-"
59 #define MAX_WINDOW_SZ 100
60 #define MAX_SOFTENING_SZ 31
61 #define SCENE_CHANGE_THRESHOLD 100
63 /*****************************************************************************
65 *****************************************************************************/
67 set_description( N_("antiflicker video filter") )
68 set_shortname( N_( "antiflicker" ))
69 set_capability( "video filter", 0 )
70 set_category( CAT_VIDEO
)
71 set_subcategory( SUBCAT_VIDEO_VFILTER
)
73 add_integer_with_range( FILTER_PREFIX
"window-size", 10, 0, MAX_WINDOW_SZ
,
74 WINDOW_TEXT
, WINDOW_LONGTEXT
, false )
76 add_integer_with_range( FILTER_PREFIX
"softening-size", 10, 0, MAX_SOFTENING_SZ
,
77 SFTN_TEXT
, SFTN_LONGTEXT
, false )
79 add_shortcut( "antiflicker" )
80 set_callbacks( Create
, Destroy
)
83 /*****************************************************************************
84 * filter_sys_t: Distort video output method descriptor
85 *****************************************************************************
86 * This structure is part of the video output thread descriptor.
87 * It describes the Distort specific properties of an output thread.
88 *****************************************************************************/
91 atomic_int i_window_size
;
92 atomic_int i_softening
;
93 int ia_luminance_data
[MAX_WINDOW_SZ
];
97 /*****************************************************************************
98 * Create: allocates Distort video thread output method
99 *****************************************************************************
100 * This function allocates and initializes a Distort vout method.
101 *****************************************************************************/
102 static int Create( vlc_object_t
*p_this
)
104 filter_t
*p_filter
= (filter_t
*)p_this
;
106 switch( p_filter
->fmt_in
.video
.i_chroma
)
112 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
113 (char*)&(p_filter
->fmt_in
.video
.i_chroma
) );
117 /* Allocate structure */
118 p_filter
->p_sys
= malloc( sizeof( *p_filter
->p_sys
) );
119 if( p_filter
->p_sys
== NULL
)
122 p_filter
->pf_video_filter
= Filter
;
124 /* Initialize the arguments */
125 atomic_init( &p_filter
->p_sys
->i_window_size
,
126 var_CreateGetIntegerCommand( p_filter
,
127 FILTER_PREFIX
"window-size" ) );
128 atomic_init( &p_filter
->p_sys
->i_softening
,
129 var_CreateGetIntegerCommand( p_filter
,
130 FILTER_PREFIX
"softening-size" ) );
132 p_filter
->p_sys
->p_old_data
= calloc( p_filter
->fmt_in
.video
.i_width
*
133 (p_filter
->fmt_in
.video
.i_height
+1),sizeof(*p_filter
->p_sys
->p_old_data
) );
135 if( p_filter
->p_sys
->p_old_data
== NULL
)
137 free( p_filter
->p_sys
);
141 memset( p_filter
->p_sys
->ia_luminance_data
, 0,
142 sizeof(p_filter
->p_sys
->ia_luminance_data
) );
143 p_filter
->p_sys
->ia_luminance_data
[p_filter
->p_sys
->i_window_size
- 1] = 256;
145 var_AddCallback(p_filter
,FILTER_PREFIX
"window-size",
146 AntiFlickerCallback
, p_filter
->p_sys
);
147 var_AddCallback(p_filter
,FILTER_PREFIX
"softening-size",
148 AntiFlickerCallback
, p_filter
->p_sys
);
153 /*****************************************************************************
154 * Destroy: destroy Distort video thread output method
155 *****************************************************************************
156 * Terminate an output method created by DistortCreateOutputMethod
157 *****************************************************************************/
158 static void Destroy( vlc_object_t
*p_this
)
160 filter_t
*p_filter
= (filter_t
*)p_this
;
162 var_DelCallback(p_filter
,FILTER_PREFIX
"window-size",
163 AntiFlickerCallback
, p_filter
->p_sys
);
164 var_DelCallback(p_filter
,FILTER_PREFIX
"softening-size",
165 AntiFlickerCallback
, p_filter
->p_sys
);
166 free(p_filter
->p_sys
->p_old_data
);
167 free( p_filter
->p_sys
);
170 /*****************************************************************************
171 * GetLuminanceAvg : The funtion returns the luminance average for a picture
172 *****************************************************************************/
173 static int GetLuminanceAvg( picture_t
*p_pic
)
175 uint8_t *p_yplane_out
= p_pic
->p
[Y_PLANE
].p_pixels
;
177 int i_num_lines
= p_pic
->p
[Y_PLANE
].i_visible_lines
;
178 int i_num_cols
= p_pic
->p
[Y_PLANE
].i_visible_pitch
;
179 int i_in_pitch
= p_pic
->p
[Y_PLANE
].i_pitch
;
181 if( i_num_lines
== 0 || i_num_cols
== 0 )
184 unsigned lum_sum
= 0;
185 for( int i_line
= 0 ; i_line
< i_num_lines
; ++i_line
)
187 for( int i_col
= 0 ; i_col
< i_num_cols
; ++i_col
)
189 lum_sum
+= p_yplane_out
[i_line
*i_in_pitch
+i_col
];
192 unsigned div
= i_num_lines
* i_num_cols
;
193 return (lum_sum
+ (div
>>1)) / div
;
196 /*****************************************************************************
197 * Filter: adjust the luminance value and renders
198 *****************************************************************************
199 * The function uses moving average of past frames to adjust the luminance
200 * of current frame also applies temporaral smoothening if enabled.
201 *****************************************************************************/
202 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
204 if( !p_pic
) return NULL
;
206 picture_t
*p_outpic
= filter_NewPicture( p_filter
);
209 picture_Release( p_pic
);
213 /****************** Get variables *************************/
215 int i_window_size
= atomic_load( &p_filter
->p_sys
->i_window_size
);
216 int i_softening
= atomic_load( &p_filter
->p_sys
->i_softening
);
218 uint8_t *p_yplane_in
= p_pic
->p
[Y_PLANE
].p_pixels
;
219 uint8_t *p_yplane_out
= p_outpic
->p
[Y_PLANE
].p_pixels
;
220 bool scene_changed
= false;
222 int i_num_lines
= p_pic
->p
[Y_PLANE
].i_visible_lines
;
223 int i_num_cols
= p_pic
->p
[Y_PLANE
].i_visible_pitch
;
224 int i_in_pitch
= p_pic
->p
[Y_PLANE
].i_pitch
;
225 int i_out_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
227 /******** Get the luminance average for the current picture ********/
228 int lum_avg
= GetLuminanceAvg(p_pic
);
230 /*Identify as scene change if the luminance average deviates
231 more than the threshold value or if it is the first frame*/
233 if( abs(lum_avg
- p_filter
->p_sys
->
234 ia_luminance_data
[i_window_size
- 1]) > SCENE_CHANGE_THRESHOLD
235 || p_filter
->p_sys
->ia_luminance_data
[i_window_size
- 1] == 256)
237 scene_changed
= true;
242 //reset the luminance data
243 for (int i
= 0; i
< i_window_size
; ++i
)
244 p_filter
->p_sys
->ia_luminance_data
[i
] = lum_avg
;
245 plane_CopyPixels( &p_outpic
->p
[Y_PLANE
], &p_pic
->p
[Y_PLANE
] );
249 /******* Compute the adjustment factor using moving average ********/
250 for (int i
= 0; i
< i_window_size
-1 ; ++i
)
251 p_filter
->p_sys
->ia_luminance_data
[i
] =
252 p_filter
->p_sys
->ia_luminance_data
[i
+1];
254 p_filter
->p_sys
->ia_luminance_data
[i_window_size
- 1] = lum_avg
;
260 for (int i
= 0; i
< i_window_size
; i
++)
261 filt
+= (float) p_filter
->p_sys
->ia_luminance_data
[i
];
262 scale
= filt
/(i_window_size
*lum_avg
);
265 /******* Apply the adjustment factor to each pixel on Y_PLANE ********/
267 int scale_num
= __MIN(scale
,255) * ( 1 << shift
);
269 for( int i_line
= 0 ; i_line
< i_num_lines
; i_line
++ )
271 for( int i_col
= 0; i_col
< i_num_cols
; i_col
++ )
273 uint8_t pixel_data
= p_yplane_in
[i_line
*i_in_pitch
+i_col
];
274 int pixel_val
= ( scale_num
* pixel_data
+
275 (1<<(shift
-1)) ) >> shift
;
276 p_yplane_out
[i_line
*i_out_pitch
+i_col
] =
277 (pixel_val
>255) ? 255:pixel_val
;
282 /***************** Copy the UV plane as such *****************************/
283 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_pic
->p
[U_PLANE
] );
284 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_pic
->p
[V_PLANE
] );
286 if (scene_changed
|| i_softening
== 0)
288 return CopyInfoAndRelease( p_outpic
, p_pic
);
291 /******* Temporal softening phase. Adapted from code by Steven Don ******/
292 uint8_t *p_yplane_out_old
= p_filter
->p_sys
->p_old_data
;
293 int i_video_width
= p_filter
->fmt_in
.video
.i_width
;
295 for( int i_line
= 0 ; i_line
< i_num_lines
; i_line
++ )
297 for( int i_col
= 0; i_col
< i_num_cols
; i_col
++ )
299 uint8_t pixel_data
= p_yplane_out
[i_line
*i_out_pitch
+i_col
];
300 uint8_t pixel_old
= p_yplane_out_old
[i_line
*i_video_width
+i_col
];
301 int diff
= abs(pixel_data
- pixel_old
);
302 if (diff
< i_softening
)
304 if (diff
> (i_softening
>> 1))
306 p_yplane_out_old
[i_line
*i_video_width
+i_col
] =
307 ((pixel_data
* 2) + pixel_old
) /3;
312 p_yplane_out_old
[i_line
*i_video_width
+i_col
] = pixel_data
;
314 p_yplane_out
[i_line
*i_out_pitch
+i_col
] =
315 p_yplane_out_old
[i_line
*i_video_width
+i_col
];
319 return CopyInfoAndRelease( p_outpic
, p_pic
);
322 /*****************************************************************************
323 * Callback function to set the parameters
324 *****************************************************************************
325 * This function sets the parameters necesscary for the filter
326 *****************************************************************************/
327 static int AntiFlickerCallback( vlc_object_t
*p_this
, char const *psz_var
,
328 vlc_value_t oldval
, vlc_value_t newval
,
331 VLC_UNUSED(p_this
); VLC_UNUSED(oldval
);
332 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
334 if( !strcmp( psz_var
, FILTER_PREFIX
"window-size" ) )
335 atomic_store( &p_sys
->i_window_size
, newval
.i_int
);
336 else if( !strcmp( psz_var
, FILTER_PREFIX
"softening-size" ) )
337 atomic_store( &p_sys
->i_softening
, newval
.i_int
);