1
/*****************************************************************************
2
* goom.c: based on libgoom (see http://ios.free.fr/?page=projet&quoi=1)
3
*****************************************************************************
4
* Copyright (C) 2003 VideoLAN
5
* $Id: goom.c 7652 2004-05-13 21:13:38Z gbazin $
7
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
* Gildas Bazin <gbazin@videolan.org>
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23
*****************************************************************************/
25
/*****************************************************************************
27
*****************************************************************************/
28
#include <stdlib.h> /* malloc(), free() */
29
#include <string.h> /* strdup() */
33
#include <vlc/input.h>
36
#include "aout_internal.h"
40
# include "goom_core.h"
41
# define PluginInfo void
42
# define goom_update(a,b,c,d,e,f) goom_update(b,c,d,e,f)
43
# define goom_close(a) goom_close()
44
# define goom_init(a,b) NULL; goom_init(a,b,0); goom_set_font(0,0,0)
49
# include <goom/goom.h>
52
/*****************************************************************************
54
*****************************************************************************/
55
static int Open ( vlc_object_t * );
56
static void Close ( vlc_object_t * );
58
#define WIDTH_TEXT N_("Goom display width")
59
#define HEIGHT_TEXT N_("Goom display height")
60
#define RES_LONGTEXT N_("Allows you to change the resolution of the " \
61
"Goom display (bigger resolution will be prettier but more CPU intensive).")
63
#define SPEED_TEXT N_("Goom animation speed")
64
#define SPEED_LONGTEXT N_("Allows you to reduce the speed of the animation " \
65
"(default 6, max 10).")
70
set_description( _("Goom effect") );
71
set_capability( "audio filter", 0 );
72
add_integer( "goom-width", 320, NULL,
73
WIDTH_TEXT, RES_LONGTEXT, VLC_FALSE );
74
add_integer( "goom-height", 240, NULL,
75
HEIGHT_TEXT, RES_LONGTEXT, VLC_FALSE );
76
add_integer( "goom-speed", 6, NULL,
77
SPEED_TEXT, SPEED_LONGTEXT, VLC_FALSE );
78
set_callbacks( Open, Close );
79
add_shortcut( "goom" );
82
/*****************************************************************************
84
*****************************************************************************/
86
#define GOOM_DELAY 400000
91
vout_thread_t *p_vout;
98
/* Audio properties */
101
/* Audio samples queue */
102
block_t *pp_blocks[MAX_BLOCKS];
109
typedef struct aout_filter_sys_t
111
goom_thread_t *p_thread;
115
static void DoWork ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
118
static void Thread ( vlc_object_t * );
120
static char *TitleGet( vlc_object_t * );
122
/*****************************************************************************
123
* Open: open a scope effect plugin
124
*****************************************************************************/
125
static int Open( vlc_object_t *p_this )
127
aout_filter_t *p_filter = (aout_filter_t *)p_this;
128
aout_filter_sys_t *p_sys;
129
goom_thread_t *p_thread;
130
vlc_value_t width, height;
132
if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2' )
133
|| p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
135
msg_Warn( p_filter, "Bad input or output format" );
138
if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
140
msg_Warn( p_filter, "input and output formats are not similar" );
144
p_filter->pf_do_work = DoWork;
145
p_filter->b_in_place = 1;
147
/* Allocate structure */
148
p_sys = p_filter->p_sys = malloc( sizeof( aout_filter_sys_t ) );
150
/* Create goom thread */
151
p_sys->p_thread = p_thread =
152
vlc_object_create( p_filter, sizeof( goom_thread_t ) );
153
vlc_object_attach( p_thread, p_this );
155
var_Create( p_thread, "goom-width", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
156
var_Get( p_thread, "goom-width", &width );
157
var_Create( p_thread, "goom-height", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
158
var_Get( p_thread, "goom-height", &height );
161
vout_Request( p_filter, NULL, width.i_int, height.i_int,
162
VLC_FOURCC('R','V','3','2'),
163
VOUT_ASPECT_FACTOR * width.i_int/height.i_int );
164
if( p_thread->p_vout == NULL )
166
msg_Err( p_filter, "no suitable vout module" );
167
vlc_object_detach( p_thread );
168
vlc_object_destroy( p_thread );
172
vlc_mutex_init( p_filter, &p_thread->lock );
173
vlc_cond_init( p_filter, &p_thread->wait );
175
p_thread->i_blocks = 0;
176
aout_DateInit( &p_thread->date, p_filter->output.i_rate );
177
aout_DateSet( &p_thread->date, 0 );
178
p_thread->i_channels = aout_FormatNbChannels( &p_filter->input );
180
p_thread->psz_title = TitleGet( VLC_OBJECT( p_filter ) );
182
if( vlc_thread_create( p_thread, "Goom Update Thread", Thread,
183
VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
185
msg_Err( p_filter, "cannot lauch goom thread" );
186
vout_Destroy( p_thread->p_vout );
187
vlc_mutex_destroy( &p_thread->lock );
188
vlc_cond_destroy( &p_thread->wait );
189
if( p_thread->psz_title ) free( p_thread->psz_title );
190
vlc_object_detach( p_thread );
191
vlc_object_destroy( p_thread );
199
/*****************************************************************************
200
* DoWork: process samples buffer
201
*****************************************************************************
202
* This function queues the audio buffer to be processed by the goom thread
203
*****************************************************************************/
204
static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
205
aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
207
aout_filter_sys_t *p_sys = p_filter->p_sys;
210
p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
211
p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
214
vlc_mutex_lock( &p_sys->p_thread->lock );
215
if( p_sys->p_thread->i_blocks == MAX_BLOCKS )
217
vlc_mutex_unlock( &p_sys->p_thread->lock );
221
p_block = block_New( p_sys->p_thread, p_in_buf->i_nb_bytes );
222
if( !p_block ) return;
223
memcpy( p_block->p_buffer, p_in_buf->p_buffer, p_in_buf->i_nb_bytes );
224
p_block->i_pts = p_in_buf->start_date;
226
p_sys->p_thread->pp_blocks[p_sys->p_thread->i_blocks++] = p_block;
228
vlc_cond_signal( &p_sys->p_thread->wait );
229
vlc_mutex_unlock( &p_sys->p_thread->lock );
232
/*****************************************************************************
233
* float to s16 conversion
234
*****************************************************************************/
235
static inline int16_t FloatToInt16( float f )
242
return (int16_t)( f * 32768.0 );
245
/*****************************************************************************
247
*****************************************************************************/
248
static int FillBuffer( int16_t *p_data, int *pi_data,
249
audio_date_t *pi_date, audio_date_t *pi_date_end,
250
goom_thread_t *p_this )
255
while( *pi_data < 512 )
257
if( !p_this->i_blocks ) return VLC_EGENERIC;
259
p_block = p_this->pp_blocks[0];
260
i_samples = __MIN( 512 - *pi_data, p_block->i_buffer /
261
sizeof(float) / p_this->i_channels );
263
/* Date management */
264
if( p_block->i_pts > 0 &&
265
p_block->i_pts != aout_DateGet( pi_date_end ) )
267
aout_DateSet( pi_date_end, p_block->i_pts );
271
aout_DateIncrement( pi_date_end, i_samples );
273
while( i_samples > 0 )
275
float *p_float = (float *)p_block->p_buffer;
277
p_data[*pi_data] = FloatToInt16( p_float[0] );
278
if( p_this->i_channels > 1 )
279
p_data[512 + *pi_data] = FloatToInt16( p_float[1] );
282
p_block->p_buffer += (sizeof(float) * p_this->i_channels);
283
p_block->i_buffer -= (sizeof(float) * p_this->i_channels);
287
if( !p_block->i_buffer )
289
block_Release( p_block );
291
if( p_this->i_blocks )
292
memmove( p_this->pp_blocks, p_this->pp_blocks + 1,
293
p_this->i_blocks * sizeof(block_t *) );
297
*pi_date = *pi_date_end;
302
/*****************************************************************************
304
*****************************************************************************/
305
static void Thread( vlc_object_t *p_this )
307
goom_thread_t *p_thread = (goom_thread_t*)p_this;
308
vlc_value_t width, height, speed;
310
int16_t p_data[2][512];
311
int i_data = 0, i_count = 0;
312
PluginInfo *p_plugin_info;
314
var_Get( p_this, "goom-width", &width );
315
var_Get( p_this, "goom-height", &height );
317
var_Create( p_thread, "goom-speed", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
318
var_Get( p_thread, "goom-speed", &speed );
319
speed.i_int = MAX_SPEED - speed.i_int;
320
if( speed.i_int < 0 ) speed.i_int = 0;
322
p_plugin_info = goom_init( width.i_int, height.i_int );
324
while( !p_thread->b_die )
329
/* goom_update is damn slow, so just copy data and release the lock */
330
vlc_mutex_lock( &p_thread->lock );
331
if( FillBuffer( (int16_t *)p_data, &i_data, &i_pts,
332
&p_thread->date, p_thread ) != VLC_SUCCESS )
333
vlc_cond_wait( &p_thread->wait, &p_thread->lock );
334
vlc_mutex_unlock( &p_thread->lock );
336
/* Speed selection */
337
if( speed.i_int && (++i_count % (speed.i_int+1)) ) continue;
339
/* Frame dropping if necessary */
340
if( aout_DateGet( &i_pts ) + GOOM_DELAY <= mdate() ) continue;
342
plane = goom_update( p_plugin_info, p_data, 0, 0.0,
343
p_thread->psz_title, NULL );
345
if( p_thread->psz_title )
347
free( p_thread->psz_title );
348
p_thread->psz_title = NULL;
351
while( !( p_pic = vout_CreatePicture( p_thread->p_vout, 0, 0, 0 ) ) &&
354
msleep( VOUT_OUTMEM_SLEEP );
357
if( p_pic == NULL ) break;
359
memcpy( p_pic->p[0].p_pixels, plane, width.i_int * height.i_int * 4 );
360
vout_DatePicture( p_thread->p_vout, p_pic,
361
aout_DateGet( &i_pts ) + GOOM_DELAY );
362
vout_DisplayPicture( p_thread->p_vout, p_pic );
365
goom_close( p_plugin_info );
368
/*****************************************************************************
369
* Close: close the plugin
370
*****************************************************************************/
371
static void Close( vlc_object_t *p_this )
373
aout_filter_t *p_filter = (aout_filter_t *)p_this;
374
aout_filter_sys_t *p_sys = p_filter->p_sys;
376
/* Stop Goom Thread */
377
p_sys->p_thread->b_die = VLC_TRUE;
379
vlc_mutex_lock( &p_sys->p_thread->lock );
380
vlc_cond_signal( &p_sys->p_thread->wait );
381
vlc_mutex_unlock( &p_sys->p_thread->lock );
383
vlc_thread_join( p_sys->p_thread );
386
vout_Request( p_filter, p_sys->p_thread->p_vout, 0, 0, 0, 0 );
387
vlc_mutex_destroy( &p_sys->p_thread->lock );
388
vlc_cond_destroy( &p_sys->p_thread->wait );
389
vlc_object_detach( p_sys->p_thread );
391
while( p_sys->p_thread->i_blocks-- )
393
block_Release( p_sys->p_thread->pp_blocks[p_sys->p_thread->i_blocks] );
396
vlc_object_destroy( p_sys->p_thread );
401
static char *TitleGet( vlc_object_t *p_this )
403
char *psz_title = NULL;
404
input_thread_t *p_input =
405
vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
409
char *psz = strrchr( p_input->psz_source, '/' );
417
psz = p_input->psz_source;
421
psz_title = strdup( psz );
423
vlc_object_release( p_input );