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 <stdatomic.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_filter.h>
37 #include <vlc_picture.h>
38 #include "filter_picture.h"
40 /*****************************************************************************
42 *****************************************************************************/
43 static int GetLuminanceAvg( picture_t
* p_pic
);
44 static picture_t
*Filter( filter_t
*, picture_t
* );
45 static int AntiFlickerCallback( vlc_object_t
*p_this
, char const *psz_var
,
46 vlc_value_t oldval
, vlc_value_t newval
,
49 static int Create ( vlc_object_t
* );
50 static void Destroy ( vlc_object_t
* );
52 #define WINDOW_TEXT N_("Window size")
53 #define WINDOW_LONGTEXT N_("Number of frames (0 to 100)")
55 #define SFTN_TEXT N_("Softening value")
56 #define SFTN_LONGTEXT N_("Number of frames consider for smoothening (0 to 30)")
58 #define FILTER_PREFIX "antiflicker-"
60 #define MAX_WINDOW_SZ 100
61 #define MAX_SOFTENING_SZ 31
62 #define SCENE_CHANGE_THRESHOLD 100
64 /*****************************************************************************
66 *****************************************************************************/
68 set_description( N_("Antiflicker video filter") )
69 set_shortname( N_( "antiflicker" ))
70 set_capability( "video filter", 0 )
71 set_category( CAT_VIDEO
)
72 set_subcategory( SUBCAT_VIDEO_VFILTER
)
74 add_integer_with_range( FILTER_PREFIX
"window-size", 10, 0, MAX_WINDOW_SZ
,
75 WINDOW_TEXT
, WINDOW_LONGTEXT
, false )
77 add_integer_with_range( FILTER_PREFIX
"softening-size", 10, 0, MAX_SOFTENING_SZ
,
78 SFTN_TEXT
, SFTN_LONGTEXT
, false )
80 add_shortcut( "antiflicker" )
81 set_callbacks( Create
, Destroy
)
84 /*****************************************************************************
85 * filter_sys_t: Distort video output method descriptor
86 *****************************************************************************
87 * This structure is part of the video output thread descriptor.
88 * It describes the Distort specific properties of an output thread.
89 *****************************************************************************/
92 atomic_int i_window_size
;
93 atomic_int i_softening
;
94 int ia_luminance_data
[MAX_WINDOW_SZ
];
98 /*****************************************************************************
99 * Create: allocates Distort video thread output method
100 *****************************************************************************
101 * This function allocates and initializes a Distort vout method.
102 *****************************************************************************/
103 static int Create( vlc_object_t
*p_this
)
105 filter_t
*p_filter
= (filter_t
*)p_this
;
107 switch( p_filter
->fmt_in
.video
.i_chroma
)
113 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
114 (char*)&(p_filter
->fmt_in
.video
.i_chroma
) );
118 /* Allocate structure */
119 filter_sys_t
*p_sys
= malloc( sizeof( filter_sys_t
) );
122 p_filter
->p_sys
= p_sys
;
124 p_filter
->pf_video_filter
= Filter
;
126 /* Initialize the arguments */
127 atomic_init( &p_sys
->i_window_size
,
128 var_CreateGetIntegerCommand( p_filter
,
129 FILTER_PREFIX
"window-size" ) );
130 atomic_init( &p_sys
->i_softening
,
131 var_CreateGetIntegerCommand( p_filter
,
132 FILTER_PREFIX
"softening-size" ) );
134 p_sys
->p_old_data
= calloc( p_filter
->fmt_in
.video
.i_width
*
135 (p_filter
->fmt_in
.video
.i_height
+1),sizeof(*p_sys
->p_old_data
) );
137 if( p_sys
->p_old_data
== NULL
)
143 memset( p_sys
->ia_luminance_data
, 0,
144 sizeof(p_sys
->ia_luminance_data
) );
145 p_sys
->ia_luminance_data
[p_sys
->i_window_size
- 1] = 256;
147 var_AddCallback(p_filter
,FILTER_PREFIX
"window-size",
148 AntiFlickerCallback
, p_sys
);
149 var_AddCallback(p_filter
,FILTER_PREFIX
"softening-size",
150 AntiFlickerCallback
, p_sys
);
155 /*****************************************************************************
156 * Destroy: destroy Distort video thread output method
157 *****************************************************************************
158 * Terminate an output method created by DistortCreateOutputMethod
159 *****************************************************************************/
160 static void Destroy( vlc_object_t
*p_this
)
162 filter_t
*p_filter
= (filter_t
*)p_this
;
163 filter_sys_t
*p_sys
= p_filter
->p_sys
;
165 var_DelCallback(p_filter
,FILTER_PREFIX
"window-size",
166 AntiFlickerCallback
, p_sys
);
167 var_DelCallback(p_filter
,FILTER_PREFIX
"softening-size",
168 AntiFlickerCallback
, p_sys
);
169 free( p_sys
->p_old_data
);
173 /*****************************************************************************
174 * GetLuminanceAvg : The funtion returns the luminance average for a picture
175 *****************************************************************************/
176 static int GetLuminanceAvg( picture_t
*p_pic
)
178 uint8_t *p_yplane_out
= p_pic
->p
[Y_PLANE
].p_pixels
;
180 int i_num_lines
= p_pic
->p
[Y_PLANE
].i_visible_lines
;
181 int i_num_cols
= p_pic
->p
[Y_PLANE
].i_visible_pitch
;
182 int i_in_pitch
= p_pic
->p
[Y_PLANE
].i_pitch
;
184 if( i_num_lines
== 0 || i_num_cols
== 0 )
187 unsigned lum_sum
= 0;
188 for( int i_line
= 0 ; i_line
< i_num_lines
; ++i_line
)
190 for( int i_col
= 0 ; i_col
< i_num_cols
; ++i_col
)
192 lum_sum
+= p_yplane_out
[i_line
*i_in_pitch
+i_col
];
195 unsigned div
= i_num_lines
* i_num_cols
;
196 return (lum_sum
+ (div
>>1)) / div
;
199 /*****************************************************************************
200 * Filter: adjust the luminance value and renders
201 *****************************************************************************
202 * The function uses moving average of past frames to adjust the luminance
203 * of current frame also applies temporaral smoothening if enabled.
204 *****************************************************************************/
205 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
207 if( !p_pic
) return NULL
;
209 picture_t
*p_outpic
= filter_NewPicture( p_filter
);
212 picture_Release( p_pic
);
216 /****************** Get variables *************************/
218 filter_sys_t
*p_sys
= p_filter
->p_sys
;
220 int i_window_size
= atomic_load( &p_sys
->i_window_size
);
221 int i_softening
= atomic_load( &p_sys
->i_softening
);
223 uint8_t *p_yplane_in
= p_pic
->p
[Y_PLANE
].p_pixels
;
224 uint8_t *p_yplane_out
= p_outpic
->p
[Y_PLANE
].p_pixels
;
225 bool scene_changed
= false;
227 int i_num_lines
= p_pic
->p
[Y_PLANE
].i_visible_lines
;
228 int i_num_cols
= p_pic
->p
[Y_PLANE
].i_visible_pitch
;
229 int i_in_pitch
= p_pic
->p
[Y_PLANE
].i_pitch
;
230 int i_out_pitch
= p_outpic
->p
[Y_PLANE
].i_pitch
;
232 /******** Get the luminance average for the current picture ********/
233 int lum_avg
= GetLuminanceAvg(p_pic
);
235 /*Identify as scene change if the luminance average deviates
236 more than the threshold value or if it is the first frame*/
238 if( abs(lum_avg
- p_sys
->
239 ia_luminance_data
[i_window_size
- 1]) > SCENE_CHANGE_THRESHOLD
240 || p_sys
->ia_luminance_data
[i_window_size
- 1] == 256)
242 scene_changed
= true;
247 //reset the luminance data
248 for (int i
= 0; i
< i_window_size
; ++i
)
249 p_sys
->ia_luminance_data
[i
] = lum_avg
;
250 plane_CopyPixels( &p_outpic
->p
[Y_PLANE
], &p_pic
->p
[Y_PLANE
] );
254 /******* Compute the adjustment factor using moving average ********/
255 for (int i
= 0; i
< i_window_size
-1 ; ++i
)
256 p_sys
->ia_luminance_data
[i
] =
257 p_sys
->ia_luminance_data
[i
+1];
259 p_sys
->ia_luminance_data
[i_window_size
- 1] = lum_avg
;
265 for (int i
= 0; i
< i_window_size
; i
++)
266 filt
+= (float) p_sys
->ia_luminance_data
[i
];
267 scale
= filt
/(i_window_size
*lum_avg
);
270 /******* Apply the adjustment factor to each pixel on Y_PLANE ********/
272 int scale_num
= __MIN(scale
,255) * ( 1 << shift
);
274 for( int i_line
= 0 ; i_line
< i_num_lines
; i_line
++ )
276 for( int i_col
= 0; i_col
< i_num_cols
; i_col
++ )
278 uint8_t pixel_data
= p_yplane_in
[i_line
*i_in_pitch
+i_col
];
279 int pixel_val
= ( scale_num
* pixel_data
+
280 (1<<(shift
-1)) ) >> shift
;
281 p_yplane_out
[i_line
*i_out_pitch
+i_col
] =
282 (pixel_val
>255) ? 255:pixel_val
;
287 /***************** Copy the UV plane as such *****************************/
288 plane_CopyPixels( &p_outpic
->p
[U_PLANE
], &p_pic
->p
[U_PLANE
] );
289 plane_CopyPixels( &p_outpic
->p
[V_PLANE
], &p_pic
->p
[V_PLANE
] );
291 if (scene_changed
|| i_softening
== 0)
293 return CopyInfoAndRelease( p_outpic
, p_pic
);
296 /******* Temporal softening phase. Adapted from code by Steven Don ******/
297 uint8_t *p_yplane_out_old
= p_sys
->p_old_data
;
298 int i_video_width
= p_filter
->fmt_in
.video
.i_width
;
300 for( int i_line
= 0 ; i_line
< i_num_lines
; i_line
++ )
302 for( int i_col
= 0; i_col
< i_num_cols
; i_col
++ )
304 uint8_t pixel_data
= p_yplane_out
[i_line
*i_out_pitch
+i_col
];
305 uint8_t pixel_old
= p_yplane_out_old
[i_line
*i_video_width
+i_col
];
306 int diff
= abs(pixel_data
- pixel_old
);
307 if (diff
< i_softening
)
309 if (diff
> (i_softening
>> 1))
311 p_yplane_out_old
[i_line
*i_video_width
+i_col
] =
312 ((pixel_data
* 2) + pixel_old
) /3;
317 p_yplane_out_old
[i_line
*i_video_width
+i_col
] = pixel_data
;
319 p_yplane_out
[i_line
*i_out_pitch
+i_col
] =
320 p_yplane_out_old
[i_line
*i_video_width
+i_col
];
324 return CopyInfoAndRelease( p_outpic
, p_pic
);
327 /*****************************************************************************
328 * Callback function to set the parameters
329 *****************************************************************************
330 * This function sets the parameters necesscary for the filter
331 *****************************************************************************/
332 static int AntiFlickerCallback( vlc_object_t
*p_this
, char const *psz_var
,
333 vlc_value_t oldval
, vlc_value_t newval
,
336 VLC_UNUSED(p_this
); VLC_UNUSED(oldval
);
337 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
339 if( !strcmp( psz_var
, FILTER_PREFIX
"window-size" ) )
340 atomic_store( &p_sys
->i_window_size
, newval
.i_int
);
341 else if( !strcmp( psz_var
, FILTER_PREFIX
"softening-size" ) )
342 atomic_store( &p_sys
->i_softening
, newval
.i_int
);