1 /*****************************************************************************
2 * projectm: visualization module based on libprojectM
3 *****************************************************************************
4 * Copyright (C) 2009 the VideoLAN team
7 * Authors: RĂ©mi Duraffort <ivoire@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * You should have received a copy of the GNU General Public License along with
20 * this program; if not, write to the Free Software Foundation, Inc., 51
21 * Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
32 #include <vlc_filter.h>
34 #include <libprojectM/projectM.hpp>
37 /*****************************************************************************
39 *****************************************************************************/
40 static int Open ( vlc_object_t * );
41 static void Close ( vlc_object_t * );
43 #define CONFIG_TEXT N_("projectM configuration file")
44 #define CONFIG_LONGTEXT N_("File that will be used to configure the projectM " \
47 #define WIDTH_TEXT N_("Video width")
48 #define WIDTH_LONGTEXT N_("The width of the video window, in pixels.")
50 #define HEIGHT_TEXT N_("Video height")
51 #define HEIGHT_LONGTEXT N_("The height of the video window, in pixels.")
54 set_shortname( N_("projectM"))
55 set_description( N_("libprojectM effect") )
56 set_capability( "visualization2", 0 )
57 set_category( CAT_AUDIO )
58 set_subcategory( SUBCAT_AUDIO_VISUAL )
59 add_file( "projectm-config", "/usr/share/projectM/config.inp", NULL,
60 CONFIG_TEXT, CONFIG_LONGTEXT, true )
61 add_integer( "projectm-width", 800, NULL, WIDTH_TEXT, WIDTH_LONGTEXT,
63 add_integer( "projectm-height", 640, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT,
65 add_shortcut( "projectm" )
66 set_callbacks( Open, Close )
70 /*****************************************************************************
72 *****************************************************************************/
77 /* video output module and opengl provider */
78 vout_thread_t *p_opengl;
81 /* libprojectM objects */
101 projectm_thread_t *p_thread;
105 static block_t *DoWork( filter_t *, block_t * );
106 static void* Thread( vlc_object_t * );
110 * Init the openGL context
111 * p_thread: projectm thread object
112 * @return VLC_SUCCESS or vlc error codes
114 static int initOpenGL( projectm_thread_t *p_thread )
116 p_thread->p_opengl = (vout_thread_t *)vlc_object_create( p_thread,
117 sizeof( vout_thread_t ) );
118 if( !p_thread->p_opengl )
121 vlc_object_attach( p_thread->p_opengl, p_thread );
123 /* Initialize the opengl object */
124 video_format_Setup( &p_thread->p_opengl->fmt_in, VLC_CODEC_RGB32,
125 p_thread->i_width, p_thread->i_height, 1 );
126 p_thread->p_opengl->i_window_width = p_thread->i_width;
127 p_thread->p_opengl->i_window_height = p_thread->i_height;
128 p_thread->p_opengl->render.i_width = p_thread->i_width;
129 p_thread->p_opengl->render.i_height = p_thread->i_height;
130 p_thread->p_opengl->render.i_aspect = VOUT_ASPECT_FACTOR;
131 p_thread->p_opengl->b_fullscreen = false;
132 p_thread->p_opengl->b_autoscale = true;
133 p_thread->p_opengl->i_alignment = 0;
134 p_thread->p_opengl->fmt_in.i_sar_num = 1;
135 p_thread->p_opengl->fmt_in.i_sar_den = 1;
136 p_thread->p_opengl->fmt_render = p_thread->p_opengl->fmt_in;
138 /* Ask for the opengl provider */
139 p_thread->p_module = module_need( p_thread->p_opengl, "opengl provider",
141 if( !p_thread->p_module )
143 msg_Err( p_thread, "unable to initialize OpenGL" );
144 vlc_object_detach( p_thread->p_opengl );
145 vlc_object_release( p_thread->p_opengl );
155 * @param p_this: the filter object
156 * @return VLC_SUCCESS or vlc error codes
158 static int Open( vlc_object_t * p_this )
160 filter_t *p_filter = (filter_t *)p_this;
162 projectm_thread_t *p_thread;
164 /* Test the audio format */
165 if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 ||
166 p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
168 msg_Warn( p_filter, "bad input or output format" );
171 if( !AOUT_FMTS_SIMILAR( &p_filter->fmt_in.audio, &p_filter->fmt_out.audio ) )
173 msg_Warn( p_filter, "input and outut are not similar" );
177 p_filter->pf_audio_filter = DoWork;
179 p_sys = p_filter->p_sys = (filter_sys_t*)malloc( sizeof( *p_sys ) );
183 /* Create the object for the thread */
184 p_sys->p_thread = p_thread = (projectm_thread_t *)
185 vlc_object_create( p_filter, sizeof( projectm_thread_t ) );
186 vlc_object_attach( p_sys->p_thread, p_filter );
187 p_thread->i_width = var_CreateGetInteger( p_filter, "projectm-width" );
188 p_thread->i_height = var_CreateGetInteger( p_filter, "projectm-height" );
190 /* Create the openGL provider */
191 int i_ret = initOpenGL( p_sys->p_thread );
192 if( i_ret != VLC_SUCCESS )
194 vlc_object_detach( p_sys->p_thread );
195 vlc_object_release( p_sys->p_thread );
200 p_thread->i_channels = aout_FormatNbChannels( &p_filter->fmt_in.audio );
201 p_thread->psz_config = var_CreateGetString( p_filter, "projectm-config" );
202 vlc_mutex_init( &p_thread->lock );
203 p_thread->p_buffer = NULL;
204 p_thread->i_buffer_size = 0;
205 p_thread->i_nb_samples = 0;
207 /* Create the thread */
208 if( vlc_thread_create( p_thread, "projectm update thread", Thread,
209 VLC_THREAD_PRIORITY_LOW ) )
211 msg_Err( p_filter, "cannot launch the projectm thread" );
212 vlc_object_detach( p_thread );
213 vlc_object_release( p_thread );
224 * @param p_this: the filter object
226 static void Close( vlc_object_t *p_this )
228 filter_t *p_filter = (filter_t *)p_this;
229 filter_sys_t *p_sys = p_filter->p_sys;
230 projectm_thread_t *p_thread = p_sys->p_thread;
232 /* Stop the thread */
233 vlc_object_kill( p_thread );
234 vlc_thread_join( p_thread );
236 /* Free the ressources */
237 vlc_mutex_destroy( &p_thread->lock );
238 free( p_thread->p_buffer );
239 free( p_thread->psz_config );
241 vlc_object_detach( p_thread );
242 vlc_object_release( p_thread );
249 * Do the actual work with the new sample
250 * @param p_aout: audio output object
251 * @param p_filter: filter object
252 * @param p_in_buf: input buffer
253 * @param p_out_buf: output buffer
255 static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf )
257 projectm_thread_t *p_thread = p_filter->p_sys->p_thread;
259 vlc_mutex_lock( &p_thread->lock );
260 if( p_thread->i_buffer_size > 0 )
262 p_thread->p_buffer[0] = 0;
263 p_thread->i_nb_samples = __MIN( p_thread->i_buffer_size,
264 p_in_buf->i_nb_samples );
265 for( int i = 0; i < p_thread->i_nb_samples; i++ )
266 p_thread->p_buffer[i] = p_in_buf->p_buffer[i];
269 vlc_mutex_unlock( &p_thread->lock );
276 * ProjectM update thread which do the rendering
277 * @param p_this: the p_thread object
279 static void* Thread( vlc_object_t *p_this )
281 /* we don't want to be interupted in this thread */
282 int cancel = vlc_savecancel();
283 projectm_thread_t *p_thread = (projectm_thread_t *)p_this;
285 /* Initialize the opengl provider for this thread */
286 p_thread->p_opengl->pf_init( p_thread->p_opengl );
288 /* Create the projectM object */
289 p_thread->p_projectm = new projectM( p_thread->psz_config );
290 p_thread->i_buffer_size = p_thread->p_projectm->pcm()->maxsamples;
291 p_thread->p_buffer = (float*)malloc( p_thread->i_buffer_size *
294 /* TODO: Give to projectm the name of the input
295 p_thread->p_projectm->projectM_setTitle( "" ); */
297 /* Reset the dislay to get the right size */
298 p_thread->p_projectm->projectM_resetGL( p_thread->i_width,
299 p_thread->i_height );
301 while( vlc_object_alive( p_thread ) )
303 /* Manage the events */
304 p_thread->p_opengl->pf_manage( p_thread->p_opengl );
305 /* Render the image and swap the buffers */
306 vlc_mutex_lock( &p_thread->lock );
307 if( p_thread->i_nb_samples > 0 )
308 p_thread->p_projectm->pcm()->addPCMfloat( p_thread->p_buffer,
309 p_thread->i_nb_samples );
311 p_thread->p_projectm->renderFrame();
312 p_thread->p_opengl->pf_swap( p_thread->p_opengl );
313 vlc_mutex_unlock( &p_thread->lock );
315 /* TODO: use a fps limiter */
321 delete p_thread->p_projectm;
323 /* Free the openGL provider */
324 module_unneed( p_thread->p_opengl, p_thread->p_module );
325 vlc_object_detach( p_thread->p_opengl );
326 vlc_object_release( p_thread->p_opengl );
329 vlc_restorecancel( cancel );