Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

goom.c

00001 /*****************************************************************************
00002  * goom.c: based on libgoom (see http://ios.free.fr/?page=projet&quoi=1)
00003  *****************************************************************************
00004  * Copyright (C) 2003 the VideoLAN team
00005  * $Id: goom.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *          Gildas Bazin <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <stdlib.h>                                      /* malloc(), free() */
00029 #include <string.h>                                              /* strdup() */
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  * Module descriptor
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  * Local prototypes
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     /* Audio properties */
00102     int i_channels;
00103 
00104     /* Audio samples queue */
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  * Open: open a scope effect plugin
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     /* Allocate structure */
00152     p_sys = p_filter->p_sys = malloc( sizeof( aout_filter_sys_t ) );
00153 
00154     /* Create goom thread */
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  * DoWork: process samples buffer
00208  *****************************************************************************
00209  * This function queues the audio buffer to be processed by the goom thread
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     /* Queue sample */
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  * float to s16 conversion
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  * Fill buffer
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         /* Date management */
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  * Thread:
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         /* goom_update is damn slow, so just copy data and release the lock */
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         /* Speed selection */
00344         if( speed.i_int && (++i_count % (speed.i_int+1)) ) continue;
00345 
00346         /* Frame dropping if necessary */
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  * Close: close the plugin
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     /* Stop Goom Thread */
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     /* Free data */
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 }

Generated on Tue Dec 20 10:14:59 2005 for vlc-0.8.4a by  doxygen 1.4.2