00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdlib.h>
00028 #include <string.h>
00029
00030 #include <vlc/vlc.h>
00031 #include <vlc/vout.h>
00032
00033 #include "filter_common.h"
00034
00035
00036
00037
00038 static int Create ( vlc_object_t * );
00039 static void Destroy ( vlc_object_t * );
00040
00041 static int Init ( vout_thread_t * );
00042 static void End ( vout_thread_t * );
00043 static void Render ( vout_thread_t *, picture_t * );
00044
00045 static void RenderBlur ( vout_thread_t *, picture_t *, picture_t *, picture_t * );
00046 static void CopyPicture ( vout_thread_t*, picture_t *, picture_t * );
00047
00048 static int SendEvents( vlc_object_t *, char const *,
00049 vlc_value_t, vlc_value_t, void * );
00050
00051
00052
00053
00054 #define MODE_TEXT N_("Blur factor (1-127)")
00055 #define MODE_LONGTEXT N_("The degree of blurring from 1 to 127.")
00056
00057 vlc_module_begin();
00058 set_shortname( _("Motion blur") );
00059 set_description( _("Motion blur filter") );
00060 set_capability( "video filter", 0 );
00061 set_category( CAT_VIDEO );
00062 set_subcategory( SUBCAT_VIDEO_VFILTER );
00063
00064 add_integer_with_range( "blur-factor", 80, 1, 127, NULL,
00065 MODE_TEXT, MODE_LONGTEXT, VLC_FALSE );
00066
00067 set_callbacks( Create, Destroy );
00068 vlc_module_end();
00069
00070
00071
00072
00073
00074
00075
00076 struct vout_sys_t
00077 {
00078 int i_factor;
00079 vlc_bool_t b_double_rate;
00080
00081 mtime_t last_date;
00082 mtime_t next_date;
00083
00084 vout_thread_t *p_vout;
00085 picture_t *p_lastpic;
00086 };
00087
00088
00089
00090
00091 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
00092 {
00093 return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
00094 }
00095
00096
00097
00098
00099
00100
00101 static int Create( vlc_object_t *p_this )
00102 {
00103 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00104
00105
00106 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00107 if( p_vout->p_sys == NULL )
00108 {
00109 msg_Err( p_vout, "out of memory" );
00110 return VLC_ENOMEM;
00111 }
00112
00113 p_vout->pf_init = Init;
00114 p_vout->pf_end = End;
00115 p_vout->pf_manage = NULL;
00116 p_vout->pf_render = Render;
00117 p_vout->pf_display = NULL;
00118 p_vout->pf_control = Control;
00119
00120 p_vout->p_sys->i_factor = config_GetInt( p_vout, "blur-factor" );
00121 p_vout->p_sys->b_double_rate = 0;
00122 p_vout->p_sys->last_date = 0;
00123 p_vout->p_sys->p_lastpic = NULL;
00124
00125 return VLC_SUCCESS;
00126 }
00127
00128
00129
00130
00131 static int Init( vout_thread_t *p_vout )
00132 {
00133 int i_index;
00134 picture_t *p_pic;
00135 video_format_t fmt = {0};
00136
00137 I_OUTPUTPICTURES = 0;
00138
00139
00140
00141 switch( p_vout->render.i_chroma )
00142 {
00143 case VLC_FOURCC('I','4','2','0'):
00144 case VLC_FOURCC('I','Y','U','V'):
00145 case VLC_FOURCC('Y','V','1','2'):
00146 case VLC_FOURCC('I','4','2','2'):
00147 p_vout->output.i_chroma = p_vout->render.i_chroma;
00148 p_vout->output.i_width = p_vout->render.i_width;
00149 p_vout->output.i_height = p_vout->render.i_height;
00150 p_vout->output.i_aspect = p_vout->render.i_aspect;
00151 p_vout->fmt_out = p_vout->fmt_in;
00152 fmt = p_vout->fmt_out;
00153 break;
00154
00155 default:
00156 return VLC_EGENERIC;
00157 break;
00158 }
00159
00160 msg_Dbg( p_vout, "spawning the real video output" );
00161
00162 switch( p_vout->render.i_chroma )
00163 {
00164 case VLC_FOURCC('I','4','2','0'):
00165 case VLC_FOURCC('I','Y','U','V'):
00166 case VLC_FOURCC('Y','V','1','2'):
00167 p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
00168 break;
00169 default:
00170 break;
00171 }
00172
00173
00174 if( p_vout->p_sys->p_vout == NULL )
00175 {
00176 msg_Err( p_vout, "cannot open vout, aborting" );
00177
00178 return VLC_EGENERIC;
00179 }
00180
00181 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
00182
00183 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00184
00185 ADD_PARENT_CALLBACKS( SendEventsToChild );
00186
00187 return VLC_SUCCESS;
00188 }
00189
00190
00191
00192
00193 static void End( vout_thread_t *p_vout )
00194 {
00195 int i_index;
00196
00197
00198 for( i_index = I_OUTPUTPICTURES ; i_index ; )
00199 {
00200 i_index--;
00201 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
00202 }
00203 }
00204
00205
00206
00207
00208
00209
00210 static void Destroy( vlc_object_t *p_this )
00211 {
00212 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00213
00214 if( p_vout->p_sys->p_vout )
00215 {
00216 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00217 vlc_object_detach( p_vout->p_sys->p_vout );
00218 vout_Destroy( p_vout->p_sys->p_vout );
00219 }
00220
00221 DEL_PARENT_CALLBACKS( SendEventsToChild );
00222
00223 free( p_vout->p_sys );
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233 static void Render ( vout_thread_t *p_vout, picture_t *p_pic )
00234 {
00235 picture_t * p_outpic;
00236 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
00237 == NULL )
00238 {
00239 if( p_vout->b_die || p_vout->b_error )
00240 {
00241 return;
00242 }
00243 msleep( VOUT_OUTMEM_SLEEP );
00244 }
00245 vout_DatePicture( p_vout, p_outpic, p_pic->date );
00246
00247 if ( p_vout->p_sys->p_lastpic == NULL )
00248 {
00249
00250 while( ( p_vout->p_sys->p_lastpic =
00251 vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
00252 == NULL )
00253 {
00254 if( p_vout->b_die || p_vout->b_error )
00255 {
00256 return;
00257 }
00258 msleep( VOUT_OUTMEM_SLEEP );
00259 }
00260 CopyPicture( p_vout, p_vout->p_sys->p_lastpic, p_pic );
00261 CopyPicture( p_vout, p_outpic, p_pic );
00262 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
00263 return;
00264 }
00265
00266
00267 RenderBlur( p_vout, p_vout->p_sys->p_lastpic, p_pic, p_outpic );
00268 vout_DestroyPicture( p_vout, p_vout->p_sys->p_lastpic );
00269
00270
00271
00272 while( ( p_vout->p_sys->p_lastpic =
00273 vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
00274 == NULL )
00275 {
00276 if( p_vout->b_die || p_vout->b_error )
00277 {
00278 return;
00279 }
00280 msleep( VOUT_OUTMEM_SLEEP );
00281 }
00282 CopyPicture( p_vout, p_vout->p_sys->p_lastpic, p_outpic );
00283 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
00284 }
00285
00286
00287
00288 static void CopyPicture( vout_thread_t * p_vout,
00289 picture_t *p_dest, picture_t *p_src )
00290 {
00291 int i;
00292
00293 for( i = 0; i < p_src->i_planes ; i++ )
00294 {
00295 if( p_src->p[i].i_pitch == p_dest->p[i].i_pitch )
00296 {
00297
00298 p_vout->p_vlc->pf_memcpy(
00299 p_dest->p[i].p_pixels, p_src->p[i].p_pixels,
00300 p_src->p[i].i_pitch * p_src->p[i].i_visible_lines );
00301 }
00302 else
00303 {
00304
00305 uint8_t *p_in = p_src->p[i].p_pixels;
00306 uint8_t *p_out = p_dest->p[i].p_pixels;
00307 int i_line;
00308
00309 for( i_line = p_src->p[i].i_visible_lines; i_line--; )
00310 {
00311 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00312 p_src->p[i].i_visible_pitch );
00313 p_in += p_src->p[i].i_pitch;
00314 p_out += p_dest->p[i].i_pitch;
00315 }
00316 }
00317 }
00318 }
00319
00320
00321
00322
00323 static void RenderBlur( vout_thread_t *p_vout, picture_t *p_oldpic,
00324 picture_t *p_newpic, picture_t *p_outpic )
00325 {
00326 int i_plane;
00327 int i_oldfactor = p_vout->p_sys->i_factor;
00328 int i_newfactor = 128 - p_vout->p_sys->i_factor;
00329 for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
00330 {
00331 uint8_t *p_old, *p_new, *p_out, *p_out_end, *p_out_line_end;
00332 p_out = p_outpic->p[i_plane].p_pixels;
00333 p_new = p_newpic->p[i_plane].p_pixels;
00334 p_old = p_oldpic->p[i_plane].p_pixels;
00335 p_out_end = p_out + p_outpic->p[i_plane].i_pitch *
00336 p_outpic->p[i_plane].i_visible_lines;
00337 while ( p_out < p_out_end )
00338 {
00339 p_out_line_end = p_out + p_outpic->p[i_plane].i_visible_pitch;
00340
00341 while ( p_out < p_out_line_end )
00342 {
00343 *p_out++ = (((*p_old++) * i_oldfactor) +
00344 ((*p_new++) * i_newfactor)) >> 7;
00345
00346
00347 }
00348
00349 p_old += p_oldpic->p[i_plane].i_pitch
00350 - p_oldpic->p[i_plane].i_visible_pitch;
00351 p_new += p_newpic->p[i_plane].i_pitch
00352 - p_newpic->p[i_plane].i_visible_pitch;
00353 p_out += p_outpic->p[i_plane].i_pitch
00354 - p_outpic->p[i_plane].i_visible_pitch;
00355 }
00356 }
00357 }
00358
00359
00360
00361
00362 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
00363 vlc_value_t oldval, vlc_value_t newval, void *p_data )
00364 {
00365 var_Set( (vlc_object_t *)p_data, psz_var, newval );
00366
00367 return VLC_SUCCESS;
00368 }
00369
00370
00371
00372
00373 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
00374 vlc_value_t oldval, vlc_value_t newval, void *p_data )
00375 {
00376 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00377 var_Set( p_vout->p_sys->p_vout, psz_var, newval );
00378 return VLC_SUCCESS;
00379 }