* modules/codec/ffmpeg/*: modified the ffmpeg video codec to use direct
[vlc.git] / modules / video_filter / motionblur.c
1 /*****************************************************************************
2  * motion_blur.c : motion blur filter for vlc
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: motionblur.c,v 1.2 2002/08/27 21:53:54 sigmunau Exp $
6  *
7  * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
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 General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <string.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/vout.h>
33
34 #include "filter_common.h"
35
36 /*****************************************************************************
37  * Local protypes
38  *****************************************************************************/
39 static int  Create    ( vlc_object_t * );
40 static void Destroy   ( vlc_object_t * );
41
42 static int  Init      ( vout_thread_t * );
43 static void End       ( vout_thread_t * );
44 static void Render    ( vout_thread_t *, picture_t * );
45
46 static void RenderBlur    ( vout_thread_t *, picture_t *, picture_t *, picture_t * );
47 static void CopyPicture ( vout_thread_t*, picture_t *, picture_t * );
48
49 /*****************************************************************************
50  * Module descriptor
51  *****************************************************************************/
52 #define MODE_TEXT N_("Blur factor")
53 #define MODE_LONGTEXT N_("The degree of blurring from 1 to 127")
54
55 vlc_module_begin();
56     add_category_hint( N_("Miscellaneous"), NULL );
57     add_integer( "blur-factor", 80, NULL, MODE_TEXT, MODE_LONGTEXT );
58     set_description( _("Motion blur filter") );
59     set_capability( "video filter", 0 );
60     set_callbacks( Create, Destroy );
61 vlc_module_end();
62
63 /*****************************************************************************
64  * vout_sys_t: Deinterlace video output method descriptor
65  *****************************************************************************
66  * This structure is part of the video output thread descriptor.
67  * It describes the Deinterlace specific properties of an output thread.
68  *****************************************************************************/
69 struct vout_sys_t
70 {
71     int        i_factor;        /* Deinterlace mode */
72     vlc_bool_t b_double_rate; /* Shall we double the framerate? */
73
74     mtime_t    last_date;
75     mtime_t    next_date;
76
77     vout_thread_t *p_vout;
78     picture_t *p_lastpic;
79 };
80
81 /*****************************************************************************
82  * Create: allocates Deinterlace video thread output method
83  *****************************************************************************
84  * This function allocates and initializes a Deinterlace vout method.
85  *****************************************************************************/
86 static int Create( vlc_object_t *p_this )
87 {   
88     vout_thread_t *p_vout = (vout_thread_t *)p_this;
89
90     /* Allocate structure */
91     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
92     if( p_vout->p_sys == NULL )
93     {
94         msg_Err( p_vout, "out of memory" );
95         return 1;
96     }
97
98     p_vout->pf_init = Init;
99     p_vout->pf_end = End;
100     p_vout->pf_manage = NULL;
101     p_vout->pf_render = Render;
102     p_vout->pf_display = NULL;
103
104     p_vout->p_sys->i_factor = config_GetInt( p_vout, "blur-factor" );
105     p_vout->p_sys->b_double_rate = 0;
106     p_vout->p_sys->last_date = 0;
107     p_vout->p_sys->p_lastpic = NULL;
108
109     return 0;
110 }
111
112 /*****************************************************************************
113  * Init: initialize Deinterlace video thread output method
114  *****************************************************************************/
115 static int Init( vout_thread_t *p_vout )
116 {
117     int i_index;
118     picture_t *p_pic;
119     
120     I_OUTPUTPICTURES = 0;
121
122     /* Initialize the output structure, full of directbuffers since we want
123      * the decoder to output directly to our structures. */
124     switch( p_vout->render.i_chroma )
125     {
126         case VLC_FOURCC('I','4','2','0'):
127         case VLC_FOURCC('I','Y','U','V'):
128         case VLC_FOURCC('Y','V','1','2'):
129         case VLC_FOURCC('I','4','2','2'):
130             p_vout->output.i_chroma = p_vout->render.i_chroma;
131             p_vout->output.i_width  = p_vout->render.i_width;
132             p_vout->output.i_height = p_vout->render.i_height;
133             p_vout->output.i_aspect = p_vout->render.i_aspect;
134             break;
135
136         default:
137             return 0; /* unknown chroma */
138             break;
139     }
140
141     msg_Dbg( p_vout, "spawning the real video output" );
142
143     switch( p_vout->render.i_chroma )
144     {
145     case VLC_FOURCC('I','4','2','0'):
146     case VLC_FOURCC('I','Y','U','V'):
147     case VLC_FOURCC('Y','V','1','2'):
148         p_vout->p_sys->p_vout =
149             vout_CreateThread( p_vout,
150                                p_vout->output.i_width, p_vout->output.i_height,
151                                p_vout->output.i_chroma, p_vout->output.i_aspect );
152         break;
153     default:
154         break;
155     }
156
157     /* Everything failed */
158     if( p_vout->p_sys->p_vout == NULL )
159     {
160         msg_Err( p_vout, "cannot open vout, aborting" );
161
162         return 0;
163     }
164  
165     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
166
167     return 0;
168 }
169
170 /*****************************************************************************
171  * End: terminate Deinterlace video thread output method
172  *****************************************************************************/
173 static void End( vout_thread_t *p_vout )
174 {
175     int i_index;
176
177     /* Free the fake output buffers we allocated */
178     for( i_index = I_OUTPUTPICTURES ; i_index ; )
179     {
180         i_index--;
181         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
182     }
183 }
184
185 /*****************************************************************************
186  * Destroy: destroy Deinterlace video thread output method
187  *****************************************************************************
188  * Terminate an output method created by DeinterlaceCreateOutputMethod
189  *****************************************************************************/
190 static void Destroy( vlc_object_t *p_this )
191 {
192     vout_thread_t *p_vout = (vout_thread_t *)p_this;
193
194     vout_DestroyThread( p_vout->p_sys->p_vout );
195
196     free( p_vout->p_sys );
197 }
198
199 /*****************************************************************************
200  * Render: displays previously rendered output
201  *****************************************************************************
202  * This function send the currently rendered image to Deinterlace image,
203  * waits until it is displayed and switch the two rendering buffers, preparing
204  * next frame.
205  *****************************************************************************/
206 static void Render ( vout_thread_t *p_vout, picture_t *p_pic )
207 {
208     picture_t * p_outpic;
209     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
210            == NULL )
211     {
212         if( p_vout->b_die || p_vout->b_error )
213         {
214             return;
215         }
216         msleep( VOUT_OUTMEM_SLEEP );
217     }
218     vout_DatePicture( p_vout, p_outpic, p_pic->date );
219     
220     if ( p_vout->p_sys->p_lastpic == NULL )
221     {
222         /* Get a new picture */
223         while( ( p_vout->p_sys->p_lastpic =
224                  vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
225                == NULL )
226         {
227             if( p_vout->b_die || p_vout->b_error )
228             {
229                 return;
230             }
231             msleep( VOUT_OUTMEM_SLEEP );
232         }
233         CopyPicture( p_vout, p_vout->p_sys->p_lastpic, p_pic );
234         CopyPicture( p_vout, p_outpic, p_pic );
235         vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
236         return;
237     }
238
239     /* Get a new picture */
240     RenderBlur( p_vout, p_vout->p_sys->p_lastpic, p_pic, p_outpic );
241     vout_DestroyPicture( p_vout, p_vout->p_sys->p_lastpic );
242
243
244     /* Get a new picture */
245     while( ( p_vout->p_sys->p_lastpic =
246              vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
247            == NULL )
248     {
249         if( p_vout->b_die || p_vout->b_error )
250         {
251             return;
252         }
253         msleep( VOUT_OUTMEM_SLEEP );
254     }
255     CopyPicture( p_vout, p_vout->p_sys->p_lastpic, p_outpic );
256     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
257
258 }
259
260 static void CopyPicture( vout_thread_t *p_vout,
261                          picture_t *p_dest, picture_t *p_source)
262 {
263     int i_plane;
264
265     for( i_plane = 0 ; i_plane < p_dest->i_planes ; i_plane++ )
266     {
267         u8 *p_in, *p_out;
268
269         p_in = p_source->p[i_plane].p_pixels;
270
271         p_out = p_dest->p[i_plane].p_pixels;
272         p_vout->p_vlc->pf_memcpy( p_out, p_in,
273                                   p_dest->p[i_plane].i_pitch *
274                                   p_dest->p[i_plane].i_lines);
275     }
276 }
277 /*****************************************************************************
278  * RenderBob: renders a bob picture
279  *****************************************************************************/
280 static void RenderBlur( vout_thread_t *p_vout, picture_t *p_oldpic,
281                         picture_t *p_newpic, picture_t *p_outpic )
282 {
283     int i_plane;
284     int i_oldfactor = p_vout->p_sys->i_factor;
285     int i_newfactor = 128 - p_vout->p_sys->i_factor;
286     for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
287     {
288         u8 *p_old, *p_new, *p_out, *p_out_end;
289         p_out = p_outpic->p[i_plane].p_pixels;
290         p_new = p_newpic->p[i_plane].p_pixels;
291         p_old = p_oldpic->p[i_plane].p_pixels;
292         p_out_end = p_out + p_outpic->p[i_plane].i_pitch *
293             p_outpic->p[i_plane].i_lines;
294         while ( p_out < p_out_end )
295         {
296             *p_out++ = (((*p_old++) * i_oldfactor) +
297                         ((*p_new++) * i_newfactor)) >> 7;
298             
299 //            *p_out++ = (*p_old++ >> 1) + (*p_new++ >> 1);
300                 
301         }
302     }
303 }