X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvisualization%2Fprojectm.cpp;h=90ca9c8eefc3752ca381b641f3ee1ad55d4565c6;hb=6478c429a2700d129485b13069d964a202fdded9;hp=0316601f083772e69b09ebdfe44ecb55c39bf017;hpb=993a516aeb4cfb2ab6341a13e16b40fcd05d2906;p=vlc diff --git a/modules/visualization/projectm.cpp b/modules/visualization/projectm.cpp index 0316601f08..90ca9c8eef 100644 --- a/modules/visualization/projectm.cpp +++ b/modules/visualization/projectm.cpp @@ -24,11 +24,16 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif #include #include #include #include +#include +#include #include @@ -43,6 +48,15 @@ static void Close ( vlc_object_t * ); #define CONFIG_LONGTEXT N_("File that will be used to configure the projectM " \ "module.") +#define PRESET_PATH_TXT N_("projectM preset path") +#define PRESET_PATH_LONGTXT N_("Path to the projectM preset directory") + +#define TITLE_FONT_TXT N_("Title font") +#define TITLE_FONT_LONGTXT N_("Font used for the titles") + +#define MENU_FONT_TXT N_("Font menu") +#define MENU_FONT_LONGTXT N_("Font used for the menus") + #define WIDTH_TEXT N_("Video width") #define WIDTH_LONGTEXT N_("The width of the video window, in pixels.") @@ -52,14 +66,23 @@ static void Close ( vlc_object_t * ); vlc_module_begin () set_shortname( N_("projectM")) set_description( N_("libprojectM effect") ) - set_capability( "visualization", 0 ) + set_capability( "visualization2", 0 ) set_category( CAT_AUDIO ) set_subcategory( SUBCAT_AUDIO_VISUAL ) +#ifndef HAVE_PROJECTM2 add_file( "projectm-config", "/usr/share/projectM/config.inp", NULL, - CONFIG_TEXT, CONFIG_LONGTEXT, true ) - add_integer( "projectm-width", 720, NULL, WIDTH_TEXT, WIDTH_LONGTEXT, + CONFIG_TEXT, CONFIG_LONGTEXT, true ) +#else + add_file( "projectm-preset-path", "/usr/share/projectM/presets", NULL, + PRESET_PATH_TXT, PRESET_PATH_LONGTXT, true ) + add_file( "projectm-title-font", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", NULL, + TITLE_FONT_TXT, TITLE_FONT_LONGTXT, true ) + add_file( "projectm-menu-font", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono.ttf", NULL, + MENU_FONT_TXT, MENU_FONT_LONGTXT, true ) +#endif + add_integer( "projectm-width", 800, NULL, WIDTH_TEXT, WIDTH_LONGTEXT, false ) - add_integer( "projectm-height", 480, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT, + add_integer( "projectm-height", 640, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT, false ) add_shortcut( "projectm" ) set_callbacks( Open, Close ) @@ -69,17 +92,26 @@ vlc_module_end () /***************************************************************************** * Local prototypes *****************************************************************************/ -typedef struct +struct filter_sys_t { - VLC_COMMON_MEMBERS + /* */ + vlc_thread_t thread; + vlc_sem_t ready; + bool b_error; - /* video output module and opengl provider */ - vout_thread_t *p_opengl; - module_t *p_module; + /* Opengl */ + vout_thread_t *p_vout; + vout_display_t *p_vd; /* libprojectM objects */ projectM *p_projectm; +#ifndef HAVE_PROJECTM2 char *psz_config; +#else + char *psz_preset_path; + char *psz_title_font; + char *psz_menu_font; +#endif /* Window size */ int i_width; @@ -87,67 +119,18 @@ typedef struct /* audio info */ int i_channels; + + /* */ + vlc_mutex_t lock; + bool b_quit; float *p_buffer; int i_buffer_size; int i_nb_samples; - - vlc_mutex_t lock; -} projectm_thread_t; - - -struct aout_filter_sys_t -{ - projectm_thread_t *p_thread; }; -static void DoWork( aout_instance_t *, aout_filter_t *, aout_buffer_t *, - aout_buffer_t * ); -static void* Thread( vlc_object_t * ); - - -/** - * Init the openGL context - * p_thread: projectm thread object - * @return VLC_SUCCESS or vlc error codes - */ -static int initOpenGL( projectm_thread_t *p_thread ) -{ - p_thread->p_opengl = (vout_thread_t *)vlc_object_create( p_thread, - sizeof( vout_thread_t ) ); - if( !p_thread->p_opengl ) - return VLC_ENOMEM; - - vlc_object_attach( p_thread->p_opengl, p_thread ); - - /* Initialize the opengl object */ - video_format_Setup( &p_thread->p_opengl->fmt_in, VLC_CODEC_RGB32, - p_thread->i_width, p_thread->i_height, 1 ); - p_thread->p_opengl->i_window_width = p_thread->i_width; - p_thread->p_opengl->i_window_height = p_thread->i_height; - p_thread->p_opengl->render.i_width = p_thread->i_width; - p_thread->p_opengl->render.i_height = p_thread->i_height; - p_thread->p_opengl->render.i_aspect = VOUT_ASPECT_FACTOR; - p_thread->p_opengl->b_fullscreen = false; - p_thread->p_opengl->i_alignment = 0; - p_thread->p_opengl->fmt_in.i_sar_num = 1; - p_thread->p_opengl->fmt_in.i_sar_den = 1; - p_thread->p_opengl->fmt_render = p_thread->p_opengl->fmt_in; - - /* Ask for the opengl provider */ - p_thread->p_module = module_need( p_thread->p_opengl, "opengl provider", - NULL, false ); - if( !p_thread->p_module ) - { - msg_Err( p_thread, "unable to initialize OpenGL" ); - vlc_object_detach( p_thread->p_opengl ); - vlc_object_release( p_thread->p_opengl ); - return VLC_EGENERIC; - } - - return VLC_SUCCESS; -} - +static block_t *DoWork( filter_t *, block_t * ); +static void *Thread( void * ); /** * Open the module @@ -156,66 +139,64 @@ static int initOpenGL( projectm_thread_t *p_thread ) */ static int Open( vlc_object_t * p_this ) { - aout_filter_t *p_filter = (aout_filter_t *)p_this; - aout_filter_sys_t *p_sys; - projectm_thread_t *p_thread; + filter_t *p_filter = (filter_t *)p_this; + filter_sys_t *p_sys; /* Test the audio format */ - if( p_filter->input.i_format != VLC_CODEC_FL32 || - p_filter->output.i_format != VLC_CODEC_FL32 ) + if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 || + p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 ) { msg_Warn( p_filter, "bad input or output format" ); return VLC_EGENERIC; } - if( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) ) + if( !AOUT_FMTS_SIMILAR( &p_filter->fmt_in.audio, &p_filter->fmt_out.audio ) ) { msg_Warn( p_filter, "input and outut are not similar" ); return VLC_EGENERIC; } - p_filter->pf_do_work = DoWork; - p_filter->b_in_place = true; + p_filter->pf_audio_filter = DoWork; - p_sys = p_filter->p_sys = (aout_filter_sys_t*)malloc( sizeof( *p_sys ) ); + p_sys = p_filter->p_sys = (filter_sys_t*)malloc( sizeof( *p_sys ) ); if( !p_sys ) return VLC_ENOMEM; /* Create the object for the thread */ - p_sys->p_thread = p_thread = (projectm_thread_t *) - vlc_object_create( p_filter, sizeof( projectm_thread_t ) ); - vlc_object_attach( p_sys->p_thread, p_filter ); - p_thread->i_width = var_CreateGetInteger( p_filter, "projectm-width" ); - p_thread->i_height = var_CreateGetInteger( p_filter, "projectm-height" ); - - /* Create the openGL provider */ - int i_ret = initOpenGL( p_sys->p_thread ); - if( i_ret != VLC_SUCCESS ) - { - vlc_object_detach( p_sys->p_thread ); - vlc_object_release( p_sys->p_thread ); - free( p_sys ); - return i_ret; - } - - p_thread->i_channels = aout_FormatNbChannels( &p_filter->input ); - p_thread->psz_config = var_CreateGetString( p_filter, "projectm-config" ); - vlc_mutex_init( &p_thread->lock ); - p_thread->p_buffer = NULL; - p_thread->i_buffer_size = 0; - p_thread->i_nb_samples = 0; + vlc_sem_init( &p_sys->ready, 0 ); + p_sys->b_error = false; + p_sys->b_quit = false; + p_sys->i_width = var_InheritInteger( p_filter, "projectm-width" ); + p_sys->i_height = var_InheritInteger( p_filter, "projectm-height" ); + p_sys->i_channels = aout_FormatNbChannels( &p_filter->fmt_in.audio ); +#ifndef HAVE_PROJECTM2 + p_sys->psz_config = var_InheritString( p_filter, "projectm-config" ); +#else + p_sys->psz_preset_path = var_InheritString( p_filter, "projectm-preset-path" ); + p_sys->psz_title_font = var_InheritString( p_filter, "projectm-title-font" ); + p_sys->psz_menu_font = var_InheritString( p_filter, "projectm-menu-font" ); +#endif + vlc_mutex_init( &p_sys->lock ); + p_sys->p_buffer = NULL; + p_sys->i_buffer_size = 0; + p_sys->i_nb_samples = 0; /* Create the thread */ - if( vlc_thread_create( p_thread, "projectm update thread", Thread, - VLC_THREAD_PRIORITY_LOW ) ) + if( vlc_clone( &p_sys->thread, Thread, p_filter, VLC_THREAD_PRIORITY_LOW ) ) + goto error; + + vlc_sem_wait( &p_sys->ready ); + if( p_sys->b_error ) { - msg_Err( p_filter, "cannot launch the projectm thread" ); - vlc_object_detach( p_thread ); - vlc_object_release( p_thread ); - free (p_sys ); - return VLC_EGENERIC; + vlc_join( p_sys->thread, NULL ); + goto error; } return VLC_SUCCESS; + +error: + vlc_sem_destroy( &p_sys->ready ); + free (p_sys ); + return VLC_EGENERIC; } @@ -225,22 +206,29 @@ static int Open( vlc_object_t * p_this ) */ static void Close( vlc_object_t *p_this ) { - aout_filter_t *p_filter = (aout_filter_t *)p_this; - aout_filter_sys_t *p_sys = p_filter->p_sys; - projectm_thread_t *p_thread = p_sys->p_thread; + filter_t *p_filter = (filter_t *)p_this; + filter_sys_t *p_sys = p_filter->p_sys; - /* Stop the thread */ - vlc_object_kill( p_thread ); - vlc_thread_join( p_thread ); + /* Stop the thread + * XXX vlc_cleanup_push does not seems to work with C++ so no + * vlc_cancel()... */ + vlc_mutex_lock( &p_sys->lock ); + p_sys->b_quit = true; + vlc_mutex_unlock( &p_sys->lock ); - /* Free the ressources */ - vlc_mutex_destroy( &p_thread->lock ); - free( p_thread->p_buffer ); - free( p_thread->psz_config ); - - vlc_object_detach( p_thread ); - vlc_object_release( p_thread ); + vlc_join( p_sys->thread, NULL ); + /* Free the ressources */ + vlc_sem_destroy( &p_sys->ready ); + vlc_mutex_destroy( &p_sys->lock ); + free( p_sys->p_buffer ); +#ifndef HAVE_PROJECTM2 + free( p_sys->psz_config ); +#else + free( p_sys->psz_preset_path ); + free( p_sys->psz_title_font ); + free( p_sys->psz_menu_font ); +#endif free( p_sys ); } @@ -252,82 +240,188 @@ static void Close( vlc_object_t *p_this ) * @param p_in_buf: input buffer * @param p_out_buf: output buffer */ -static void DoWork( aout_instance_t *p_aout, aout_filter_t *p_filter, - aout_buffer_t *p_in_buf, aout_buffer_t *p_out_buf ) +static block_t *DoWork( filter_t *p_filter, block_t *p_in_buf ) { - projectm_thread_t *p_thread = p_filter->p_sys->p_thread; - - p_out_buf->i_nb_samples = p_in_buf->i_nb_samples; - p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes; + filter_sys_t *p_sys = p_filter->p_sys; - vlc_mutex_lock( &p_thread->lock ); - if( p_thread->i_buffer_size > 0 ) + vlc_mutex_lock( &p_sys->lock ); + if( p_sys->i_buffer_size > 0 ) { - p_thread->p_buffer[0] = 0; - p_thread->i_nb_samples = __MIN( p_thread->i_buffer_size, - p_in_buf->i_nb_samples ); - for( int i = 0; i < p_thread->i_nb_samples; i++ ) - p_thread->p_buffer[i] = p_in_buf->p_buffer[i]; + p_sys->i_nb_samples = __MIN( p_sys->i_buffer_size, + p_in_buf->i_nb_samples ); + + const float *p_src = (float*)p_in_buf->p_buffer; + for( int i = 0; i < p_sys->i_nb_samples; i++ ) + { + float v = 0; + for( int j = 0; j < p_sys->i_channels; j++ ) + v += p_src[p_sys->i_channels * i + j]; + p_sys->p_buffer[i] = v / p_sys->i_channels; + } } + vlc_mutex_unlock( &p_sys->lock ); - vlc_mutex_unlock( &p_thread->lock ); - - return; + return p_in_buf; } +/** + * Variable callback for the dummy vout + */ +static int VoutCallback( vlc_object_t *p_vout, char const *psz_name, + vlc_value_t oldv, vlc_value_t newv, void *p_data ) +{ + vout_display_t *p_vd = (vout_display_t*)p_data; + + if( !strcmp(psz_name, "fullscreen") ) + { + vout_SetDisplayFullscreen( p_vd, newv.b_bool ); + } + return VLC_SUCCESS; +} /** * ProjectM update thread which do the rendering * @param p_this: the p_thread object */ -static void* Thread( vlc_object_t *p_this ) +static void *Thread( void *p_data ) { - /* we don't want to be interupted in this thread */ + filter_t *p_filter = (filter_t*)p_data; + filter_sys_t *p_sys = p_filter->p_sys; int cancel = vlc_savecancel(); - projectm_thread_t *p_thread = (projectm_thread_t *)p_this; + video_format_t fmt; + vout_opengl_t *gl; + int i_last_width = 0; + int i_last_height = 0; +#ifdef HAVE_PROJECTM2 + projectM::Settings settings; +#endif - /* Initialize the opengl provider for this thread */ - p_thread->p_opengl->pf_init( p_thread->p_opengl ); + /* Create the openGL provider */ + p_sys->p_vout = + (vout_thread_t *)vlc_object_create( p_filter, sizeof(vout_thread_t) ); + if( !p_sys->p_vout ) + goto error; + + vlc_object_attach( p_sys->p_vout, p_filter ); + + /* */ + video_format_Init( &fmt, 0 ); + video_format_Setup( &fmt, VLC_CODEC_RGB32, + p_sys->i_width, p_sys->i_height, 0, 1 ); + fmt.i_sar_num = 1; + fmt.i_sar_den = 1; + + vout_display_state_t state; + memset( &state, 0, sizeof(state) ); + state.cfg.display.sar.num = 1; + state.cfg.display.sar.den = 1; + state.cfg.is_display_filled = true; + state.cfg.zoom.num = 1; + state.cfg.zoom.den = 1; + state.sar.num = 1; + state.sar.den = 1; + + p_sys->p_vd = vout_NewDisplay( p_sys->p_vout, &fmt, &state, "opengl", + 300000, 1000000 ); + if( !p_sys->p_vd ) + { + vlc_object_release( p_sys->p_vout ); + goto error; + } + var_Create( p_sys->p_vout, "fullscreen", VLC_VAR_BOOL ); + var_AddCallback( p_sys->p_vout, "fullscreen", VoutCallback, p_sys->p_vd ); + + gl = vout_GetDisplayOpengl( p_sys->p_vd ); + if( !gl ) + { + vout_DeleteDisplay( p_sys->p_vd, NULL ); + vlc_object_release( p_sys->p_vout ); + goto error; + } /* Create the projectM object */ - p_thread->p_projectm = new projectM( p_thread->psz_config ); - p_thread->i_buffer_size = p_thread->p_projectm->pcm()->maxsamples; - p_thread->p_buffer = (float*)malloc( p_thread->i_buffer_size * - sizeof( float ) ); +#ifndef HAVE_PROJECTM2 + p_sys->p_projectm = new projectM( p_sys->psz_config ); +#else + settings.meshX = 32; + settings.meshY = 24; + settings.fps = 35; + settings.textureSize = 1024; + settings.windowWidth = p_sys->i_width; + settings.windowHeight = p_sys->i_height; + settings.presetURL = p_sys->psz_preset_path; + settings.titleFontURL = p_sys->psz_title_font; + settings.menuFontURL = p_sys->psz_menu_font; + settings.smoothPresetDuration = 5; + settings.presetDuration = 30; + settings.beatSensitivity = 10; + settings.aspectCorrection = 1; + settings.easterEgg = 1; + settings.shuffleEnabled = 1; + p_sys->p_projectm = new projectM( settings ); +#endif + p_sys->i_buffer_size = p_sys->p_projectm->pcm()->maxsamples; + p_sys->p_buffer = (float*)calloc( p_sys->i_buffer_size, + sizeof( float ) ); - /* TODO: Give to projectm the name of the input - p_thread->p_projectm->projectM_setTitle( "" ); */ + vlc_sem_post( &p_sys->ready ); - /* Reset the dislay to get the right size */ - p_thread->p_projectm->projectM_resetGL( p_thread->i_width, - p_thread->i_height ); + /* TODO: Give to projectm the name of the input + p_sys->p_projectm->projectM_setTitle( "" ); */ - while( vlc_object_alive( p_thread ) ) + /* */ + for( ;; ) { - /* Render the image and swap the buffers */ - vlc_mutex_lock( &p_thread->lock ); - if( p_thread->i_nb_samples > 0 ) - p_thread->p_projectm->pcm()->addPCMfloat( p_thread->p_buffer, - p_thread->i_nb_samples ); - - p_thread->p_projectm->renderFrame(); - p_thread->p_opengl->pf_swap( p_thread->p_opengl ); - vlc_mutex_unlock( &p_thread->lock ); + const mtime_t i_deadline = mdate() + CLOCK_FREQ / 50; /* 50 fps max */ + /* Manage the events */ + vout_ManageDisplay( p_sys->p_vd, true ); + if( p_sys->p_vd->cfg->display.width != i_last_width || + p_sys->p_vd->cfg->display.height != i_last_height ) + { + /* FIXME it is not perfect as we will have black bands */ + vout_display_place_t place; + vout_display_PlacePicture( &place, &p_sys->p_vd->source, p_sys->p_vd->cfg, false ); + p_sys->p_projectm->projectM_resetGL( place.width, place.height ); + + i_last_width = p_sys->p_vd->cfg->display.width; + i_last_height = p_sys->p_vd->cfg->display.height; + } - /* TODO: use a fps limiter */ - msleep( 1000 ); + /* Render the image and swap the buffers */ + vlc_mutex_lock( &p_sys->lock ); + if( p_sys->i_nb_samples > 0 ) + { + p_sys->p_projectm->pcm()->addPCMfloat( p_sys->p_buffer, + p_sys->i_nb_samples ); + p_sys->i_nb_samples = 0; + } + if( p_sys->b_quit ) + { + vlc_mutex_unlock( &p_sys->lock ); + + delete p_sys->p_projectm; + vout_DeleteDisplay( p_sys->p_vd, NULL ); + vlc_object_release( p_sys->p_vout ); + return NULL; + } + vlc_mutex_unlock( &p_sys->lock ); + + p_sys->p_projectm->renderFrame(); + + /* */ + mwait( i_deadline ); + + if( !vout_opengl_Lock(gl) ) + { + vout_opengl_Swap( gl ); + vout_opengl_Unlock( gl ); + } } + abort(); - - /* Cleanup */ - delete p_thread->p_projectm; - - /* Free the openGL provider */ - module_unneed( p_thread->p_opengl, p_thread->p_module ); - vlc_object_detach( p_thread->p_opengl ); - vlc_object_release( p_thread->p_opengl ); - - - vlc_restorecancel( cancel ); +error: + p_sys->b_error = true; + vlc_sem_post( &p_sys->ready ); return NULL; } +