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
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <errno.h>
00031
00032 #include <vlc/vlc.h>
00033 #include <vlc/input.h>
00034 #include <vlc/aout.h>
00035 #include <vlc/vout.h>
00036 #include "aout_internal.h"
00037
00038 #ifdef USE_GOOM_TREE
00039 # ifdef OLD_GOOM
00040 # include "goom_core.h"
00041 # define PluginInfo void
00042 # define goom_update(a,b,c,d,e,f) goom_update(b,c,d,e,f)
00043 # define goom_close(a) goom_close()
00044 # define goom_init(a,b) NULL; goom_init(a,b,0); goom_set_font(0,0,0)
00045 # else
00046 # include "goom.h"
00047 # endif
00048 #else
00049 # include <goom/goom.h>
00050 #endif
00051
00052
00053
00054
00055 static int Open ( vlc_object_t * );
00056 static void Close ( vlc_object_t * );
00057
00058 #define WIDTH_TEXT N_("Goom display width")
00059 #define HEIGHT_TEXT N_("Goom display height")
00060 #define RES_LONGTEXT N_("Allows you to change the resolution of the " \
00061 "Goom display (bigger resolution will be prettier but more CPU intensive).")
00062
00063 #define SPEED_TEXT N_("Goom animation speed")
00064 #define SPEED_LONGTEXT N_("Allows you to reduce the speed of the animation " \
00065 "(default 6, max 10).")
00066
00067 #define MAX_SPEED 10
00068
00069 vlc_module_begin();
00070 set_shortname( _("Goom"));
00071 set_description( _("Goom effect") );
00072 set_category( CAT_AUDIO );
00073 set_subcategory( SUBCAT_AUDIO_VISUAL );
00074 set_capability( "visualization", 0 );
00075 add_integer( "goom-width", 320, NULL,
00076 WIDTH_TEXT, RES_LONGTEXT, VLC_FALSE );
00077 add_integer( "goom-height", 240, NULL,
00078 HEIGHT_TEXT, RES_LONGTEXT, VLC_FALSE );
00079 add_integer( "goom-speed", 6, NULL,
00080 SPEED_TEXT, SPEED_LONGTEXT, VLC_FALSE );
00081 set_callbacks( Open, Close );
00082 add_shortcut( "goom" );
00083 vlc_module_end();
00084
00085
00086
00087
00088 #define MAX_BLOCKS 100
00089 #define GOOM_DELAY 400000
00090
00091 typedef struct
00092 {
00093 VLC_COMMON_MEMBERS
00094 vout_thread_t *p_vout;
00095
00096 char *psz_title;
00097
00098 vlc_mutex_t lock;
00099 vlc_cond_t wait;
00100
00101
00102 int i_channels;
00103
00104
00105 block_t *pp_blocks[MAX_BLOCKS];
00106 int i_blocks;
00107
00108 audio_date_t date;
00109
00110 } goom_thread_t;
00111
00112 typedef struct aout_filter_sys_t
00113 {
00114 goom_thread_t *p_thread;
00115
00116 } aout_filter_sys_t;
00117
00118 static void DoWork ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
00119 aout_buffer_t * );
00120
00121 static void Thread ( vlc_object_t * );
00122
00123 static char *TitleGet( vlc_object_t * );
00124
00125
00126
00127
00128 static int Open( vlc_object_t *p_this )
00129 {
00130 aout_filter_t *p_filter = (aout_filter_t *)p_this;
00131 aout_filter_sys_t *p_sys;
00132 goom_thread_t *p_thread;
00133 vlc_value_t width, height;
00134 video_format_t fmt = {0};
00135
00136 if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2' )
00137 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
00138 {
00139 msg_Warn( p_filter, "Bad input or output format" );
00140 return VLC_EGENERIC;
00141 }
00142 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
00143 {
00144 msg_Warn( p_filter, "input and output formats are not similar" );
00145 return VLC_EGENERIC;
00146 }
00147
00148 p_filter->pf_do_work = DoWork;
00149 p_filter->b_in_place = 1;
00150
00151
00152 p_sys = p_filter->p_sys = malloc( sizeof( aout_filter_sys_t ) );
00153
00154
00155 p_sys->p_thread = p_thread =
00156 vlc_object_create( p_filter, sizeof( goom_thread_t ) );
00157 vlc_object_attach( p_thread, p_this );
00158
00159 var_Create( p_thread, "goom-width", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
00160 var_Get( p_thread, "goom-width", &width );
00161 var_Create( p_thread, "goom-height", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
00162 var_Get( p_thread, "goom-height", &height );
00163
00164 fmt.i_width = fmt.i_visible_width = width.i_int;
00165 fmt.i_height = fmt.i_visible_height = height.i_int;
00166 fmt.i_chroma = VLC_FOURCC('R','V','3','2');
00167 fmt.i_aspect = VOUT_ASPECT_FACTOR * width.i_int/height.i_int;
00168 fmt.i_sar_num = fmt.i_sar_den = 1;
00169
00170 p_thread->p_vout = vout_Request( p_filter, NULL, &fmt );
00171 if( p_thread->p_vout == NULL )
00172 {
00173 msg_Err( p_filter, "no suitable vout module" );
00174 vlc_object_detach( p_thread );
00175 vlc_object_destroy( p_thread );
00176 free( p_sys );
00177 return VLC_EGENERIC;
00178 }
00179 vlc_mutex_init( p_filter, &p_thread->lock );
00180 vlc_cond_init( p_filter, &p_thread->wait );
00181
00182 p_thread->i_blocks = 0;
00183 aout_DateInit( &p_thread->date, p_filter->output.i_rate );
00184 aout_DateSet( &p_thread->date, 0 );
00185 p_thread->i_channels = aout_FormatNbChannels( &p_filter->input );
00186
00187 p_thread->psz_title = TitleGet( VLC_OBJECT( p_filter ) );
00188
00189 if( vlc_thread_create( p_thread, "Goom Update Thread", Thread,
00190 VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
00191 {
00192 msg_Err( p_filter, "cannot lauch goom thread" );
00193 vout_Destroy( p_thread->p_vout );
00194 vlc_mutex_destroy( &p_thread->lock );
00195 vlc_cond_destroy( &p_thread->wait );
00196 if( p_thread->psz_title ) free( p_thread->psz_title );
00197 vlc_object_detach( p_thread );
00198 vlc_object_destroy( p_thread );
00199 free( p_sys );
00200 return VLC_EGENERIC;
00201 }
00202
00203 return VLC_SUCCESS;
00204 }
00205
00206
00207
00208
00209
00210
00211 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
00212 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
00213 {
00214 aout_filter_sys_t *p_sys = p_filter->p_sys;
00215 block_t *p_block;
00216
00217 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
00218 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
00219
00220
00221 vlc_mutex_lock( &p_sys->p_thread->lock );
00222 if( p_sys->p_thread->i_blocks == MAX_BLOCKS )
00223 {
00224 vlc_mutex_unlock( &p_sys->p_thread->lock );
00225 return;
00226 }
00227
00228 p_block = block_New( p_sys->p_thread, p_in_buf->i_nb_bytes );
00229 if( !p_block ) return;
00230 memcpy( p_block->p_buffer, p_in_buf->p_buffer, p_in_buf->i_nb_bytes );
00231 p_block->i_pts = p_in_buf->start_date;
00232
00233 p_sys->p_thread->pp_blocks[p_sys->p_thread->i_blocks++] = p_block;
00234
00235 vlc_cond_signal( &p_sys->p_thread->wait );
00236 vlc_mutex_unlock( &p_sys->p_thread->lock );
00237 }
00238
00239
00240
00241
00242 static inline int16_t FloatToInt16( float f )
00243 {
00244 if( f >= 1.0 )
00245 return 32767;
00246 else if( f < -1.0 )
00247 return -32768;
00248 else
00249 return (int16_t)( f * 32768.0 );
00250 }
00251
00252
00253
00254
00255 static int FillBuffer( int16_t *p_data, int *pi_data,
00256 audio_date_t *pi_date, audio_date_t *pi_date_end,
00257 goom_thread_t *p_this )
00258 {
00259 int i_samples = 0;
00260 block_t *p_block;
00261
00262 while( *pi_data < 512 )
00263 {
00264 if( !p_this->i_blocks ) return VLC_EGENERIC;
00265
00266 p_block = p_this->pp_blocks[0];
00267 i_samples = __MIN( 512 - *pi_data, p_block->i_buffer /
00268 sizeof(float) / p_this->i_channels );
00269
00270
00271 if( p_block->i_pts > 0 &&
00272 p_block->i_pts != aout_DateGet( pi_date_end ) )
00273 {
00274 aout_DateSet( pi_date_end, p_block->i_pts );
00275 }
00276 p_block->i_pts = 0;
00277
00278 aout_DateIncrement( pi_date_end, i_samples );
00279
00280 while( i_samples > 0 )
00281 {
00282 float *p_float = (float *)p_block->p_buffer;
00283
00284 p_data[*pi_data] = FloatToInt16( p_float[0] );
00285 if( p_this->i_channels > 1 )
00286 p_data[512 + *pi_data] = FloatToInt16( p_float[1] );
00287
00288 (*pi_data)++;
00289 p_block->p_buffer += (sizeof(float) * p_this->i_channels);
00290 p_block->i_buffer -= (sizeof(float) * p_this->i_channels);
00291 i_samples--;
00292 }
00293
00294 if( !p_block->i_buffer )
00295 {
00296 block_Release( p_block );
00297 p_this->i_blocks--;
00298 if( p_this->i_blocks )
00299 memmove( p_this->pp_blocks, p_this->pp_blocks + 1,
00300 p_this->i_blocks * sizeof(block_t *) );
00301 }
00302 }
00303
00304 *pi_date = *pi_date_end;
00305 *pi_data = 0;
00306 return VLC_SUCCESS;
00307 }
00308
00309
00310
00311
00312 static void Thread( vlc_object_t *p_this )
00313 {
00314 goom_thread_t *p_thread = (goom_thread_t*)p_this;
00315 vlc_value_t width, height, speed;
00316 audio_date_t i_pts;
00317 int16_t p_data[2][512];
00318 int i_data = 0, i_count = 0;
00319 PluginInfo *p_plugin_info;
00320
00321 var_Get( p_this, "goom-width", &width );
00322 var_Get( p_this, "goom-height", &height );
00323
00324 var_Create( p_thread, "goom-speed", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
00325 var_Get( p_thread, "goom-speed", &speed );
00326 speed.i_int = MAX_SPEED - speed.i_int;
00327 if( speed.i_int < 0 ) speed.i_int = 0;
00328
00329 p_plugin_info = goom_init( width.i_int, height.i_int );
00330
00331 while( !p_thread->b_die )
00332 {
00333 uint32_t *plane;
00334 picture_t *p_pic;
00335
00336
00337 vlc_mutex_lock( &p_thread->lock );
00338 if( FillBuffer( (int16_t *)p_data, &i_data, &i_pts,
00339 &p_thread->date, p_thread ) != VLC_SUCCESS )
00340 vlc_cond_wait( &p_thread->wait, &p_thread->lock );
00341 vlc_mutex_unlock( &p_thread->lock );
00342
00343
00344 if( speed.i_int && (++i_count % (speed.i_int+1)) ) continue;
00345
00346
00347 if( aout_DateGet( &i_pts ) + GOOM_DELAY <= mdate() ) continue;
00348
00349 plane = goom_update( p_plugin_info, p_data, 0, 0.0,
00350 p_thread->psz_title, NULL );
00351
00352 if( p_thread->psz_title )
00353 {
00354 free( p_thread->psz_title );
00355 p_thread->psz_title = NULL;
00356 }
00357
00358 while( !( p_pic = vout_CreatePicture( p_thread->p_vout, 0, 0, 0 ) ) &&
00359 !p_thread->b_die )
00360 {
00361 msleep( VOUT_OUTMEM_SLEEP );
00362 }
00363
00364 if( p_pic == NULL ) break;
00365
00366 memcpy( p_pic->p[0].p_pixels, plane, width.i_int * height.i_int * 4 );
00367 vout_DatePicture( p_thread->p_vout, p_pic,
00368 aout_DateGet( &i_pts ) + GOOM_DELAY );
00369 vout_DisplayPicture( p_thread->p_vout, p_pic );
00370 }
00371
00372 goom_close( p_plugin_info );
00373 }
00374
00375
00376
00377
00378 static void Close( vlc_object_t *p_this )
00379 {
00380 aout_filter_t *p_filter = (aout_filter_t *)p_this;
00381 aout_filter_sys_t *p_sys = p_filter->p_sys;
00382
00383
00384 p_sys->p_thread->b_die = VLC_TRUE;
00385
00386 vlc_mutex_lock( &p_sys->p_thread->lock );
00387 vlc_cond_signal( &p_sys->p_thread->wait );
00388 vlc_mutex_unlock( &p_sys->p_thread->lock );
00389
00390 vlc_thread_join( p_sys->p_thread );
00391
00392
00393 vout_Request( p_filter, p_sys->p_thread->p_vout, 0 );
00394 vlc_mutex_destroy( &p_sys->p_thread->lock );
00395 vlc_cond_destroy( &p_sys->p_thread->wait );
00396 vlc_object_detach( p_sys->p_thread );
00397
00398 while( p_sys->p_thread->i_blocks-- )
00399 {
00400 block_Release( p_sys->p_thread->pp_blocks[p_sys->p_thread->i_blocks] );
00401 }
00402
00403 vlc_object_destroy( p_sys->p_thread );
00404
00405 free( p_sys );
00406 }
00407
00408 static char *TitleGet( vlc_object_t *p_this )
00409 {
00410 char *psz_title = NULL;
00411 input_thread_t *p_input =
00412 vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
00413
00414 if( p_input )
00415 {
00416 char *psz = strrchr( p_input->input.p_item->psz_uri, '/' );
00417
00418 if( psz )
00419 {
00420 psz++;
00421 }
00422 else
00423 {
00424 psz = p_input->input.p_item->psz_uri;
00425 }
00426 if( psz && *psz )
00427 {
00428 psz_title = strdup( psz );
00429 }
00430 vlc_object_release( p_input );
00431 }
00432
00433 return psz_title;
00434 }